@gmickel/gno 1.22.0 → 1.24.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 +33 -12
- package/assets/skill/SKILL.md +41 -19
- package/package.json +1 -1
- package/spec/cli.md +127 -20
- package/spec/evals-agentic.md +35 -0
- package/spec/evals.md +6 -0
- package/spec/mcp.md +18 -0
- package/spec/output-schemas/query-diagnose-v1.schema.json +123 -0
- package/spec/output-schemas/query-diagnose.schema.json +89 -2
- package/spec/output-schemas/setup-activation-result.schema.json +456 -0
- package/spec/output-schemas/setup-command-result.schema.json +93 -0
- package/spec/output-schemas/setup-receipt.schema.json +258 -0
- package/spec/output-schemas/setup-semantic-receipt.schema.json +195 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +1 -0
- package/src/app/context-surface.ts +4 -2
- package/src/cli/commands/ask.ts +31 -20
- package/src/cli/commands/completion/scripts.ts +2 -0
- package/src/cli/commands/context-build.ts +17 -7
- package/src/cli/commands/embed.ts +7 -2
- package/src/cli/commands/query.ts +58 -37
- package/src/cli/commands/search.ts +29 -19
- package/src/cli/commands/setup-activation.ts +324 -0
- package/src/cli/commands/setup-semantic.ts +591 -0
- package/src/cli/commands/setup.ts +410 -0
- package/src/cli/commands/vsearch.ts +31 -22
- package/src/cli/options.ts +39 -0
- package/src/cli/program.ts +112 -0
- package/src/cli/setup-semantic-worker.ts +177 -0
- package/src/config/defaults.ts +10 -1
- package/src/config/types.ts +71 -0
- package/src/core/config-mutation.ts +94 -64
- package/src/core/file-lock.ts +70 -31
- package/src/core/folder-setup-planning.ts +453 -0
- package/src/core/folder-setup.ts +490 -0
- package/src/core/project-affinity-surface.ts +114 -0
- package/src/core/project-affinity.ts +330 -0
- package/src/core/setup-activation.ts +309 -0
- package/src/core/setup-receipt.ts +321 -0
- package/src/core/validation.ts +20 -1
- package/src/mcp/tools/ask.ts +10 -1
- package/src/mcp/tools/context.ts +18 -0
- package/src/mcp/tools/index.ts +13 -2
- package/src/mcp/tools/query.ts +12 -0
- package/src/mcp/tools/search.ts +7 -0
- package/src/mcp/tools/vsearch.ts +7 -0
- package/src/pipeline/diagnose.ts +48 -3
- package/src/pipeline/explain.ts +54 -13
- package/src/pipeline/hybrid.ts +100 -59
- package/src/pipeline/project-affinity.ts +162 -0
- package/src/pipeline/search.ts +76 -10
- package/src/pipeline/types.ts +9 -0
- package/src/pipeline/vsearch.ts +117 -91
- package/src/sdk/client.ts +80 -20
- package/src/sdk/index.ts +2 -0
- package/src/sdk/types.ts +20 -7
- package/src/serve/connectors.ts +29 -2
- package/src/serve/context-capsule.ts +18 -1
- package/src/serve/routes/api.ts +69 -0
package/src/cli/program.ts
CHANGED
|
@@ -32,7 +32,9 @@ import { CliError } from "./errors";
|
|
|
32
32
|
import {
|
|
33
33
|
assertFormatSupported,
|
|
34
34
|
CMD,
|
|
35
|
+
collectRepeatableValue,
|
|
35
36
|
getDefaultLimit,
|
|
37
|
+
parseCliProjectAffinityOptions,
|
|
36
38
|
parseOptionalFloat,
|
|
37
39
|
parsePositiveInt,
|
|
38
40
|
} from "./options";
|
|
@@ -594,6 +596,13 @@ function wireSearchCommands(program: Command): void {
|
|
|
594
596
|
)
|
|
595
597
|
.option("--tags-all <tags>", "require ALL tags (comma-separated)")
|
|
596
598
|
.option("--tags-any <tags>", "require ANY tag (comma-separated)")
|
|
599
|
+
.option(
|
|
600
|
+
"--project-root <path>",
|
|
601
|
+
"trusted project root (repeatable; replaces cwd affinity)",
|
|
602
|
+
collectRepeatableValue,
|
|
603
|
+
[]
|
|
604
|
+
)
|
|
605
|
+
.option("--no-project-affinity", "disable project-aware ranking")
|
|
597
606
|
.option("--full", "include full content")
|
|
598
607
|
.option("--line-numbers", "include line numbers in output")
|
|
599
608
|
.option("--json", "JSON output")
|
|
@@ -641,6 +650,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
641
650
|
: getDefaultLimit(format);
|
|
642
651
|
const categories = parseCsvValues(cmdOpts.category);
|
|
643
652
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
653
|
+
const projectAffinity = parseCliProjectAffinityOptions(cmdOpts);
|
|
644
654
|
|
|
645
655
|
const { search, formatSearch } = await import("./commands/search");
|
|
646
656
|
const result = await search(queryText, {
|
|
@@ -658,6 +668,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
658
668
|
exclude,
|
|
659
669
|
tagsAll,
|
|
660
670
|
tagsAny,
|
|
671
|
+
...projectAffinity,
|
|
661
672
|
full: Boolean(cmdOpts.full),
|
|
662
673
|
lineNumbers: Boolean(cmdOpts.lineNumbers),
|
|
663
674
|
json: format === "json",
|
|
@@ -714,6 +725,13 @@ function wireSearchCommands(program: Command): void {
|
|
|
714
725
|
)
|
|
715
726
|
.option("--tags-all <tags>", "require ALL tags (comma-separated)")
|
|
716
727
|
.option("--tags-any <tags>", "require ANY tag (comma-separated)")
|
|
728
|
+
.option(
|
|
729
|
+
"--project-root <path>",
|
|
730
|
+
"trusted project root (repeatable; replaces cwd affinity)",
|
|
731
|
+
collectRepeatableValue,
|
|
732
|
+
[]
|
|
733
|
+
)
|
|
734
|
+
.option("--no-project-affinity", "disable project-aware ranking")
|
|
717
735
|
.option("--full", "include full content")
|
|
718
736
|
.option("--line-numbers", "include line numbers in output")
|
|
719
737
|
.option("--json", "JSON output")
|
|
@@ -759,6 +777,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
759
777
|
: getDefaultLimit(format);
|
|
760
778
|
const categories = parseCsvValues(cmdOpts.category);
|
|
761
779
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
780
|
+
const projectAffinity = parseCliProjectAffinityOptions(cmdOpts);
|
|
762
781
|
|
|
763
782
|
const { vsearch, formatVsearch } = await import("./commands/vsearch");
|
|
764
783
|
const result = await vsearch(queryText, {
|
|
@@ -776,6 +795,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
776
795
|
exclude,
|
|
777
796
|
tagsAll,
|
|
778
797
|
tagsAny,
|
|
798
|
+
...projectAffinity,
|
|
779
799
|
full: Boolean(cmdOpts.full),
|
|
780
800
|
lineNumbers: Boolean(cmdOpts.lineNumbers),
|
|
781
801
|
json: format === "json",
|
|
@@ -827,6 +847,13 @@ function wireSearchCommands(program: Command): void {
|
|
|
827
847
|
)
|
|
828
848
|
.option("--tags-all <tags>", "require ALL tags (comma-separated)")
|
|
829
849
|
.option("--tags-any <tags>", "require ANY tag (comma-separated)")
|
|
850
|
+
.option(
|
|
851
|
+
"--project-root <path>",
|
|
852
|
+
"trusted project root (repeatable; replaces cwd affinity)",
|
|
853
|
+
collectRepeatableValue,
|
|
854
|
+
[]
|
|
855
|
+
)
|
|
856
|
+
.option("--no-project-affinity", "disable project-aware ranking")
|
|
830
857
|
.option("--full", "include full content")
|
|
831
858
|
.option("--line-numbers", "include line numbers in output")
|
|
832
859
|
.option("--fast", "skip expansion and reranking (fastest, ~0.7s)")
|
|
@@ -931,6 +958,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
931
958
|
: undefined;
|
|
932
959
|
const categories = parseCsvValues(cmdOpts.category);
|
|
933
960
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
961
|
+
const projectAffinity = parseCliProjectAffinityOptions(cmdOpts);
|
|
934
962
|
|
|
935
963
|
const depthPolicy = resolveDepthPolicy({
|
|
936
964
|
presetId: activePresetId,
|
|
@@ -960,6 +988,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
960
988
|
exclude,
|
|
961
989
|
tagsAll,
|
|
962
990
|
tagsAny,
|
|
991
|
+
...projectAffinity,
|
|
963
992
|
noExpand: depthPolicy.noExpand,
|
|
964
993
|
noRerank: depthPolicy.noRerank,
|
|
965
994
|
graph: Boolean(cmdOpts.graph),
|
|
@@ -995,6 +1024,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
995
1024
|
exclude,
|
|
996
1025
|
tagsAll,
|
|
997
1026
|
tagsAny,
|
|
1027
|
+
...projectAffinity,
|
|
998
1028
|
full: Boolean(cmdOpts.full),
|
|
999
1029
|
lineNumbers: Boolean(cmdOpts.lineNumbers),
|
|
1000
1030
|
noExpand: depthPolicy.noExpand,
|
|
@@ -1121,6 +1151,13 @@ function wireSearchCommands(program: Command): void {
|
|
|
1121
1151
|
.option("--context-budget-bytes <num>", "verified Context byte budget")
|
|
1122
1152
|
.option("--min-score <score>", "minimum retrieval score (0-1)")
|
|
1123
1153
|
.option("--graph", "include bounded graph expansion")
|
|
1154
|
+
.option(
|
|
1155
|
+
"--project-root <path>",
|
|
1156
|
+
"trusted project root (repeatable; replaces cwd affinity)",
|
|
1157
|
+
collectRepeatableValue,
|
|
1158
|
+
[]
|
|
1159
|
+
)
|
|
1160
|
+
.option("--no-project-affinity", "disable project-aware ranking")
|
|
1124
1161
|
.option("--show-sources", "show all retrieved sources (not just cited)")
|
|
1125
1162
|
.option("--json", "JSON output")
|
|
1126
1163
|
.option("--md", "Markdown output")
|
|
@@ -1169,6 +1206,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1169
1206
|
}
|
|
1170
1207
|
const categories = parseCsvValues(cmdOpts.category);
|
|
1171
1208
|
const exclude = parseCsvValues(cmdOpts.exclude);
|
|
1209
|
+
const projectAffinity = parseCliProjectAffinityOptions(cmdOpts);
|
|
1172
1210
|
|
|
1173
1211
|
let queryModes: import("../pipeline/types").QueryModeInput[] | undefined;
|
|
1174
1212
|
if (Array.isArray(cmdOpts.queryMode) && cmdOpts.queryMode.length > 0) {
|
|
@@ -1229,6 +1267,7 @@ function wireSearchCommands(program: Command): void {
|
|
|
1229
1267
|
maxAnswerTokens,
|
|
1230
1268
|
contextBudgetTokens,
|
|
1231
1269
|
contextBudgetBytes,
|
|
1270
|
+
...projectAffinity,
|
|
1232
1271
|
showSources,
|
|
1233
1272
|
json: format === "json",
|
|
1234
1273
|
md: format === "md",
|
|
@@ -1307,6 +1346,69 @@ function wireOnboardingCommands(program: Command): void {
|
|
|
1307
1346
|
}
|
|
1308
1347
|
);
|
|
1309
1348
|
|
|
1349
|
+
// setup - Verify a folder is lexically retrievable, then hand off semantics
|
|
1350
|
+
program
|
|
1351
|
+
.command("setup <folder>")
|
|
1352
|
+
.description("Add and verify a folder with a real lexical retrieval")
|
|
1353
|
+
.option("-n, --name <name>", "collection name")
|
|
1354
|
+
.option(
|
|
1355
|
+
"--exclude <pattern>",
|
|
1356
|
+
"literal exclusion pattern (repeatable)",
|
|
1357
|
+
collectRepeatableValue,
|
|
1358
|
+
[]
|
|
1359
|
+
)
|
|
1360
|
+
.option(
|
|
1361
|
+
"--authorize-secret-risk",
|
|
1362
|
+
"explicitly authorize indexing likely secret files"
|
|
1363
|
+
)
|
|
1364
|
+
.option(
|
|
1365
|
+
"--connector <id>",
|
|
1366
|
+
"install and verify one connector (repeatable)",
|
|
1367
|
+
collectRepeatableValue,
|
|
1368
|
+
[]
|
|
1369
|
+
)
|
|
1370
|
+
.option("--no-semantic", "skip background semantic indexing")
|
|
1371
|
+
.option("--json", "JSON output")
|
|
1372
|
+
.action(async (folder: string, cmdOpts: Record<string, unknown>) => {
|
|
1373
|
+
const globals = getGlobals();
|
|
1374
|
+
const json = Boolean(cmdOpts.json) || globals.json;
|
|
1375
|
+
const { formatSetupOutputResult, setupWithActivation } =
|
|
1376
|
+
await import("./commands/setup-activation");
|
|
1377
|
+
const exclusions = cmdOpts.exclude as string[];
|
|
1378
|
+
const outcome = await setupWithActivation({
|
|
1379
|
+
folder,
|
|
1380
|
+
name: cmdOpts.name as string | undefined,
|
|
1381
|
+
exclude: exclusions.length > 0 ? exclusions : undefined,
|
|
1382
|
+
authorizeSecretRisk: Boolean(cmdOpts.authorizeSecretRisk),
|
|
1383
|
+
connectorIds: cmdOpts.connector as string[],
|
|
1384
|
+
semantic: cmdOpts.semantic !== false,
|
|
1385
|
+
indexName: globals.index,
|
|
1386
|
+
configPath: globals.config,
|
|
1387
|
+
offline: globals.offline,
|
|
1388
|
+
yes: globals.yes,
|
|
1389
|
+
json,
|
|
1390
|
+
quiet: globals.quiet,
|
|
1391
|
+
progress: (stage) => {
|
|
1392
|
+
process.stderr.write(`setup: ${stage}\n`);
|
|
1393
|
+
},
|
|
1394
|
+
});
|
|
1395
|
+
const output = formatSetupOutputResult(outcome.result, { json });
|
|
1396
|
+
if (json || outcome.exitCode === 0) {
|
|
1397
|
+
process.stdout.write(`${output}\n`);
|
|
1398
|
+
} else {
|
|
1399
|
+
process.stderr.write(`${output}\n`);
|
|
1400
|
+
}
|
|
1401
|
+
if (outcome.exitCode !== 0) {
|
|
1402
|
+
const setupResult =
|
|
1403
|
+
"setup" in outcome.result ? outcome.result.setup : outcome.result;
|
|
1404
|
+
throw new CliError(
|
|
1405
|
+
outcome.exitCode === 1 ? "VALIDATION" : "RUNTIME",
|
|
1406
|
+
setupResult.lexical.error?.message ?? "Setup failed",
|
|
1407
|
+
{ silent: true }
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
|
|
1310
1412
|
// index - Index collections
|
|
1311
1413
|
program
|
|
1312
1414
|
.command("index [collection]")
|
|
@@ -1974,6 +2076,13 @@ function wireManagementCommands(program: Command): void {
|
|
|
1974
2076
|
.option("--since <date>", "modified-at lower bound")
|
|
1975
2077
|
.option("--until <date>", "modified-at upper bound")
|
|
1976
2078
|
.option("--graph", "enable graph neighbor expansion")
|
|
2079
|
+
.option(
|
|
2080
|
+
"--project-root <path>",
|
|
2081
|
+
"trusted project root (repeatable; replaces cwd affinity)",
|
|
2082
|
+
collectRepeatableValue,
|
|
2083
|
+
[]
|
|
2084
|
+
)
|
|
2085
|
+
.option("--no-project-affinity", "disable project-aware ranking")
|
|
1977
2086
|
.option("--fast", "use lexical-first fast retrieval")
|
|
1978
2087
|
.option("--thorough", "use a wider retrieval pool")
|
|
1979
2088
|
.option("-n, --limit <num>", "maximum retrieved results")
|
|
@@ -1991,6 +2100,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
1991
2100
|
throw new CliError("VALIDATION", "Choose either --fast or --thorough");
|
|
1992
2101
|
}
|
|
1993
2102
|
const globals = getGlobals();
|
|
2103
|
+
const projectAffinity = parseCliProjectAffinityOptions(cmdOpts);
|
|
1994
2104
|
const { contextBuild } = await import("./commands/context-build");
|
|
1995
2105
|
let queryModes: import("../pipeline/types").QueryModeInput[] | undefined;
|
|
1996
2106
|
if (Array.isArray(cmdOpts.queryMode) && cmdOpts.queryMode.length > 0) {
|
|
@@ -2022,6 +2132,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2022
2132
|
true
|
|
2023
2133
|
),
|
|
2024
2134
|
query: cmdOpts.query as string | undefined,
|
|
2135
|
+
...projectAffinity,
|
|
2025
2136
|
queryModes,
|
|
2026
2137
|
collections: cmdOpts.collection as string[],
|
|
2027
2138
|
uriPrefix: cmdOpts.uriPrefix as string | undefined,
|
|
@@ -2350,6 +2461,7 @@ function wireManagementCommands(program: Command): void {
|
|
|
2350
2461
|
yes: globals.yes,
|
|
2351
2462
|
json: format === "json",
|
|
2352
2463
|
verbose: globals.verbose,
|
|
2464
|
+
offline: globals.offline,
|
|
2353
2465
|
};
|
|
2354
2466
|
const result = await embed(opts);
|
|
2355
2467
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot semantic worker started by `gno setup`.
|
|
3
|
+
*
|
|
4
|
+
* It owns its store/model lifecycle through the existing collection-scoped
|
|
5
|
+
* embed command, updates one durable receipt, and exits.
|
|
6
|
+
*
|
|
7
|
+
* @module src/cli/setup-semantic-worker
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { loadSetupReceipt } from "../core/setup-receipt";
|
|
11
|
+
import { embed, type EmbedOptions, type EmbedResult } from "./commands/embed";
|
|
12
|
+
import {
|
|
13
|
+
loadSetupSemanticReceipt,
|
|
14
|
+
type SetupSemanticReceipt,
|
|
15
|
+
setupSemanticSourceFingerprint,
|
|
16
|
+
updateSetupSemanticReceipt,
|
|
17
|
+
} from "./commands/setup-semantic";
|
|
18
|
+
|
|
19
|
+
const PARENT_REGISTRATION_TIMEOUT_MS = 2000;
|
|
20
|
+
const PARENT_REGISTRATION_POLL_MS = 20;
|
|
21
|
+
const MAX_ERROR_LENGTH = 500;
|
|
22
|
+
|
|
23
|
+
export interface SetupSemanticWorkerDependencies {
|
|
24
|
+
embedFn?: (options: EmbedOptions) => Promise<EmbedResult>;
|
|
25
|
+
now?: () => Date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function boundedError(error: unknown): string {
|
|
29
|
+
return (
|
|
30
|
+
(error instanceof Error ? error.message : String(error)).slice(
|
|
31
|
+
0,
|
|
32
|
+
MAX_ERROR_LENGTH
|
|
33
|
+
) || "Unknown semantic setup error"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function waitForParentRegistration(
|
|
38
|
+
receiptPath: string,
|
|
39
|
+
jobId: string
|
|
40
|
+
): Promise<SetupSemanticReceipt> {
|
|
41
|
+
const deadline = Date.now() + PARENT_REGISTRATION_TIMEOUT_MS;
|
|
42
|
+
while (Date.now() < deadline) {
|
|
43
|
+
const receipt = await loadSetupSemanticReceipt(receiptPath);
|
|
44
|
+
if (
|
|
45
|
+
receipt?.jobId === jobId &&
|
|
46
|
+
(receipt.pid === process.pid ||
|
|
47
|
+
receipt.status === "pending" ||
|
|
48
|
+
receipt.status === "skipped")
|
|
49
|
+
) {
|
|
50
|
+
return receipt;
|
|
51
|
+
}
|
|
52
|
+
await Bun.sleep(PARENT_REGISTRATION_POLL_MS);
|
|
53
|
+
}
|
|
54
|
+
throw new Error("Setup parent did not register the semantic worker");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function runSetupSemanticWorker(
|
|
58
|
+
receiptPath: string,
|
|
59
|
+
jobId: string,
|
|
60
|
+
dependencies: SetupSemanticWorkerDependencies = {}
|
|
61
|
+
): Promise<number> {
|
|
62
|
+
try {
|
|
63
|
+
const registered = await waitForParentRegistration(receiptPath, jobId);
|
|
64
|
+
if (registered.status === "pending") {
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
if (registered.status === "skipped") {
|
|
68
|
+
return 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const setupReceipt = await loadSetupReceipt(registered.setupReceiptPath);
|
|
72
|
+
if (
|
|
73
|
+
!setupReceipt ||
|
|
74
|
+
setupReceipt.status !== "completed" ||
|
|
75
|
+
setupReceipt.collection.name !== registered.collection ||
|
|
76
|
+
setupReceipt.input.indexName !== registered.indexName ||
|
|
77
|
+
setupReceipt.paths.receipt !== registered.setupReceiptPath ||
|
|
78
|
+
setupSemanticSourceFingerprint(setupReceipt) !==
|
|
79
|
+
registered.setupReceiptFingerprint
|
|
80
|
+
) {
|
|
81
|
+
throw new Error("Lexical setup receipt no longer matches semantic job");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const startedAt = (dependencies.now ?? (() => new Date()))().toISOString();
|
|
85
|
+
await updateSetupSemanticReceipt(receiptPath, jobId, (current) => ({
|
|
86
|
+
...current,
|
|
87
|
+
status: "running",
|
|
88
|
+
generatedAt: startedAt,
|
|
89
|
+
startedAt: current.startedAt ?? startedAt,
|
|
90
|
+
completedAt: null,
|
|
91
|
+
pid: process.pid,
|
|
92
|
+
counts: null,
|
|
93
|
+
error: null,
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
const result = await (dependencies.embedFn ?? embed)({
|
|
97
|
+
configPath: setupReceipt.paths.config,
|
|
98
|
+
indexName: registered.indexName,
|
|
99
|
+
collection: registered.collection,
|
|
100
|
+
yes: true,
|
|
101
|
+
json: true,
|
|
102
|
+
offline: registered.offline,
|
|
103
|
+
});
|
|
104
|
+
if (!result.success) {
|
|
105
|
+
throw new Error(result.error);
|
|
106
|
+
}
|
|
107
|
+
if (result.errors > 0 || result.syncError) {
|
|
108
|
+
const completedAt = (
|
|
109
|
+
dependencies.now ?? (() => new Date())
|
|
110
|
+
)().toISOString();
|
|
111
|
+
const message = result.syncError
|
|
112
|
+
? `Vector index sync failed: ${result.syncError}`
|
|
113
|
+
: `Embedding completed with ${result.errors} failed chunk${result.errors === 1 ? "" : "s"}`;
|
|
114
|
+
await updateSetupSemanticReceipt(receiptPath, jobId, (current) => ({
|
|
115
|
+
...current,
|
|
116
|
+
status: "failed",
|
|
117
|
+
generatedAt: completedAt,
|
|
118
|
+
completedAt,
|
|
119
|
+
pid: null,
|
|
120
|
+
counts: {
|
|
121
|
+
embedded: result.embedded,
|
|
122
|
+
errors: result.errors,
|
|
123
|
+
},
|
|
124
|
+
error: {
|
|
125
|
+
message: boundedError(message),
|
|
126
|
+
remediation: `Run: ${current.resumeCommand}`,
|
|
127
|
+
},
|
|
128
|
+
}));
|
|
129
|
+
return 2;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const completedAt = (
|
|
133
|
+
dependencies.now ?? (() => new Date())
|
|
134
|
+
)().toISOString();
|
|
135
|
+
await updateSetupSemanticReceipt(receiptPath, jobId, (current) => ({
|
|
136
|
+
...current,
|
|
137
|
+
status: "completed",
|
|
138
|
+
generatedAt: completedAt,
|
|
139
|
+
completedAt,
|
|
140
|
+
pid: null,
|
|
141
|
+
counts: {
|
|
142
|
+
embedded: result.embedded,
|
|
143
|
+
errors: result.errors,
|
|
144
|
+
},
|
|
145
|
+
error: null,
|
|
146
|
+
}));
|
|
147
|
+
return 0;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const completedAt = (
|
|
150
|
+
dependencies.now ?? (() => new Date())
|
|
151
|
+
)().toISOString();
|
|
152
|
+
await updateSetupSemanticReceipt(receiptPath, jobId, (current) => ({
|
|
153
|
+
...current,
|
|
154
|
+
status: "failed",
|
|
155
|
+
generatedAt: completedAt,
|
|
156
|
+
startedAt: current.startedAt ?? completedAt,
|
|
157
|
+
completedAt,
|
|
158
|
+
pid: null,
|
|
159
|
+
counts: null,
|
|
160
|
+
error: {
|
|
161
|
+
message: boundedError(error),
|
|
162
|
+
remediation: `Run: ${current.resumeCommand}`,
|
|
163
|
+
},
|
|
164
|
+
})).catch(() => undefined);
|
|
165
|
+
return 2;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (import.meta.main) {
|
|
170
|
+
const receiptPath = process.argv[2];
|
|
171
|
+
const jobId = process.argv[3];
|
|
172
|
+
if (!(receiptPath && jobId)) {
|
|
173
|
+
process.exitCode = 1;
|
|
174
|
+
} else {
|
|
175
|
+
process.exitCode = await runSetupSemanticWorker(receiptPath, jobId);
|
|
176
|
+
}
|
|
177
|
+
}
|
package/src/config/defaults.ts
CHANGED
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
* @module src/config/defaults
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
CONFIG_VERSION,
|
|
9
|
+
type Config,
|
|
10
|
+
DEFAULT_FTS_TOKENIZER,
|
|
11
|
+
PROJECT_AFFINITY_MAX_CONTRIBUTION,
|
|
12
|
+
} from "./types";
|
|
8
13
|
|
|
9
14
|
/**
|
|
10
15
|
* Create a default config object.
|
|
@@ -17,5 +22,9 @@ export function createDefaultConfig(): Config {
|
|
|
17
22
|
collections: [],
|
|
18
23
|
contexts: [],
|
|
19
24
|
contentTypes: [],
|
|
25
|
+
projectAffinity: {
|
|
26
|
+
enabled: true,
|
|
27
|
+
contribution: PROJECT_AFFINITY_MAX_CONTRIBUTION,
|
|
28
|
+
},
|
|
20
29
|
};
|
|
21
30
|
}
|
package/src/config/types.ts
CHANGED
|
@@ -115,6 +115,74 @@ export const CollectionSchema = z.object({
|
|
|
115
115
|
export type Collection = z.infer<typeof CollectionSchema>;
|
|
116
116
|
export type CollectionModelOverrides = NonNullable<Collection["models"]>;
|
|
117
117
|
|
|
118
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
119
|
+
// Project Affinity Input
|
|
120
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
export const TrustedProjectRootSourceSchema = z.enum([
|
|
123
|
+
"cli_cwd",
|
|
124
|
+
"cli_explicit",
|
|
125
|
+
"cli_worktree",
|
|
126
|
+
]);
|
|
127
|
+
export type TrustedProjectRootSource = z.infer<
|
|
128
|
+
typeof TrustedProjectRootSourceSchema
|
|
129
|
+
>;
|
|
130
|
+
|
|
131
|
+
export const LocalProjectAffinityRootSchema = z.object({
|
|
132
|
+
source: TrustedProjectRootSourceSchema,
|
|
133
|
+
path: z.string().min(1),
|
|
134
|
+
});
|
|
135
|
+
export type LocalProjectAffinityRoot = z.infer<
|
|
136
|
+
typeof LocalProjectAffinityRootSchema
|
|
137
|
+
>;
|
|
138
|
+
|
|
139
|
+
export const RemoteProjectAffinityRootSchema = z.object({
|
|
140
|
+
source: z.literal("remote_hint"),
|
|
141
|
+
hint: z.string().min(1),
|
|
142
|
+
});
|
|
143
|
+
export type RemoteProjectAffinityRoot = z.infer<
|
|
144
|
+
typeof RemoteProjectAffinityRootSchema
|
|
145
|
+
>;
|
|
146
|
+
|
|
147
|
+
export const ProjectAffinityRootSchema = z.discriminatedUnion("source", [
|
|
148
|
+
LocalProjectAffinityRootSchema,
|
|
149
|
+
RemoteProjectAffinityRootSchema,
|
|
150
|
+
]);
|
|
151
|
+
export type ProjectAffinityRoot = z.infer<typeof ProjectAffinityRootSchema>;
|
|
152
|
+
|
|
153
|
+
export const LocalProjectAffinityInputSchema = z.object({
|
|
154
|
+
roots: z.array(LocalProjectAffinityRootSchema).max(16).default([]),
|
|
155
|
+
});
|
|
156
|
+
export type LocalProjectAffinityInput = z.infer<
|
|
157
|
+
typeof LocalProjectAffinityInputSchema
|
|
158
|
+
>;
|
|
159
|
+
|
|
160
|
+
export const RemoteProjectAffinityInputSchema = z.object({
|
|
161
|
+
roots: z.array(RemoteProjectAffinityRootSchema).max(16).default([]),
|
|
162
|
+
});
|
|
163
|
+
export type RemoteProjectAffinityInput = z.infer<
|
|
164
|
+
typeof RemoteProjectAffinityInputSchema
|
|
165
|
+
>;
|
|
166
|
+
|
|
167
|
+
export const ProjectAffinityInputSchema = z.object({
|
|
168
|
+
roots: z.array(ProjectAffinityRootSchema).max(16).default([]),
|
|
169
|
+
});
|
|
170
|
+
export type ProjectAffinityInput = z.infer<typeof ProjectAffinityInputSchema>;
|
|
171
|
+
|
|
172
|
+
export const PROJECT_AFFINITY_MAX_CONTRIBUTION = 0.03;
|
|
173
|
+
export const AUXILIARY_RANKING_MAX_CONTRIBUTION = 0.08;
|
|
174
|
+
|
|
175
|
+
export const ProjectAffinityConfigSchema = z.object({
|
|
176
|
+
enabled: z.boolean().default(true),
|
|
177
|
+
contribution: z
|
|
178
|
+
.number()
|
|
179
|
+
.finite()
|
|
180
|
+
.min(0)
|
|
181
|
+
.max(PROJECT_AFFINITY_MAX_CONTRIBUTION)
|
|
182
|
+
.default(PROJECT_AFFINITY_MAX_CONTRIBUTION),
|
|
183
|
+
});
|
|
184
|
+
export type ProjectAffinityConfig = z.infer<typeof ProjectAffinityConfigSchema>;
|
|
185
|
+
|
|
118
186
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
119
187
|
// Context Schema
|
|
120
188
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -342,6 +410,9 @@ export const ConfigSchema = z.object({
|
|
|
342
410
|
|
|
343
411
|
/** Private local retrieval trace recording. Absent means recording off. */
|
|
344
412
|
retrievalTraces: RetrievalTraceConfigSchema.optional(),
|
|
413
|
+
|
|
414
|
+
/** Bounded project-aware retrieval affinity. */
|
|
415
|
+
projectAffinity: ProjectAffinityConfigSchema.optional(),
|
|
345
416
|
});
|
|
346
417
|
|
|
347
418
|
export type Config = Omit<z.infer<typeof ConfigSchema>, "contentTypes"> & {
|