diff --git a/packages/agentctx/src/cli/search.ts b/packages/agentctx/src/cli/search.ts index 61b05d8..63bff74 100644 --- a/packages/agentctx/src/cli/search.ts +++ b/packages/agentctx/src/cli/search.ts @@ -8,6 +8,7 @@ */ import { existsSync } from "node:fs"; import { parseArgs } from "node:util"; +import { SEARCH_LIMIT_DEFAULT, SEARCH_LIMIT_MAX } from "../mcp/tools.js"; import { openDatabase } from "../storage/db.js"; import { resolveProjectId } from "../storage/namespace.js"; import { searchRecords } from "../storage/search.js"; @@ -18,10 +19,7 @@ export const SEARCH_USAGE = `Usage: agentctx search [options] Options: --type restrict to one record type (${RECORD_TYPES.join(", ")}) - --limit maximum results (default 10, max 50)`; - -const LIMIT_DEFAULT = 10; -const LIMIT_MAX = 50; + --limit maximum results (default ${SEARCH_LIMIT_DEFAULT}, max ${SEARCH_LIMIT_MAX})`; export async function runSearch(env: CliEnv, args: string[]): Promise { if (args.includes("--help")) { @@ -53,11 +51,11 @@ export async function runSearch(env: CliEnv, args: string[]): Promise { } type = values.type as RecordType; } - let limit = LIMIT_DEFAULT; + let limit = SEARCH_LIMIT_DEFAULT; if (values.limit !== undefined) { const parsed = Number(values.limit); - if (!Number.isInteger(parsed) || parsed < 1 || parsed > LIMIT_MAX) { - env.io.err(`agentctx search: --limit must be an integer between 1 and ${LIMIT_MAX}`); + if (!Number.isInteger(parsed) || parsed < 1 || parsed > SEARCH_LIMIT_MAX) { + env.io.err(`agentctx search: --limit must be an integer between 1 and ${SEARCH_LIMIT_MAX}`); return 1; } limit = parsed; diff --git a/packages/agentctx/test/cli/commands.test.ts b/packages/agentctx/test/cli/commands.test.ts index 81f58e4..cb5a9b4 100644 --- a/packages/agentctx/test/cli/commands.test.ts +++ b/packages/agentctx/test/cli/commands.test.ts @@ -139,6 +139,35 @@ describe("agentctx config", () => { }); }); +describe("agentctx search", () => { + it("rejects limits above the shared MCP/SPEC cap", async () => { + await main(["init", "--no-profile", "--no-mcp"], t.env); + + expect(await main(["search", "caching", "--limit", "16"], t.env)).toBe(1); + expect(t.stderr.join("\n")).toContain("between 1 and 15"); + }); + + it("accepts the documented max limit", async () => { + await main(["init", "--no-profile", "--no-mcp"], t.env); + const projectId = resolveProjectId(t.env.cwd); + + const db = openDatabase(t.env.dbPath); + for (let i = 0; i < 20; i++) { + insertRecord(db, { + projectId, + type: "decision", + title: `Decision ${i}`, + body: `caching detail ${i}`, + source: "cli", + }); + } + db.close(); + + expect(await main(["search", "caching", "--limit", "15"], t.env)).toBe(0); + expect(t.stdout.filter((line) => line.includes("Decision "))).toHaveLength(15); + }); +}); + describe("agentctx reset", () => { it("deletes only the current project's records, after confirmation", async () => { await main(["init", "--no-profile", "--no-mcp"], t.env);