@gmickel/gno 1.27.1 → 1.29.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 +46 -20
- package/assets/skill/SKILL.md +59 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.29.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-b2zm0jjd.js +50 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +6 -6
- package/package.json +2 -2
- package/spec/cli.md +82 -5
- package/spec/db/schema.sql +31 -0
- package/spec/mcp.md +71 -0
- package/spec/output-schemas/ask.schema.json +156 -1
- package/spec/output-schemas/browser-clip-preview.schema.json +30 -0
- package/spec/output-schemas/collection-egress-check.schema.json +91 -0
- package/spec/output-schemas/collection-egress-policy-set.schema.json +56 -0
- package/spec/output-schemas/collection-egress-policy.schema.json +41 -0
- package/spec/output-schemas/context-capsule-v1.schema.json +183 -3
- package/spec/output-schemas/context-capsule-verification.schema.json +1 -1
- package/spec/output-schemas/egress-audit-management.schema.json +88 -0
- package/spec/output-schemas/get.schema.json +94 -0
- package/spec/output-schemas/mcp-http-error.schema.json +113 -2
- package/spec/output-schemas/mcp-job-status.schema.json +28 -0
- package/spec/output-schemas/multi-get.schema.json +128 -0
- package/spec/output-schemas/publish-artifact.schema.json +32 -0
- package/spec/output-schemas/record-import.schema.json +223 -0
- package/spec/output-schemas/retrieval-trace-common.schema.json +31 -0
- package/spec/output-schemas/retrieval-trace-export.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-qrels.schema.json +3 -0
- package/spec/output-schemas/retrieval-trace-summary.schema.json +4 -0
- package/spec/output-schemas/search-result.schema.json +94 -0
- package/spec/output-schemas/search-results.schema.json +155 -0
- package/spec/project-profile.schema.json +66 -0
- package/src/app/context-format.ts +1 -1
- package/src/app/context-runtime-contract.ts +16 -7
- package/src/cli/commands/ask.ts +7 -0
- package/src/cli/commands/collection/index.ts +5 -0
- package/src/cli/commands/collection/policy.ts +126 -0
- package/src/cli/commands/context-build.ts +5 -0
- package/src/cli/commands/daemon.ts +45 -3
- package/src/cli/commands/egress-audit.ts +68 -0
- package/src/cli/commands/embed.ts +2 -0
- package/src/cli/commands/get.ts +12 -2
- package/src/cli/commands/index-cmd.ts +13 -0
- package/src/cli/commands/multi-get.ts +9 -2
- package/src/cli/commands/query.ts +12 -0
- package/src/cli/commands/replay.ts +13 -3
- package/src/cli/commands/shared.ts +28 -0
- package/src/cli/commands/update.ts +5 -0
- package/src/cli/commands/vsearch.ts +3 -1
- package/src/cli/program.ts +127 -0
- package/src/config/index.ts +9 -0
- package/src/config/project-profile.ts +2 -0
- package/src/config/types.ts +66 -0
- package/src/converters/adapters/browser-export/adapter.ts +199 -0
- package/src/converters/adapters/browser-export/formats.ts +358 -0
- package/src/converters/adapters/email/adapter.ts +429 -0
- package/src/converters/adapters/email/html.ts +162 -0
- package/src/converters/adapters/email/mime.ts +454 -0
- package/src/converters/adapters/email/parameters.ts +77 -0
- package/src/converters/adapters/ical/adapter.ts +475 -0
- package/src/converters/adapters/ical/recurrence.ts +186 -0
- package/src/converters/adapters/jsonl/adapter.ts +238 -0
- package/src/converters/adapters/jsonl/config.ts +105 -0
- package/src/converters/adapters/shared/html-text.ts +165 -0
- package/src/converters/adapters/shared/record-utils.ts +79 -0
- package/src/converters/adapters/shared/utf8-lines.ts +141 -0
- package/src/converters/adapters/transcript/adapter.ts +295 -0
- package/src/converters/adapters/transcript/json.ts +184 -0
- package/src/converters/adapters/transcript/model.ts +171 -0
- package/src/converters/adapters/transcript/text.ts +58 -0
- package/src/converters/adapters/transcript/timed.ts +152 -0
- package/src/converters/index.ts +11 -1
- package/src/converters/mime.ts +8 -0
- package/src/converters/pipeline.ts +15 -1
- package/src/converters/registry.ts +37 -1
- package/src/converters/types.ts +136 -0
- package/src/core/browser-clip.ts +16 -1
- package/src/core/collection-egress-policy-projection.ts +28 -0
- package/src/core/collection-egress-policy-service.ts +443 -0
- package/src/core/collection-egress-policy-validation.ts +242 -0
- package/src/core/config-mutation.ts +31 -19
- package/src/core/context-capsule-schema.ts +198 -1
- package/src/core/context-capsule-validation.ts +4 -4
- package/src/core/context-capsule-verification.ts +5 -1
- package/src/core/context-capsule.ts +177 -112
- package/src/core/context-evidence.ts +93 -15
- package/src/core/destination-classifier.ts +402 -0
- package/src/core/document-capabilities.ts +12 -0
- package/src/core/egress-audit.ts +239 -0
- package/src/core/egress-authorization.ts +50 -0
- package/src/core/egress-enforcement.ts +264 -0
- package/src/core/egress-policy.ts +440 -0
- package/src/core/egress-provenance.ts +336 -0
- package/src/core/job-manager.ts +37 -0
- package/src/core/network-boundary-inventory.ts +261 -0
- package/src/core/project-profile-apply-state.ts +5 -0
- package/src/core/project-profile.ts +4 -0
- package/src/core/record-metadata.ts +49 -0
- package/src/core/retrieval-qrels.ts +6 -0
- package/src/core/retrieval-replay.ts +18 -4
- package/src/core/retrieval-trace-export.ts +23 -4
- package/src/core/retrieval-trace-management-helpers.ts +1 -0
- package/src/core/retrieval-trace-management-types.ts +3 -0
- package/src/core/retrieval-trace-management.ts +9 -1
- package/src/core/retrieval-trace-session.ts +94 -0
- package/src/core/retrieval-trace.ts +22 -0
- package/src/ingestion/record-adapter-canonical.ts +433 -0
- package/src/ingestion/record-adapter.ts +448 -0
- package/src/ingestion/record-container.ts +704 -0
- package/src/ingestion/record-path.ts +20 -0
- package/src/ingestion/record-sync.ts +70 -0
- package/src/ingestion/sync.ts +243 -36
- package/src/ingestion/types.ts +71 -1
- package/src/ingestion/walker.ts +31 -11
- package/src/llm/errors.ts +10 -0
- package/src/llm/http-inference.ts +175 -0
- package/src/llm/http-policy.ts +537 -0
- package/src/llm/httpEmbedding.ts +47 -28
- package/src/llm/httpGeneration.ts +31 -18
- package/src/llm/httpRerank.ts +30 -18
- package/src/llm/index.ts +1 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +55 -20
- package/src/llm/pinned-http-connection.ts +177 -0
- package/src/mcp/context.ts +53 -1
- package/src/mcp/http-egress.ts +220 -0
- package/src/mcp/http-security.ts +32 -21
- package/src/mcp/http-session.ts +13 -2
- package/src/mcp/http-transport.ts +96 -6
- package/src/mcp/sync-egress.ts +24 -0
- package/src/mcp/tools/add-collection.ts +4 -0
- package/src/mcp/tools/ask.ts +1 -1
- package/src/mcp/tools/context.ts +9 -2
- package/src/mcp/tools/egress.ts +247 -0
- package/src/mcp/tools/embed.ts +1 -0
- package/src/mcp/tools/get.ts +10 -2
- package/src/mcp/tools/index-cmd.ts +7 -0
- package/src/mcp/tools/index.ts +98 -0
- package/src/mcp/tools/multi-get.ts +9 -2
- package/src/mcp/tools/query.ts +10 -0
- package/src/mcp/tools/remove-collection.ts +4 -0
- package/src/mcp/tools/sync.ts +6 -0
- package/src/mcp/tools/trace.ts +7 -1
- package/src/mcp/tools/vsearch.ts +1 -0
- package/src/mcp/tools/workspace-write.ts +2 -0
- package/src/pipeline/egress-lineage.ts +124 -0
- package/src/pipeline/filters.ts +1 -1
- package/src/pipeline/graph-retrieval.ts +7 -4
- package/src/pipeline/hybrid.ts +21 -4
- package/src/pipeline/result-context.ts +12 -4
- package/src/pipeline/search.ts +23 -4
- package/src/pipeline/types.ts +6 -0
- package/src/pipeline/vsearch.ts +67 -28
- package/src/publish/artifact.ts +31 -3
- package/src/publish/export-service.ts +25 -0
- package/src/sdk/client.ts +119 -2
- package/src/sdk/documents.ts +13 -5
- package/src/sdk/embed.ts +1 -0
- package/src/sdk/types.ts +33 -0
- package/src/serve/browse-tree.ts +4 -2
- package/src/serve/clipper-capture.ts +5 -1
- package/src/serve/closed-json.ts +61 -0
- package/src/serve/config-sync.ts +4 -1
- package/src/serve/context.ts +1 -0
- package/src/serve/doc-events.ts +110 -39
- package/src/serve/public/components/CollectionEgressCheckPanel.tsx +411 -0
- package/src/serve/public/components/CollectionEgressPolicyEditor.tsx +78 -0
- package/src/serve/public/components/CollectionModelDialog.tsx +93 -9
- package/src/serve/public/components/EgressAuditPanel.tsx +278 -0
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +3 -0
- package/src/serve/resident-request.ts +80 -3
- package/src/serve/resident-runtime.ts +63 -1
- package/src/serve/routes/api.ts +237 -65
- package/src/serve/routes/clipper.ts +64 -1
- package/src/serve/routes/mcp.ts +6 -0
- package/src/serve/routes/traces.ts +27 -4
- package/src/serve/server.ts +118 -7
- package/src/store/migrations/022-record-export-lineage.ts +42 -0
- package/src/store/migrations/023-collection-egress-policy.ts +61 -0
- package/src/store/migrations/024-egress-derived-lineage.ts +121 -0
- package/src/store/migrations/025-collection-egress-policy-revision.ts +40 -0
- package/src/store/migrations/index.ts +8 -0
- package/src/store/retrieval-trace-codec.ts +15 -0
- package/src/store/sqlite/adapter.ts +284 -14
- package/src/store/sqlite/change-journal-store.ts +41 -2
- package/src/store/sqlite/egress-audit-store.ts +485 -0
- package/src/store/sqlite/retrieval-trace-management-store.ts +47 -6
- package/src/store/sqlite/retrieval-trace-retention.ts +2 -0
- package/src/store/sqlite/retrieval-trace-rows.ts +8 -1
- package/src/store/sqlite/retrieval-trace-store.ts +104 -5
- package/src/store/types.ts +166 -1
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.27.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-vn5f663b.js +0 -50
|
@@ -492,6 +492,7 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
492
492
|
}
|
|
493
493
|
await llm.getManager().dispose(modelUri);
|
|
494
494
|
const recreated = await llm.createEmbeddingPort(modelUri, {
|
|
495
|
+
egressCollections: options.collection ? [options.collection] : "all",
|
|
495
496
|
policy,
|
|
496
497
|
onProgress: downloadProgress
|
|
497
498
|
? (progress) => downloadProgress("embed", progress)
|
|
@@ -508,6 +509,7 @@ export async function embed(options: EmbedOptions = {}): Promise<EmbedResult> {
|
|
|
508
509
|
return { ok: true as const, value: recreated.value };
|
|
509
510
|
};
|
|
510
511
|
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
512
|
+
egressCollections: options.collection ? [options.collection] : "all",
|
|
511
513
|
policy,
|
|
512
514
|
onProgress: downloadProgress
|
|
513
515
|
? (progress) => downloadProgress("embed", progress)
|
package/src/cli/commands/get.ts
CHANGED
|
@@ -21,6 +21,10 @@ import {
|
|
|
21
21
|
getDocumentCapabilities,
|
|
22
22
|
type DocumentCapabilities,
|
|
23
23
|
} from "../../core/document-capabilities";
|
|
24
|
+
import {
|
|
25
|
+
projectRecordEvidenceMetadata,
|
|
26
|
+
type RecordEvidenceMetadata,
|
|
27
|
+
} from "../../core/record-metadata";
|
|
24
28
|
import {
|
|
25
29
|
evidenceFromExactDocument,
|
|
26
30
|
RetrievalTraceSession as TraceSession,
|
|
@@ -85,6 +89,7 @@ export interface GetResponse {
|
|
|
85
89
|
converterVersion?: string;
|
|
86
90
|
mirrorHash?: string;
|
|
87
91
|
};
|
|
92
|
+
record?: RecordEvidenceMetadata;
|
|
88
93
|
capabilities: DocumentCapabilities;
|
|
89
94
|
}
|
|
90
95
|
|
|
@@ -332,6 +337,7 @@ function buildResponse(ctx: BuildResponseContext): GetResult {
|
|
|
332
337
|
language: doc.languageHint ?? undefined,
|
|
333
338
|
source: buildSourceMeta(doc, config),
|
|
334
339
|
conversion: buildConversionMeta(doc),
|
|
340
|
+
record: projectRecordEvidenceMetadata(doc),
|
|
335
341
|
capabilities: buildCapabilities(doc),
|
|
336
342
|
},
|
|
337
343
|
};
|
|
@@ -349,6 +355,7 @@ interface DocRow {
|
|
|
349
355
|
sourceSize: number;
|
|
350
356
|
sourceMtime?: string;
|
|
351
357
|
sourceHash: string;
|
|
358
|
+
recordSourcePath?: string | null;
|
|
352
359
|
}
|
|
353
360
|
|
|
354
361
|
function buildSourceMeta(
|
|
@@ -356,11 +363,12 @@ function buildSourceMeta(
|
|
|
356
363
|
config: ConfigLike
|
|
357
364
|
): GetResponse["source"] {
|
|
358
365
|
const coll = config.collections.find((c) => c.name === doc.collection);
|
|
359
|
-
const
|
|
366
|
+
const relPath = doc.recordSourcePath ?? doc.relPath;
|
|
367
|
+
const absPath = coll ? `${coll.path}/${relPath}` : undefined;
|
|
360
368
|
|
|
361
369
|
return {
|
|
362
370
|
absPath,
|
|
363
|
-
relPath
|
|
371
|
+
relPath,
|
|
364
372
|
mime: doc.sourceMime,
|
|
365
373
|
ext: doc.sourceExt,
|
|
366
374
|
modifiedAt: doc.sourceMtime ?? undefined,
|
|
@@ -373,11 +381,13 @@ function buildCapabilities(doc: {
|
|
|
373
381
|
sourceExt: string;
|
|
374
382
|
sourceMime: string;
|
|
375
383
|
mirrorHash?: string | null;
|
|
384
|
+
recordKey?: string | null;
|
|
376
385
|
}): DocumentCapabilities {
|
|
377
386
|
return getDocumentCapabilities({
|
|
378
387
|
sourceExt: doc.sourceExt,
|
|
379
388
|
sourceMime: doc.sourceMime,
|
|
380
389
|
contentAvailable: doc.mirrorHash !== null,
|
|
390
|
+
recordKey: doc.recordKey,
|
|
381
391
|
});
|
|
382
392
|
}
|
|
383
393
|
|
|
@@ -32,6 +32,8 @@ export interface IndexOptions {
|
|
|
32
32
|
yes?: boolean;
|
|
33
33
|
/** Verbose output */
|
|
34
34
|
verbose?: boolean;
|
|
35
|
+
/** Emit the complete structured index receipt. */
|
|
36
|
+
json?: boolean;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
/**
|
|
@@ -124,6 +126,17 @@ export function formatIndex(
|
|
|
124
126
|
return `Error: ${result.error}`;
|
|
125
127
|
}
|
|
126
128
|
|
|
129
|
+
if (options.json) {
|
|
130
|
+
return JSON.stringify(
|
|
131
|
+
{
|
|
132
|
+
syncResult: result.syncResult,
|
|
133
|
+
embedSkipped: result.embedSkipped,
|
|
134
|
+
...(result.embedResult ? { embedResult: result.embedResult } : {}),
|
|
135
|
+
},
|
|
136
|
+
null,
|
|
137
|
+
2
|
|
138
|
+
);
|
|
139
|
+
}
|
|
127
140
|
const { syncResult, embedSkipped } = result;
|
|
128
141
|
const lines: string[] = ["Indexing complete.", ""];
|
|
129
142
|
|
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
indexNamesMatch,
|
|
18
18
|
isValidIndexName,
|
|
19
19
|
} from "../../app/index-name";
|
|
20
|
+
import {
|
|
21
|
+
projectRecordEvidenceMetadata,
|
|
22
|
+
type RecordEvidenceMetadata,
|
|
23
|
+
} from "../../core/record-metadata";
|
|
20
24
|
import { isGlobPattern, parseRef, splitRefs } from "./ref-parser";
|
|
21
25
|
import { initStore } from "./shared";
|
|
22
26
|
|
|
@@ -53,6 +57,7 @@ export interface MultiGetDocument {
|
|
|
53
57
|
truncated?: boolean;
|
|
54
58
|
totalLines?: number;
|
|
55
59
|
source: { absPath?: string; relPath: string; mime: string; ext: string };
|
|
60
|
+
record?: RecordEvidenceMetadata;
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
export interface SkippedDoc {
|
|
@@ -230,6 +235,7 @@ async function fetchSingleDocument(
|
|
|
230
235
|
);
|
|
231
236
|
const coll = ctx.config.collections.find((c) => c.name === doc.collection);
|
|
232
237
|
|
|
238
|
+
const sourceRelPath = doc.recordSourcePath ?? doc.relPath;
|
|
233
239
|
ctx.documents.push({
|
|
234
240
|
docid: doc.docid,
|
|
235
241
|
uri: decorateUriForIndex(doc.uri, ctx.indexName),
|
|
@@ -238,11 +244,12 @@ async function fetchSingleDocument(
|
|
|
238
244
|
truncated: truncated || undefined,
|
|
239
245
|
totalLines: content.split("\n").length,
|
|
240
246
|
source: {
|
|
241
|
-
absPath: coll ? `${coll.path}/${
|
|
242
|
-
relPath:
|
|
247
|
+
absPath: coll ? `${coll.path}/${sourceRelPath}` : undefined,
|
|
248
|
+
relPath: sourceRelPath,
|
|
243
249
|
mime: doc.sourceMime,
|
|
244
250
|
ext: doc.sourceExt,
|
|
245
251
|
},
|
|
252
|
+
record: projectRecordEvidenceMetadata(doc),
|
|
246
253
|
});
|
|
247
254
|
}
|
|
248
255
|
|
|
@@ -195,6 +195,9 @@ export async function query(
|
|
|
195
195
|
}
|
|
196
196
|
traceSession = traceStart.value ?? undefined;
|
|
197
197
|
const llm = new LlmAdapter(config);
|
|
198
|
+
const egressCollections = options.collection
|
|
199
|
+
? [options.collection]
|
|
200
|
+
: ("all" as const);
|
|
198
201
|
|
|
199
202
|
// Resolve download policy from env/flags
|
|
200
203
|
const globals = getGlobals();
|
|
@@ -210,6 +213,7 @@ export async function query(
|
|
|
210
213
|
|
|
211
214
|
// Create embedding port (for vector search)
|
|
212
215
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
216
|
+
egressCollections,
|
|
213
217
|
policy,
|
|
214
218
|
onProgress: downloadProgress
|
|
215
219
|
? (progress) => downloadProgress("embed", progress)
|
|
@@ -223,6 +227,7 @@ export async function query(
|
|
|
223
227
|
// Skip when structured query modes are provided.
|
|
224
228
|
if (expandUri) {
|
|
225
229
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
230
|
+
egressCollections,
|
|
226
231
|
policy,
|
|
227
232
|
onProgress: downloadProgress
|
|
228
233
|
? (progress) => downloadProgress("expand", progress)
|
|
@@ -236,6 +241,7 @@ export async function query(
|
|
|
236
241
|
// Create rerank port - optional
|
|
237
242
|
if (rerankUri) {
|
|
238
243
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
244
|
+
egressCollections,
|
|
239
245
|
policy,
|
|
240
246
|
onProgress: downloadProgress
|
|
241
247
|
? (progress) => downloadProgress("rerank", progress)
|
|
@@ -354,12 +360,16 @@ export async function queryDiagnose(
|
|
|
354
360
|
const shouldCreateAnyModel =
|
|
355
361
|
shouldCreateEmbeddingPort || !options.noExpand || !options.noRerank;
|
|
356
362
|
const llm = shouldCreateAnyModel ? new LlmAdapter(config) : null;
|
|
363
|
+
const egressCollections = options.collection
|
|
364
|
+
? [options.collection]
|
|
365
|
+
: ("all" as const);
|
|
357
366
|
|
|
358
367
|
const embedUri = shouldCreateEmbeddingPort
|
|
359
368
|
? resolveModelUri(config, "embed", options.embedModel, options.collection)
|
|
360
369
|
: null;
|
|
361
370
|
if (embedUri && llm) {
|
|
362
371
|
const embedResult = await llm.createEmbeddingPort(embedUri, {
|
|
372
|
+
egressCollections,
|
|
363
373
|
policy,
|
|
364
374
|
onProgress: downloadProgress
|
|
365
375
|
? (progress) => downloadProgress("embed", progress)
|
|
@@ -378,6 +388,7 @@ export async function queryDiagnose(
|
|
|
378
388
|
options.collection
|
|
379
389
|
);
|
|
380
390
|
const genResult = await llm.createExpansionPort(expandUri, {
|
|
391
|
+
egressCollections,
|
|
381
392
|
policy,
|
|
382
393
|
onProgress: downloadProgress
|
|
383
394
|
? (progress) => downloadProgress("expand", progress)
|
|
@@ -396,6 +407,7 @@ export async function queryDiagnose(
|
|
|
396
407
|
options.collection
|
|
397
408
|
);
|
|
398
409
|
const rerankResult = await llm.createRerankPort(rerankUri, {
|
|
410
|
+
egressCollections,
|
|
399
411
|
policy,
|
|
400
412
|
onProgress: downloadProgress
|
|
401
413
|
? (progress) => downloadProgress("rerank", progress)
|
|
@@ -91,16 +91,26 @@ export const traceReplay = async (
|
|
|
91
91
|
const policy = resolveDownloadPolicy(process.env, {
|
|
92
92
|
offline: options.offline,
|
|
93
93
|
});
|
|
94
|
+
const egressCollections = "all" as const;
|
|
94
95
|
if (embedUri) {
|
|
95
|
-
const created = await llm.createEmbeddingPort(embedUri, {
|
|
96
|
+
const created = await llm.createEmbeddingPort(embedUri, {
|
|
97
|
+
egressCollections,
|
|
98
|
+
policy,
|
|
99
|
+
});
|
|
96
100
|
if (created.ok) embedPort = created.value;
|
|
97
101
|
}
|
|
98
102
|
if (expandUri) {
|
|
99
|
-
const created = await llm.createExpansionPort(expandUri, {
|
|
103
|
+
const created = await llm.createExpansionPort(expandUri, {
|
|
104
|
+
egressCollections,
|
|
105
|
+
policy,
|
|
106
|
+
});
|
|
100
107
|
if (created.ok) expandPort = created.value;
|
|
101
108
|
}
|
|
102
109
|
if (rerankUri) {
|
|
103
|
-
const created = await llm.createRerankPort(rerankUri, {
|
|
110
|
+
const created = await llm.createRerankPort(rerankUri, {
|
|
111
|
+
egressCollections,
|
|
112
|
+
policy,
|
|
113
|
+
});
|
|
104
114
|
if (created.ok) rerankPort = created.value;
|
|
105
115
|
}
|
|
106
116
|
if (embedPort && embedUri) {
|
|
@@ -168,6 +168,34 @@ export function formatSyncResultLines(
|
|
|
168
168
|
lines.push(` ${c.filesMarkedInactive} marked inactive`);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
for (const file of c.files ?? []) {
|
|
172
|
+
const receipt = file.recordImport;
|
|
173
|
+
if (
|
|
174
|
+
!receipt ||
|
|
175
|
+
(receipt.failures.length === 0 && receipt.warnings.length === 0)
|
|
176
|
+
)
|
|
177
|
+
continue;
|
|
178
|
+
const warningCount = receipt.failures.length + receipt.warnings.length;
|
|
179
|
+
lines.push(
|
|
180
|
+
` ${file.relPath}: ${warningCount} record warning${warningCount === 1 ? "" : "s"} (${receipt.snapshotState} snapshot)`
|
|
181
|
+
);
|
|
182
|
+
if (options.verbose) {
|
|
183
|
+
for (const warning of receipt.warnings) {
|
|
184
|
+
lines.push(
|
|
185
|
+
` [${warning.code}]: ${warning.message} (retryable=${warning.retryable ? "yes" : "no"})`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
for (const failure of receipt.failures) {
|
|
189
|
+
const locator = failure.sourceLocator
|
|
190
|
+
? ` at ${failure.sourceLocator}`
|
|
191
|
+
: "";
|
|
192
|
+
lines.push(
|
|
193
|
+
` [${failure.code}]${locator}: ${failure.message} (retryable=${failure.retryable ? "yes" : "no"})`
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
171
199
|
if (options.verbose && c.errors.length > 0) {
|
|
172
200
|
for (const err of c.errors) {
|
|
173
201
|
lines.push(` [${err.code}] ${err.relPath}: ${err.message}`);
|
|
@@ -24,6 +24,8 @@ export interface UpdateOptions {
|
|
|
24
24
|
gitPull?: boolean;
|
|
25
25
|
/** Verbose output */
|
|
26
26
|
verbose?: boolean;
|
|
27
|
+
/** Emit the complete structured sync receipt. */
|
|
28
|
+
json?: boolean;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
/**
|
|
@@ -80,5 +82,8 @@ export function formatUpdate(
|
|
|
80
82
|
return `Error: ${result.error}`;
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
if (options.json) {
|
|
86
|
+
return JSON.stringify(result.result, null, 2);
|
|
87
|
+
}
|
|
83
88
|
return formatSyncResultLines(result.result, options).join("\n");
|
|
84
89
|
}
|
|
@@ -128,7 +128,9 @@ export async function vsearch(
|
|
|
128
128
|
|
|
129
129
|
// Create LLM adapter for embeddings
|
|
130
130
|
const llm = new LlmAdapter(config);
|
|
131
|
-
const embedResult = await llm.createEmbeddingPort(modelUri
|
|
131
|
+
const embedResult = await llm.createEmbeddingPort(modelUri, {
|
|
132
|
+
egressCollections: options.collection ? [options.collection] : "all",
|
|
133
|
+
});
|
|
132
134
|
if (!embedResult.ok) {
|
|
133
135
|
await traceSession?.finish("failed");
|
|
134
136
|
return { success: false, error: embedResult.error.message };
|
package/src/cli/program.ts
CHANGED
|
@@ -1509,6 +1509,7 @@ function wireOnboardingCommands(program: Command): void {
|
|
|
1509
1509
|
.option("--no-embed", "skip embedding after sync")
|
|
1510
1510
|
.option("--git-pull", "run git pull in git repositories")
|
|
1511
1511
|
.option("--models-pull", "download models if missing")
|
|
1512
|
+
.option("--json", "JSON output")
|
|
1512
1513
|
.action(
|
|
1513
1514
|
async (
|
|
1514
1515
|
collection: string | undefined,
|
|
@@ -1525,6 +1526,7 @@ function wireOnboardingCommands(program: Command): void {
|
|
|
1525
1526
|
modelsPull: Boolean(cmdOpts.modelsPull),
|
|
1526
1527
|
yes: globals.yes,
|
|
1527
1528
|
verbose: globals.verbose,
|
|
1529
|
+
json: getFormat(cmdOpts) === "json",
|
|
1528
1530
|
};
|
|
1529
1531
|
const result = await index(opts);
|
|
1530
1532
|
|
|
@@ -2103,6 +2105,129 @@ function wireManagementCommands(program: Command): void {
|
|
|
2103
2105
|
});
|
|
2104
2106
|
});
|
|
2105
2107
|
|
|
2108
|
+
const collectionPolicyCmd = collectionCmd
|
|
2109
|
+
.command("policy")
|
|
2110
|
+
.description("Inspect and change collection egress policy");
|
|
2111
|
+
|
|
2112
|
+
collectionPolicyCmd
|
|
2113
|
+
.command("get <name>")
|
|
2114
|
+
.description("Show effective policy, source, and confirmation revision")
|
|
2115
|
+
.action(async (name: string) => {
|
|
2116
|
+
const { collectionPolicyGet } = await import("./commands/collection");
|
|
2117
|
+
await collectionPolicyGet(name, { configPath: getGlobals().config });
|
|
2118
|
+
});
|
|
2119
|
+
|
|
2120
|
+
collectionPolicyCmd
|
|
2121
|
+
.command("set <name> <policy>")
|
|
2122
|
+
.description("Set local_only, lan, or remote policy")
|
|
2123
|
+
.option(
|
|
2124
|
+
"--confirm-relaxation <current-revision>",
|
|
2125
|
+
"confirm relaxation against the current policy revision"
|
|
2126
|
+
)
|
|
2127
|
+
.action(
|
|
2128
|
+
async (
|
|
2129
|
+
name: string,
|
|
2130
|
+
policy: string,
|
|
2131
|
+
cmdOpts: Record<string, unknown>
|
|
2132
|
+
) => {
|
|
2133
|
+
if (!["local_only", "lan", "remote"].includes(policy)) {
|
|
2134
|
+
throw new CliError(
|
|
2135
|
+
"VALIDATION",
|
|
2136
|
+
"Policy must be local_only, lan, or remote"
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
const { collectionPolicySet } = await import("./commands/collection");
|
|
2140
|
+
await collectionPolicySet(
|
|
2141
|
+
name,
|
|
2142
|
+
policy as "local_only" | "lan" | "remote",
|
|
2143
|
+
{
|
|
2144
|
+
configPath: getGlobals().config,
|
|
2145
|
+
confirmRelaxation: cmdOpts.confirmRelaxation as string | undefined,
|
|
2146
|
+
}
|
|
2147
|
+
);
|
|
2148
|
+
}
|
|
2149
|
+
);
|
|
2150
|
+
|
|
2151
|
+
collectionPolicyCmd
|
|
2152
|
+
.command("check")
|
|
2153
|
+
.description("Check or explain an exact egress decision without acting")
|
|
2154
|
+
.requiredOption("--action <action>", "egress action")
|
|
2155
|
+
.requiredOption(
|
|
2156
|
+
"--destination <zone>",
|
|
2157
|
+
"local_process, loopback, lan, remote"
|
|
2158
|
+
)
|
|
2159
|
+
.requiredOption("--content-class <class>", "content class")
|
|
2160
|
+
.option(
|
|
2161
|
+
"-c, --collection <name>",
|
|
2162
|
+
"collection scope (repeatable)",
|
|
2163
|
+
collectRepeatableValue,
|
|
2164
|
+
[]
|
|
2165
|
+
)
|
|
2166
|
+
.option("--authenticated", "caller authentication succeeded")
|
|
2167
|
+
.option("--authorized", "operation authorization succeeded")
|
|
2168
|
+
.option("--partial", "explicitly permit partial collection results")
|
|
2169
|
+
.option(
|
|
2170
|
+
"--explain-egress",
|
|
2171
|
+
"return the same decision contract without performing an action"
|
|
2172
|
+
)
|
|
2173
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2174
|
+
const { collectionPolicyCheck } = await import("./commands/collection");
|
|
2175
|
+
await collectionPolicyCheck(
|
|
2176
|
+
{
|
|
2177
|
+
collections: cmdOpts.collection as string[],
|
|
2178
|
+
action: cmdOpts.action as Parameters<
|
|
2179
|
+
typeof collectionPolicyCheck
|
|
2180
|
+
>[0]["action"],
|
|
2181
|
+
destinationZone: cmdOpts.destination as Parameters<
|
|
2182
|
+
typeof collectionPolicyCheck
|
|
2183
|
+
>[0]["destinationZone"],
|
|
2184
|
+
contentClass: cmdOpts.contentClass as Parameters<
|
|
2185
|
+
typeof collectionPolicyCheck
|
|
2186
|
+
>[0]["contentClass"],
|
|
2187
|
+
authenticated: Boolean(cmdOpts.authenticated),
|
|
2188
|
+
authorized: Boolean(cmdOpts.authorized),
|
|
2189
|
+
partial: Boolean(cmdOpts.partial),
|
|
2190
|
+
},
|
|
2191
|
+
{ configPath: getGlobals().config }
|
|
2192
|
+
);
|
|
2193
|
+
});
|
|
2194
|
+
|
|
2195
|
+
const egressAuditCmd = program
|
|
2196
|
+
.command("egress-audit")
|
|
2197
|
+
.description("Manage local content-free egress audit receipts");
|
|
2198
|
+
egressAuditCmd
|
|
2199
|
+
.command("list")
|
|
2200
|
+
.option("--limit <count>", "page size", Number)
|
|
2201
|
+
.option("--cursor <cursor>", "opaque next-page cursor")
|
|
2202
|
+
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2203
|
+
const { egressAuditList } = await import("./commands/egress-audit");
|
|
2204
|
+
await egressAuditList(
|
|
2205
|
+
{
|
|
2206
|
+
limit: cmdOpts.limit as number | undefined,
|
|
2207
|
+
cursor: cmdOpts.cursor as string | undefined,
|
|
2208
|
+
},
|
|
2209
|
+
{ configPath: getGlobals().config }
|
|
2210
|
+
);
|
|
2211
|
+
});
|
|
2212
|
+
egressAuditCmd.command("show <audit-id>").action(async (auditId: string) => {
|
|
2213
|
+
const { egressAuditShow } = await import("./commands/egress-audit");
|
|
2214
|
+
await egressAuditShow(auditId, { configPath: getGlobals().config });
|
|
2215
|
+
});
|
|
2216
|
+
egressAuditCmd.command("status").action(async () => {
|
|
2217
|
+
const { egressAuditStatus } = await import("./commands/egress-audit");
|
|
2218
|
+
await egressAuditStatus({ configPath: getGlobals().config });
|
|
2219
|
+
});
|
|
2220
|
+
egressAuditCmd
|
|
2221
|
+
.command("delete <audit-id>")
|
|
2222
|
+
.action(async (auditId: string) => {
|
|
2223
|
+
const { egressAuditDelete } = await import("./commands/egress-audit");
|
|
2224
|
+
await egressAuditDelete(auditId, { configPath: getGlobals().config });
|
|
2225
|
+
});
|
|
2226
|
+
egressAuditCmd.command("purge").action(async () => {
|
|
2227
|
+
const { egressAuditPurge } = await import("./commands/egress-audit");
|
|
2228
|
+
await egressAuditPurge({ configPath: getGlobals().config });
|
|
2229
|
+
});
|
|
2230
|
+
|
|
2106
2231
|
// context subcommands
|
|
2107
2232
|
const contextCmd = program
|
|
2108
2233
|
.command("context")
|
|
@@ -2515,6 +2640,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2515
2640
|
.command("update")
|
|
2516
2641
|
.description("Sync files from disk into the index")
|
|
2517
2642
|
.option("--git-pull", "run git pull in git repositories")
|
|
2643
|
+
.option("--json", "JSON output")
|
|
2518
2644
|
.action(async (cmdOpts: Record<string, unknown>) => {
|
|
2519
2645
|
const globals = getGlobals();
|
|
2520
2646
|
const { update, formatUpdate } = await import("./commands/update");
|
|
@@ -2523,6 +2649,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2523
2649
|
indexName: globals.index,
|
|
2524
2650
|
gitPull: Boolean(cmdOpts.gitPull),
|
|
2525
2651
|
verbose: globals.verbose,
|
|
2652
|
+
json: getFormat(cmdOpts) === "json",
|
|
2526
2653
|
};
|
|
2527
2654
|
const result = await update(opts);
|
|
2528
2655
|
|
package/src/config/index.ts
CHANGED
|
@@ -59,6 +59,7 @@ export {
|
|
|
59
59
|
CollectionSchema,
|
|
60
60
|
type Config,
|
|
61
61
|
ConfigSchema,
|
|
62
|
+
DEFAULT_EGRESS_POLICY,
|
|
62
63
|
HttpGatewayConfigSchema,
|
|
63
64
|
HttpGatewayLimitsSchema,
|
|
64
65
|
CONTENT_TYPE_GRAPH_HINTS,
|
|
@@ -70,11 +71,19 @@ export {
|
|
|
70
71
|
DEFAULT_EXCLUDES,
|
|
71
72
|
DEFAULT_FTS_TOKENIZER,
|
|
72
73
|
DEFAULT_PATTERN,
|
|
74
|
+
type EffectiveConfiguredEgressPolicy,
|
|
75
|
+
EGRESS_POLICIES,
|
|
76
|
+
EGRESS_POLICY_SOURCES,
|
|
77
|
+
type EgressPolicy,
|
|
78
|
+
EgressPolicySchema,
|
|
79
|
+
type EgressPolicySource,
|
|
80
|
+
EgressPolicySourceSchema,
|
|
73
81
|
FTS_TOKENIZERS,
|
|
74
82
|
type FtsTokenizer,
|
|
75
83
|
getCollectionFromScope,
|
|
76
84
|
isValidLanguageHint,
|
|
77
85
|
parseScope,
|
|
86
|
+
resolveConfiguredEgressPolicy,
|
|
78
87
|
type ProjectProfileBinding,
|
|
79
88
|
ProjectProfileBindingSchema,
|
|
80
89
|
type ScopeType,
|
|
@@ -5,6 +5,7 @@ import { hasLikelySecretPath } from "../core/path-rules";
|
|
|
5
5
|
import {
|
|
6
6
|
CONTENT_TYPE_SEARCH_BOOST_MAX,
|
|
7
7
|
CONTENT_TYPE_SEARCH_BOOST_MIN,
|
|
8
|
+
CollectionSchema,
|
|
8
9
|
isValidLanguageHint,
|
|
9
10
|
PROJECT_AFFINITY_MAX_CONTRIBUTION,
|
|
10
11
|
} from "./types";
|
|
@@ -218,6 +219,7 @@ export const ProjectProfileCollectionSchema = z
|
|
|
218
219
|
.refine(isValidLanguageHint, "Invalid BCP-47 language hint")
|
|
219
220
|
.optional(),
|
|
220
221
|
modelPreset: z.string().regex(REFERENCE_PATTERN).optional(),
|
|
222
|
+
recordAdapters: CollectionSchema.shape.recordAdapters,
|
|
221
223
|
})
|
|
222
224
|
.strict();
|
|
223
225
|
|
package/src/config/types.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { isAbsolute } from "node:path";
|
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
|
|
12
12
|
import { URI_PREFIX } from "../app/constants";
|
|
13
|
+
import { JsonlFieldMappingSchema } from "../converters/adapters/jsonl/config";
|
|
13
14
|
import { RetrievalTraceConfigSchema } from "./retrieval-traces";
|
|
14
15
|
|
|
15
16
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -47,6 +48,28 @@ export type FtsTokenizer = (typeof FTS_TOKENIZERS)[number];
|
|
|
47
48
|
/** Default FTS tokenizer - snowball english for multilingual stemming */
|
|
48
49
|
export const DEFAULT_FTS_TOKENIZER: FtsTokenizer = "snowball english";
|
|
49
50
|
|
|
51
|
+
/** Collection-owned boundary for where indexed content may travel. */
|
|
52
|
+
export const EGRESS_POLICIES = ["local_only", "lan", "remote"] as const;
|
|
53
|
+
export const EgressPolicySchema = z.enum(EGRESS_POLICIES);
|
|
54
|
+
export type EgressPolicy = z.infer<typeof EgressPolicySchema>;
|
|
55
|
+
|
|
56
|
+
/** Missing policy is always interpreted as the fail-closed local-only default. */
|
|
57
|
+
export const DEFAULT_EGRESS_POLICY: EgressPolicy = "local_only";
|
|
58
|
+
|
|
59
|
+
/** Provenance for an effective collection egress policy. */
|
|
60
|
+
export const EGRESS_POLICY_SOURCES = [
|
|
61
|
+
"explicit",
|
|
62
|
+
"config_default",
|
|
63
|
+
"legacy_default",
|
|
64
|
+
] as const;
|
|
65
|
+
export const EgressPolicySourceSchema = z.enum(EGRESS_POLICY_SOURCES);
|
|
66
|
+
export type EgressPolicySource = z.infer<typeof EgressPolicySourceSchema>;
|
|
67
|
+
|
|
68
|
+
export interface EffectiveConfiguredEgressPolicy {
|
|
69
|
+
policy: EgressPolicy;
|
|
70
|
+
source: Extract<EgressPolicySource, "explicit" | "config_default">;
|
|
71
|
+
}
|
|
72
|
+
|
|
50
73
|
/**
|
|
51
74
|
* BCP-47 language tag pattern (simplified, case-insensitive).
|
|
52
75
|
* Matches: en, de, fr, zh-CN, zh-Hans, und, en-US, etc.
|
|
@@ -103,6 +126,18 @@ export const CollectionSchema = z.object({
|
|
|
103
126
|
})
|
|
104
127
|
.optional(),
|
|
105
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Explicit collection egress boundary. Absence remains valid for legacy
|
|
131
|
+
* configs and resolves to local_only rather than relaxing access.
|
|
132
|
+
*/
|
|
133
|
+
egressPolicy: EgressPolicySchema.optional(),
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Durable monotonic token for egress policy/source changes. Legacy configs
|
|
137
|
+
* start at zero; guarded mutations advance it under the config write lock.
|
|
138
|
+
*/
|
|
139
|
+
egressPolicyRevision: z.number().int().nonnegative().optional(),
|
|
140
|
+
|
|
106
141
|
/** Optional per-collection model overrides */
|
|
107
142
|
models: z
|
|
108
143
|
.object({
|
|
@@ -112,11 +147,42 @@ export const CollectionSchema = z.object({
|
|
|
112
147
|
gen: z.string().min(1).optional(),
|
|
113
148
|
})
|
|
114
149
|
.optional(),
|
|
150
|
+
|
|
151
|
+
/** Optional declarative overrides for ambiguous export formats. */
|
|
152
|
+
recordAdapters: z
|
|
153
|
+
.object({
|
|
154
|
+
jsonl: z
|
|
155
|
+
.object({ fieldMapping: JsonlFieldMappingSchema.optional() })
|
|
156
|
+
.strict()
|
|
157
|
+
.optional(),
|
|
158
|
+
transcript: z
|
|
159
|
+
.object({ format: z.enum(["json", "srt", "text", "vtt"]) })
|
|
160
|
+
.strict()
|
|
161
|
+
.optional(),
|
|
162
|
+
})
|
|
163
|
+
.strict()
|
|
164
|
+
.optional(),
|
|
115
165
|
});
|
|
116
166
|
|
|
117
167
|
export type Collection = z.infer<typeof CollectionSchema>;
|
|
118
168
|
export type CollectionModelOverrides = NonNullable<Collection["models"]>;
|
|
119
169
|
|
|
170
|
+
/** Resolve config input without erasing whether the user made an explicit choice. */
|
|
171
|
+
export function resolveConfiguredEgressPolicy(
|
|
172
|
+
collection: Pick<Collection, "egressPolicy">
|
|
173
|
+
): EffectiveConfiguredEgressPolicy {
|
|
174
|
+
if (collection.egressPolicy === undefined) {
|
|
175
|
+
return {
|
|
176
|
+
policy: DEFAULT_EGRESS_POLICY,
|
|
177
|
+
source: "config_default",
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
policy: collection.egressPolicy,
|
|
182
|
+
source: "explicit",
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
120
186
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
121
187
|
// Project Affinity Input
|
|
122
188
|
// ─────────────────────────────────────────────────────────────────────────────
|