import { log } from "@clack/prompts" import { defineCommand } from "../lib/command" import { globalOptions, globalOptionsSchema } from "../lib/global-options" import { z } from "zod" import { searchExecutionData } from "../lib/execution-data" import { renderTable } from "../lib/io" import { clearSpinner, startSpinner } from "../lib/spinner" import { output } from "../utils" const SEARCH_SCHEMA = globalOptionsSchema.extend({ limit: z.coerce.number().int().min(1).max(100).default(20), positionals: z.tuple([z.string().trim().min(1)]), }) export const searchCommand = defineCommand({ name: "search", description: "Search synchronized execution data", options: { ...globalOptions, limit: { type: "string", short: "n", default: "20", }, }, optionDescriptions: { limit: "Maximum ranked results", }, positionals: [ { name: "query", description: "Words, quoted phrases, OR expressions, or exclusions", required: true, }, ], schema: globalOptionsSchema.extend(SEARCH_SCHEMA.shape), run: searchData, }) /** * Searches the active local execution dataset and prints ranked matches. * * @param opts - Natural search query and maximum result count. */ async function searchData(opts: z.infer) { startSpinner("Searching execution data") const result = await searchExecutionData({ limit: opts.limit, query: opts.positionals[0], }) clearSpinner() output .normal(() => { log.message( renderTable({ columns: [ { header: "Rank", cell: (row) => row.rank.toFixed(3) }, { header: "Resource", cell: (row) => row.resource }, { header: "ID", cell: (row) => row.id }, { header: "Context", cell: (row) => row.context }, { header: "Timestamp", cell: (row) => row.timestamp }, { header: "Match", cell: (row) => formatSearchContent(row.content), }, ], rows: result.results, }), ) }) .json(result) } /** * Collapses and bounds one search excerpt for terminal output. * * @param content - Ranked matching excerpt. */ function formatSearchContent(content: string) { const singleLine = content.replaceAll(/\s+/g, " ").trim() return singleLine.length > 100 ? `${singleLine.slice(0, 99)}…` : singleLine }