@wrongstack/cli 0.307.1 → 0.308.1
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/dist/{auth-TVOOHL4Q.js → auth-WOKC2RVG.js} +2 -2
- package/dist/boot/dispatch-webui.d.ts +11 -0
- package/dist/boot/tool-registry.d.ts +8 -0
- package/dist/{chunk-TOG7OMKJ.js → chunk-7JOMY3HO.js} +10 -10
- package/dist/{cli-main-DD3I7KOO.js → cli-main-5JPPEJ6N.js} +371 -12
- package/dist/execute-deps.d.ts +7 -0
- package/dist/{execution-4ASWJ7EY.js → execution-PHX3NFEK.js} +13 -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-IPHGJGXE.js → webui-server-CKIKAM2P.js} +25 -14
- package/dist/webui-server-options.d.ts +11 -0
- package/dist/wiring/cli-execute-builder.d.ts +2 -0
- package/dist/wiring/cli-prompt-and-tools-setup.d.ts +8 -0
- 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 -24
|
@@ -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
|
|
@@ -4,6 +4,7 @@ import type { JournalEntry } from '@wrongstack/core/goal';
|
|
|
4
4
|
import type { EventBus } from '@wrongstack/core/kernel';
|
|
5
5
|
import type { Config, MemoryPort, ModelsRegistry, ModeStore, SessionStore, SessionWriter, SkillLoader } from '@wrongstack/core/types';
|
|
6
6
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
7
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
7
8
|
import type { TerminalRenderer } from '../renderer.js';
|
|
8
9
|
import type { AutonomyMode } from '../services/autonomy-mode.js';
|
|
9
10
|
import type { CliWebUIOptions } from '../webui-server-options.js';
|
|
@@ -40,6 +41,16 @@ export interface WebUIDispatchContext {
|
|
|
40
41
|
subscribeEternalIteration: ((fn: (entry: JournalEntry) => void) => () => void) | undefined;
|
|
41
42
|
sessionStore: SessionStore | undefined;
|
|
42
43
|
memoryStore: MemoryPort | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Optional vector-memory store. When provided, the four
|
|
46
|
+
* `/api/vector-memory/{status,search,store,store/:id}` endpoints become
|
|
47
|
+
* active on the embedded WebUI server. When omitted, the routes respond
|
|
48
|
+
* with `{ enabled: false }` or 503 — the embedded WebUI stays on its
|
|
49
|
+
* existing surface with zero behavior change.
|
|
50
|
+
*/
|
|
51
|
+
getVectorMemoryStore?: (() => VectorMemoryStore | undefined) | undefined;
|
|
52
|
+
/** Model cache directory for the vector-memory provider. */
|
|
53
|
+
vectorMemoryModelCacheDir?: string | undefined;
|
|
43
54
|
skillLoader: SkillLoader | undefined;
|
|
44
55
|
promptLoader: import('@wrongstack/core/types').PromptLoader | undefined;
|
|
45
56
|
modeStore: ModeStore | undefined;
|
|
@@ -3,6 +3,7 @@ import type { EventBus } from '@wrongstack/core/kernel';
|
|
|
3
3
|
import type { ToolRegistry } from '@wrongstack/core/registry';
|
|
4
4
|
import type { MemoryPort, TokenSavingTier, ToolDescriptionModeConfig, ToolResultRenderModeConfig } from '@wrongstack/core/types';
|
|
5
5
|
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
6
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
6
7
|
interface RegisterBuiltinToolsDeps {
|
|
7
8
|
toolRegistry: ToolRegistry;
|
|
8
9
|
compactor: unknown;
|
|
@@ -34,6 +35,13 @@ interface RegisterBuiltinToolsDeps {
|
|
|
34
35
|
} | undefined;
|
|
35
36
|
};
|
|
36
37
|
memoryStore: MemoryPort | null | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Optional vector memory store. When provided, the four
|
|
40
|
+
* `vector_memory_*` tools are registered alongside the SAGE tools so
|
|
41
|
+
* agents get both lexical and semantic retrieval paths in one surface.
|
|
42
|
+
* Omit (or pass `undefined`) to keep the CLI on the SAGE-only surface.
|
|
43
|
+
*/
|
|
44
|
+
vectorMemoryStore?: VectorMemoryStore | undefined;
|
|
37
45
|
events: EventBus;
|
|
38
46
|
wpaths: Pick<WstackPaths, 'projectDir'>;
|
|
39
47
|
}
|
|
@@ -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
|
|
@@ -5563,7 +5563,7 @@ async function runCliExecution(params) {
|
|
|
5563
5563
|
governanceHandle,
|
|
5564
5564
|
setConfig
|
|
5565
5565
|
} = params;
|
|
5566
|
-
const { execute } = await import("./execution-
|
|
5566
|
+
const { execute } = await import("./execution-PHX3NFEK.js");
|
|
5567
5567
|
return execute(
|
|
5568
5568
|
toExecuteDeps({
|
|
5569
5569
|
core: {
|
|
@@ -6457,6 +6457,7 @@ function registerBuiltinTools(deps) {
|
|
|
6457
6457
|
tier,
|
|
6458
6458
|
contextTool: createContextManagerTool({ compactor: deps.compactor }),
|
|
6459
6459
|
memory: { enabled: deps.config.features.memory, store: deps.memoryStore },
|
|
6460
|
+
vectorMemory: deps.vectorMemoryStore ? { store: deps.vectorMemoryStore } : void 0,
|
|
6460
6461
|
nextSteps: { enabled: deps.config.tools?.nextsteps?.enabled === true },
|
|
6461
6462
|
coordinationTools: [
|
|
6462
6463
|
makeMailboxTool({ projectDir: deps.wpaths.projectDir, events: deps.events }),
|
|
@@ -6516,7 +6517,7 @@ import { SageDomainTermExtractor } from "@wrongstack/sage";
|
|
|
6516
6517
|
async function refreshDomainTermsMirror(options) {
|
|
6517
6518
|
try {
|
|
6518
6519
|
const extractor = new SageDomainTermExtractor();
|
|
6519
|
-
return await extractor.writeDomainTermsFile(options.projectRoot,
|
|
6520
|
+
return await extractor.writeDomainTermsFile(options.projectRoot, []);
|
|
6520
6521
|
} catch (err) {
|
|
6521
6522
|
writeErr2(
|
|
6522
6523
|
`[wrongstack] domain-terms mirror refresh failed: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -6541,7 +6542,8 @@ async function setupCliPromptAndTools(params) {
|
|
|
6541
6542
|
config,
|
|
6542
6543
|
wpaths,
|
|
6543
6544
|
projectRoot,
|
|
6544
|
-
events
|
|
6545
|
+
events,
|
|
6546
|
+
vectorMemoryStore
|
|
6545
6547
|
} = params;
|
|
6546
6548
|
bindSystemPromptBuilder({
|
|
6547
6549
|
container,
|
|
@@ -6568,13 +6570,14 @@ async function setupCliPromptAndTools(params) {
|
|
|
6568
6570
|
pathJoiner: { join: (a, b) => path7.join(a, b) },
|
|
6569
6571
|
systemPromptBuilderToken: TOKENS8.SystemPromptBuilder
|
|
6570
6572
|
});
|
|
6571
|
-
await refreshDomainTermsMirror({ projectRoot
|
|
6573
|
+
await refreshDomainTermsMirror({ projectRoot });
|
|
6572
6574
|
const toolRegistry = new ToolRegistry2();
|
|
6573
6575
|
registerBuiltinTools({
|
|
6574
6576
|
toolRegistry,
|
|
6575
6577
|
compactor: container.resolve(TOKENS8.Compactor),
|
|
6576
6578
|
config,
|
|
6577
6579
|
memoryStore,
|
|
6580
|
+
vectorMemoryStore,
|
|
6578
6581
|
events,
|
|
6579
6582
|
wpaths
|
|
6580
6583
|
});
|
|
@@ -18342,6 +18345,47 @@ function formatAudit(rows) {
|
|
|
18342
18345
|
function formatLegacyImport(result) {
|
|
18343
18346
|
return `Legacy import complete: ${result.imported} imported, ${result.skipped} skipped from ${result.files} file(s).`;
|
|
18344
18347
|
}
|
|
18348
|
+
function formatMemoryDiagnostics(diag) {
|
|
18349
|
+
const lines = ["\u{1FA7A} Memory diagnostics", ""];
|
|
18350
|
+
const byStatus = Object.entries(diag.sageStats.byStatus).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18351
|
+
const byKind = Object.entries(diag.sageStats.byKind).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
18352
|
+
lines.push("SAGE (lexical):");
|
|
18353
|
+
lines.push(` total entries: ${diag.sageTotal}`);
|
|
18354
|
+
lines.push(` by status: ${byStatus || "\u2205"}`);
|
|
18355
|
+
lines.push(` by kind: ${byKind || "\u2205"}`);
|
|
18356
|
+
if (diag.sageStats.injections !== void 0) {
|
|
18357
|
+
lines.push(` injections: ${diag.sageStats.injections}`);
|
|
18358
|
+
}
|
|
18359
|
+
if (diag.sageStats.uses !== void 0) {
|
|
18360
|
+
lines.push(` uses: ${diag.sageStats.uses}`);
|
|
18361
|
+
}
|
|
18362
|
+
lines.push("");
|
|
18363
|
+
if (!diag.vector) {
|
|
18364
|
+
lines.push("Vector memory: disabled \u2014 running on the SAGE-only surface.");
|
|
18365
|
+
} else {
|
|
18366
|
+
const v = diag.vector;
|
|
18367
|
+
lines.push("Vector (semantic):");
|
|
18368
|
+
lines.push(` entries: ${v.entries}`);
|
|
18369
|
+
lines.push(` with vectors: ${v.vectors}`);
|
|
18370
|
+
lines.push(` providers: ${v.providers.join(", ") || "\u2205"}`);
|
|
18371
|
+
lines.push(` model: ${v.modelId} (${v.dimensions}-dim)`);
|
|
18372
|
+
lines.push(` cache: ${v.cacheEntries} rows \xB7 ${v.cacheProviders} provider(s) \xB7 ${v.totalUseCount} hits`);
|
|
18373
|
+
if (v.oldestLastUsedAt) {
|
|
18374
|
+
lines.push(` cache oldest: ${v.oldestLastUsedAt}`);
|
|
18375
|
+
}
|
|
18376
|
+
lines.push(` store path: ${v.storePath}`);
|
|
18377
|
+
lines.push("");
|
|
18378
|
+
lines.push("Cross-system coverage:");
|
|
18379
|
+
lines.push(` vector \u2194 SAGE: ${v.mirroredInSage} mirrored`);
|
|
18380
|
+
if (v.standalone > 0) {
|
|
18381
|
+
lines.push(` standalone: ${v.standalone} vector-only entries (no SAGE id \u2014 lexical recall misses these)`);
|
|
18382
|
+
}
|
|
18383
|
+
if (v.mirroredInSage === 0 && diag.sageTotal > 0) {
|
|
18384
|
+
lines.push(" \u{1F4A1} Run `wrongstack --vector-sync` to backfill the vector mirror.");
|
|
18385
|
+
}
|
|
18386
|
+
}
|
|
18387
|
+
return lines.join("\n");
|
|
18388
|
+
}
|
|
18345
18389
|
function formatSageStats(stats, scopedCount, scopedRoles) {
|
|
18346
18390
|
const lines = [
|
|
18347
18391
|
"## SAGE Stats",
|
|
@@ -18404,6 +18448,60 @@ function formatSageShow(stats, memories) {
|
|
|
18404
18448
|
lines.push(`*${memories.length} entr${memories.length === 1 ? "y" : "ies"}*`);
|
|
18405
18449
|
return lines.join("\n");
|
|
18406
18450
|
}
|
|
18451
|
+
function formatSearchRace(race) {
|
|
18452
|
+
const lines = [];
|
|
18453
|
+
const pct2 = (value) => `${Math.round(value * 100)}%`;
|
|
18454
|
+
lines.push(`## \u{1F3C1} Search race \u2014 "${race.query}"`);
|
|
18455
|
+
lines.push("");
|
|
18456
|
+
lines.push(
|
|
18457
|
+
`lexical: ${race.metrics.lexicalCount} \xB7 vector: ${race.metrics.vectorCount} \xB7 overlap: ${race.metrics.overlapCount} \xB7 agreement: ${pct2(race.metrics.agreementRatio)}`
|
|
18458
|
+
);
|
|
18459
|
+
if (race.metrics.lexicalOnlyRatio > 0) {
|
|
18460
|
+
lines.push(
|
|
18461
|
+
` \u21B3 lexical-only: ${pct2(race.metrics.lexicalOnlyRatio)} of lexical recall is invisible to vector.`
|
|
18462
|
+
);
|
|
18463
|
+
}
|
|
18464
|
+
if (race.metrics.vectorOnlyRatio > 0) {
|
|
18465
|
+
lines.push(
|
|
18466
|
+
` \u21B3 vector-only: ${pct2(race.metrics.vectorOnlyRatio)} of vector recall is invisible to lexical.`
|
|
18467
|
+
);
|
|
18468
|
+
}
|
|
18469
|
+
lines.push("");
|
|
18470
|
+
if (race.overlap.length > 0) {
|
|
18471
|
+
lines.push("### \u2705 Both channels");
|
|
18472
|
+
for (const row of race.overlap) {
|
|
18473
|
+
lines.push(
|
|
18474
|
+
`- \`${row.id.slice(0, 12)}\u2026\` L=${pct2(row.lexicalScore)} V=${pct2(row.vectorScore)} ${row.preview}`
|
|
18475
|
+
);
|
|
18476
|
+
}
|
|
18477
|
+
lines.push("");
|
|
18478
|
+
}
|
|
18479
|
+
if (race.lexicalOnly.length > 0) {
|
|
18480
|
+
lines.push("### \u{1F170}\uFE0F Lexical only (vector missed)");
|
|
18481
|
+
for (const row of race.lexicalOnly) {
|
|
18482
|
+
lines.push(
|
|
18483
|
+
`- \`${row.id.slice(0, 12)}\u2026\` L=${pct2(row.lexicalScore ?? 0)} ${row.preview}`
|
|
18484
|
+
);
|
|
18485
|
+
}
|
|
18486
|
+
lines.push("");
|
|
18487
|
+
}
|
|
18488
|
+
if (race.vectorOnly.length > 0) {
|
|
18489
|
+
lines.push("### \u{1F171}\uFE0F Vector only (lexical missed)");
|
|
18490
|
+
for (const row of race.vectorOnly) {
|
|
18491
|
+
lines.push(
|
|
18492
|
+
`- \`${row.id.slice(0, 12)}\u2026\` V=${pct2(row.vectorScore ?? 0)} ${row.preview}`
|
|
18493
|
+
);
|
|
18494
|
+
}
|
|
18495
|
+
lines.push("");
|
|
18496
|
+
}
|
|
18497
|
+
if (race.overlap.length === 0 && race.lexicalOnly.length === 0 && race.vectorOnly.length === 0) {
|
|
18498
|
+
lines.push("_No memories matched either channel for this query._");
|
|
18499
|
+
}
|
|
18500
|
+
return lines.join("\n");
|
|
18501
|
+
}
|
|
18502
|
+
|
|
18503
|
+
// src/slash-commands/memory.ts
|
|
18504
|
+
import { runSearchRace } from "@wrongstack/vector-memory";
|
|
18407
18505
|
|
|
18408
18506
|
// src/slash-commands/memory-gather.ts
|
|
18409
18507
|
import { toErrorMessage as toErrorMessage15 } from "@wrongstack/core/utils";
|
|
@@ -18932,11 +19030,12 @@ async function fileProposals(Sage, proposals) {
|
|
|
18932
19030
|
}
|
|
18933
19031
|
|
|
18934
19032
|
// src/slash-commands/memory.ts
|
|
19033
|
+
var DOMAIN_TERM_TAG = "domain-term";
|
|
18935
19034
|
function buildMemoryCommand(opts) {
|
|
18936
19035
|
return {
|
|
18937
19036
|
name: "memory",
|
|
18938
19037
|
category: "Inspect",
|
|
18939
|
-
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]",
|
|
19038
|
+
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]",
|
|
18940
19039
|
async run(args) {
|
|
18941
19040
|
const store = opts.memoryStore;
|
|
18942
19041
|
if (!store) return { message: "No memory store configured." };
|
|
@@ -19136,6 +19235,32 @@ function buildMemoryCommand(opts) {
|
|
|
19136
19235
|
)
|
|
19137
19236
|
};
|
|
19138
19237
|
}
|
|
19238
|
+
case "race": {
|
|
19239
|
+
if (!restJoined) return { message: "Usage: /memory race <query>" };
|
|
19240
|
+
if (!Sage) {
|
|
19241
|
+
return {
|
|
19242
|
+
message: "`/memory race` requires the SAGE surface. Run the search with `/memory search <query>` instead."
|
|
19243
|
+
};
|
|
19244
|
+
}
|
|
19245
|
+
const vectorStore = opts.vectorMemoryStore;
|
|
19246
|
+
if (!vectorStore) {
|
|
19247
|
+
const entries = await Sage.searchSage(restJoined, { limit: 20 });
|
|
19248
|
+
return {
|
|
19249
|
+
message: `Vector memory is not wired in this host \u2014 only the lexical channel is available.
|
|
19250
|
+
|
|
19251
|
+
` + formatSageMemories(entries, `Search: ${restJoined}`)
|
|
19252
|
+
};
|
|
19253
|
+
}
|
|
19254
|
+
try {
|
|
19255
|
+
const lexical = await Sage.searchSage(restJoined, { limit: 20 });
|
|
19256
|
+
const race = await runSearchRace(restJoined, lexical, vectorStore, { limit: 20 });
|
|
19257
|
+
return { message: formatSearchRace(race) };
|
|
19258
|
+
} catch (err) {
|
|
19259
|
+
return {
|
|
19260
|
+
message: `Race failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19261
|
+
};
|
|
19262
|
+
}
|
|
19263
|
+
}
|
|
19139
19264
|
case "graph": {
|
|
19140
19265
|
if (!Sage?.graphFor) return requiresSage("graph");
|
|
19141
19266
|
if (!restJoined) return { message: "Usage: /memory graph <memory-id|path|query>" };
|
|
@@ -19215,6 +19340,94 @@ function buildMemoryCommand(opts) {
|
|
|
19215
19340
|
await store.clear();
|
|
19216
19341
|
return { message: "Cleared all non-permanent memory scopes by explicit force request." };
|
|
19217
19342
|
}
|
|
19343
|
+
case "purge-domain-terms": {
|
|
19344
|
+
if (!Sage) return requiresSage("purge-domain-terms");
|
|
19345
|
+
const force = rest.includes("--force");
|
|
19346
|
+
if (!force) {
|
|
19347
|
+
return {
|
|
19348
|
+
message: `Refusing to run /memory purge-domain-terms without --force.
|
|
19349
|
+
|
|
19350
|
+
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.`
|
|
19351
|
+
};
|
|
19352
|
+
}
|
|
19353
|
+
try {
|
|
19354
|
+
const targets = [];
|
|
19355
|
+
const PAGE = 200;
|
|
19356
|
+
let cursor;
|
|
19357
|
+
const listPage = Sage.listSagePage;
|
|
19358
|
+
if (typeof listPage === "function") {
|
|
19359
|
+
while (true) {
|
|
19360
|
+
const page = await listPage({
|
|
19361
|
+
statuses: ["active", "stale"],
|
|
19362
|
+
limit: PAGE,
|
|
19363
|
+
...cursor !== void 0 ? { cursor } : {}
|
|
19364
|
+
});
|
|
19365
|
+
for (const mem of page.memories) {
|
|
19366
|
+
if (Array.isArray(mem.tags) && mem.tags.some(
|
|
19367
|
+
(t) => t === DOMAIN_TERM_TAG || t === "glossary" || t === "project-jargon"
|
|
19368
|
+
)) {
|
|
19369
|
+
targets.push({ id: mem.id, tags: mem.tags });
|
|
19370
|
+
}
|
|
19371
|
+
}
|
|
19372
|
+
if (!page.nextCursor || page.memories.length === 0) break;
|
|
19373
|
+
cursor = page.nextCursor;
|
|
19374
|
+
}
|
|
19375
|
+
} else {
|
|
19376
|
+
const memories = await Sage.listSage(["active", "stale"]);
|
|
19377
|
+
for (const mem of memories) {
|
|
19378
|
+
if (Array.isArray(mem.tags) && mem.tags.some(
|
|
19379
|
+
(t) => t === DOMAIN_TERM_TAG || t === "glossary" || t === "project-jargon"
|
|
19380
|
+
)) {
|
|
19381
|
+
targets.push({ id: mem.id, tags: mem.tags });
|
|
19382
|
+
}
|
|
19383
|
+
}
|
|
19384
|
+
}
|
|
19385
|
+
if (targets.length === 0) {
|
|
19386
|
+
return {
|
|
19387
|
+
message: `No SAGE memories matched the legacy domain-term tag trio. Nothing to purge.`
|
|
19388
|
+
};
|
|
19389
|
+
}
|
|
19390
|
+
let deleted = 0;
|
|
19391
|
+
const failures = [];
|
|
19392
|
+
for (const t of targets) {
|
|
19393
|
+
try {
|
|
19394
|
+
await Sage.deleteSage(
|
|
19395
|
+
t.id,
|
|
19396
|
+
"domain-term persistence removed; pre-migration cleanup",
|
|
19397
|
+
{ force: true }
|
|
19398
|
+
);
|
|
19399
|
+
deleted++;
|
|
19400
|
+
} catch (err) {
|
|
19401
|
+
failures.push(`${t.id}: ${toErrorMessage17(err)}`);
|
|
19402
|
+
}
|
|
19403
|
+
}
|
|
19404
|
+
const tagSummary = /* @__PURE__ */ new Map();
|
|
19405
|
+
for (const t of targets) {
|
|
19406
|
+
for (const tag of t.tags) {
|
|
19407
|
+
if (tag === DOMAIN_TERM_TAG || tag === "glossary" || tag === "project-jargon") {
|
|
19408
|
+
tagSummary.set(tag, (tagSummary.get(tag) ?? 0) + 1);
|
|
19409
|
+
}
|
|
19410
|
+
}
|
|
19411
|
+
}
|
|
19412
|
+
const tagBreakdown = [...tagSummary.entries()].sort((a, b) => b[1] - a[1]).map(([tag, count]) => ` - ${tag}: ${count}`).join("\n");
|
|
19413
|
+
const tail = failures.length > 0 ? `
|
|
19414
|
+
|
|
19415
|
+
Failures (${failures.length}):
|
|
19416
|
+
${failures.slice(0, 10).map((f) => ` - ${f}`).join("\n")}` : "";
|
|
19417
|
+
return {
|
|
19418
|
+
message: `Purged ${deleted} of ${targets.length} legacy domain-term memories.
|
|
19419
|
+
|
|
19420
|
+
Tag breakdown of matched memories:
|
|
19421
|
+
${tagBreakdown}
|
|
19422
|
+
|
|
19423
|
+
The \`${DOMAIN_TERM_TAG}\` / \`glossary\` / \`project-jargon\` tags are now absent from the live corpus. Run \`/memory show\` to confirm.${tail}`
|
|
19424
|
+
};
|
|
19425
|
+
} catch (err) {
|
|
19426
|
+
return {
|
|
19427
|
+
message: `purge-domain-terms failed: ${toErrorMessage17(err)}`
|
|
19428
|
+
};
|
|
19429
|
+
}
|
|
19430
|
+
}
|
|
19218
19431
|
case "compact": {
|
|
19219
19432
|
return runCompact(opts);
|
|
19220
19433
|
}
|
|
@@ -19279,6 +19492,71 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19279
19492
|
if (!Sage) return requiresSage("audience");
|
|
19280
19493
|
return runAudienceMemory(Sage, rest);
|
|
19281
19494
|
}
|
|
19495
|
+
case "diagnostics": {
|
|
19496
|
+
if (!Sage) {
|
|
19497
|
+
return {
|
|
19498
|
+
message: "Memory diagnostics require the SAGE surface (this memory store does not expose it)."
|
|
19499
|
+
};
|
|
19500
|
+
}
|
|
19501
|
+
const vectorStore = opts.vectorMemoryStore;
|
|
19502
|
+
let sageStats;
|
|
19503
|
+
let sageTotal = 0;
|
|
19504
|
+
try {
|
|
19505
|
+
[sageStats, sageTotal] = await Promise.all([
|
|
19506
|
+
Sage.stats(),
|
|
19507
|
+
Sage.listSagePage({ limit: 1 }).then(
|
|
19508
|
+
(page) => page.total ?? page.memories.length
|
|
19509
|
+
)
|
|
19510
|
+
]);
|
|
19511
|
+
} catch (err) {
|
|
19512
|
+
return {
|
|
19513
|
+
message: `Memory diagnostics failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19514
|
+
};
|
|
19515
|
+
}
|
|
19516
|
+
let vectorDiag;
|
|
19517
|
+
if (vectorStore) {
|
|
19518
|
+
try {
|
|
19519
|
+
const stats = vectorStore.stats();
|
|
19520
|
+
const cache = vectorStore.cacheStats();
|
|
19521
|
+
const vectorRows = vectorStore.list({ limit: 5e3 });
|
|
19522
|
+
let mirroredInSage = 0;
|
|
19523
|
+
let standalone = 0;
|
|
19524
|
+
for (const row of vectorRows) {
|
|
19525
|
+
const sageId = row.metadata?.sageId;
|
|
19526
|
+
if (typeof sageId === "string" && sageId.length > 0) {
|
|
19527
|
+
mirroredInSage++;
|
|
19528
|
+
} else {
|
|
19529
|
+
standalone++;
|
|
19530
|
+
}
|
|
19531
|
+
}
|
|
19532
|
+
vectorDiag = {
|
|
19533
|
+
entries: stats.entries,
|
|
19534
|
+
vectors: stats.vectors,
|
|
19535
|
+
providers: stats.providers,
|
|
19536
|
+
modelId: stats.modelId,
|
|
19537
|
+
dimensions: stats.dimensions,
|
|
19538
|
+
cacheEntries: cache.entries,
|
|
19539
|
+
cacheProviders: cache.providers,
|
|
19540
|
+
totalUseCount: cache.totalUseCount,
|
|
19541
|
+
oldestLastUsedAt: cache.oldestLastUsedAt,
|
|
19542
|
+
storePath: vectorStore.directory,
|
|
19543
|
+
mirroredInSage,
|
|
19544
|
+
standalone
|
|
19545
|
+
};
|
|
19546
|
+
} catch (err) {
|
|
19547
|
+
return {
|
|
19548
|
+
message: `Memory diagnostics (vector side) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
19549
|
+
};
|
|
19550
|
+
}
|
|
19551
|
+
}
|
|
19552
|
+
return {
|
|
19553
|
+
message: formatMemoryDiagnostics({
|
|
19554
|
+
sageStats,
|
|
19555
|
+
sageTotal,
|
|
19556
|
+
vector: vectorDiag
|
|
19557
|
+
})
|
|
19558
|
+
};
|
|
19559
|
+
}
|
|
19282
19560
|
default:
|
|
19283
19561
|
return {
|
|
19284
19562
|
message: unknownSubcommand(
|
|
@@ -19286,6 +19564,7 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19286
19564
|
[
|
|
19287
19565
|
"show",
|
|
19288
19566
|
"search",
|
|
19567
|
+
"race",
|
|
19289
19568
|
"file",
|
|
19290
19569
|
"path",
|
|
19291
19570
|
"for-file",
|
|
@@ -19304,7 +19583,8 @@ File size reduced. Audit-logged as \`memory.log_compacted\`.`
|
|
|
19304
19583
|
"clear",
|
|
19305
19584
|
"compact",
|
|
19306
19585
|
"stats",
|
|
19307
|
-
"audience"
|
|
19586
|
+
"audience",
|
|
19587
|
+
"purge-domain-terms"
|
|
19308
19588
|
],
|
|
19309
19589
|
"memory"
|
|
19310
19590
|
)
|
|
@@ -23524,7 +23804,8 @@ var THEME_META = {
|
|
|
23524
23804
|
desc: "Anthony Fu's minimal palette \u2014 muted, print-like"
|
|
23525
23805
|
},
|
|
23526
23806
|
aura: { name: "Aura Dark", desc: "Vivid purple and spring green on near-black violet" },
|
|
23527
|
-
"dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" }
|
|
23807
|
+
"dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" },
|
|
23808
|
+
monochrome: { name: "Monochrome", desc: "Pure grayscale \u2014 no hue, only luminance" }
|
|
23528
23809
|
};
|
|
23529
23810
|
var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({ id, ...THEME_META[id] }));
|
|
23530
23811
|
function presetHelpLines(perLine = 4) {
|
|
@@ -29416,6 +29697,7 @@ function setupCliSlashCommands(params) {
|
|
|
29416
29697
|
renderer,
|
|
29417
29698
|
events,
|
|
29418
29699
|
memoryStore,
|
|
29700
|
+
vectorMemoryStore,
|
|
29419
29701
|
context,
|
|
29420
29702
|
cwd,
|
|
29421
29703
|
projectRoot,
|
|
@@ -29492,6 +29774,7 @@ function setupCliSlashCommands(params) {
|
|
|
29492
29774
|
renderer,
|
|
29493
29775
|
events,
|
|
29494
29776
|
memoryStore,
|
|
29777
|
+
vectorMemoryStore,
|
|
29495
29778
|
context,
|
|
29496
29779
|
cwd,
|
|
29497
29780
|
projectRoot,
|
|
@@ -32059,6 +32342,17 @@ function warnUnlessMissing(logger, operation, error) {
|
|
|
32059
32342
|
}
|
|
32060
32343
|
}
|
|
32061
32344
|
|
|
32345
|
+
// src/cli-main.ts
|
|
32346
|
+
import {
|
|
32347
|
+
TransformersEmbeddingProvider,
|
|
32348
|
+
VectorMemoryStore,
|
|
32349
|
+
wrapMemoryPortWithVectorRecall
|
|
32350
|
+
} from "@wrongstack/vector-memory";
|
|
32351
|
+
import {
|
|
32352
|
+
startFirstBootSageSync,
|
|
32353
|
+
subscribeVectorMemoryToSage
|
|
32354
|
+
} from "@wrongstack/vector-memory";
|
|
32355
|
+
|
|
32062
32356
|
// src/wiring/replay-governance-setup.ts
|
|
32063
32357
|
async function setupReplayAndGovernance({
|
|
32064
32358
|
flags,
|
|
@@ -32663,8 +32957,58 @@ async function runInteractive(cliCtx) {
|
|
|
32663
32957
|
const modelCapabilitiesRef = {
|
|
32664
32958
|
current: modelCapabilities
|
|
32665
32959
|
};
|
|
32666
|
-
|
|
32960
|
+
let memoryStore = container.resolve(TOKENS12.MemoryStore);
|
|
32667
32961
|
await memoryStore.initialize();
|
|
32962
|
+
const teardownHandlers = [];
|
|
32963
|
+
let vectorMemoryStore;
|
|
32964
|
+
const vectorMemoryModelCacheDir = path32.join(
|
|
32965
|
+
projectRoot,
|
|
32966
|
+
".wrongstack",
|
|
32967
|
+
"cache",
|
|
32968
|
+
"transformers-models"
|
|
32969
|
+
);
|
|
32970
|
+
try {
|
|
32971
|
+
vectorMemoryStore = new VectorMemoryStore({
|
|
32972
|
+
provider: new TransformersEmbeddingProvider({
|
|
32973
|
+
cacheDir: vectorMemoryModelCacheDir
|
|
32974
|
+
}),
|
|
32975
|
+
projectRoot
|
|
32976
|
+
});
|
|
32977
|
+
} catch (error) {
|
|
32978
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
32979
|
+
logger.warn(
|
|
32980
|
+
`vector memory store disabled: ${message} \u2014 CLI will run with the SAGE-only surface.`
|
|
32981
|
+
);
|
|
32982
|
+
vectorMemoryStore = void 0;
|
|
32983
|
+
}
|
|
32984
|
+
if (vectorMemoryStore) {
|
|
32985
|
+
void startFirstBootSageSync({
|
|
32986
|
+
store: vectorMemoryStore,
|
|
32987
|
+
memoryStore,
|
|
32988
|
+
logger
|
|
32989
|
+
});
|
|
32990
|
+
memoryStore = wrapMemoryPortWithVectorRecall(memoryStore, {
|
|
32991
|
+
store: vectorMemoryStore,
|
|
32992
|
+
weight: 0.3
|
|
32993
|
+
});
|
|
32994
|
+
const mirrorHandle = subscribeVectorMemoryToSage({
|
|
32995
|
+
store: vectorMemoryStore,
|
|
32996
|
+
memoryStore,
|
|
32997
|
+
logger
|
|
32998
|
+
});
|
|
32999
|
+
teardownHandlers.push(() => mirrorHandle.dispose());
|
|
33000
|
+
if (flags["vector-sync"] === true) {
|
|
33001
|
+
const forced = await startFirstBootSageSync({
|
|
33002
|
+
store: vectorMemoryStore,
|
|
33003
|
+
memoryStore,
|
|
33004
|
+
logger,
|
|
33005
|
+
force: true
|
|
33006
|
+
});
|
|
33007
|
+
logger.info(
|
|
33008
|
+
forced.synced ? `vector-memory forced re-sync complete (${forced.marker?.indexed ?? 0} new)` : `vector-memory forced re-sync skipped: ${forced.reason}`
|
|
33009
|
+
);
|
|
33010
|
+
}
|
|
33011
|
+
}
|
|
32668
33012
|
const skillLoader = container.resolve(TOKENS12.SkillLoader);
|
|
32669
33013
|
const promptLoader = container.resolve(TOKENS12.PromptLoader);
|
|
32670
33014
|
const sessionRef = {
|
|
@@ -32684,7 +33028,8 @@ async function runInteractive(cliCtx) {
|
|
|
32684
33028
|
config,
|
|
32685
33029
|
wpaths,
|
|
32686
33030
|
projectRoot,
|
|
32687
|
-
events
|
|
33031
|
+
events,
|
|
33032
|
+
vectorMemoryStore
|
|
32688
33033
|
});
|
|
32689
33034
|
const stdinInteractive = process.stdin.isTTY;
|
|
32690
33035
|
const hookRunnerRef = { current: null };
|
|
@@ -32705,8 +33050,19 @@ async function runInteractive(cliCtx) {
|
|
|
32705
33050
|
config: { provider: config.provider, model: config.model }
|
|
32706
33051
|
});
|
|
32707
33052
|
const tuiOwnsScreen = flags.tui === true && flags["no-tui"] !== true;
|
|
32708
|
-
const teardownHandlers = [];
|
|
32709
33053
|
const evOn = createTeardownEventRegistrar(events, teardownHandlers);
|
|
33054
|
+
if (vectorMemoryStore) {
|
|
33055
|
+
const store = vectorMemoryStore;
|
|
33056
|
+
teardownHandlers.push(() => {
|
|
33057
|
+
try {
|
|
33058
|
+
store.close();
|
|
33059
|
+
} catch (error) {
|
|
33060
|
+
logger.debug?.(
|
|
33061
|
+
`vector memory close failed: ${error instanceof Error ? error.message : String(error)}`
|
|
33062
|
+
);
|
|
33063
|
+
}
|
|
33064
|
+
});
|
|
33065
|
+
}
|
|
32710
33066
|
const eventWiring = wireEventWiring({
|
|
32711
33067
|
evOn,
|
|
32712
33068
|
events,
|
|
@@ -33123,6 +33479,7 @@ async function runInteractive(cliCtx) {
|
|
|
33123
33479
|
renderer,
|
|
33124
33480
|
events,
|
|
33125
33481
|
memoryStore,
|
|
33482
|
+
vectorMemoryStore,
|
|
33126
33483
|
context,
|
|
33127
33484
|
cwd,
|
|
33128
33485
|
projectRoot,
|
|
@@ -33283,6 +33640,8 @@ async function runInteractive(cliCtx) {
|
|
|
33283
33640
|
sessResult,
|
|
33284
33641
|
sessionStore,
|
|
33285
33642
|
memoryStore,
|
|
33643
|
+
vectorMemoryStore,
|
|
33644
|
+
vectorMemoryModelCacheDir,
|
|
33286
33645
|
modeStore,
|
|
33287
33646
|
needsSetup,
|
|
33288
33647
|
statusTracker,
|
|
@@ -33357,4 +33716,4 @@ export {
|
|
|
33357
33716
|
CLI_VERSION,
|
|
33358
33717
|
runInteractive
|
|
33359
33718
|
};
|
|
33360
|
-
//# sourceMappingURL=cli-main-
|
|
33719
|
+
//# sourceMappingURL=cli-main-5JPPEJ6N.js.map
|
package/dist/execute-deps.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import type { AttachmentStore, AutonomyStage, Config, ConfigStore, MemoryPort, M
|
|
|
19
19
|
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
20
20
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
21
21
|
import type { SddLifecycleResult, SddRunControl } from '@wrongstack/sdd';
|
|
22
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
22
23
|
import type { WebuiSessionChildOptions } from './boot/webui-session-child.js';
|
|
23
24
|
import type { ReadlineInputReader } from './input-reader.js';
|
|
24
25
|
import type { LiveSettingsInput } from './live-settings-input.js';
|
|
@@ -126,6 +127,12 @@ export interface SessionDeps {
|
|
|
126
127
|
queueStore: QueueStore;
|
|
127
128
|
sessionStore?: SessionStore | undefined;
|
|
128
129
|
memoryStore?: MemoryPort | undefined;
|
|
130
|
+
/** Optional vector-memory store (additional to SAGE). When omitted, the
|
|
131
|
+
* embedded WebUI's `/api/vector-memory/*` routes default to disabled. */
|
|
132
|
+
vectorMemoryStore?: VectorMemoryStore | undefined;
|
|
133
|
+
/** Model cache directory for the vector-memory provider (shared with the
|
|
134
|
+
* CLI's on-disk transformers cache so a future cleanup never sweeps it). */
|
|
135
|
+
vectorMemoryModelCacheDir?: string | undefined;
|
|
129
136
|
modeStore?: ModeStore | undefined;
|
|
130
137
|
mcpRegistry: MCPRegistry;
|
|
131
138
|
mailbox: RemoteMailbox;
|
|
@@ -184,6 +184,8 @@ async function runWebUIDispatch(ctx) {
|
|
|
184
184
|
subscribeEternalIteration,
|
|
185
185
|
sessionStore,
|
|
186
186
|
memoryStore,
|
|
187
|
+
getVectorMemoryStore,
|
|
188
|
+
vectorMemoryModelCacheDir,
|
|
187
189
|
skillLoader,
|
|
188
190
|
promptLoader,
|
|
189
191
|
modeStore,
|
|
@@ -205,7 +207,7 @@ async function runWebUIDispatch(ctx) {
|
|
|
205
207
|
const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
|
|
206
208
|
agent.disableInteractiveConfirmation();
|
|
207
209
|
renderer.setSilent(true);
|
|
208
|
-
const { runWebUI } = await import("./webui-server-
|
|
210
|
+
const { runWebUI } = await import("./webui-server-CKIKAM2P.js");
|
|
209
211
|
const flagValue = (names) => {
|
|
210
212
|
for (const name of names) {
|
|
211
213
|
if (!Object.hasOwn(flags, name)) continue;
|
|
@@ -334,6 +336,8 @@ async function runWebUIDispatch(ctx) {
|
|
|
334
336
|
sddSubagentFactory,
|
|
335
337
|
updateInfo: ctx.updateInfo,
|
|
336
338
|
onKanbanDispatch,
|
|
339
|
+
getVectorMemoryStore,
|
|
340
|
+
vectorMemoryModelCacheDir,
|
|
337
341
|
// Print the "open this" banner only once the server is actually
|
|
338
342
|
// listening, using the RESOLVED port. Requested ports auto-advance past
|
|
339
343
|
// busy ports inside runWebUI, so a banner printed up-front lies whenever
|
|
@@ -1416,6 +1420,9 @@ async function resumeSession(ctx, sessionId) {
|
|
|
1416
1420
|
}
|
|
1417
1421
|
tokenCounter.reset();
|
|
1418
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
|
+
}
|
|
1419
1426
|
const reqTokens = tokenCounter.currentRequestTokens?.();
|
|
1420
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);
|
|
1421
1428
|
const maxContext = agent.ctx.provider?.capabilities?.maxContext ?? 0;
|
|
@@ -5456,6 +5463,8 @@ async function execute(deps) {
|
|
|
5456
5463
|
mailbox,
|
|
5457
5464
|
sessionStore,
|
|
5458
5465
|
memoryStore,
|
|
5466
|
+
vectorMemoryStore: vectorMemoryStoreFromExecute,
|
|
5467
|
+
vectorMemoryModelCacheDir: vectorMemoryModelCacheDirFromExecute,
|
|
5459
5468
|
modeStore,
|
|
5460
5469
|
detachTodosCheckpoint,
|
|
5461
5470
|
rebindTodosCheckpoint,
|
|
@@ -5917,6 +5926,8 @@ async function execute(deps) {
|
|
|
5917
5926
|
subscribeEternalIteration,
|
|
5918
5927
|
sessionStore: activeSessionStore,
|
|
5919
5928
|
memoryStore,
|
|
5929
|
+
getVectorMemoryStore: () => vectorMemoryStoreFromExecute,
|
|
5930
|
+
vectorMemoryModelCacheDir: vectorMemoryModelCacheDirFromExecute,
|
|
5920
5931
|
skillLoader,
|
|
5921
5932
|
promptLoader,
|
|
5922
5933
|
modeStore,
|
|
@@ -6034,4 +6045,4 @@ export {
|
|
|
6034
6045
|
execute,
|
|
6035
6046
|
resolveReviewerFallbackModels
|
|
6036
6047
|
};
|
|
6037
|
-
//# sourceMappingURL=execution-
|
|
6048
|
+
//# sourceMappingURL=execution-PHX3NFEK.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-5JPPEJ6N.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,
|
|
@@ -1331,16 +1333,25 @@ async function runWebUI(opts) {
|
|
|
1331
1333
|
publicWsUrl,
|
|
1332
1334
|
apiToken: wsToken,
|
|
1333
1335
|
requireToken,
|
|
1334
|
-
deferListen: surface === "simpleui"
|
|
1336
|
+
deferListen: surface === "simpleui",
|
|
1337
|
+
strictPort,
|
|
1338
|
+
...opts.getVectorMemoryStore ? { getVectorMemoryStore: opts.getVectorMemoryStore } : {},
|
|
1339
|
+
...opts.vectorMemoryModelCacheDir ? { vectorMemoryModelCacheDir: opts.vectorMemoryModelCacheDir } : {}
|
|
1335
1340
|
});
|
|
1336
1341
|
const wss = httpServer ? new WebSocketServer({ server: httpServer.server, maxPayload: 20 * 1024 * 1024 }) : new WebSocketServer({ port: httpPort, host, maxPayload: 20 * 1024 * 1024 });
|
|
1337
|
-
if (httpServer
|
|
1338
|
-
await startDeferredHttpListen({
|
|
1342
|
+
if (httpServer) {
|
|
1343
|
+
const boundPort = surface === "simpleui" ? await startDeferredHttpListen({
|
|
1339
1344
|
server: httpServer.server,
|
|
1340
1345
|
host,
|
|
1341
1346
|
httpPort,
|
|
1342
|
-
logger: consoleLogger
|
|
1343
|
-
|
|
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
|
+
}
|
|
1344
1355
|
}
|
|
1345
1356
|
let ipv6LoopbackServer = null;
|
|
1346
1357
|
if (httpServer && host === "127.0.0.1") {
|
|
@@ -1669,4 +1680,4 @@ async function runWebUI(opts) {
|
|
|
1669
1680
|
export {
|
|
1670
1681
|
runWebUI
|
|
1671
1682
|
};
|
|
1672
|
-
//# sourceMappingURL=webui-server-
|
|
1683
|
+
//# sourceMappingURL=webui-server-CKIKAM2P.js.map
|
|
@@ -5,6 +5,7 @@ import type { EventBus } from '@wrongstack/core/kernel';
|
|
|
5
5
|
import type { TrustBoundary } from '@wrongstack/core/security';
|
|
6
6
|
import type { MemoryPort, ModelsRegistry, ModeStore, PromptLoader, SessionStore, SessionWriter, SkillLoader } from '@wrongstack/core/types';
|
|
7
7
|
import type { MCPRegistry } from '@wrongstack/mcp';
|
|
8
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
8
9
|
import type { WebuiSessionChildOptions } from './boot/webui-session-child.js';
|
|
9
10
|
/**
|
|
10
11
|
* CLI-shaped webui options. Distinct from the standalone
|
|
@@ -170,6 +171,16 @@ export interface CliWebUIOptions {
|
|
|
170
171
|
}) => void | Promise<void>) | undefined;
|
|
171
172
|
/** Memory store — enables the Memory panel + chat `/memory` (memory.list) and the structured memory.sage.* operations. */
|
|
172
173
|
memoryStore?: MemoryPort | undefined;
|
|
174
|
+
/**
|
|
175
|
+
* Optional vector-memory store. When provided, the four
|
|
176
|
+
* `/api/vector-memory/{status,search,store,store/:id}` endpoints become
|
|
177
|
+
* active. When omitted, the routes respond with `{ enabled: false }` or
|
|
178
|
+
* 503 — a non-CLI webui-server host stays on its existing surface with
|
|
179
|
+
* zero behavior change.
|
|
180
|
+
*/
|
|
181
|
+
getVectorMemoryStore?: (() => VectorMemoryStore | undefined) | undefined;
|
|
182
|
+
/** Model cache directory for the vector-memory provider. */
|
|
183
|
+
vectorMemoryModelCacheDir?: string | undefined;
|
|
173
184
|
/** Skill loader — enables the SkillsPanel (skills.list). */
|
|
174
185
|
skillLoader?: SkillLoader | undefined;
|
|
175
186
|
/** Prompt loader — enables the prompt library (prompts.list/search/content/favorite/create). */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ToolRegistry } from '@wrongstack/core/registry';
|
|
2
|
+
import type { VectorMemoryStore } from '@wrongstack/vector-memory';
|
|
2
3
|
export declare function setupCliPromptAndTools(params: {
|
|
3
4
|
container: any;
|
|
4
5
|
modeStore: any;
|
|
@@ -19,6 +20,13 @@ export declare function setupCliPromptAndTools(params: {
|
|
|
19
20
|
wpaths: any;
|
|
20
21
|
projectRoot: string;
|
|
21
22
|
events: any;
|
|
23
|
+
/**
|
|
24
|
+
* Optional vector memory store. When provided, the four
|
|
25
|
+
* `vector_memory_*` tools are registered alongside the SAGE tools so
|
|
26
|
+
* agents get both lexical and semantic retrieval paths in one surface.
|
|
27
|
+
* Omit (or pass `undefined`) to keep the CLI on the SAGE-only surface.
|
|
28
|
+
*/
|
|
29
|
+
vectorMemoryStore?: VectorMemoryStore | undefined;
|
|
22
30
|
}): Promise<{
|
|
23
31
|
toolRegistry: ToolRegistry;
|
|
24
32
|
}>;
|
|
@@ -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.
|
|
3
|
+
"version": "0.308.1",
|
|
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,31 +42,32 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"ws": "^8.21.3",
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/mcp": "0.
|
|
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/simpleui": "0.
|
|
63
|
-
"@wrongstack/
|
|
64
|
-
"@wrongstack/webui": "0.
|
|
65
|
-
"@wrongstack/
|
|
66
|
-
"@wrongstack/
|
|
45
|
+
"@wrongstack/bench": "0.308.1",
|
|
46
|
+
"@wrongstack/core": "0.308.1",
|
|
47
|
+
"@wrongstack/acp": "0.308.1",
|
|
48
|
+
"@wrongstack/kanban": "0.308.1",
|
|
49
|
+
"@wrongstack/mcp": "0.308.1",
|
|
50
|
+
"@wrongstack/plugins": "0.308.1",
|
|
51
|
+
"@wrongstack/plug-lsp": "0.308.1",
|
|
52
|
+
"@wrongstack/providers": "0.308.1",
|
|
53
|
+
"@wrongstack/requirement-intake": "0.308.1",
|
|
54
|
+
"@wrongstack/persistence": "0.308.1",
|
|
55
|
+
"@wrongstack/runtime": "0.308.1",
|
|
56
|
+
"@wrongstack/telegram": "0.308.1",
|
|
57
|
+
"@wrongstack/techstack": "0.308.1",
|
|
58
|
+
"@wrongstack/sage": "0.308.1",
|
|
59
|
+
"@wrongstack/security-scanner": "0.308.1",
|
|
60
|
+
"@wrongstack/tools": "0.308.1",
|
|
61
|
+
"@wrongstack/tui": "0.308.1",
|
|
62
|
+
"@wrongstack/simpleui": "0.308.1",
|
|
63
|
+
"@wrongstack/sdd": "0.308.1",
|
|
64
|
+
"@wrongstack/webui-hq": "0.308.1",
|
|
65
|
+
"@wrongstack/webui": "0.308.1",
|
|
66
|
+
"@wrongstack/vector-memory": "0.308.1",
|
|
67
|
+
"@wrongstack/webui-server": "0.308.1"
|
|
67
68
|
},
|
|
68
69
|
"optionalDependencies": {
|
|
69
|
-
"@wrongstack/desktop": "0.
|
|
70
|
+
"@wrongstack/desktop": "0.308.1"
|
|
70
71
|
},
|
|
71
72
|
"devDependencies": {
|
|
72
73
|
"@types/node": "^26.2.0",
|
|
@@ -80,6 +81,7 @@
|
|
|
80
81
|
"scripts": {
|
|
81
82
|
"build": "node ../../scripts/build.mjs --target @wrongstack/webui-hq --skip-if-workspace-build && node ../../scripts/build-package.mjs",
|
|
82
83
|
"typecheck": "pnpm --filter @wrongstack/tools run build && pnpm --filter @wrongstack/tui run build && tsc --noEmit",
|
|
84
|
+
"test": "vitest run",
|
|
83
85
|
"test:hqdash": "vitest run --config vitest.hqdash.config.ts",
|
|
84
86
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
|
|
85
87
|
}
|