@wrongstack/cli 0.308.0 → 0.308.2
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/data/providers.json +3 -3
- package/dist/{auth-TVOOHL4Q.js → auth-WOKC2RVG.js} +2 -2
- package/dist/{chunk-TOG7OMKJ.js → chunk-7JOMY3HO.js} +10 -10
- package/dist/{cli-main-RJSOWUGD.js → cli-main-WWZJF33V.js} +363 -14
- package/dist/context-limit.d.ts +7 -4
- package/dist/{execution-4S6RSEQI.js → execution-6HIKTAUB.js} +5 -2
- package/dist/index.js +2 -2
- package/dist/slash-commands/command-context.d.ts +8 -0
- package/dist/slash-commands/memory-formatters.d.ts +42 -0
- package/dist/webui-server/listen-helpers.d.ts +3 -1
- package/dist/{webui-server-A3H2SM6J.js → webui-server-JXJ4CGIX.js} +32 -14
- package/dist/wiring/cli-slash-commands-setup.d.ts +7 -0
- package/dist/wiring/domain-terms-mirror.d.ts +4 -38
- package/package.json +26 -25
package/data/providers.json
CHANGED
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"output": ["text"]
|
|
112
112
|
},
|
|
113
113
|
"limit": {
|
|
114
|
-
"context":
|
|
114
|
+
"context": 1050000,
|
|
115
115
|
"output": 128000
|
|
116
116
|
}
|
|
117
117
|
},
|
|
@@ -126,8 +126,8 @@
|
|
|
126
126
|
"output": ["text"]
|
|
127
127
|
},
|
|
128
128
|
"limit": {
|
|
129
|
-
"context":
|
|
130
|
-
"output":
|
|
129
|
+
"context": 1050000,
|
|
130
|
+
"output": 128000
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
runOAuthLoginKind,
|
|
14
14
|
runOAuthLoginMenu,
|
|
15
15
|
validateFamily
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7JOMY3HO.js";
|
|
17
17
|
import {
|
|
18
18
|
restoreFlags
|
|
19
19
|
} from "./chunk-CSAPOCBP.js";
|
|
@@ -596,4 +596,4 @@ async function runAuthRemove(deps, providerId) {
|
|
|
596
596
|
export {
|
|
597
597
|
authCmd
|
|
598
598
|
};
|
|
599
|
-
//# sourceMappingURL=auth-
|
|
599
|
+
//# sourceMappingURL=auth-WOKC2RVG.js.map
|
|
@@ -795,15 +795,15 @@ var COPILOT_PROVIDER_ID = "github-copilot";
|
|
|
795
795
|
function sleep(ms, signal) {
|
|
796
796
|
return new Promise((resolve, reject) => {
|
|
797
797
|
if (signal.aborted) return reject(new DOMException("Aborted", "AbortError"));
|
|
798
|
-
const t = setTimeout(
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
);
|
|
798
|
+
const t = setTimeout(() => {
|
|
799
|
+
signal.removeEventListener("abort", onAbort);
|
|
800
|
+
resolve();
|
|
801
|
+
}, ms);
|
|
802
|
+
function onAbort() {
|
|
803
|
+
clearTimeout(t);
|
|
804
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
805
|
+
}
|
|
806
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
807
807
|
});
|
|
808
808
|
}
|
|
809
809
|
async function startDeviceFlow(signal) {
|
|
@@ -1374,4 +1374,4 @@ export {
|
|
|
1374
1374
|
addCustomProvider,
|
|
1375
1375
|
addKeyForProvider
|
|
1376
1376
|
};
|
|
1377
|
-
//# sourceMappingURL=chunk-
|
|
1377
|
+
//# sourceMappingURL=chunk-7JOMY3HO.js.map
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
runClaudeOAuthLogin,
|
|
82
82
|
runCopilotOAuthLogin,
|
|
83
83
|
validateFamily
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-7JOMY3HO.js";
|
|
85
85
|
import {
|
|
86
86
|
LOCAL_LLM_PRESETS,
|
|
87
87
|
parseSpawnFlags
|
|
@@ -850,9 +850,21 @@ async function resolveRuntimeMaxContextDetailed(input) {
|
|
|
850
850
|
const providerConfig = input.runtimeProviderConfig ?? input.config.providers?.[input.providerId];
|
|
851
851
|
const providerOverride = positiveNumber(readConfiguredMaxContext(providerConfig));
|
|
852
852
|
if (providerOverride) return { maxContext: providerOverride, branch: "provider-override" };
|
|
853
|
+
const catalogId = providerConfig?.type && providerConfig.type !== input.providerId ? providerConfig.type : input.providerId;
|
|
853
854
|
const sibling = providerConfig?.family ? SIBLING_CATALOG[providerConfig.family] : void 0;
|
|
854
855
|
if (sibling && input.modelsRegistry) {
|
|
855
856
|
const mergedModels = mergeCustomModelDefs2(providerConfig?.customModels, input.config.models);
|
|
857
|
+
const ownModel = await input.modelsRegistry.getModel(catalogId, input.modelId).catch(() => void 0);
|
|
858
|
+
if (ownModel) {
|
|
859
|
+
const ownCaps = await capabilitiesFor2(
|
|
860
|
+
input.modelsRegistry,
|
|
861
|
+
catalogId,
|
|
862
|
+
input.modelId,
|
|
863
|
+
mergedModels
|
|
864
|
+
).catch(() => void 0);
|
|
865
|
+
const ownMax = positiveNumber(ownCaps?.maxContext) ?? positiveNumber(ownModel.capabilities.maxContext);
|
|
866
|
+
if (ownMax) return { maxContext: ownMax, branch: "catalog-capabilities" };
|
|
867
|
+
}
|
|
856
868
|
const caps = await capabilitiesFor2(
|
|
857
869
|
input.modelsRegistry,
|
|
858
870
|
sibling,
|
|
@@ -865,7 +877,6 @@ async function resolveRuntimeMaxContextDetailed(input) {
|
|
|
865
877
|
const directMax = positiveNumber(directModel?.capabilities.maxContext);
|
|
866
878
|
if (directMax) return { maxContext: directMax, branch: "sibling-direct-model" };
|
|
867
879
|
}
|
|
868
|
-
const catalogId = providerConfig?.type && providerConfig.type !== input.providerId ? providerConfig.type : input.providerId;
|
|
869
880
|
let divergedFromCatalog = false;
|
|
870
881
|
if (input.modelsRegistry) {
|
|
871
882
|
const topLevelBaseUrlApplies = input.providerId === input.config.provider;
|
|
@@ -5501,6 +5512,8 @@ async function runCliExecution(params) {
|
|
|
5501
5512
|
sessResult,
|
|
5502
5513
|
sessionStore,
|
|
5503
5514
|
memoryStore,
|
|
5515
|
+
vectorMemoryStore,
|
|
5516
|
+
vectorMemoryModelCacheDir,
|
|
5504
5517
|
modeStore,
|
|
5505
5518
|
needsSetup,
|
|
5506
5519
|
statusTracker,
|
|
@@ -5563,7 +5576,7 @@ async function runCliExecution(params) {
|
|
|
5563
5576
|
governanceHandle,
|
|
5564
5577
|
setConfig
|
|
5565
5578
|
} = params;
|
|
5566
|
-
const { execute } = await import("./execution-
|
|
5579
|
+
const { execute } = await import("./execution-6HIKTAUB.js");
|
|
5567
5580
|
return execute(
|
|
5568
5581
|
toExecuteDeps({
|
|
5569
5582
|
core: {
|
|
@@ -5593,6 +5606,8 @@ async function runCliExecution(params) {
|
|
|
5593
5606
|
rebindTodosCheckpoint: sessResult.rebindTodosCheckpoint,
|
|
5594
5607
|
sessionStore,
|
|
5595
5608
|
memoryStore,
|
|
5609
|
+
vectorMemoryStore,
|
|
5610
|
+
vectorMemoryModelCacheDir,
|
|
5596
5611
|
modeStore,
|
|
5597
5612
|
restoredMessages: sessResult.restoredMessages,
|
|
5598
5613
|
restoredToolCalls: sessResult.restoredToolCalls,
|
|
@@ -6517,7 +6532,7 @@ import { SageDomainTermExtractor } from "@wrongstack/sage";
|
|
|
6517
6532
|
async function refreshDomainTermsMirror(options) {
|
|
6518
6533
|
try {
|
|
6519
6534
|
const extractor = new SageDomainTermExtractor();
|
|
6520
|
-
return await extractor.writeDomainTermsFile(options.projectRoot,
|
|
6535
|
+
return await extractor.writeDomainTermsFile(options.projectRoot, []);
|
|
6521
6536
|
} catch (err) {
|
|
6522
6537
|
writeErr2(
|
|
6523
6538
|
`[wrongstack] domain-terms mirror refresh failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -6570,7 +6585,7 @@ async function setupCliPromptAndTools(params) {
|
|
|
6570
6585
|
pathJoiner: { join: (a, b) => path7.join(a, b) },
|
|
6571
6586
|
systemPromptBuilderToken: TOKENS8.SystemPromptBuilder
|
|
6572
6587
|
});
|
|
6573
|
-
await refreshDomainTermsMirror({ projectRoot
|
|
6588
|
+
await refreshDomainTermsMirror({ projectRoot });
|
|
6574
6589
|
const toolRegistry = new ToolRegistry2();
|
|
6575
6590
|
registerBuiltinTools({
|
|
6576
6591
|
toolRegistry,
|
|
@@ -10274,6 +10289,7 @@ function buildCompactCommand(opts) {
|
|
|
10274
10289
|
// src/slash-commands/context.ts
|
|
10275
10290
|
import * as fs4 from "node:fs/promises";
|
|
10276
10291
|
import {
|
|
10292
|
+
CONTEXT_WINDOW_MODE_PINNED_META_KEY,
|
|
10277
10293
|
formatContextWindowModeList,
|
|
10278
10294
|
getContextWindowMode,
|
|
10279
10295
|
resolveContextWindowPolicy
|
|
@@ -10398,6 +10414,7 @@ ${formatContextWindowModeList(active2)}`;
|
|
|
10398
10414
|
const policy2 = { ...base, thresholds: { warn, soft, hard } };
|
|
10399
10415
|
ctx.meta["contextWindowMode"] = policy2.id;
|
|
10400
10416
|
ctx.meta["contextWindowPolicy"] = policy2;
|
|
10417
|
+
ctx.meta[CONTEXT_WINDOW_MODE_PINNED_META_KEY] = true;
|
|
10401
10418
|
if (persist) {
|
|
10402
10419
|
const error = await persistContextConfig(opts, {
|
|
10403
10420
|
warnThreshold: warn,
|
|
@@ -10424,9 +10441,10 @@ ${formatContextWindowModeList(active2)}`;
|
|
|
10424
10441
|
`);
|
|
10425
10442
|
return { message: msg3 };
|
|
10426
10443
|
}
|
|
10427
|
-
const policy2 = resolveContextWindowPolicy({}, mode.id);
|
|
10444
|
+
const policy2 = resolveContextWindowPolicy({}, mode.id, readEffectiveLimit(ctx, opts));
|
|
10428
10445
|
ctx.meta["contextWindowMode"] = policy2.id;
|
|
10429
10446
|
ctx.meta["contextWindowPolicy"] = policy2;
|
|
10447
|
+
ctx.meta[CONTEXT_WINDOW_MODE_PINNED_META_KEY] = true;
|
|
10430
10448
|
const msg2 = [
|
|
10431
10449
|
`${color20.green("Context mode set:")} ${policy2.id} (${policy2.name})`,
|
|
10432
10450
|
` thresholds: warn ${pct(policy2.thresholds.warn)}, soft ${pct(policy2.thresholds.soft)}, hard ${pct(policy2.thresholds.hard)}`,
|
|
@@ -18345,6 +18363,47 @@ function formatAudit(rows) {
|
|
|
18345
18363
|
function formatLegacyImport(result) {
|
|
18346
18364
|
return `Legacy import complete: ${result.imported} imported, ${result.skipped} skipped from ${result.files} file(s).`;
|
|
18347
18365
|
}
|
|
18366
|
+
function formatMemoryDiagnostics(diag) {
|
|
18367
|
+
const lines = ["\u{1FA7A} Memory diagnostics", ""];
|
|
18368
|
+
const byStatus = Object.entries(diag.sageStats.byStatus).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18369
|
+
const byKind = Object.entries(diag.sageStats.byKind).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18370
|
+
lines.push("SAGE (lexical):");
|
|
18371
|
+
lines.push(` total entries: ${diag.sageTotal}`);
|
|
18372
|
+
lines.push(` by status: ${byStatus || "\u2205"}`);
|
|
18373
|
+
lines.push(` by kind: ${byKind || "\u2205"}`);
|
|
18374
|
+
if (diag.sageStats.injections !== void 0) {
|
|
18375
|
+
lines.push(` injections: ${diag.sageStats.injections}`);
|
|
18376
|
+
}
|
|
18377
|
+
if (diag.sageStats.uses !== void 0) {
|
|
18378
|
+
lines.push(` uses: ${diag.sageStats.uses}`);
|
|
18379
|
+
}
|
|
18380
|
+
lines.push("");
|
|
18381
|
+
if (!diag.vector) {
|
|
18382
|
+
lines.push("Vector memory: disabled \u2014 running on the SAGE-only surface.");
|
|
18383
|
+
} else {
|
|
18384
|
+
const v = diag.vector;
|
|
18385
|
+
lines.push("Vector (semantic):");
|
|
18386
|
+
lines.push(` entries: ${v.entries}`);
|
|
18387
|
+
lines.push(` with vectors: ${v.vectors}`);
|
|
18388
|
+
lines.push(` providers: ${v.providers.join(", ") || "\u2205"}`);
|
|
18389
|
+
lines.push(` model: ${v.modelId} (${v.dimensions}-dim)`);
|
|
18390
|
+
lines.push(` cache: ${v.cacheEntries} rows \xB7 ${v.cacheProviders} provider(s) \xB7 ${v.totalUseCount} hits`);
|
|
18391
|
+
if (v.oldestLastUsedAt) {
|
|
18392
|
+
lines.push(` cache oldest: ${v.oldestLastUsedAt}`);
|
|
18393
|
+
}
|
|
18394
|
+
lines.push(` store path: ${v.storePath}`);
|
|
18395
|
+
lines.push("");
|
|
18396
|
+
lines.push("Cross-system coverage:");
|
|
18397
|
+
lines.push(` vector \u2194 SAGE: ${v.mirroredInSage} mirrored`);
|
|
18398
|
+
if (v.standalone > 0) {
|
|
18399
|
+
lines.push(` standalone: ${v.standalone} vector-only entries (no SAGE id \u2014 lexical recall misses these)`);
|
|
18400
|
+
}
|
|
18401
|
+
if (v.mirroredInSage === 0 && diag.sageTotal > 0) {
|
|
18402
|
+
lines.push(" \u{1F4A1} Run `wrongstack --vector-sync` to backfill the vector mirror.");
|
|
18403
|
+
}
|
|
18404
|
+
}
|
|
18405
|
+
return lines.join("\n");
|
|
18406
|
+
}
|
|
18348
18407
|
function formatSageStats(stats, scopedCount, scopedRoles) {
|
|
18349
18408
|
const lines = [
|
|
18350
18409
|
"## SAGE Stats",
|
|
@@ -18407,6 +18466,60 @@ function formatSageShow(stats, memories) {
|
|
|
18407
18466
|
lines.push(`*${memories.length} entr${memories.length === 1 ? "y" : "ies"}*`);
|
|
18408
18467
|
return lines.join("\n");
|
|
18409
18468
|
}
|
|
18469
|
+
function formatSearchRace(race) {
|
|
18470
|
+
const lines = [];
|
|
18471
|
+
const pct2 = (value) => `${Math.round(value * 100)}%`;
|
|
18472
|
+
lines.push(`## \u{1F3C1} Search race \u2014 "${race.query}"`);
|
|
18473
|
+
lines.push("");
|
|
18474
|
+
lines.push(
|
|
18475
|
+
`lexical: ${race.metrics.lexicalCount} \xB7 vector: ${race.metrics.vectorCount} \xB7 overlap: ${race.metrics.overlapCount} \xB7 agreement: ${pct2(race.metrics.agreementRatio)}`
|
|
18476
|
+
);
|
|
18477
|
+
if (race.metrics.lexicalOnlyRatio > 0) {
|
|
18478
|
+
lines.push(
|
|
18479
|
+
` \u21B3 lexical-only: ${pct2(race.metrics.lexicalOnlyRatio)} of lexical recall is invisible to vector.`
|
|
18480
|
+
);
|
|
18481
|
+
}
|
|
18482
|
+
if (race.metrics.vectorOnlyRatio > 0) {
|
|
18483
|
+
lines.push(
|
|
18484
|
+
` \u21B3 vector-only: ${pct2(race.metrics.vectorOnlyRatio)} of vector recall is invisible to lexical.`
|
|
18485
|
+
);
|
|
18486
|
+
}
|
|
18487
|
+
lines.push("");
|
|
18488
|
+
if (race.overlap.length > 0) {
|
|
18489
|
+
lines.push("### \u2705 Both channels");
|
|
18490
|
+
for (const row of race.overlap) {
|
|
18491
|
+
lines.push(
|
|
18492
|
+
`- \`${row.id.slice(0, 12)}\u2026\` L=${pct2(row.lexicalScore)} V=${pct2(row.vectorScore)} ${row.preview}`
|
|
18493
|
+
);
|
|
18494
|
+
}
|
|
18495
|
+
lines.push("");
|
|
18496
|
+
}
|
|
18497
|
+
if (race.lexicalOnly.length > 0) {
|
|
18498
|
+
lines.push("### \u{1F170}\uFE0F Lexical only (vector missed)");
|
|
18499
|
+
for (const row of race.lexicalOnly) {
|
|
18500
|
+
lines.push(
|
|
18501
|
+
`- \`${row.id.slice(0, 12)}\u2026\` L=${pct2(row.lexicalScore ?? 0)} ${row.preview}`
|
|
18502
|
+
);
|
|
18503
|
+
}
|
|
18504
|
+
lines.push("");
|
|
18505
|
+
}
|
|
18506
|
+
if (race.vectorOnly.length > 0) {
|
|
18507
|
+
lines.push("### \u{1F171}\uFE0F Vector only (lexical missed)");
|
|
18508
|
+
for (const row of race.vectorOnly) {
|
|
18509
|
+
lines.push(
|
|
18510
|
+
`- \`${row.id.slice(0, 12)}\u2026\` V=${pct2(row.vectorScore ?? 0)} ${row.preview}`
|
|
18511
|
+
);
|
|
18512
|
+
}
|
|
18513
|
+
lines.push("");
|
|
18514
|
+
}
|
|
18515
|
+
if (race.overlap.length === 0 && race.lexicalOnly.length === 0 && race.vectorOnly.length === 0) {
|
|
18516
|
+
lines.push("_No memories matched either channel for this query._");
|
|
18517
|
+
}
|
|
18518
|
+
return lines.join("\n");
|
|
18519
|
+
}
|
|
18520
|
+
|
|
18521
|
+
// src/slash-commands/memory.ts
|
|
18522
|
+
import { runSearchRace } from "@wrongstack/vector-memory";
|
|
18410
18523
|
|
|
18411
18524
|
// src/slash-commands/memory-gather.ts
|
|
18412
18525
|
import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
|
|
@@ -18935,11 +19048,12 @@ async function fileProposals(Sage, proposals) {
|
|
|
18935
19048
|
}
|
|
18936
19049
|
|
|
18937
19050
|
// src/slash-commands/memory.ts
|
|
19051
|
+
var DOMAIN_TERM_TAG = "domain-term";
|
|
18938
19052
|
function buildMemoryCommand(opts) {
|
|
18939
19053
|
return {
|
|
18940
19054
|
name: "memory",
|
|
18941
19055
|
category: "Inspect",
|
|
18942
|
-
description: "Inspect or edit persistent memory: /memory [show|search|file|path|for-file|graph|gather|remember|update|delete|forget|hygiene|verify|candidates|triage|audit|import-legacy|clear|compact|compact-log|stats|audience]",
|
|
19056
|
+
description: "Inspect or edit persistent memory: /memory [show|search|race|file|path|for-file|graph|gather|remember|update|delete|forget|hygiene|verify|candidates|triage|audit|import-legacy|clear|compact|compact-log|stats|audience|diagnostics|purge-domain-terms]",
|
|
18943
19057
|
async run(args) {
|
|
18944
19058
|
const store = opts.memoryStore;
|
|
18945
19059
|
if (!store) return { message: "No memory store configured." };
|
|
@@ -19139,6 +19253,32 @@ function buildMemoryCommand(opts) {
|
|
|
19139
19253
|
)
|
|
19140
19254
|
};
|
|
19141
19255
|
}
|
|
19256
|
+
case "race": {
|
|
19257
|
+
if (!restJoined) return { message: "Usage: /memory race <query>" };
|
|
19258
|
+
if (!Sage) {
|
|
19259
|
+
return {
|
|
19260
|
+
message: "`/memory race` requires the SAGE surface. Run the search with `/memory search <query>` instead."
|
|
19261
|
+
};
|
|
19262
|
+
}
|
|
19263
|
+
const vectorStore = opts.vectorMemoryStore;
|
|
19264
|
+
if (!vectorStore) {
|
|
19265
|
+
const entries = await Sage.searchSage(restJoined, { limit: 20 });
|
|
19266
|
+
return {
|
|
19267
|
+
message: `Vector memory is not wired in this host \u2014 only the lexical channel is available.
|
|
19268
|
+
|
|
19269
|
+
` + formatSageMemories(entries, `Search: ${restJoined}`)
|
|
19270
|
+
};
|
|
19271
|
+
}
|
|
19272
|
+
try {
|
|
19273
|
+
const lexical = await Sage.searchSage(restJoined, { limit: 20 });
|
|
19274
|
+
const race = await runSearchRace(restJoined, lexical, vectorStore, { limit: 20 });
|
|
19275
|
+
return { message: formatSearchRace(race) };
|
|
19276
|
+
} catch (err) {
|
|
19277
|
+
return {
|
|
19278
|
+
message: `Race failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19279
|
+
};
|
|
19280
|
+
}
|
|
19281
|
+
}
|
|
19142
19282
|
case "graph": {
|
|
19143
19283
|
if (!Sage?.graphFor) return requiresSage("graph");
|
|
19144
19284
|
if (!restJoined) return { message: "Usage: /memory graph <memory-id|path|query>" };
|
|
@@ -19218,6 +19358,94 @@ function buildMemoryCommand(opts) {
|
|
|
19218
19358
|
await store.clear();
|
|
19219
19359
|
return { message: "Cleared all non-permanent memory scopes by explicit force request." };
|
|
19220
19360
|
}
|
|
19361
|
+
case "purge-domain-terms": {
|
|
19362
|
+
if (!Sage) return requiresSage("purge-domain-terms");
|
|
19363
|
+
const force = rest.includes("--force");
|
|
19364
|
+
if (!force) {
|
|
19365
|
+
return {
|
|
19366
|
+
message: `Refusing to run /memory purge-domain-terms without --force.
|
|
19367
|
+
|
|
19368
|
+
This is a one-off migration that permanently removes every SAGE memory tagged \`${DOMAIN_TERM_TAG}\` (and the historical \`glossary\` / \`project-jargon\` companion tags). It cannot be undone. Run /memory purge-domain-terms --force when you are ready.`
|
|
19369
|
+
};
|
|
19370
|
+
}
|
|
19371
|
+
try {
|
|
19372
|
+
const targets = [];
|
|
19373
|
+
const PAGE = 200;
|
|
19374
|
+
let cursor;
|
|
19375
|
+
const listPage = Sage.listSagePage;
|
|
19376
|
+
if (typeof listPage === "function") {
|
|
19377
|
+
while (true) {
|
|
19378
|
+
const page = await listPage({
|
|
19379
|
+
statuses: ["active", "stale"],
|
|
19380
|
+
limit: PAGE,
|
|
19381
|
+
...cursor !== void 0 ? { cursor } : {}
|
|
19382
|
+
});
|
|
19383
|
+
for (const mem of page.memories) {
|
|
19384
|
+
if (Array.isArray(mem.tags) && mem.tags.some(
|
|
19385
|
+
(t) => t === DOMAIN_TERM_TAG || t === "glossary" || t === "project-jargon"
|
|
19386
|
+
)) {
|
|
19387
|
+
targets.push({ id: mem.id, tags: mem.tags });
|
|
19388
|
+
}
|
|
19389
|
+
}
|
|
19390
|
+
if (!page.nextCursor || page.memories.length === 0) break;
|
|
19391
|
+
cursor = page.nextCursor;
|
|
19392
|
+
}
|
|
19393
|
+
} else {
|
|
19394
|
+
const memories = await Sage.listSage(["active", "stale"]);
|
|
19395
|
+
for (const mem of memories) {
|
|
19396
|
+
if (Array.isArray(mem.tags) && mem.tags.some(
|
|
19397
|
+
(t) => t === DOMAIN_TERM_TAG || t === "glossary" || t === "project-jargon"
|
|
19398
|
+
)) {
|
|
19399
|
+
targets.push({ id: mem.id, tags: mem.tags });
|
|
19400
|
+
}
|
|
19401
|
+
}
|
|
19402
|
+
}
|
|
19403
|
+
if (targets.length === 0) {
|
|
19404
|
+
return {
|
|
19405
|
+
message: `No SAGE memories matched the legacy domain-term tag trio. Nothing to purge.`
|
|
19406
|
+
};
|
|
19407
|
+
}
|
|
19408
|
+
let deleted = 0;
|
|
19409
|
+
const failures = [];
|
|
19410
|
+
for (const t of targets) {
|
|
19411
|
+
try {
|
|
19412
|
+
await Sage.deleteSage(
|
|
19413
|
+
t.id,
|
|
19414
|
+
"domain-term persistence removed; pre-migration cleanup",
|
|
19415
|
+
{ force: true }
|
|
19416
|
+
);
|
|
19417
|
+
deleted++;
|
|
19418
|
+
} catch (err) {
|
|
19419
|
+
failures.push(`${t.id}: ${toErrorMessage17(err)}`);
|
|
19420
|
+
}
|
|
19421
|
+
}
|
|
19422
|
+
const tagSummary = /* @__PURE__ */ new Map();
|
|
19423
|
+
for (const t of targets) {
|
|
19424
|
+
for (const tag of t.tags) {
|
|
19425
|
+
if (tag === DOMAIN_TERM_TAG || tag === "glossary" || tag === "project-jargon") {
|
|
19426
|
+
tagSummary.set(tag, (tagSummary.get(tag) ?? 0) + 1);
|
|
19427
|
+
}
|
|
19428
|
+
}
|
|
19429
|
+
}
|
|
19430
|
+
const tagBreakdown = [...tagSummary.entries()].sort((a, b) => b[1] - a[1]).map(([tag, count]) => ` - ${tag}: ${count}`).join("\n");
|
|
19431
|
+
const tail = failures.length > 0 ? `
|
|
19432
|
+
|
|
19433
|
+
Failures (${failures.length}):
|
|
19434
|
+
${failures.slice(0, 10).map((f) => ` - ${f}`).join("\n")}` : "";
|
|
19435
|
+
return {
|
|
19436
|
+
message: `Purged ${deleted} of ${targets.length} legacy domain-term memories.
|
|
19437
|
+
|
|
19438
|
+
Tag breakdown of matched memories:
|
|
19439
|
+
${tagBreakdown}
|
|
19440
|
+
|
|
19441
|
+
The \`${DOMAIN_TERM_TAG}\` / \`glossary\` / \`project-jargon\` tags are now absent from the live corpus. Run \`/memory show\` to confirm.${tail}`
|
|
19442
|
+
};
|
|
19443
|
+
} catch (err) {
|
|
19444
|
+
return {
|
|
19445
|
+
message: `purge-domain-terms failed: ${toErrorMessage17(err)}`
|
|
19446
|
+
};
|
|
19447
|
+
}
|
|
19448
|
+
}
|
|
19221
19449
|
case "compact": {
|
|
19222
19450
|
return runCompact(opts);
|
|
19223
19451
|
}
|
|
@@ -19282,6 +19510,71 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19282
19510
|
if (!Sage) return requiresSage("audience");
|
|
19283
19511
|
return runAudienceMemory(Sage, rest);
|
|
19284
19512
|
}
|
|
19513
|
+
case "diagnostics": {
|
|
19514
|
+
if (!Sage) {
|
|
19515
|
+
return {
|
|
19516
|
+
message: "Memory diagnostics require the SAGE surface (this memory store does not expose it)."
|
|
19517
|
+
};
|
|
19518
|
+
}
|
|
19519
|
+
const vectorStore = opts.vectorMemoryStore;
|
|
19520
|
+
let sageStats;
|
|
19521
|
+
let sageTotal = 0;
|
|
19522
|
+
try {
|
|
19523
|
+
[sageStats, sageTotal] = await Promise.all([
|
|
19524
|
+
Sage.stats(),
|
|
19525
|
+
Sage.listSagePage({ limit: 1 }).then(
|
|
19526
|
+
(page) => page.total ?? page.memories.length
|
|
19527
|
+
)
|
|
19528
|
+
]);
|
|
19529
|
+
} catch (err) {
|
|
19530
|
+
return {
|
|
19531
|
+
message: `Memory diagnostics failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19532
|
+
};
|
|
19533
|
+
}
|
|
19534
|
+
let vectorDiag;
|
|
19535
|
+
if (vectorStore) {
|
|
19536
|
+
try {
|
|
19537
|
+
const stats = vectorStore.stats();
|
|
19538
|
+
const cache = vectorStore.cacheStats();
|
|
19539
|
+
const vectorRows = vectorStore.list({ limit: 5e3 });
|
|
19540
|
+
let mirroredInSage = 0;
|
|
19541
|
+
let standalone = 0;
|
|
19542
|
+
for (const row of vectorRows) {
|
|
19543
|
+
const sageId = row.metadata?.sageId;
|
|
19544
|
+
if (typeof sageId === "string" && sageId.length > 0) {
|
|
19545
|
+
mirroredInSage++;
|
|
19546
|
+
} else {
|
|
19547
|
+
standalone++;
|
|
19548
|
+
}
|
|
19549
|
+
}
|
|
19550
|
+
vectorDiag = {
|
|
19551
|
+
entries: stats.entries,
|
|
19552
|
+
vectors: stats.vectors,
|
|
19553
|
+
providers: stats.providers,
|
|
19554
|
+
modelId: stats.modelId,
|
|
19555
|
+
dimensions: stats.dimensions,
|
|
19556
|
+
cacheEntries: cache.entries,
|
|
19557
|
+
cacheProviders: cache.providers,
|
|
19558
|
+
totalUseCount: cache.totalUseCount,
|
|
19559
|
+
oldestLastUsedAt: cache.oldestLastUsedAt,
|
|
19560
|
+
storePath: vectorStore.directory,
|
|
19561
|
+
mirroredInSage,
|
|
19562
|
+
standalone
|
|
19563
|
+
};
|
|
19564
|
+
} catch (err) {
|
|
19565
|
+
return {
|
|
19566
|
+
message: `Memory diagnostics (vector side) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19567
|
+
};
|
|
19568
|
+
}
|
|
19569
|
+
}
|
|
19570
|
+
return {
|
|
19571
|
+
message: formatMemoryDiagnostics({
|
|
19572
|
+
sageStats,
|
|
19573
|
+
sageTotal,
|
|
19574
|
+
vector: vectorDiag
|
|
19575
|
+
})
|
|
19576
|
+
};
|
|
19577
|
+
}
|
|
19285
19578
|
default:
|
|
19286
19579
|
return {
|
|
19287
19580
|
message: unknownSubcommand(
|
|
@@ -19289,6 +19582,7 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19289
19582
|
[
|
|
19290
19583
|
"show",
|
|
19291
19584
|
"search",
|
|
19585
|
+
"race",
|
|
19292
19586
|
"file",
|
|
19293
19587
|
"path",
|
|
19294
19588
|
"for-file",
|
|
@@ -19307,7 +19601,8 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19307
19601
|
"clear",
|
|
19308
19602
|
"compact",
|
|
19309
19603
|
"stats",
|
|
19310
|
-
"audience"
|
|
19604
|
+
"audience",
|
|
19605
|
+
"purge-domain-terms"
|
|
19311
19606
|
],
|
|
19312
19607
|
"memory"
|
|
19313
19608
|
)
|
|
@@ -23527,7 +23822,8 @@ var THEME_META = {
|
|
|
23527
23822
|
desc: "Anthony Fu's minimal palette \u2014 muted, print-like"
|
|
23528
23823
|
},
|
|
23529
23824
|
aura: { name: "Aura Dark", desc: "Vivid purple and spring green on near-black violet" },
|
|
23530
|
-
"dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" }
|
|
23825
|
+
"dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" },
|
|
23826
|
+
monochrome: { name: "Monochrome", desc: "Pure grayscale \u2014 no hue, only luminance" }
|
|
23531
23827
|
};
|
|
23532
23828
|
var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({ id, ...THEME_META[id] }));
|
|
23533
23829
|
function presetHelpLines(perLine = 4) {
|
|
@@ -29419,6 +29715,7 @@ function setupCliSlashCommands(params) {
|
|
|
29419
29715
|
renderer,
|
|
29420
29716
|
events,
|
|
29421
29717
|
memoryStore,
|
|
29718
|
+
vectorMemoryStore,
|
|
29422
29719
|
context,
|
|
29423
29720
|
cwd,
|
|
29424
29721
|
projectRoot,
|
|
@@ -29495,6 +29792,7 @@ function setupCliSlashCommands(params) {
|
|
|
29495
29792
|
renderer,
|
|
29496
29793
|
events,
|
|
29497
29794
|
memoryStore,
|
|
29795
|
+
vectorMemoryStore,
|
|
29498
29796
|
context,
|
|
29499
29797
|
cwd,
|
|
29500
29798
|
projectRoot,
|
|
@@ -30419,6 +30717,10 @@ import {
|
|
|
30419
30717
|
SlashCommandRegistry
|
|
30420
30718
|
} from "@wrongstack/core/registry";
|
|
30421
30719
|
import { normalizeTokenSavingTier as normalizeTokenSavingTier3 } from "@wrongstack/core/types";
|
|
30720
|
+
import {
|
|
30721
|
+
CONTEXT_WINDOW_MODE_PINNED_META_KEY as CONTEXT_WINDOW_MODE_PINNED_META_KEY2,
|
|
30722
|
+
resolveContextWindowPolicy as resolveContextWindowPolicy3
|
|
30723
|
+
} from "@wrongstack/core/types";
|
|
30422
30724
|
import {
|
|
30423
30725
|
createVaultBackedMcpAuthorizationProviderFactory,
|
|
30424
30726
|
MCPAuthorizationManager,
|
|
@@ -30929,7 +31231,11 @@ async function setupCompaction(params) {
|
|
|
30929
31231
|
providerId: config.provider ?? provider.id,
|
|
30930
31232
|
modelId: config.model ?? context.model
|
|
30931
31233
|
});
|
|
30932
|
-
const initialPolicy = resolveContextWindowPolicy2(
|
|
31234
|
+
const initialPolicy = resolveContextWindowPolicy2(
|
|
31235
|
+
config.context,
|
|
31236
|
+
void 0,
|
|
31237
|
+
effectiveMaxContext
|
|
31238
|
+
);
|
|
30933
31239
|
context.meta ??= {};
|
|
30934
31240
|
context.meta["contextWindowMode"] = initialPolicy.id;
|
|
30935
31241
|
context.meta["contextWindowPolicy"] = initialPolicy;
|
|
@@ -31366,6 +31672,15 @@ async function setupLifecycleAndPlugins(deps) {
|
|
|
31366
31672
|
context.meta["effectiveMaxContext"] = effectiveMaxContextRef.current;
|
|
31367
31673
|
autoCompactor?.setMaxContext(effectiveMaxContextRef.current);
|
|
31368
31674
|
autoCompactor?.setEnabled(config.context.autoCompact !== false);
|
|
31675
|
+
if (context.meta[CONTEXT_WINDOW_MODE_PINNED_META_KEY2] !== true) {
|
|
31676
|
+
const policy = resolveContextWindowPolicy3(
|
|
31677
|
+
config.context,
|
|
31678
|
+
void 0,
|
|
31679
|
+
effectiveMaxContextRef.current
|
|
31680
|
+
);
|
|
31681
|
+
context.meta["contextWindowMode"] = policy.id;
|
|
31682
|
+
context.meta["contextWindowPolicy"] = policy;
|
|
31683
|
+
}
|
|
31369
31684
|
} else {
|
|
31370
31685
|
delete context.meta["effectiveMaxContext"];
|
|
31371
31686
|
autoCompactor?.setEnabled(false);
|
|
@@ -32065,7 +32380,12 @@ function warnUnlessMissing(logger, operation, error) {
|
|
|
32065
32380
|
// src/cli-main.ts
|
|
32066
32381
|
import {
|
|
32067
32382
|
TransformersEmbeddingProvider,
|
|
32068
|
-
VectorMemoryStore
|
|
32383
|
+
VectorMemoryStore,
|
|
32384
|
+
wrapMemoryPortWithVectorRecall
|
|
32385
|
+
} from "@wrongstack/vector-memory";
|
|
32386
|
+
import {
|
|
32387
|
+
startFirstBootSageSync,
|
|
32388
|
+
subscribeVectorMemoryToSage
|
|
32069
32389
|
} from "@wrongstack/vector-memory";
|
|
32070
32390
|
|
|
32071
32391
|
// src/wiring/replay-governance-setup.ts
|
|
@@ -32672,8 +32992,9 @@ async function runInteractive(cliCtx) {
|
|
|
32672
32992
|
const modelCapabilitiesRef = {
|
|
32673
32993
|
current: modelCapabilities
|
|
32674
32994
|
};
|
|
32675
|
-
|
|
32995
|
+
let memoryStore = container.resolve(TOKENS12.MemoryStore);
|
|
32676
32996
|
await memoryStore.initialize();
|
|
32997
|
+
const teardownHandlers = [];
|
|
32677
32998
|
let vectorMemoryStore;
|
|
32678
32999
|
const vectorMemoryModelCacheDir = path32.join(
|
|
32679
33000
|
projectRoot,
|
|
@@ -32695,6 +33016,34 @@ async function runInteractive(cliCtx) {
|
|
|
32695
33016
|
);
|
|
32696
33017
|
vectorMemoryStore = void 0;
|
|
32697
33018
|
}
|
|
33019
|
+
if (vectorMemoryStore) {
|
|
33020
|
+
void startFirstBootSageSync({
|
|
33021
|
+
store: vectorMemoryStore,
|
|
33022
|
+
memoryStore,
|
|
33023
|
+
logger
|
|
33024
|
+
});
|
|
33025
|
+
memoryStore = wrapMemoryPortWithVectorRecall(memoryStore, {
|
|
33026
|
+
store: vectorMemoryStore,
|
|
33027
|
+
weight: 0.3
|
|
33028
|
+
});
|
|
33029
|
+
const mirrorHandle = subscribeVectorMemoryToSage({
|
|
33030
|
+
store: vectorMemoryStore,
|
|
33031
|
+
memoryStore,
|
|
33032
|
+
logger
|
|
33033
|
+
});
|
|
33034
|
+
teardownHandlers.push(() => mirrorHandle.dispose());
|
|
33035
|
+
if (flags["vector-sync"] === true) {
|
|
33036
|
+
const forced = await startFirstBootSageSync({
|
|
33037
|
+
store: vectorMemoryStore,
|
|
33038
|
+
memoryStore,
|
|
33039
|
+
logger,
|
|
33040
|
+
force: true
|
|
33041
|
+
});
|
|
33042
|
+
logger.info(
|
|
33043
|
+
forced.synced ? `vector-memory forced re-sync complete (${forced.marker?.indexed ?? 0} new)` : `vector-memory forced re-sync skipped: ${forced.reason}`
|
|
33044
|
+
);
|
|
33045
|
+
}
|
|
33046
|
+
}
|
|
32698
33047
|
const skillLoader = container.resolve(TOKENS12.SkillLoader);
|
|
32699
33048
|
const promptLoader = container.resolve(TOKENS12.PromptLoader);
|
|
32700
33049
|
const sessionRef = {
|
|
@@ -32736,7 +33085,6 @@ async function runInteractive(cliCtx) {
|
|
|
32736
33085
|
config: { provider: config.provider, model: config.model }
|
|
32737
33086
|
});
|
|
32738
33087
|
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
32739
|
-
const teardownHandlers = [];
|
|
32740
33088
|
const evOn = createTeardownEventRegistrar(events, teardownHandlers);
|
|
32741
33089
|
if (vectorMemoryStore) {
|
|
32742
33090
|
const store = vectorMemoryStore;
|
|
@@ -33166,6 +33514,7 @@ async function runInteractive(cliCtx) {
|
|
|
33166
33514
|
renderer,
|
|
33167
33515
|
events,
|
|
33168
33516
|
memoryStore,
|
|
33517
|
+
vectorMemoryStore,
|
|
33169
33518
|
context,
|
|
33170
33519
|
cwd,
|
|
33171
33520
|
projectRoot,
|
|
@@ -33402,4 +33751,4 @@ export {
|
|
|
33402
33751
|
CLI_VERSION,
|
|
33403
33752
|
runInteractive
|
|
33404
33753
|
};
|
|
33405
|
-
//# sourceMappingURL=cli-main-
|
|
33754
|
+
//# sourceMappingURL=cli-main-WWZJF33V.js.map
|
package/dist/context-limit.d.ts
CHANGED
|
@@ -23,10 +23,13 @@ export interface ResolveMaxContextInput {
|
|
|
23
23
|
* Priority chain (first hit wins):
|
|
24
24
|
* 1. providers.<id>.capabilities.maxContext — explicit per-provider override.
|
|
25
25
|
* Provider-SCOPED, so it can't silently pin unrelated providers.
|
|
26
|
-
* 2.
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* 2. own catalog entry, else sibling, for OAuth families — when the family is
|
|
27
|
+
* itself published under its own id (openai-codex ships via the curated
|
|
28
|
+
* overlay), that entry is authoritative. Otherwise
|
|
29
|
+
* anthropic-oauth/openai-codex/github-copilot share their models with a
|
|
30
|
+
* canonical models.dev provider (anthropic/openai) but aren't themselves
|
|
31
|
+
* listed, so resolve the real per-model window there
|
|
32
|
+
* (e.g. Opus 4.8 → 1M, gpt-5.5 → 1.05M)
|
|
30
33
|
* 3. models.dev catalog (capabilitiesFor → getModel) — the published per-model
|
|
31
34
|
* window, keyed by provider (e.g. 1M for an OpenRouter model)
|
|
32
35
|
* 4. config.context.effectiveMaxContext — global FALLBACK for models whose
|
|
@@ -207,7 +207,7 @@ async function runWebUIDispatch(ctx) {
|
|
|
207
207
|
const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
|
|
208
208
|
agent.disableInteractiveConfirmation();
|
|
209
209
|
renderer.setSilent(true);
|
|
210
|
-
const { runWebUI } = await import("./webui-server-
|
|
210
|
+
const { runWebUI } = await import("./webui-server-JXJ4CGIX.js");
|
|
211
211
|
const flagValue = (names) => {
|
|
212
212
|
for (const name of names) {
|
|
213
213
|
if (!Object.hasOwn(flags, name)) continue;
|
|
@@ -1420,6 +1420,9 @@ async function resumeSession(ctx, sessionId) {
|
|
|
1420
1420
|
}
|
|
1421
1421
|
tokenCounter.reset();
|
|
1422
1422
|
tokenCounter.account(resumed.data.usage, targetModel, targetProviderId);
|
|
1423
|
+
if (typeof resumed.data.usage?.input === "number" && resumed.data.usage.input > 0) {
|
|
1424
|
+
agent.ctx.lastRequestTokens = resumed.data.usage.input;
|
|
1425
|
+
}
|
|
1423
1426
|
const reqTokens = tokenCounter.currentRequestTokens?.();
|
|
1424
1427
|
const tokens = (typeof reqTokens === "number" ? reqTokens : 0) + (typeof reqTokens?.input === "number" ? reqTokens.input : 0) + (typeof reqTokens?.cacheRead === "number" ? reqTokens.cacheRead : 0) + (typeof reqTokens?.cacheWrite === "number" ? reqTokens.cacheWrite : 0);
|
|
1425
1428
|
const maxContext = agent.ctx.provider?.capabilities?.maxContext ?? 0;
|
|
@@ -6042,4 +6045,4 @@ export {
|
|
|
6042
6045
|
execute,
|
|
6043
6046
|
resolveReviewerFallbackModels
|
|
6044
6047
|
};
|
|
6045
|
-
//# sourceMappingURL=execution-
|
|
6048
|
+
//# sourceMappingURL=execution-6HIKTAUB.js.map
|
package/dist/index.js
CHANGED
|
@@ -1836,7 +1836,7 @@ var subcommandsWithFocusedHelp = Object.keys(helpTable);
|
|
|
1836
1836
|
var loaders = {
|
|
1837
1837
|
acp: async () => (await import("./acp-5ZLGFHWP.js")).acpCmd,
|
|
1838
1838
|
init: async () => (await import("./init-E2NDDOHI.js")).initCmd,
|
|
1839
|
-
auth: async () => (await import("./auth-
|
|
1839
|
+
auth: async () => (await import("./auth-WOKC2RVG.js")).authCmd,
|
|
1840
1840
|
update: async () => (await import("./update-VZSOZGYC.js")).updateCmd,
|
|
1841
1841
|
sessions: async () => (await import("./sessions-config-YX2ZPAFM.js")).sessionsCmd,
|
|
1842
1842
|
config: async () => (await import("./sessions-config-YX2ZPAFM.js")).configCmd,
|
|
@@ -4447,7 +4447,7 @@ async function initializeCli(argv) {
|
|
|
4447
4447
|
async function main(argv) {
|
|
4448
4448
|
const cliCtx = await initializeCli(argv);
|
|
4449
4449
|
if (typeof cliCtx === "number") return cliCtx;
|
|
4450
|
-
const { runInteractive } = await import("./cli-main-
|
|
4450
|
+
const { runInteractive } = await import("./cli-main-WWZJF33V.js");
|
|
4451
4451
|
return runInteractive(cliCtx);
|
|
4452
4452
|
}
|
|
4453
4453
|
|
|
@@ -3,6 +3,7 @@ import type { EventBus } from '@wrongstack/core/kernel';
|
|
|
3
3
|
import type { SlashCommandRegistry, ToolRegistry } from '@wrongstack/core/registry';
|
|
4
4
|
import type { CompactReport, HealthRegistry, MemoryPort, MetricsRuntimeStatus, MetricsSink, ModeStore, Renderer, SessionStore, SkillLoader, TokenCounter } from '@wrongstack/core/types';
|
|
5
5
|
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
6
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
6
7
|
/** Host capabilities supplied to command adapters. */
|
|
7
8
|
export interface SlashCommandContext {
|
|
8
9
|
registry: SlashCommandRegistry;
|
|
@@ -28,6 +29,13 @@ export interface SlashCommandContext {
|
|
|
28
29
|
/** App-level EventBus — used by GoalRunner to emit phase/graph events to the TUI. */
|
|
29
30
|
events: EventBus;
|
|
30
31
|
memoryStore?: MemoryPort | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Optional vector memory store. Wired when the host has enabled the
|
|
34
|
+
* dual-channel system; slash commands like `/memory diagnostics`
|
|
35
|
+
* and `/memory race` use it to surface cross-system health and
|
|
36
|
+
* run lexical vs semantic channel comparisons.
|
|
37
|
+
*/
|
|
38
|
+
vectorMemoryStore?: VectorMemoryStore | undefined;
|
|
31
39
|
context?: Context | undefined;
|
|
32
40
|
/** Working directory for the current session. */
|
|
33
41
|
cwd: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FindMemoriesForFileResponse, LegacyImportResult, MemoryCandidate, MemoryGraphEdge, MemoryVerificationResult, Sage, SageAuditRecord, SageHygieneReport, SageStats } from '@wrongstack/sage';
|
|
2
|
+
import type { SearchRaceResult } from '@wrongstack/vector-memory';
|
|
2
3
|
export declare function formatForFileResponse(filePath: string, response: FindMemoriesForFileResponse): string;
|
|
3
4
|
export declare function requiresSage(command: string): {
|
|
4
5
|
message: string;
|
|
@@ -11,6 +12,47 @@ export declare function formatHygiene(report: SageHygieneReport): string;
|
|
|
11
12
|
export declare function formatCandidates(candidates: MemoryCandidate[]): string;
|
|
12
13
|
export declare function formatAudit(rows: SageAuditRecord[]): string;
|
|
13
14
|
export declare function formatLegacyImport(result: LegacyImportResult): string;
|
|
15
|
+
/** Pre-collected diagnostic data for `formatMemoryDiagnostics`. */
|
|
16
|
+
export interface MemoryDiagnostics {
|
|
17
|
+
sageStats: SageStats;
|
|
18
|
+
/** Total SAGE entries (active + non-active) in the corpus. */
|
|
19
|
+
sageTotal: number;
|
|
20
|
+
vector: {
|
|
21
|
+
entries: number;
|
|
22
|
+
vectors: number;
|
|
23
|
+
providers: string[];
|
|
24
|
+
modelId: string;
|
|
25
|
+
dimensions: number;
|
|
26
|
+
cacheEntries: number;
|
|
27
|
+
cacheProviders: number;
|
|
28
|
+
totalUseCount: number;
|
|
29
|
+
oldestLastUsedAt: string | null;
|
|
30
|
+
storePath: string;
|
|
31
|
+
/** Vector entries whose `metadata.sageId` resolves in SAGE. */
|
|
32
|
+
mirroredInSage: number;
|
|
33
|
+
/** Vector entries without a `metadata.sageId` (standalone). */
|
|
34
|
+
standalone: number;
|
|
35
|
+
} | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Two-system health snapshot — covers SAGE stats, vector memory
|
|
39
|
+
* stats, and the cross-system coverage (how many SAGE memories have a
|
|
40
|
+
* vector mirror). Surfaces the value of running both stores side by
|
|
41
|
+
* side: the operator sees drift (vector entries without a SAGE id),
|
|
42
|
+
* the embedding cache hit ratio, and the active provider / dimension.
|
|
43
|
+
*/
|
|
44
|
+
export declare function formatMemoryDiagnostics(diag: MemoryDiagnostics): string;
|
|
14
45
|
export declare function formatSageStats(stats: SageStats, scopedCount?: number, scopedRoles?: string): string;
|
|
15
46
|
export declare function formatSageShow(stats: SageStats, memories: Sage[]): string;
|
|
47
|
+
/**
|
|
48
|
+
* Human-readable rendering of a `SearchRaceResult` — the channel
|
|
49
|
+
* comparison that makes the dual system's value visible. The output
|
|
50
|
+
* groups memories into three buckets: **both** (lexical + vector
|
|
51
|
+
* agreement), **lexical only** (rare-token matches the embedding
|
|
52
|
+
* model would under-rank), and **vector only** (semantic recall the
|
|
53
|
+
* FTS index would have missed). The summary metrics above the lists
|
|
54
|
+
* make the "what would I have missed?" question answerable in one
|
|
55
|
+
* glance.
|
|
56
|
+
*/
|
|
57
|
+
export declare function formatSearchRace(race: SearchRaceResult): string;
|
|
16
58
|
//# sourceMappingURL=memory-formatters.d.ts.map
|
|
@@ -8,7 +8,9 @@ export declare function startDeferredHttpListen(args: {
|
|
|
8
8
|
host: string;
|
|
9
9
|
httpPort: number;
|
|
10
10
|
logger: ListenLogger;
|
|
11
|
-
|
|
11
|
+
/** Fail-fast bind (no auto-advance on EADDRINUSE). Mirrors WEBUI_STRICT_PORT. */
|
|
12
|
+
strictPort?: boolean;
|
|
13
|
+
}): Promise<number>;
|
|
12
14
|
export declare function startIpv6LoopbackProxy(args: {
|
|
13
15
|
primary: http.Server;
|
|
14
16
|
httpPort: number;
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
createEmbeddedProviderOperations,
|
|
33
33
|
envFlag,
|
|
34
34
|
findFreePort,
|
|
35
|
+
isStrictPort,
|
|
35
36
|
resolveAuthToken,
|
|
36
37
|
sendSerialized
|
|
37
38
|
} from "@wrongstack/webui-server";
|
|
@@ -649,18 +650,19 @@ import {
|
|
|
649
650
|
|
|
650
651
|
// src/webui-server/listen-helpers.ts
|
|
651
652
|
import * as http from "node:http";
|
|
653
|
+
import { listenWithRetry } from "@wrongstack/webui-server";
|
|
652
654
|
async function startDeferredHttpListen(args) {
|
|
653
|
-
const { server, host, httpPort, logger } = args;
|
|
654
|
-
await
|
|
655
|
-
|
|
656
|
-
server.once("error", rejectListen);
|
|
655
|
+
const { server, host, httpPort, logger, strictPort } = args;
|
|
656
|
+
const boundPort = await listenWithRetry(server, host, httpPort, {
|
|
657
|
+
maxTries: strictPort ? 1 : 10
|
|
657
658
|
});
|
|
658
659
|
server.on("error", (err) => {
|
|
659
660
|
logger.error("http_server_error", {
|
|
660
661
|
message: err.message,
|
|
661
|
-
port:
|
|
662
|
+
port: boundPort
|
|
662
663
|
});
|
|
663
664
|
});
|
|
665
|
+
return boundPort;
|
|
664
666
|
}
|
|
665
667
|
async function startIpv6LoopbackProxy(args) {
|
|
666
668
|
const { primary, httpPort, logger } = args;
|
|
@@ -1207,12 +1209,12 @@ async function runWebUI(opts) {
|
|
|
1207
1209
|
const surface = opts.surface ?? "webui";
|
|
1208
1210
|
const surfaceDefaults = surface === "simpleui" ? { http: 3466 } : { http: 3456 };
|
|
1209
1211
|
const requestedHttpPort = opts.httpPort ?? opts.port ?? surfaceDefaults.http;
|
|
1210
|
-
const strictPort = opts.strictPort ?? (
|
|
1212
|
+
const strictPort = opts.strictPort ?? isStrictPort();
|
|
1211
1213
|
let httpPort = requestedHttpPort;
|
|
1212
1214
|
if (!strictPort) {
|
|
1213
1215
|
httpPort = await findFreePort(host, requestedHttpPort);
|
|
1214
1216
|
}
|
|
1215
|
-
|
|
1217
|
+
let wsPort = httpPort;
|
|
1216
1218
|
const globalRoot = opts.globalConfigPath ? path7.dirname(opts.globalConfigPath) : wstackGlobalRoot();
|
|
1217
1219
|
const profileConfigPath = opts.profileConfigPath ?? opts.globalConfigPath ?? path7.join(globalRoot, "config.json");
|
|
1218
1220
|
const rateLimitMax = Number.parseInt(process.env["WEBUI_RATE_LIMIT"] ?? "600", 10);
|
|
@@ -1303,7 +1305,7 @@ async function runWebUI(opts) {
|
|
|
1303
1305
|
return void 0;
|
|
1304
1306
|
}
|
|
1305
1307
|
}).filter((value) => Boolean(value));
|
|
1306
|
-
|
|
1308
|
+
let accessUrl = buildWebUIAccessUrl({
|
|
1307
1309
|
host,
|
|
1308
1310
|
port: httpPort,
|
|
1309
1311
|
token: wsToken,
|
|
@@ -1332,17 +1334,24 @@ async function runWebUI(opts) {
|
|
|
1332
1334
|
apiToken: wsToken,
|
|
1333
1335
|
requireToken,
|
|
1334
1336
|
deferListen: surface === "simpleui",
|
|
1337
|
+
strictPort,
|
|
1335
1338
|
...opts.getVectorMemoryStore ? { getVectorMemoryStore: opts.getVectorMemoryStore } : {},
|
|
1336
1339
|
...opts.vectorMemoryModelCacheDir ? { vectorMemoryModelCacheDir: opts.vectorMemoryModelCacheDir } : {}
|
|
1337
1340
|
});
|
|
1338
1341
|
const wss = httpServer ? new WebSocketServer({ server: httpServer.server, maxPayload: 20 * 1024 * 1024 }) : new WebSocketServer({ port: httpPort, host, maxPayload: 20 * 1024 * 1024 });
|
|
1339
|
-
if (httpServer
|
|
1340
|
-
await startDeferredHttpListen({
|
|
1342
|
+
if (httpServer) {
|
|
1343
|
+
const boundPort = surface === "simpleui" ? await startDeferredHttpListen({
|
|
1341
1344
|
server: httpServer.server,
|
|
1342
1345
|
host,
|
|
1343
1346
|
httpPort,
|
|
1344
|
-
logger: consoleLogger
|
|
1345
|
-
|
|
1347
|
+
logger: consoleLogger,
|
|
1348
|
+
strictPort
|
|
1349
|
+
}) : httpServer.port;
|
|
1350
|
+
if (boundPort !== httpPort) {
|
|
1351
|
+
httpPort = boundPort;
|
|
1352
|
+
wsPort = boundPort;
|
|
1353
|
+
accessUrl = buildWebUIAccessUrl({ host, port: httpPort, token: wsToken, publicUrl });
|
|
1354
|
+
}
|
|
1346
1355
|
}
|
|
1347
1356
|
let ipv6LoopbackServer = null;
|
|
1348
1357
|
if (httpServer && host === "127.0.0.1") {
|
|
@@ -1488,6 +1497,7 @@ async function runWebUI(opts) {
|
|
|
1488
1497
|
});
|
|
1489
1498
|
let signalShutdown;
|
|
1490
1499
|
const shutdown = () => signalShutdown?.();
|
|
1500
|
+
let embeddedAutoHealDispose = null;
|
|
1491
1501
|
const handleMessage = createEmbeddedMessageRouter({
|
|
1492
1502
|
trustBoundary,
|
|
1493
1503
|
opts,
|
|
@@ -1497,6 +1507,11 @@ async function runWebUI(opts) {
|
|
|
1497
1507
|
sessionPayload,
|
|
1498
1508
|
currentSessionId,
|
|
1499
1509
|
shutdown,
|
|
1510
|
+
// Auto-heal watchdog disposer — `disposeResources` awaits it (bounded) so
|
|
1511
|
+
// an in-flight daemon restart drains before the host exits.
|
|
1512
|
+
onDispose: (dispose) => {
|
|
1513
|
+
embeddedAutoHealDispose = dispose;
|
|
1514
|
+
},
|
|
1500
1515
|
providerCtx: wsHandlerCtx,
|
|
1501
1516
|
brainCtx: routeContexts.brainCtx,
|
|
1502
1517
|
introspectionCtx: routeContexts.introspectionCtx,
|
|
@@ -1589,6 +1604,7 @@ async function runWebUI(opts) {
|
|
|
1589
1604
|
});
|
|
1590
1605
|
signalShutdown = createWebuiShutdown({
|
|
1591
1606
|
abortInFlight: () => {
|
|
1607
|
+
void embeddedAutoHealDispose?.();
|
|
1592
1608
|
if (abortController) {
|
|
1593
1609
|
abortController.abort();
|
|
1594
1610
|
abortController = null;
|
|
@@ -1619,7 +1635,7 @@ async function runWebUI(opts) {
|
|
|
1619
1635
|
}
|
|
1620
1636
|
}
|
|
1621
1637
|
},
|
|
1622
|
-
disposeResources: () => {
|
|
1638
|
+
disposeResources: async () => {
|
|
1623
1639
|
credentialWatcherClose?.();
|
|
1624
1640
|
credentialWatcherClose = void 0;
|
|
1625
1641
|
goalHandler.dispose();
|
|
@@ -1629,6 +1645,8 @@ async function runWebUI(opts) {
|
|
|
1629
1645
|
kanbanRunMirror?.dispose();
|
|
1630
1646
|
kanbanSupervisor?.dispose();
|
|
1631
1647
|
void stopKanbanSupervisorMemoryStats?.();
|
|
1648
|
+
await embeddedAutoHealDispose?.();
|
|
1649
|
+
embeddedAutoHealDispose = null;
|
|
1632
1650
|
unregisterWebuiClient();
|
|
1633
1651
|
},
|
|
1634
1652
|
closeClients: () => {
|
|
@@ -1671,4 +1689,4 @@ async function runWebUI(opts) {
|
|
|
1671
1689
|
export {
|
|
1672
1690
|
runWebUI
|
|
1673
1691
|
};
|
|
1674
|
-
//# sourceMappingURL=webui-server-
|
|
1692
|
+
//# sourceMappingURL=webui-server-JXJ4CGIX.js.map
|
|
@@ -12,6 +12,13 @@ export declare function setupCliSlashCommands(params: {
|
|
|
12
12
|
renderer: any;
|
|
13
13
|
events: any;
|
|
14
14
|
memoryStore: any;
|
|
15
|
+
/**
|
|
16
|
+
* Vector memory store (semantic recall channel). When supplied, the
|
|
17
|
+
* `/memory diagnostics` and `/memory race` slash commands can
|
|
18
|
+
* surface cross-system health and the lexical vs semantic channel
|
|
19
|
+
* comparison.
|
|
20
|
+
*/
|
|
21
|
+
vectorMemoryStore?: any;
|
|
15
22
|
context: any;
|
|
16
23
|
cwd: string;
|
|
17
24
|
projectRoot: string;
|
|
@@ -1,49 +1,15 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Refresh the `.wrongstack/domain-terms.md` mirror file from the
|
|
3
|
-
* resolved SAGE `MemoryPort` at CLI boot.
|
|
4
|
-
*
|
|
5
|
-
* Background
|
|
6
|
-
* ----------
|
|
7
|
-
* The Project Jargon Dictionary feature splits ownership between two
|
|
8
|
-
* storage backends (per `packages/sage/docs/direct-icp-usage.md`):
|
|
9
|
-
* - SAGE's SQLite store is the authoritative source of truth.
|
|
10
|
-
* - `.wrongstack/domain-terms.md` is a *derived* view of the same
|
|
11
|
-
* data, kept on disk so humans (and ProjectRoot sandboxes) can
|
|
12
|
-
* read the glossary without going through the IPC client.
|
|
13
|
-
*
|
|
14
|
-
* `SageDomainTermExtractor.writeDomainTermsFile` already knows how to
|
|
15
|
-
* regenerate the file from the canonical SAGE state. What it lacks
|
|
16
|
-
* is a runtime host caller — the helper exists only in tests. This
|
|
17
|
-
* module closes that gap for the CLI host.
|
|
18
|
-
*
|
|
19
|
-
* Behaviour
|
|
20
|
-
* ---------
|
|
21
|
-
* - **Fire and forget at boot.** The mirror is a derived artefact;
|
|
22
|
-
* a failure to refresh at startup must not abort the CLI. The
|
|
23
|
-
* helper logs via `writeErr` and returns `null` on failure.
|
|
24
|
-
* - **Idempotent.** Calling this on every boot is safe: the file is
|
|
25
|
-
* regenerated atomically by `writeDomainTermsFile`, and the content
|
|
26
|
-
* is fully derived from SAGE state.
|
|
27
|
-
* - **Honest about scope.** Only the CLI host invokes this. TUI and
|
|
28
|
-
* WebUI hosts share the same SAGE port and read the same file; the
|
|
29
|
-
* CLI boot path is the canonical place to refresh the mirror.
|
|
30
|
-
*/
|
|
31
|
-
import type { MemoryPort } from '@wrongstack/core/types';
|
|
32
1
|
export interface RefreshDomainTermsMirrorOptions {
|
|
33
2
|
/** Absolute project root whose `.wrongstack/domain-terms.md` should be refreshed. */
|
|
34
3
|
projectRoot: string;
|
|
35
|
-
/**
|
|
36
|
-
* Resolved SAGE `MemoryPort`. The extractor reads the `domain-term`
|
|
37
|
-
* tagged subset from this port.
|
|
38
|
-
*/
|
|
39
|
-
memoryStore: MemoryPort;
|
|
40
4
|
}
|
|
41
5
|
/**
|
|
42
|
-
* Regenerate the mirror file
|
|
6
|
+
* Regenerate the mirror file with the empty placeholder so the path
|
|
7
|
+
* always exists. The next per-turn or session-end extraction pass
|
|
8
|
+
* overwrites the file with the freshly extracted terms.
|
|
43
9
|
*
|
|
44
10
|
* Returns the absolute path of the written file, or `null` when the
|
|
45
11
|
* refresh failed (the CLI logs the underlying reason to stderr and
|
|
46
|
-
* continues
|
|
12
|
+
* continues).
|
|
47
13
|
*
|
|
48
14
|
* Never throws — callers are guaranteed to receive a `string | null`
|
|
49
15
|
* outcome.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/cli",
|
|
3
|
-
"version": "0.308.
|
|
3
|
+
"version": "0.308.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack CLI — terminal AI coding agent with provider catalog from models.dev. Provides `wrongstack` and `wstack` binaries.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,32 +42,32 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"ws": "^8.21.3",
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
52
|
-
"@wrongstack/
|
|
53
|
-
"@wrongstack/
|
|
54
|
-
"@wrongstack/
|
|
55
|
-
"@wrongstack/
|
|
56
|
-
"@wrongstack/
|
|
57
|
-
"@wrongstack/
|
|
58
|
-
"@wrongstack/
|
|
59
|
-
"@wrongstack/
|
|
60
|
-
"@wrongstack/
|
|
61
|
-
"@wrongstack/
|
|
62
|
-
"@wrongstack/
|
|
63
|
-
"@wrongstack/
|
|
64
|
-
"@wrongstack/
|
|
65
|
-
"@wrongstack/
|
|
66
|
-
"@wrongstack/webui-
|
|
67
|
-
"@wrongstack/webui-
|
|
45
|
+
"@wrongstack/bench": "0.308.2",
|
|
46
|
+
"@wrongstack/core": "0.308.2",
|
|
47
|
+
"@wrongstack/kanban": "0.308.2",
|
|
48
|
+
"@wrongstack/mcp": "0.308.2",
|
|
49
|
+
"@wrongstack/providers": "0.308.2",
|
|
50
|
+
"@wrongstack/persistence": "0.308.2",
|
|
51
|
+
"@wrongstack/requirement-intake": "0.308.2",
|
|
52
|
+
"@wrongstack/plug-lsp": "0.308.2",
|
|
53
|
+
"@wrongstack/plugins": "0.308.2",
|
|
54
|
+
"@wrongstack/acp": "0.308.2",
|
|
55
|
+
"@wrongstack/runtime": "0.308.2",
|
|
56
|
+
"@wrongstack/sage": "0.308.2",
|
|
57
|
+
"@wrongstack/simpleui": "0.308.2",
|
|
58
|
+
"@wrongstack/techstack": "0.308.2",
|
|
59
|
+
"@wrongstack/sdd": "0.308.2",
|
|
60
|
+
"@wrongstack/tools": "0.308.2",
|
|
61
|
+
"@wrongstack/security-scanner": "0.308.2",
|
|
62
|
+
"@wrongstack/tui": "0.308.2",
|
|
63
|
+
"@wrongstack/telegram": "0.308.2",
|
|
64
|
+
"@wrongstack/vector-memory": "0.308.2",
|
|
65
|
+
"@wrongstack/webui": "0.308.2",
|
|
66
|
+
"@wrongstack/webui-hq": "0.308.2",
|
|
67
|
+
"@wrongstack/webui-server": "0.308.2"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
|
-
"@wrongstack/desktop": "0.308.
|
|
70
|
+
"@wrongstack/desktop": "0.308.2"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@types/node": "^26.2.0",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"scripts": {
|
|
82
82
|
"build": "node ../../scripts/build.mjs --target @wrongstack/webui-hq --skip-if-workspace-build && node ../../scripts/build-package.mjs",
|
|
83
83
|
"typecheck": "pnpm --filter @wrongstack/tools run build && pnpm --filter @wrongstack/tui run build && tsc --noEmit",
|
|
84
|
+
"test": "vitest run",
|
|
84
85
|
"test:hqdash": "vitest run --config vitest.hqdash.config.ts",
|
|
85
86
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
86
87
|
}
|