@gmickel/gno 1.17.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -4
- package/assets/skill/SKILL.md +44 -1
- package/assets/skill/mcp-reference.md +21 -0
- package/package.json +3 -2
- package/spec/AGENTS.md +83 -0
- package/spec/CLAUDE.md +83 -0
- package/spec/bench-fixture.schema.json +137 -0
- package/spec/cli.md +2894 -0
- package/spec/db/schema.sql +442 -0
- package/spec/evals-agentic.md +510 -0
- package/spec/evals.md +1106 -0
- package/spec/mcp.md +2229 -0
- package/spec/output-schemas/activation-verification.schema.json +515 -0
- package/spec/output-schemas/ask.schema.json +366 -0
- package/spec/output-schemas/backlinks.schema.json +131 -0
- package/spec/output-schemas/bench-result.schema.json +120 -0
- package/spec/output-schemas/capture-receipt.schema.json +143 -0
- package/spec/output-schemas/collection-list.schema.json +45 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +691 -0
- package/spec/output-schemas/context-capsule-verification.schema.json +1338 -0
- package/spec/output-schemas/context-list.schema.json +21 -0
- package/spec/output-schemas/doctor.schema.json +313 -0
- package/spec/output-schemas/error.schema.json +30 -0
- package/spec/output-schemas/expansion.schema.json +37 -0
- package/spec/output-schemas/get.schema.json +140 -0
- package/spec/output-schemas/graph-query.schema.json +99 -0
- package/spec/output-schemas/graph.schema.json +371 -0
- package/spec/output-schemas/links-list.schema.json +186 -0
- package/spec/output-schemas/mcp-add-collection-result.schema.json +23 -0
- package/spec/output-schemas/mcp-capture-result.schema.json +152 -0
- package/spec/output-schemas/mcp-http-error.schema.json +30 -0
- package/spec/output-schemas/mcp-job-list.schema.json +58 -0
- package/spec/output-schemas/mcp-job-status.schema.json +224 -0
- package/spec/output-schemas/mcp-remove-result.schema.json +39 -0
- package/spec/output-schemas/mcp-sync-result.schema.json +41 -0
- package/spec/output-schemas/mcp-tag-result.schema.json +33 -0
- package/spec/output-schemas/models-list.schema.json +93 -0
- package/spec/output-schemas/multi-get.schema.json +103 -0
- package/spec/output-schemas/process-status.schema.json +119 -0
- package/spec/output-schemas/query-diagnose.schema.json +123 -0
- package/spec/output-schemas/resident-status.schema.json +154 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +492 -0
- package/spec/output-schemas/retrieval-trace-delete.schema.json +16 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +61 -0
- package/spec/output-schemas/retrieval-trace-filters.schema.json +139 -0
- package/spec/output-schemas/retrieval-trace-judgment.schema.json +15 -0
- package/spec/output-schemas/retrieval-trace-list.schema.json +18 -0
- package/spec/output-schemas/retrieval-trace-payloads.schema.json +178 -0
- package/spec/output-schemas/retrieval-trace-purge.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +303 -0
- package/spec/output-schemas/retrieval-trace-replay.schema.json +286 -0
- package/spec/output-schemas/retrieval-trace-show.schema.json +69 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +65 -0
- package/spec/output-schemas/search-result.schema.json +154 -0
- package/spec/output-schemas/search-results.schema.json +338 -0
- package/spec/output-schemas/similar.schema.json +84 -0
- package/spec/output-schemas/status.schema.json +676 -0
- package/spec/output-schemas/tags-list.schema.json +48 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +15 -1
- package/src/cli/commands/ask.ts +106 -36
- package/src/cli/commands/context-build.ts +56 -9
- package/src/cli/commands/daemon.ts +69 -2
- package/src/cli/commands/get.ts +64 -3
- package/src/cli/commands/models/pull.ts +13 -3
- package/src/cli/commands/query.ts +62 -23
- package/src/cli/commands/replay.ts +140 -0
- package/src/cli/commands/search.ts +48 -3
- package/src/cli/commands/shared.ts +3 -1
- package/src/cli/commands/status.ts +2 -0
- package/src/cli/commands/trace.ts +200 -0
- package/src/cli/commands/vsearch.ts +75 -53
- package/src/cli/detach.ts +37 -20
- package/src/cli/program.ts +329 -27
- package/src/config/index.ts +12 -0
- package/src/config/retrieval-traces.ts +56 -0
- package/src/config/types.ts +41 -0
- package/src/core/context-compiler.ts +11 -4
- package/src/core/job-manager.ts +19 -0
- package/src/core/mutation-generations.ts +33 -0
- package/src/core/retrieval-qrels.ts +405 -0
- package/src/core/retrieval-replay-candidate.ts +368 -0
- package/src/core/retrieval-replay-types.ts +109 -0
- package/src/core/retrieval-replay-validation.ts +89 -0
- package/src/core/retrieval-replay.ts +441 -0
- package/src/core/retrieval-trace-evidence-origin.ts +175 -0
- package/src/core/retrieval-trace-export.ts +113 -0
- package/src/core/retrieval-trace-filter-normalization.ts +27 -0
- package/src/core/retrieval-trace-filters.ts +19 -0
- package/src/core/retrieval-trace-management-helpers.ts +247 -0
- package/src/core/retrieval-trace-management-types.ts +132 -0
- package/src/core/retrieval-trace-management.ts +422 -0
- package/src/core/retrieval-trace-request.ts +141 -0
- package/src/core/retrieval-trace-session.ts +494 -0
- package/src/core/retrieval-trace.ts +472 -0
- package/src/llm/cache.ts +13 -3
- package/src/llm/nodeLlamaCpp/adapter.ts +10 -1
- package/src/llm/nodeLlamaCpp/lifecycle.ts +71 -0
- package/src/mcp/context.ts +161 -0
- package/src/mcp/http-security.ts +477 -0
- package/src/mcp/http-session.ts +272 -0
- package/src/mcp/http-transport.ts +370 -0
- package/src/mcp/resources/index.ts +141 -134
- package/src/mcp/server.ts +19 -79
- package/src/mcp/tools/add-collection.ts +3 -1
- package/src/mcp/tools/capture.ts +3 -0
- package/src/mcp/tools/clear-collection-embeddings.ts +2 -0
- package/src/mcp/tools/context.ts +68 -16
- package/src/mcp/tools/embed.ts +62 -52
- package/src/mcp/tools/get.ts +35 -1
- package/src/mcp/tools/index-cmd.ts +88 -74
- package/src/mcp/tools/index.ts +96 -2
- package/src/mcp/tools/query.ts +95 -64
- package/src/mcp/tools/remove-collection.ts +2 -0
- package/src/mcp/tools/search.ts +36 -13
- package/src/mcp/tools/status.ts +11 -0
- package/src/mcp/tools/sync.ts +16 -14
- package/src/mcp/tools/trace.ts +143 -0
- package/src/mcp/tools/vsearch.ts +71 -38
- package/src/mcp/tools/workspace-write.ts +7 -3
- package/src/pipeline/answer.ts +167 -26
- package/src/pipeline/graph-retrieval.ts +15 -1
- package/src/pipeline/hybrid.ts +151 -43
- package/src/pipeline/search.ts +36 -3
- package/src/pipeline/trace-metadata.ts +47 -0
- package/src/pipeline/types.ts +43 -0
- package/src/pipeline/vsearch.ts +101 -38
- package/src/sdk/client.ts +380 -71
- package/src/sdk/documents.ts +48 -1
- package/src/sdk/index.ts +17 -0
- package/src/sdk/types.ts +28 -0
- package/src/serve/background-runtime.ts +12 -212
- package/src/serve/context-capsule.ts +67 -8
- package/src/serve/embed-scheduler.ts +74 -43
- package/src/serve/index.ts +9 -0
- package/src/serve/jobs.ts +78 -80
- package/src/serve/public/app.tsx +12 -1
- package/src/serve/public/components/HealthCenter.tsx +74 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/workspace-tabs.ts +2 -0
- package/src/serve/public/pages/Dashboard.tsx +11 -0
- package/src/serve/public/pages/TraceHistory.tsx +478 -0
- package/src/serve/public/pages/trace-history-detail.tsx +224 -0
- package/src/serve/resident-admission.ts +159 -0
- package/src/serve/resident-background-work.ts +39 -0
- package/src/serve/resident-request.ts +55 -0
- package/src/serve/resident-runtime.ts +490 -0
- package/src/serve/resident-status.ts +96 -0
- package/src/serve/retrieval-trace.ts +28 -0
- package/src/serve/routes/api.ts +629 -239
- package/src/serve/routes/mcp.ts +69 -0
- package/src/serve/routes/traces.ts +156 -0
- package/src/serve/server.ts +276 -37
- package/src/serve/status-model.ts +51 -0
- package/src/serve/status.ts +5 -0
- package/src/store/index.ts +31 -0
- package/src/store/migrations/014-retrieval-traces.ts +303 -0
- package/src/store/migrations/index.ts +2 -0
- package/src/store/retrieval-trace-codec.ts +384 -0
- package/src/store/sqlite/adapter.ts +179 -10
- package/src/store/sqlite/retrieval-trace-management-store.ts +341 -0
- package/src/store/sqlite/retrieval-trace-retention.ts +349 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +267 -0
- package/src/store/sqlite/retrieval-trace-store.ts +515 -0
- package/src/store/types.ts +297 -0
- package/src/store/vector/sqlite-vec.ts +76 -1
- package/src/store/vector/types.ts +1 -1
package/src/cli/program.ts
CHANGED
|
@@ -164,6 +164,15 @@ async function writeOutput(
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/** Emit opt-in trace identity without changing command stdout payloads. */
|
|
168
|
+
export function writeRetrievalTraceReceipt(
|
|
169
|
+
metadata: { traceId: string } | undefined
|
|
170
|
+
): void {
|
|
171
|
+
if (metadata) {
|
|
172
|
+
process.stderr.write(`Trace: ${metadata.traceId}\n`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
167
176
|
async function resolveTerminalLinkPolicy(
|
|
168
177
|
format: "terminal" | "json" | "files" | "csv" | "md" | "xml"
|
|
169
178
|
): Promise<
|
|
@@ -292,6 +301,7 @@ export function createProgram(): Command {
|
|
|
292
301
|
wireOnboardingCommands(program);
|
|
293
302
|
wireCaptureCommand(program);
|
|
294
303
|
wireManagementCommands(program);
|
|
304
|
+
wireTraceCommands(program);
|
|
295
305
|
wirePublishCommand(program);
|
|
296
306
|
wireVecCommands(program);
|
|
297
307
|
wireRetrievalCommands(program);
|
|
@@ -315,6 +325,244 @@ Report issues: ${ISSUES_URL}`
|
|
|
315
325
|
return program;
|
|
316
326
|
}
|
|
317
327
|
|
|
328
|
+
function wireTraceCommands(program: Command): void {
|
|
329
|
+
const traceCmd = program
|
|
330
|
+
.command("trace")
|
|
331
|
+
.description("Inspect and manage private local retrieval traces");
|
|
332
|
+
|
|
333
|
+
const outputFormat = (options: Record<string, unknown>): "json" | "md" =>
|
|
334
|
+
getFormat(options) === "json" ? "json" : "md";
|
|
335
|
+
|
|
336
|
+
traceCmd
|
|
337
|
+
.command("list")
|
|
338
|
+
.description("List bounded, redacted retrieval trace summaries")
|
|
339
|
+
.option("-n, --limit <num>", "maximum traces", "50")
|
|
340
|
+
.option("--cursor <cursor>", "continue from a previous list receipt")
|
|
341
|
+
.option("--json", "JSON output")
|
|
342
|
+
.option("--md", "Markdown output")
|
|
343
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
344
|
+
const globals = getGlobals();
|
|
345
|
+
const { traceList } = await import("./commands/trace");
|
|
346
|
+
const output = await traceList(
|
|
347
|
+
{
|
|
348
|
+
limit: parsePositiveInt("limit", cmdOpts.limit),
|
|
349
|
+
cursor: cmdOpts.cursor as string | undefined,
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
configPath: globals.config,
|
|
353
|
+
indexName: globals.index,
|
|
354
|
+
format: outputFormat(cmdOpts),
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
process.stdout.write(output);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
traceCmd
|
|
361
|
+
.command("show <trace-id>")
|
|
362
|
+
.description("Inspect one bounded retrieval trace receipt")
|
|
363
|
+
.option("--detail-limit <num>", "maximum records per detail section", "500")
|
|
364
|
+
.option("--json", "JSON output")
|
|
365
|
+
.option("--md", "Markdown output")
|
|
366
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
367
|
+
const globals = getGlobals();
|
|
368
|
+
const { traceShow } = await import("./commands/trace");
|
|
369
|
+
const output = await traceShow(
|
|
370
|
+
traceId,
|
|
371
|
+
{
|
|
372
|
+
detailLimit: parsePositiveInt("detail-limit", cmdOpts.detailLimit),
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
configPath: globals.config,
|
|
376
|
+
indexName: globals.index,
|
|
377
|
+
format: outputFormat(cmdOpts),
|
|
378
|
+
}
|
|
379
|
+
);
|
|
380
|
+
process.stdout.write(output);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
traceCmd
|
|
384
|
+
.command("label <trace-id>")
|
|
385
|
+
.description("Append an explicit retrieval relevance judgment")
|
|
386
|
+
.requiredOption(
|
|
387
|
+
"--label <label>",
|
|
388
|
+
"relevant, irrelevant, or missing-expected"
|
|
389
|
+
)
|
|
390
|
+
.requiredOption("--target <ref>", "evidence or expected-document reference")
|
|
391
|
+
.option("--target-kind <kind>", "document, chunk, or span")
|
|
392
|
+
.option("--from-line <num>", "exact evidence start line")
|
|
393
|
+
.option("--to-line <num>", "exact evidence end line")
|
|
394
|
+
.option("--source-hash <sha256>", "expected immutable source hash")
|
|
395
|
+
.option("--docid <docid>", "expected document ID")
|
|
396
|
+
.option("--idempotency-key <key>", "caller retry key")
|
|
397
|
+
.option("--json", "JSON output")
|
|
398
|
+
.option("--md", "Markdown output")
|
|
399
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
400
|
+
const globals = getGlobals();
|
|
401
|
+
const rawLabel = String(cmdOpts.label).replace("-", "_");
|
|
402
|
+
if (!["relevant", "irrelevant", "missing_expected"].includes(rawLabel)) {
|
|
403
|
+
throw new CliError(
|
|
404
|
+
"VALIDATION",
|
|
405
|
+
"--label must be relevant, irrelevant, or missing-expected"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const rawTargetKind = cmdOpts.targetKind;
|
|
409
|
+
if (
|
|
410
|
+
rawTargetKind !== undefined &&
|
|
411
|
+
(typeof rawTargetKind !== "string" ||
|
|
412
|
+
!["document", "chunk", "span"].includes(rawTargetKind))
|
|
413
|
+
) {
|
|
414
|
+
throw new CliError(
|
|
415
|
+
"VALIDATION",
|
|
416
|
+
"--target-kind must be document, chunk, or span"
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
const { traceLabel } = await import("./commands/trace");
|
|
420
|
+
const output = await traceLabel(
|
|
421
|
+
{
|
|
422
|
+
traceId,
|
|
423
|
+
label: rawLabel as "relevant" | "irrelevant" | "missing_expected",
|
|
424
|
+
targetRef: String(cmdOpts.target),
|
|
425
|
+
targetKind: rawTargetKind as
|
|
426
|
+
| "document"
|
|
427
|
+
| "chunk"
|
|
428
|
+
| "span"
|
|
429
|
+
| undefined,
|
|
430
|
+
startLine:
|
|
431
|
+
cmdOpts.fromLine === undefined
|
|
432
|
+
? undefined
|
|
433
|
+
: parsePositiveInt("from-line", cmdOpts.fromLine),
|
|
434
|
+
endLine:
|
|
435
|
+
cmdOpts.toLine === undefined
|
|
436
|
+
? undefined
|
|
437
|
+
: parsePositiveInt("to-line", cmdOpts.toLine),
|
|
438
|
+
sourceHash: cmdOpts.sourceHash as string | undefined,
|
|
439
|
+
docid: cmdOpts.docid as string | undefined,
|
|
440
|
+
idempotencyKey: cmdOpts.idempotencyKey as string | undefined,
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
configPath: globals.config,
|
|
444
|
+
indexName: globals.index,
|
|
445
|
+
format: outputFormat(cmdOpts),
|
|
446
|
+
}
|
|
447
|
+
);
|
|
448
|
+
process.stdout.write(output);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
traceCmd
|
|
452
|
+
.command("export <trace-ids...>")
|
|
453
|
+
.description("Export immutable terminal traces as one local receipt")
|
|
454
|
+
.option("--format <format>", "agentic-receipt or qrels", "agentic-receipt")
|
|
455
|
+
.option("--output <path>", "write canonical artifact atomically")
|
|
456
|
+
.option("--json", "JSON output")
|
|
457
|
+
.action(async (traceIds: string[], cmdOpts: Record<string, unknown>) => {
|
|
458
|
+
const globals = getGlobals();
|
|
459
|
+
const exportFormat = String(cmdOpts.format);
|
|
460
|
+
if (!["agentic-receipt", "qrels"].includes(exportFormat)) {
|
|
461
|
+
throw new CliError(
|
|
462
|
+
"VALIDATION",
|
|
463
|
+
"--format must be agentic-receipt or qrels"
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
const { traceExport } = await import("./commands/trace");
|
|
467
|
+
process.stdout.write(
|
|
468
|
+
await traceExport(traceIds, {
|
|
469
|
+
configPath: globals.config,
|
|
470
|
+
indexName: globals.index,
|
|
471
|
+
format: "json",
|
|
472
|
+
output: cmdOpts.output as string | undefined,
|
|
473
|
+
exportFormat: exportFormat as "agentic-receipt" | "qrels",
|
|
474
|
+
})
|
|
475
|
+
);
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
traceCmd
|
|
479
|
+
.command("replay <export-id>")
|
|
480
|
+
.description("Compare one immutable qrels baseline with a candidate")
|
|
481
|
+
.requiredOption("--candidate <type>", "bm25, vector, or hybrid")
|
|
482
|
+
.option("-n, --limit <num>", "result cutoff")
|
|
483
|
+
.option("--candidate-limit <num>", "candidate pool size")
|
|
484
|
+
.option("--no-expand", "disable query expansion")
|
|
485
|
+
.option("--no-rerank", "disable reranking")
|
|
486
|
+
.option("--json", "JSON output")
|
|
487
|
+
.option("--md", "Markdown output")
|
|
488
|
+
.action(async (exportId: string, cmdOpts: Record<string, unknown>) => {
|
|
489
|
+
const globals = getGlobals();
|
|
490
|
+
const candidateType = String(cmdOpts.candidate);
|
|
491
|
+
if (!["bm25", "vector", "hybrid"].includes(candidateType)) {
|
|
492
|
+
throw new CliError(
|
|
493
|
+
"VALIDATION",
|
|
494
|
+
"--candidate must be bm25, vector, or hybrid"
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
const { traceReplay } = await import("./commands/replay");
|
|
498
|
+
process.stdout.write(
|
|
499
|
+
await traceReplay(
|
|
500
|
+
exportId,
|
|
501
|
+
{
|
|
502
|
+
id: `cli-${candidateType}`,
|
|
503
|
+
type: candidateType as "bm25" | "vector" | "hybrid",
|
|
504
|
+
limit:
|
|
505
|
+
cmdOpts.limit === undefined
|
|
506
|
+
? undefined
|
|
507
|
+
: parsePositiveInt("limit", cmdOpts.limit),
|
|
508
|
+
candidateLimit:
|
|
509
|
+
cmdOpts.candidateLimit === undefined
|
|
510
|
+
? undefined
|
|
511
|
+
: parsePositiveInt("candidate-limit", cmdOpts.candidateLimit),
|
|
512
|
+
noExpand: cmdOpts.expand === false,
|
|
513
|
+
noRerank: cmdOpts.rerank === false,
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
configPath: globals.config,
|
|
517
|
+
indexName: globals.index,
|
|
518
|
+
format: outputFormat(cmdOpts),
|
|
519
|
+
offline: globals.offline,
|
|
520
|
+
}
|
|
521
|
+
)
|
|
522
|
+
);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
traceCmd
|
|
526
|
+
.command("delete <trace-id>")
|
|
527
|
+
.description("Delete one trace and every owned local record")
|
|
528
|
+
.option("--json", "JSON output")
|
|
529
|
+
.option("--md", "Markdown output")
|
|
530
|
+
.action(async (traceId: string, cmdOpts: Record<string, unknown>) => {
|
|
531
|
+
const globals = getGlobals();
|
|
532
|
+
const { traceDelete } = await import("./commands/trace");
|
|
533
|
+
process.stdout.write(
|
|
534
|
+
await traceDelete(traceId, {
|
|
535
|
+
configPath: globals.config,
|
|
536
|
+
indexName: globals.index,
|
|
537
|
+
format: outputFormat(cmdOpts),
|
|
538
|
+
})
|
|
539
|
+
);
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
traceCmd
|
|
543
|
+
.command("purge")
|
|
544
|
+
.description("Delete every local retrieval trace receipt")
|
|
545
|
+
.option("--json", "JSON output")
|
|
546
|
+
.option("--md", "Markdown output")
|
|
547
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
548
|
+
const globals = getGlobals();
|
|
549
|
+
if (!globals.yes) {
|
|
550
|
+
throw new CliError(
|
|
551
|
+
"VALIDATION",
|
|
552
|
+
"Trace purge requires the global --yes confirmation"
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
const { tracePurge } = await import("./commands/trace");
|
|
556
|
+
process.stdout.write(
|
|
557
|
+
await tracePurge({
|
|
558
|
+
configPath: globals.config,
|
|
559
|
+
indexName: globals.index,
|
|
560
|
+
format: outputFormat(cmdOpts),
|
|
561
|
+
})
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
318
566
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
319
567
|
// Search Commands (search, vsearch, query, ask)
|
|
320
568
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -435,6 +683,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
435
683
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
436
684
|
});
|
|
437
685
|
await writeOutput(output, format);
|
|
686
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
438
687
|
});
|
|
439
688
|
|
|
440
689
|
// vsearch - Vector similarity search
|
|
@@ -547,6 +796,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
547
796
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
548
797
|
});
|
|
549
798
|
await writeOutput(output, format);
|
|
799
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
550
800
|
});
|
|
551
801
|
|
|
552
802
|
// query - Hybrid search with expansion and reranking
|
|
@@ -768,6 +1018,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
768
1018
|
terminalLinks: await resolveTerminalLinkPolicy(format),
|
|
769
1019
|
});
|
|
770
1020
|
await writeOutput(output, format);
|
|
1021
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
771
1022
|
});
|
|
772
1023
|
|
|
773
1024
|
// bench - Retrieval benchmark fixture runner
|
|
@@ -960,6 +1211,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
960
1211
|
showSources,
|
|
961
1212
|
});
|
|
962
1213
|
await writeOutput(output, format);
|
|
1214
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
963
1215
|
});
|
|
964
1216
|
}
|
|
965
1217
|
|
|
@@ -1191,6 +1443,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1191
1443
|
parsePositiveInt.bind(null, "limit")
|
|
1192
1444
|
)
|
|
1193
1445
|
.option("--line-numbers", "Prefix lines with numbers")
|
|
1446
|
+
.option("--trace-id <id>", "Continue an open retrieval trace")
|
|
1194
1447
|
.option("--source", "Include source metadata")
|
|
1195
1448
|
.option("--json", "JSON output")
|
|
1196
1449
|
.option("--md", "Markdown output")
|
|
@@ -1209,6 +1462,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1209
1462
|
source: Boolean(cmdOpts.source),
|
|
1210
1463
|
json: format === "json",
|
|
1211
1464
|
md: format === "md",
|
|
1465
|
+
traceId: cmdOpts.traceId as string | undefined,
|
|
1212
1466
|
});
|
|
1213
1467
|
|
|
1214
1468
|
if (!result.success) {
|
|
@@ -1225,6 +1479,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
1225
1479
|
md: format === "md",
|
|
1226
1480
|
})}\n`
|
|
1227
1481
|
);
|
|
1482
|
+
writeRetrievalTraceReceipt(result.metadata);
|
|
1228
1483
|
});
|
|
1229
1484
|
|
|
1230
1485
|
// multi-get - Retrieve multiple documents
|
|
@@ -2806,20 +3061,46 @@ function wireGraphCommand(program: Command): void {
|
|
|
2806
3061
|
// Serve Command (web UI)
|
|
2807
3062
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2808
3063
|
|
|
2809
|
-
function
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
3064
|
+
function addGatewayOptions(
|
|
3065
|
+
command: Command,
|
|
3066
|
+
hostDescription = "HTTP listen address (default: 127.0.0.1)"
|
|
3067
|
+
): Command {
|
|
3068
|
+
return command
|
|
3069
|
+
.option("--host <address>", hostDescription)
|
|
3070
|
+
.option("--mcp-token-file <path>", "restrictive bearer token file")
|
|
2813
3071
|
.option(
|
|
2814
|
-
"--
|
|
2815
|
-
"
|
|
3072
|
+
"--mcp-allowed-host <host>",
|
|
3073
|
+
"exact allowed Host header (repeatable)",
|
|
3074
|
+
(value: string, previous: string[] = []) => [...previous, value]
|
|
2816
3075
|
)
|
|
2817
|
-
// Local `--json` so `gno daemon --status --json` parses cleanly in any
|
|
2818
|
-
// argv position. Mirrors the serve wiring: gated to --status only.
|
|
2819
3076
|
.option(
|
|
2820
|
-
"--
|
|
2821
|
-
"
|
|
3077
|
+
"--mcp-allowed-origin <origin>",
|
|
3078
|
+
"exact allowed Origin (repeatable)",
|
|
3079
|
+
(value: string, previous: string[] = []) => [...previous, value]
|
|
3080
|
+
)
|
|
3081
|
+
.option(
|
|
3082
|
+
"--mcp-enable-write",
|
|
3083
|
+
"authorize HTTP MCP mutation tools (independent of authentication)"
|
|
2822
3084
|
);
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
function wireDaemonCommand(program: Command): void {
|
|
3088
|
+
const daemonCmd = addGatewayOptions(
|
|
3089
|
+
program
|
|
3090
|
+
.command("daemon")
|
|
3091
|
+
.description("Start headless continuous indexing")
|
|
3092
|
+
.option("-p, --port <num>", "MCP gateway port", "3000")
|
|
3093
|
+
.option(
|
|
3094
|
+
"--no-sync-on-start",
|
|
3095
|
+
"skip initial sync and only watch future file changes"
|
|
3096
|
+
)
|
|
3097
|
+
// Local `--json` so `gno daemon --status --json` parses cleanly in any
|
|
3098
|
+
// argv position. Mirrors the serve wiring: gated to --status only.
|
|
3099
|
+
.option(
|
|
3100
|
+
"--json",
|
|
3101
|
+
"JSON output (applies to --status; see process-status schema)"
|
|
3102
|
+
)
|
|
3103
|
+
);
|
|
2823
3104
|
|
|
2824
3105
|
// --detach / --status / --stop are mutually exclusive. Use Commander's
|
|
2825
3106
|
// Option API so the conflict error is the native "option '--status'
|
|
@@ -2873,8 +3154,8 @@ function wireDaemonCommand(program: Command): void {
|
|
|
2873
3154
|
* the foreground + detached-child paths boot the runtime.
|
|
2874
3155
|
*
|
|
2875
3156
|
* Mirrors `handleServeAction` exactly — same helper imports, same JSON
|
|
2876
|
-
* gating, same detached-child verification + pid-file cleanup. Daemon
|
|
2877
|
-
*
|
|
3157
|
+
* gating, same detached-child verification + pid-file cleanup. Daemon's port
|
|
3158
|
+
* identifies its headless MCP gateway.
|
|
2878
3159
|
*/
|
|
2879
3160
|
async function handleDaemonAction(
|
|
2880
3161
|
cmdOpts: Record<string, unknown>,
|
|
@@ -2927,7 +3208,9 @@ async function handleDaemonAction(
|
|
|
2927
3208
|
}
|
|
2928
3209
|
|
|
2929
3210
|
if (cmdOpts.detach) {
|
|
3211
|
+
const port = parsePositiveInt("port", cmdOpts.port);
|
|
2930
3212
|
await runDaemonDetach({
|
|
3213
|
+
port,
|
|
2931
3214
|
paths,
|
|
2932
3215
|
spawnDetached,
|
|
2933
3216
|
argv: resolveCliArgv(cmd),
|
|
@@ -2954,6 +3237,8 @@ async function handleDaemonAction(
|
|
|
2954
3237
|
installPidFileCleanup(paths.pidFile);
|
|
2955
3238
|
}
|
|
2956
3239
|
|
|
3240
|
+
const port = parsePositiveInt("port", cmdOpts.port);
|
|
3241
|
+
|
|
2957
3242
|
const { daemon } = await import("./commands/daemon.js");
|
|
2958
3243
|
const result = await daemon({
|
|
2959
3244
|
configPath: globals.config,
|
|
@@ -2962,6 +3247,12 @@ async function handleDaemonAction(
|
|
|
2962
3247
|
verbose: globals.verbose,
|
|
2963
3248
|
quiet: globals.quiet,
|
|
2964
3249
|
noSyncOnStart: cmdOpts.syncOnStart === false,
|
|
3250
|
+
port,
|
|
3251
|
+
host: cmdOpts.host as string | undefined,
|
|
3252
|
+
tokenFile: cmdOpts.mcpTokenFile as string | undefined,
|
|
3253
|
+
allowedHosts: cmdOpts.mcpAllowedHost as string[] | undefined,
|
|
3254
|
+
allowedOrigins: cmdOpts.mcpAllowedOrigin as string[] | undefined,
|
|
3255
|
+
enableWrite: cmdOpts.mcpEnableWrite === true ? true : undefined,
|
|
2965
3256
|
});
|
|
2966
3257
|
if (!result.success) {
|
|
2967
3258
|
throw new CliError("RUNTIME", result.error);
|
|
@@ -2995,8 +3286,9 @@ async function runDaemonStatus(deps: DaemonStatusDeps): Promise<void> {
|
|
|
2995
3286
|
process.stdout.write("gno daemon status\n");
|
|
2996
3287
|
process.stdout.write(`${"─".repeat(50)}\n`);
|
|
2997
3288
|
if (status.running) {
|
|
2998
|
-
|
|
2999
|
-
|
|
3289
|
+
process.stdout.write(
|
|
3290
|
+
` running yes (pid ${status.pid}, port ${status.port})\n`
|
|
3291
|
+
);
|
|
3000
3292
|
if (status.version) {
|
|
3001
3293
|
process.stdout.write(` version ${status.version}\n`);
|
|
3002
3294
|
}
|
|
@@ -3091,6 +3383,7 @@ async function runDaemonStop(deps: DaemonStopDeps): Promise<void> {
|
|
|
3091
3383
|
}
|
|
3092
3384
|
|
|
3093
3385
|
interface DaemonDetachDeps {
|
|
3386
|
+
port: number;
|
|
3094
3387
|
paths: { pidFile: string; logFile: string };
|
|
3095
3388
|
spawnDetached: typeof import("./detach.js").spawnDetached;
|
|
3096
3389
|
/**
|
|
@@ -3111,24 +3404,28 @@ async function runDaemonDetach(deps: DaemonDetachDeps): Promise<void> {
|
|
|
3111
3404
|
argv: childArgv,
|
|
3112
3405
|
pidFile: deps.paths.pidFile,
|
|
3113
3406
|
logFile: deps.paths.logFile,
|
|
3407
|
+
port: deps.port,
|
|
3114
3408
|
});
|
|
3115
|
-
// Daemon
|
|
3409
|
+
// Daemon has no Web UI URL; its listener exists solely for MCP.
|
|
3116
3410
|
process.stdout.write(`PID ${result.pid}\n`);
|
|
3117
3411
|
}
|
|
3118
3412
|
|
|
3119
3413
|
function wireServeCommand(program: Command): void {
|
|
3120
|
-
const serveCmd =
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3414
|
+
const serveCmd = addGatewayOptions(
|
|
3415
|
+
program
|
|
3416
|
+
.command("serve")
|
|
3417
|
+
.description("Start web UI server")
|
|
3418
|
+
.option("-p, --port <num>", "port to listen on", "3000")
|
|
3419
|
+
// Local `--json` so `gno serve --status --json` parses cleanly in any
|
|
3420
|
+
// argv position. Global `--json` already exists on the root program
|
|
3421
|
+
// (see line 208); resolution goes through `getFormat()` /
|
|
3422
|
+
// `getGlobals()` which precedence-merges local over global.
|
|
3423
|
+
.option(
|
|
3424
|
+
"--json",
|
|
3425
|
+
"JSON output (applies to --status; see process-status schema)"
|
|
3426
|
+
),
|
|
3427
|
+
"loopback HTTP listen address (default: 127.0.0.1)"
|
|
3428
|
+
);
|
|
3132
3429
|
|
|
3133
3430
|
// --detach / --status / --stop are mutually exclusive. Use Commander's
|
|
3134
3431
|
// Option API so the conflict error is the native "option '--status'
|
|
@@ -3275,6 +3572,11 @@ async function handleServeAction(
|
|
|
3275
3572
|
port,
|
|
3276
3573
|
configPath: globals.config,
|
|
3277
3574
|
index: globals.index,
|
|
3575
|
+
host: cmdOpts.host as string | undefined,
|
|
3576
|
+
tokenFile: cmdOpts.mcpTokenFile as string | undefined,
|
|
3577
|
+
allowedHosts: cmdOpts.mcpAllowedHost as string[] | undefined,
|
|
3578
|
+
allowedOrigins: cmdOpts.mcpAllowedOrigin as string[] | undefined,
|
|
3579
|
+
enableWrite: cmdOpts.mcpEnableWrite === true ? true : undefined,
|
|
3278
3580
|
});
|
|
3279
3581
|
|
|
3280
3582
|
if (!result.success) {
|
package/src/config/index.ts
CHANGED
|
@@ -50,6 +50,8 @@ export {
|
|
|
50
50
|
CollectionSchema,
|
|
51
51
|
type Config,
|
|
52
52
|
ConfigSchema,
|
|
53
|
+
HttpGatewayConfigSchema,
|
|
54
|
+
HttpGatewayLimitsSchema,
|
|
53
55
|
CONTENT_TYPE_GRAPH_HINTS,
|
|
54
56
|
type ContentTypeConfig,
|
|
55
57
|
type ContentTypeGraphHint,
|
|
@@ -67,3 +69,13 @@ export {
|
|
|
67
69
|
type ScopeType,
|
|
68
70
|
ScopeTypeSchema,
|
|
69
71
|
} from "./types";
|
|
72
|
+
export type { HttpGatewayConfig } from "./types";
|
|
73
|
+
export {
|
|
74
|
+
RETRIEVAL_TRACE_DEFAULT_RETENTION,
|
|
75
|
+
type RetrievalTraceConfig,
|
|
76
|
+
RetrievalTraceConfigSchema,
|
|
77
|
+
type RetrievalTraceRedactionMode,
|
|
78
|
+
RetrievalTraceRedactionModeSchema,
|
|
79
|
+
type RetrievalTraceRetention,
|
|
80
|
+
RetrievalTraceRetentionSchema,
|
|
81
|
+
} from "./retrieval-traces";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Opt-in retrieval trace configuration and bounded-retention defaults. */
|
|
2
|
+
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
|
|
5
|
+
export const RETRIEVAL_TRACE_DEFAULT_RETENTION = {
|
|
6
|
+
maxAgeDays: 30,
|
|
7
|
+
maxTraces: 1_000,
|
|
8
|
+
maxRecordsPerTrace: 10_000,
|
|
9
|
+
maxBytes: 16 * 1024 * 1024,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const RetrievalTraceRetentionSchema = z
|
|
13
|
+
.object({
|
|
14
|
+
maxAgeDays: z.number().int().min(1).max(3_650),
|
|
15
|
+
maxTraces: z.number().int().min(1).max(1_000_000),
|
|
16
|
+
maxRecordsPerTrace: z.number().int().min(1).max(100_000),
|
|
17
|
+
maxBytes: z
|
|
18
|
+
.number()
|
|
19
|
+
.int()
|
|
20
|
+
.min(64 * 1024)
|
|
21
|
+
.max(1024 * 1024 * 1024),
|
|
22
|
+
})
|
|
23
|
+
.strict();
|
|
24
|
+
|
|
25
|
+
export const RetrievalTraceRedactionModeSchema = z.enum(["metadata", "replay"]);
|
|
26
|
+
|
|
27
|
+
const DisabledRetrievalTraceConfigSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
enabled: z.literal(false),
|
|
30
|
+
})
|
|
31
|
+
.strict();
|
|
32
|
+
|
|
33
|
+
const EnabledRetrievalTraceConfigSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
enabled: z.literal(true),
|
|
36
|
+
/**
|
|
37
|
+
* `replay` stores replay inputs such as the raw query and filters. Choosing
|
|
38
|
+
* it is explicit consent; the safer metadata-only projection is recommended.
|
|
39
|
+
*/
|
|
40
|
+
redactionMode: RetrievalTraceRedactionModeSchema,
|
|
41
|
+
retention: RetrievalTraceRetentionSchema,
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
44
|
+
|
|
45
|
+
export const RetrievalTraceConfigSchema = z.discriminatedUnion("enabled", [
|
|
46
|
+
DisabledRetrievalTraceConfigSchema,
|
|
47
|
+
EnabledRetrievalTraceConfigSchema,
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
export type RetrievalTraceConfig = z.infer<typeof RetrievalTraceConfigSchema>;
|
|
51
|
+
export type RetrievalTraceRetention = z.infer<
|
|
52
|
+
typeof RetrievalTraceRetentionSchema
|
|
53
|
+
>;
|
|
54
|
+
export type RetrievalTraceRedactionMode = z.infer<
|
|
55
|
+
typeof RetrievalTraceRedactionModeSchema
|
|
56
|
+
>;
|
package/src/config/types.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
10
10
|
import { URI_PREFIX } from "../app/constants";
|
|
11
|
+
import { RetrievalTraceConfigSchema } from "./retrieval-traces";
|
|
11
12
|
|
|
12
13
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
14
|
// Constants
|
|
@@ -245,6 +246,40 @@ export const ModelConfigSchema = z.object({
|
|
|
245
246
|
|
|
246
247
|
export type ModelConfig = z.infer<typeof ModelConfigSchema>;
|
|
247
248
|
|
|
249
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
250
|
+
// Resident HTTP gateway schema
|
|
251
|
+
// ────────────────────────────────────────────────────────────────────────────
|
|
252
|
+
|
|
253
|
+
export const HttpGatewayLimitsSchema = z.object({
|
|
254
|
+
maxBodyBytes: z
|
|
255
|
+
.number()
|
|
256
|
+
.int()
|
|
257
|
+
.min(1)
|
|
258
|
+
.max(16 * 1024 * 1024)
|
|
259
|
+
.optional(),
|
|
260
|
+
maxRequestsPerMinute: z.number().int().min(1).max(100_000).optional(),
|
|
261
|
+
maxConcurrentRequests: z.number().int().min(1).max(10_000).optional(),
|
|
262
|
+
maxQueuedRequests: z.number().int().min(0).max(10_000).optional(),
|
|
263
|
+
maxSessions: z.number().int().min(1).max(10_000).optional(),
|
|
264
|
+
sessionIdleTimeoutMs: z.number().int().min(1_000).optional(),
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
export const HttpGatewayConfigSchema = z.object({
|
|
268
|
+
/** Literal listen address. Defaults to IPv4 loopback. */
|
|
269
|
+
host: z.string().min(1).optional(),
|
|
270
|
+
/** Bearer token file. Required for wildcard/non-loopback binding. */
|
|
271
|
+
tokenFile: z.string().min(1).optional(),
|
|
272
|
+
/** Exact Host header allowlist. */
|
|
273
|
+
allowedHosts: z.array(z.string().min(1)).optional(),
|
|
274
|
+
/** Exact Origin allowlist. Origin-less non-browser clients remain supported. */
|
|
275
|
+
allowedOrigins: z.array(z.string().min(1)).optional(),
|
|
276
|
+
/** Separate mutation authorization; authentication alone never enables it. */
|
|
277
|
+
enableWrite: z.boolean().optional(),
|
|
278
|
+
limits: HttpGatewayLimitsSchema.optional(),
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
export type HttpGatewayConfig = z.infer<typeof HttpGatewayConfigSchema>;
|
|
282
|
+
|
|
248
283
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
249
284
|
// Content Type Schema
|
|
250
285
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -301,6 +336,12 @@ export const ConfigSchema = z.object({
|
|
|
301
336
|
|
|
302
337
|
/** Model configuration */
|
|
303
338
|
models: ModelConfigSchema.optional(),
|
|
339
|
+
|
|
340
|
+
/** Resident Streamable HTTP MCP gateway configuration */
|
|
341
|
+
gateway: HttpGatewayConfigSchema.optional(),
|
|
342
|
+
|
|
343
|
+
/** Private local retrieval trace recording. Absent means recording off. */
|
|
344
|
+
retrievalTraces: RetrievalTraceConfigSchema.optional(),
|
|
304
345
|
});
|
|
305
346
|
|
|
306
347
|
export type Config = Omit<z.infer<typeof ConfigSchema>, "contentTypes"> & {
|
|
@@ -29,6 +29,7 @@ import type { ContextConfiguredGuidance } from "./context-guidance";
|
|
|
29
29
|
import { decorateUriForIndex } from "../app/constants";
|
|
30
30
|
import { canonicalizeIndexName } from "../app/index-name";
|
|
31
31
|
import { resolveTemporalRange } from "../pipeline/temporal";
|
|
32
|
+
import { attachSearchResultPlannerMetadata } from "../pipeline/trace-metadata";
|
|
32
33
|
import {
|
|
33
34
|
SEARCH_RESULT_PLANNER_METADATA,
|
|
34
35
|
type SearchResultPlannerMetadata,
|
|
@@ -363,10 +364,16 @@ export const planContextEvidence = async <T, P>(
|
|
|
363
364
|
}
|
|
364
365
|
const decoratedResults = responses
|
|
365
366
|
.flatMap((response) => response.results)
|
|
366
|
-
.map((result) =>
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
.map((result) => {
|
|
368
|
+
const decorated = {
|
|
369
|
+
...result,
|
|
370
|
+
uri: decorateUriForIndex(result.uri, indexName),
|
|
371
|
+
};
|
|
372
|
+
const metadata = result[SEARCH_RESULT_PLANNER_METADATA];
|
|
373
|
+
return metadata
|
|
374
|
+
? attachSearchResultPlannerMetadata(decorated, metadata)
|
|
375
|
+
: decorated;
|
|
376
|
+
});
|
|
370
377
|
const results = decoratedResults
|
|
371
378
|
.map((result, index) => ({
|
|
372
379
|
result,
|