@wrongstack/cli 0.303.0 → 0.305.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,6 +48,7 @@ export interface ToolPickerItem {
48
48
  owner: string;
49
49
  category: string;
50
50
  enabled: boolean;
51
+ exposure: 'direct' | 'lazy' | 'disabled';
51
52
  mutating: boolean;
52
53
  permission: string;
53
54
  descMode: 'extend' | 'simple';
@@ -89,6 +90,21 @@ export interface CoreDeps {
89
90
  positional: string[];
90
91
  slashRegistry: SlashCommandRegistry;
91
92
  tokenCounter: TokenCounter;
93
+ /**
94
+ * Forward-declared session ref owned by the host (cli-main). When an
95
+ * in-process `/resume` swaps the agent's active writer, the resume
96
+ * handler repoints `sessionRef.current` so provider-side
97
+ * `getSessionId: () => sessionRef.current?.id` callbacks and the
98
+ * record-mode `bindReplayToContainer` binding follow the resumed
99
+ * session instead of staying pinned to the boot session.
100
+ *
101
+ * Optional: hosts that don't need post-resume propagation (or tests
102
+ * that predate the refactor) can omit it; provider calls then stay
103
+ * pinned to the boot session — same behavior as before this existed.
104
+ */
105
+ sessionRef?: {
106
+ current: import('@wrongstack/core/types').SessionWriter | undefined;
107
+ } | undefined;
92
108
  /** Atomically move this process's SessionRegistry ownership after explicit resume. */
93
109
  activateSessionIdentity?: ((sessionId: string, target?: import('./wiring/session-registry.js').SessionIdentityTarget) => Promise<void>) | undefined;
94
110
  /**
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-V3XH6XBJ.js";
11
11
  import {
12
12
  startCliHqConnection
13
- } from "./chunk-JW75HY4F.js";
13
+ } from "./chunk-FKWHSFX4.js";
14
14
  import "./chunk-WHOIR577.js";
15
15
  import {
16
16
  advanceToNextTask,
@@ -25,17 +25,17 @@ import {
25
25
  trySaveSpecFromAIOutput,
26
26
  trySaveTasksFromAIOutput
27
27
  } from "./chunk-DGXNL7OT.js";
28
- import {
29
- WEBUI_SESSION_CHILD_CAPABILITIES,
30
- writeWebuiSessionChildError,
31
- writeWebuiSessionChildReady
32
- } from "./chunk-3JPTNADJ.js";
33
28
  import {
34
29
  theme
35
30
  } from "./chunk-QD544J2B.js";
36
31
  import {
37
32
  fmtTok
38
33
  } from "./chunk-TYO2OVAD.js";
34
+ import {
35
+ WEBUI_SESSION_CHILD_CAPABILITIES,
36
+ writeWebuiSessionChildError,
37
+ writeWebuiSessionChildReady
38
+ } from "./chunk-3JPTNADJ.js";
39
39
  import {
40
40
  resolveActiveApiKey
41
41
  } from "./chunk-SZ42FYPT.js";
@@ -203,7 +203,7 @@ async function runWebUIDispatch(ctx) {
203
203
  const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
204
204
  agent.disableInteractiveConfirmation();
205
205
  renderer.setSilent(true);
206
- const { runWebUI } = await import("./webui-server-E3OPEKU5.js");
206
+ const { runWebUI } = await import("./webui-server-FTG7JAZU.js");
207
207
  const flagValue = (names) => {
208
208
  for (const name of names) {
209
209
  if (!Object.hasOwn(flags, name)) continue;
@@ -985,8 +985,13 @@ import {
985
985
  DefaultSystemPromptBuilder,
986
986
  setQueuedMessagesSnapshot
987
987
  } from "@wrongstack/core/agent";
988
+ import { TOKENS } from "@wrongstack/core/kernel";
988
989
  import { DefaultSessionStore } from "@wrongstack/core/storage";
989
- import { resolveWstackPaths, sessionScopedPath } from "@wrongstack/core/utils";
990
+ import {
991
+ activateProjectStateGuard,
992
+ resolveWstackPaths,
993
+ sessionScopedPath
994
+ } from "@wrongstack/core/utils";
990
995
  async function switchProjectInPlace(ctx, targetRoot, displayName) {
991
996
  const {
992
997
  state,
@@ -1064,6 +1069,7 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1064
1069
  });
1065
1070
  targetActivated = true;
1066
1071
  await state.activateSessionIdentity(nextWriter.id, target);
1072
+ await activateProjectStateGuard(resolved);
1067
1073
  } catch (err) {
1068
1074
  if (!targetActivated) await targetClaim?.cancel().catch(() => void 0);
1069
1075
  else if (oldWriter) {
@@ -1124,6 +1130,13 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1124
1130
  modeStore,
1125
1131
  modeId: modeId ?? "default",
1126
1132
  modePrompt: switchMode?.prompt ?? "",
1133
+ tokenSavingMode: config.features.tokenSavingMode,
1134
+ modelCapabilities: {
1135
+ maxContextTokens: context.provider.capabilities.maxContext,
1136
+ supportsTools: !!context.provider.capabilities.tools,
1137
+ supportsVision: !!context.provider.capabilities.vision,
1138
+ supportsReasoning: !!context.provider.capabilities.reasoning
1139
+ },
1127
1140
  instructionPaths: {
1128
1141
  globalDir: nextWpaths.globalInstructions,
1129
1142
  projectDir: nextWpaths.inProjectInstructions,
@@ -1138,6 +1151,11 @@ async function switchProjectInPlace(ctx, targetRoot, displayName) {
1138
1151
  provider: context.provider.id,
1139
1152
  model: context.model
1140
1153
  });
1154
+ if (agent.container.has(TOKENS.SystemPromptBuilder)) {
1155
+ agent.container.override(TOKENS.SystemPromptBuilder, () => switchBuilder, {
1156
+ owner: "tui-project-switch"
1157
+ });
1158
+ }
1141
1159
  } catch (err) {
1142
1160
  console.error(
1143
1161
  JSON.stringify({
@@ -1298,6 +1316,7 @@ async function resumeSession(ctx, sessionId) {
1298
1316
  throw err;
1299
1317
  }
1300
1318
  writerSwapped = true;
1319
+ state.sessionRef && (state.sessionRef.current = resumed.writer);
1301
1320
  await agent.ctx.flushConversationJournal().catch((err) => {
1302
1321
  console.error(
1303
1322
  JSON.stringify({
@@ -2319,7 +2338,9 @@ async function finalizeExecutionCleanup(input) {
2319
2338
 
2320
2339
  // src/execution-kanban-dispatch.ts
2321
2340
  import { randomUUID } from "node:crypto";
2341
+ import { missingRequiredRuntimeTools } from "@wrongstack/core/agent-catalog";
2322
2342
  import { WIDE_SUBAGENT_CAPABILITIES } from "@wrongstack/core/security";
2343
+ import { stripFrontmatter } from "@wrongstack/core/skills";
2323
2344
 
2324
2345
  // src/kanban-dispatch-route.ts
2325
2346
  import { fallbackProfileChain, parseModelRef as parseModelRef2 } from "@wrongstack/core/agent";
@@ -2358,21 +2379,43 @@ function createKanbanDispatchHandler({
2358
2379
  } = resolveKanbanDispatchRoute(config, spawnOpts);
2359
2380
  let agentDescription = description;
2360
2381
  if (spawnOpts?.skills?.length && skillLoader) {
2361
- const loaded = await Promise.all(
2362
- spawnOpts.skills.map(async (skillName) => {
2382
+ const availableToolNames = spawnOpts.tools;
2383
+ const loaded = [];
2384
+ for (const skillName of spawnOpts.skills) {
2385
+ try {
2363
2386
  const manifest = await skillLoader.find(skillName);
2364
- if (!manifest) throw new Error(`Kanban skill not found: ${skillName}`);
2365
- const body = await skillLoader.readBody(skillName);
2366
- return `## Required skill: ${skillName}
2387
+ if (!manifest) {
2388
+ process.emitWarning(`Kanban dispatch skill not found, skipped: ${skillName}`, {
2389
+ code: "WRONGSTACK_KANBAN_SKILL_SKIPPED"
2390
+ });
2391
+ continue;
2392
+ }
2393
+ if (availableToolNames !== void 0 && missingRequiredRuntimeTools(manifest.requiredTools, availableToolNames).length > 0) {
2394
+ process.emitWarning(
2395
+ `Kanban dispatch skill "${skillName}" needs tools this worker does not have, skipped.`,
2396
+ { code: "WRONGSTACK_KANBAN_SKILL_SKIPPED" }
2397
+ );
2398
+ continue;
2399
+ }
2400
+ const body = stripFrontmatter(await skillLoader.readBody(skillName)).trim();
2401
+ if (!body) continue;
2402
+ loaded.push(`## Required skill: ${skillName}
2367
2403
 
2368
- ${body}`;
2369
- })
2370
- );
2371
- agentDescription = `${description}
2404
+ ${body}`);
2405
+ } catch (err) {
2406
+ process.emitWarning(
2407
+ `Kanban dispatch skill "${skillName}" could not be loaded, skipped: ${err instanceof Error ? err.message : String(err)}`,
2408
+ { code: "WRONGSTACK_KANBAN_SKILL_SKIPPED" }
2409
+ );
2410
+ }
2411
+ }
2412
+ if (loaded.length > 0) {
2413
+ agentDescription = `${description}
2372
2414
 
2373
2415
  # Required agentic skill instructions
2374
2416
 
2375
2417
  ${loaded.join("\n\n")}`;
2418
+ }
2376
2419
  }
2377
2420
  void (async () => {
2378
2421
  const built = await sddSubagentFactory({
@@ -4738,6 +4781,7 @@ async function execute(deps) {
4738
4781
  positional,
4739
4782
  slashRegistry,
4740
4783
  tokenCounter,
4784
+ sessionRef,
4741
4785
  activateSessionIdentity,
4742
4786
  updateInfo: initialUpdateInfo,
4743
4787
  webuiSessionChild
@@ -4934,6 +4978,12 @@ async function execute(deps) {
4934
4978
  activeSessionStore,
4935
4979
  activateSessionIdentity,
4936
4980
  detachActiveTodosCheckpoint,
4981
+ // Plumbed from cli-main.ts so `resumeSession` can repoint the ref
4982
+ // when an in-process `/resume` swaps the active writer. Optional
4983
+ // on TuiRuntimeState; tests/hosts that omit it revert to the
4984
+ // pre-refactor behavior where provider calls stay pinned to the
4985
+ // boot session.
4986
+ sessionRef,
4937
4987
  pendingProjectSwitch: null,
4938
4988
  autonomousCoordinator: null,
4939
4989
  coordinatorRun: null,
@@ -5312,4 +5362,4 @@ export {
5312
5362
  execute,
5313
5363
  resolveReviewerFallbackModels
5314
5364
  };
5315
- //# sourceMappingURL=execution-MVOH6PAQ.js.map
5365
+ //# sourceMappingURL=execution-YMBD7YWC.js.map
@@ -6,6 +6,8 @@ export interface SkillResolutionReport {
6
6
  selected: string[];
7
7
  /** skill → why it was dropped, so the omission is never silent. */
8
8
  dropped: Record<string, 'not-found' | 'missing-capability' | 'missing-tool' | 'budget' | 'empty'>;
9
+ /** Skills kept under budget by shortening their bundled body. */
10
+ trimmed: string[];
9
11
  }
10
12
  export declare function resolveHostSubagentSkillResolution(deps: MultiAgentDeps, roster: Record<string, SubagentConfig>, subCfg: SubagentConfig, availableToolNames?: readonly string[]): Promise<SkillResolutionReport>;
11
13
  /** Backwards-compatible wrapper for callers that only need the prompt text. */
@@ -1,3 +1,36 @@
1
1
  import type { SessionWriter } from '@wrongstack/core/types';
2
+ /**
3
+ * Session writer for a subagent that has no journal of its own: its events are
4
+ * interleaved into the parent's JSONL.
5
+ *
6
+ * Lifecycle and rewind *control* stay no-ops — `writeCheckpoint`,
7
+ * `writeInFlightMarker`, `truncateToCheckpoint`, `clearSession` and `close`
8
+ * belong to the parent, and a subagent driving them would corrupt the parent's
9
+ * checkpoint chain and crash-recovery markers.
10
+ *
11
+ * Rewind *evidence* is a different thing and is forwarded. A subagent's file
12
+ * mutations are real edits to the user's working tree, made under the parent
13
+ * prompt that spawned it; dropping their `file_snapshot` records left `/rewind`
14
+ * quietly unable to undo them, with nothing in the transcript saying so. The
15
+ * parent writer files them against its own `activePromptIndex`, which is
16
+ * exactly the prompt a user rewinding this work would target.
17
+ */
2
18
  export declare function createParentSubagentSessionWriter(parentSession: SessionWriter): SessionWriter;
19
+ /**
20
+ * Wrap a subagent's own `SessionWriter` so its file mutations are ALSO recorded
21
+ * against the parent session.
22
+ *
23
+ * When a subagent gets a real per-subagent JSONL, its `file_snapshot` events
24
+ * land in that file — under the director run directory, which
25
+ * `DefaultSessionRewinder` never reads: it resolves one path, the session being
26
+ * rewound. So the richer, "proper" subagent-session path was the one that lost
27
+ * rewind coverage entirely, while the fallback shim above at least had the
28
+ * parent handle in reach.
29
+ *
30
+ * Recording to the parent as well keeps one authority for undo (the session the
31
+ * user actually rewinds) without taking anything away from the subagent's own
32
+ * transcript, which still receives every other event including the conversation
33
+ * that produced the edit.
34
+ */
35
+ export declare function withParentFileSnapshots(subagentSession: SessionWriter, parentSession: SessionWriter): SessionWriter;
3
36
  //# sourceMappingURL=host-session-writer.d.ts.map
@@ -211,6 +211,16 @@ export declare class MultiAgentHost {
211
211
  * Returns null when auto-optimization is switched off.
212
212
  */
213
213
  private getLearningOptimizer;
214
+ /**
215
+ * Break a dispatch tie with a model when the keyword heuristic is ambiguous.
216
+ *
217
+ * Routes through the `dispatcher` model-matrix slot when one is configured —
218
+ * picking a role is a short classification, so it belongs on a cheap fast
219
+ * model rather than the leader's — and the session default otherwise.
220
+ * Returning `null` on any failure leaves the dispatcher on its heuristic
221
+ * result, so routing degrades rather than breaking a spawn.
222
+ */
223
+ private classifyDispatch;
214
224
  /**
215
225
  * Resolve a model for the distillation pass. Uses the `memory-curator` slot
216
226
  * of the model matrix when one is configured — curating learned knowledge is
@@ -47,7 +47,7 @@ var hqCmd = async (args, deps) => {
47
47
  return 1;
48
48
  };
49
49
  async function startServer(deps) {
50
- const { startHqServer } = await import("./hq-server-DME6EWIO.js");
50
+ const { startHqServer } = await import("./hq-server-IVZLVCFV.js");
51
51
  const dataDir = resolveDataDir(deps);
52
52
  const flags = deps.flags ?? {};
53
53
  const host = typeof flags["host"] === "string" ? flags["host"] : HQ_CLI_DEFAULT_HOST;
@@ -612,4 +612,4 @@ export {
612
612
  hqCmd,
613
613
  resolveAuditActor
614
614
  };
615
- //# sourceMappingURL=hq-CD77GVSS.js.map
615
+ //# sourceMappingURL=hq-5G6D5YIU.js.map
@@ -15,7 +15,7 @@ import {
15
15
  readLocalSubagentTranscript,
16
16
  sanitizeApiError,
17
17
  startHqServer
18
- } from "./chunk-LUAFQIXT.js";
18
+ } from "./chunk-RHLQT3EV.js";
19
19
  import "./chunk-KE7E7DPX.js";
20
20
  import "./chunk-Q5GTM25S.js";
21
21
  import "./chunk-7OCVIDC7.js";
@@ -37,4 +37,4 @@ export {
37
37
  sanitizeApiError,
38
38
  startHqServer
39
39
  };
40
- //# sourceMappingURL=hq-server-DME6EWIO.js.map
40
+ //# sourceMappingURL=hq-server-IVZLVCFV.js.map
package/dist/index.js CHANGED
@@ -1,8 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- parseWebuiSessionChildOptions,
4
- writeWebuiSessionChildError
5
- } from "./chunk-3JPTNADJ.js";
6
2
  import {
7
3
  applySimpleUiFullAutoProfile,
8
4
  detectProjectFacts,
@@ -17,6 +13,10 @@ import {
17
13
  import {
18
14
  patchConfig
19
15
  } from "./chunk-TYO2OVAD.js";
16
+ import {
17
+ parseWebuiSessionChildOptions,
18
+ writeWebuiSessionChildError
19
+ } from "./chunk-3JPTNADJ.js";
20
20
  import {
21
21
  parseArgs,
22
22
  runPicker,
@@ -43,7 +43,7 @@ import "./chunk-U3SS4NRH.js";
43
43
  import "./chunk-NUIHRGPY.js";
44
44
  import {
45
45
  DEFAULT_PORT
46
- } from "./chunk-LUAFQIXT.js";
46
+ } from "./chunk-RHLQT3EV.js";
47
47
  import "./chunk-KE7E7DPX.js";
48
48
  import "./chunk-Q5GTM25S.js";
49
49
  import {
@@ -59,7 +59,7 @@ import {
59
59
  import "./chunk-7OCVIDC7.js";
60
60
 
61
61
  // src/cli-context.ts
62
- import { TOKENS as TOKENS4 } from "@wrongstack/core/kernel";
62
+ import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
63
63
  import { writeErr as writeErr3 } from "@wrongstack/core/utils";
64
64
  import { setOAuthTokenPersister } from "@wrongstack/providers";
65
65
 
@@ -761,7 +761,7 @@ async function isPortInUse(host, port) {
761
761
  }
762
762
  async function handleHqShortCircuit(flags) {
763
763
  if (flags["hq"] !== true) return null;
764
- const { startHqServer } = await import("./hq-server-DME6EWIO.js");
764
+ const { startHqServer } = await import("./hq-server-IVZLVCFV.js");
765
765
  const tunnelRequested = flags["tunnel"] === true;
766
766
  const host = typeof flags["host"] === "string" ? flags["host"] : tunnelRequested ? "127.0.0.1" : HQ_CLI_DEFAULT_HOST2;
767
767
  if (tunnelRequested && !isLoopbackHost(host)) {
@@ -2306,7 +2306,7 @@ function compactSingleLine(text) {
2306
2306
 
2307
2307
  // src/subcommands/index.ts
2308
2308
  var loaders = {
2309
- acp: async () => (await import("./acp-AQMGKW6O.js")).acpCmd,
2309
+ acp: async () => (await import("./acp-5ZLGFHWP.js")).acpCmd,
2310
2310
  init: async () => (await import("./init-E2NDDOHI.js")).initCmd,
2311
2311
  auth: async () => (await import("./auth-K7CYVVKH.js")).authCmd,
2312
2312
  update: async () => (await import("./update-VZSOZGYC.js")).updateCmd,
@@ -2319,7 +2319,7 @@ var loaders = {
2319
2319
  skills: async () => (await import("./tools-skills-UNKLOB7M.js")).skillsCmd,
2320
2320
  providers: async () => (await import("./providers-models-VV74TRQ2.js")).providersCmd,
2321
2321
  models: async () => (await import("./providers-models-VV74TRQ2.js")).modelsCmd,
2322
- mcp: async () => (await import("./mcp-AX6ZAFJR.js")).mcpCmd,
2322
+ mcp: async () => (await import("./mcp-MSARYOPN.js")).mcpCmd,
2323
2323
  plugin: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
2324
2324
  plugins: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
2325
2325
  diag: async () => (await import("./diag-doctor-ZF5BF2MK.js")).diagCmd,
@@ -2333,8 +2333,8 @@ var loaders = {
2333
2333
  quick: async () => (await import("./quick-VIO2BEHS.js")).quickCmd,
2334
2334
  bench: async () => (await import("./bench-XNDUJOSZ.js")).benchCmd,
2335
2335
  chronicle: async () => (await import("./chronicle-63MFCZN6.js")).chronicleCmd,
2336
- hq: async () => (await import("./hq-CD77GVSS.js")).hqCmd,
2337
- mailbox: async () => (await import("./mailbox-serve-DBOOOOWZ.js")).mailboxServeCmd,
2336
+ hq: async () => (await import("./hq-5G6D5YIU.js")).hqCmd,
2337
+ mailbox: async () => (await import("./mailbox-serve-V3QIJBDH.js")).mailboxServeCmd,
2338
2338
  permissions: async () => (await import("./permissions-2PWBL4YU.js")).permissionsCmd,
2339
2339
  project: async () => (await import("./project-BLQ3ALVL.js")).projectCmd,
2340
2340
  governance: async () => (await import("./governance-V2Z42RBE.js")).governanceCmd
@@ -2916,35 +2916,6 @@ async function runPreflight(config, initialUpdateInfo) {
2916
2916
  };
2917
2917
  }
2918
2918
 
2919
- // src/wiring/replay.ts
2920
- import { runProviderWithRetry } from "@wrongstack/core/agent";
2921
- import { TOKENS as TOKENS3 } from "@wrongstack/core/kernel";
2922
- import { ReplayProviderRunner } from "@wrongstack/core/replay";
2923
- import { ReplayLogStore } from "@wrongstack/core/storage";
2924
- function bindReplayToContainer(opts) {
2925
- const { container, wpaths, sessionId, mode, logger } = opts;
2926
- if (!opts.container.has(TOKENS3.ProviderRunner)) {
2927
- container.bind(
2928
- TOKENS3.ProviderRunner,
2929
- () => ({
2930
- run: (o) => runProviderWithRetry(o)
2931
- })
2932
- );
2933
- }
2934
- const inner = container.resolve(TOKENS3.ProviderRunner);
2935
- const log = new ReplayLogStore({ dir: wpaths.projectSessions });
2936
- const wrapped = new ReplayProviderRunner(inner, {
2937
- log,
2938
- sessionId,
2939
- mode,
2940
- logger: logger ? {
2941
- debug: (m) => logger.debug?.(m),
2942
- warn: (m) => logger.warn?.(m)
2943
- } : void 0
2944
- });
2945
- container.bind(TOKENS3.ProviderRunner, () => wrapped);
2946
- }
2947
-
2948
2919
  // src/cli-context.ts
2949
2920
  async function initializeCli(argv) {
2950
2921
  applyNodeEnvDefault();
@@ -3103,21 +3074,7 @@ async function initializeCli(argv) {
3103
3074
  renderer,
3104
3075
  modelsRegistry
3105
3076
  });
3106
- const replayFlag = ctx.flags["replay"];
3107
- const recordFlag = ctx.flags["record"];
3108
- if (typeof replayFlag === "string" || recordFlag === true) {
3109
- const sessionId = typeof replayFlag === "string" ? replayFlag : `record-${Date.now()}`;
3110
- const mode = recordFlag === true ? "record" : "replay";
3111
- bindReplayToContainer({
3112
- container,
3113
- wpaths,
3114
- sessionId,
3115
- mode,
3116
- logger
3117
- });
3118
- logger.info(`replay: ProviderRunner bound in '${mode}' mode for session ${sessionId}`);
3119
- }
3120
- const configStore = container.resolve(TOKENS4.ConfigStore);
3077
+ const configStore = container.resolve(TOKENS3.ConfigStore);
3121
3078
  return {
3122
3079
  ...ctx,
3123
3080
  updateInfo: refreshedUpdateInfo,
@@ -3132,7 +3089,7 @@ async function initializeCli(argv) {
3132
3089
  async function main(argv) {
3133
3090
  const cliCtx = await initializeCli(argv);
3134
3091
  if (typeof cliCtx === "number") return cliCtx;
3135
- const { runInteractive } = await import("./cli-main-37XO26GK.js");
3092
+ const { runInteractive } = await import("./cli-main-W3T56YCY.js");
3136
3093
  return runInteractive(cliCtx);
3137
3094
  }
3138
3095
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startCliHqConnection
3
- } from "./chunk-JW75HY4F.js";
3
+ } from "./chunk-FKWHSFX4.js";
4
4
  import "./chunk-7OCVIDC7.js";
5
5
 
6
6
  // src/subcommands/handlers/mailbox-serve.ts
@@ -341,4 +341,4 @@ function printHelp(deps) {
341
341
  export {
342
342
  mailboxServeCmd
343
343
  };
344
- //# sourceMappingURL=mailbox-serve-DBOOOOWZ.js.map
344
+ //# sourceMappingURL=mailbox-serve-V3QIJBDH.js.map
@@ -221,7 +221,9 @@ async function serveMcpStdio(deps) {
221
221
  secretScrubber: new DefaultSecretScrubber(),
222
222
  maxToolTimeoutMs: deps.config.tools?.maxToolTimeoutMs ?? 3e5,
223
223
  perIterationOutputCapBytes: 1e6,
224
- requireKanbanGovernance: true
224
+ // Kanban tracks work; it does not gate it. Off unless the operator opts in.
225
+ // See wiring/pipeline.ts for why all four hosts must agree.
226
+ requireKanbanGovernance: deps.config.tools?.kanbanGovernance ?? false
225
227
  });
226
228
  const allowed = await selectExposedTools(registry, ctx, permissionPolicy, whitelist);
227
229
  const allowedNames = new Set(allowed.map((t) => t.name));
@@ -415,4 +417,4 @@ function isRecord(value) {
415
417
  export {
416
418
  mcpCmd
417
419
  };
418
- //# sourceMappingURL=mcp-AX6ZAFJR.js.map
420
+ //# sourceMappingURL=mcp-MSARYOPN.js.map
@@ -0,0 +1,34 @@
1
+ import "./chunk-7OCVIDC7.js";
2
+
3
+ // src/wiring/replay.ts
4
+ import { runProviderWithRetry } from "@wrongstack/core/agent";
5
+ import { TOKENS } from "@wrongstack/core/kernel";
6
+ import { ReplayProviderRunner } from "@wrongstack/core/replay";
7
+ import { ReplayLogStore } from "@wrongstack/core/storage";
8
+ function bindReplayToContainer(opts) {
9
+ const { container, wpaths, sessionId, mode, logger } = opts;
10
+ if (!opts.container.has(TOKENS.ProviderRunner)) {
11
+ container.bind(
12
+ TOKENS.ProviderRunner,
13
+ () => ({
14
+ run: (o) => runProviderWithRetry(o)
15
+ })
16
+ );
17
+ }
18
+ const inner = container.resolve(TOKENS.ProviderRunner);
19
+ const log = new ReplayLogStore({ dir: wpaths.projectSessions });
20
+ const wrapped = new ReplayProviderRunner(inner, {
21
+ log,
22
+ sessionId,
23
+ mode,
24
+ logger: logger ? {
25
+ debug: (m) => logger.debug?.(m),
26
+ warn: (m) => logger.warn?.(m)
27
+ } : void 0
28
+ });
29
+ container.bind(TOKENS.ProviderRunner, () => wrapped);
30
+ }
31
+ export {
32
+ bindReplayToContainer
33
+ };
34
+ //# sourceMappingURL=replay-XU6ZD7GM.js.map
@@ -19,29 +19,16 @@
19
19
  * `/memory compact`. Falls back to a no-op LLM if the provider is absent
20
20
  * (Phase 3 and 4 will degrade to skip-only; report is still useful).
21
21
  */
22
- import type { CreateCandidateInput, SageSurface } from '@wrongstack/sage';
22
+ import type { SageSurface } from '@wrongstack/sage';
23
23
  import { type TriageReport } from '@wrongstack/sage';
24
24
  import type { SlashCommandContext } from './command-context.js';
25
25
  export declare function runTriageCommand(opts: SlashCommandContext, args: string[]): Promise<{
26
26
  message: string;
27
27
  }>;
28
- export interface ProposalFileResult {
29
- filed: number;
30
- failed: number;
31
- total: number;
32
- failures: Array<{
33
- memoryId: string;
34
- error: string;
35
- }>;
36
- /** All inputs that were submitted to Sage.createCandidate, for test verification. */
37
- inputs: CreateCandidateInput[];
38
- }
28
+ export type { ProposalFileResult } from '@wrongstack/sage';
39
29
  /**
40
30
  * File triage proposals as MemoryCandidates via the Sage surface.
41
- *
42
- * Exported for unit testing — the round-trip path through
43
- * Sage.createCandidate is the key contract: every proposal must
44
- * surface in `/memory candidates` for human review.
31
+ * Implementation lives in `@wrongstack/sage` (shared with daily dry-run).
45
32
  */
46
- export declare function fileProposals(Sage: SageSurface, proposals: TriageReport['dispatch']['proposals']): Promise<ProposalFileResult>;
33
+ export declare function fileProposals(Sage: SageSurface, proposals: TriageReport['dispatch']['proposals']): Promise<import('@wrongstack/sage').ProposalFileResult>;
47
34
  //# sourceMappingURL=memory-triage.d.ts.map
@@ -1,12 +1,12 @@
1
- import {
2
- createKanbanRunMirror
3
- } from "./chunk-VCYZ3WZV.js";
4
1
  import {
5
2
  createHqCommandDispatcher
6
3
  } from "./chunk-7YLN7YUA.js";
4
+ import {
5
+ createKanbanRunMirror
6
+ } from "./chunk-VCYZ3WZV.js";
7
7
  import {
8
8
  startCliHqConnection
9
- } from "./chunk-JW75HY4F.js";
9
+ } from "./chunk-FKWHSFX4.js";
10
10
  import {
11
11
  WEBUI_SESSION_CHILD_CAPABILITIES
12
12
  } from "./chunk-3JPTNADJ.js";
@@ -1591,4 +1591,4 @@ async function runWebUI(opts) {
1591
1591
  export {
1592
1592
  runWebUI
1593
1593
  };
1594
- //# sourceMappingURL=webui-server-E3OPEKU5.js.map
1594
+ //# sourceMappingURL=webui-server-FTG7JAZU.js.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Narrow adapter that bridges the resolved SAGE `MemoryPort` to the
3
+ * `DomainGlossary` shape the prompt builder consumes.
4
+ *
5
+ * Background
6
+ * ----------
7
+ * The agent system prompt wants a compact `[Project Jargon Dictionary]`
8
+ * block listing only the project's `domain-term`-tagged memories. The
9
+ * block must come from SAGE so the same single-owner-of-SQLite invariant
10
+ * holds (per `packages/sage/docs/direct-icp-usage.md`). But the prompt
11
+ * builder runs **before** any per-turn SAGE middleware has filtered the
12
+ * corpus — so we can't simply hand it the legacy `MemoryStore` and ask
13
+ * it to call `list()`. That would scan every memory on every prompt
14
+ * build, which is exactly what the glossary block was supposed to
15
+ * avoid.
16
+ *
17
+ * Instead, we ask SAGE for only the `domain-term`-tagged subset using
18
+ * the typed `SageServiceLike.searchSage({ query: 'domain-term', limit })`
19
+ * op (which performs the tag/keyword filter at the SQL layer), then map
20
+ * the resulting `Sage[]` into the canonical `MemoryEntry` shape that
21
+ * `renderDomainGlossary` in `packages/core/src/core/system-prompt-glossary.ts`
22
+ * is typed against.
23
+ *
24
+ * Architectural rule
25
+ * ------------------
26
+ * This module imports from `@wrongstack/sage` directly — **never** from
27
+ * `@wrongstack/sage-mcp`. The CLI is an in-process consumer; the MCP
28
+ * surface is reserved for out-of-process clients (Claude Desktop, other
29
+ * agent runtimes).
30
+ */
31
+ import type { MemoryEntry, MemoryPort } from '@wrongstack/core/types';
32
+ /**
33
+ * Narrow `MemoryEntry`-shaped list provider for the `[Project Jargon Dictionary]`
34
+ * block. Returns only `domain-term`-tagged SAGE memories, mapped to the
35
+ * canonical `MemoryEntry` shape `renderDomainGlossary` is typed against.
36
+ *
37
+ * Robustness contract:
38
+ * - If the port is the legacy `LegacyMemoryPortAdapter` (no SAGE
39
+ * capability), the helper returns an empty glossary rather than
40
+ * throwing — the prompt must still assemble.
41
+ * - If `searchSage` rejects, the wrapper returns an empty glossary
42
+ * for this prompt build; SAGE itself remains the source of truth and
43
+ * the next prompt retry can succeed.
44
+ */
45
+ export interface DomainGlossaryListProvider {
46
+ list(scope: 'project-memory', limit?: number): Promise<ReadonlyArray<MemoryEntry>>;
47
+ }
48
+ /**
49
+ * Build a `DomainGlossaryListProvider` over a SAGE-aware `MemoryPort`.
50
+ *
51
+ * The mapping is honest: every `MemoryEntry` field that core will read
52
+ * (`text`, `tags`, `confidence`, `ts`, `priority`) is populated from the
53
+ * corresponding `Sage` field. `text` is preserved verbatim because
54
+ * `SageDomainTermExtractor` writes the canonical `"Term — Definition"`
55
+ * format that `parseTermEntry` in core splits back apart.
56
+ */
57
+ export declare function createDomainGlossaryAdapter(memoryStore: MemoryPort): DomainGlossaryListProvider;
58
+ //# sourceMappingURL=domain-glossary.d.ts.map