@wrongstack/cli 1.0.19 → 1.0.26

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.
Files changed (195) hide show
  1. package/data/providers.json +44 -0
  2. package/dist/{acp-INCNOH42.js → acp-LI665LO2.js} +18 -7
  3. package/dist/arg-parser.d.ts +1 -0
  4. package/dist/ascii-mode-SG4PRNLP.js +7 -0
  5. package/dist/{auth-YXK3EDUL.js → auth-TE55JF4Z.js} +68 -22
  6. package/dist/auth-menu/direct.d.ts +1 -0
  7. package/dist/auth-menu/local.d.ts +2 -0
  8. package/dist/auth-menu/oauth-menu.d.ts +3 -1
  9. package/dist/auth-menu/panel-service.d.ts +20 -0
  10. package/dist/{bench-YBU6BVQP.js → bench-GTLPM22B.js} +2 -2
  11. package/dist/boot/append-system-prompt.d.ts +10 -0
  12. package/dist/boot/ascii-mode.d.ts +12 -0
  13. package/dist/boot/config-backup-recovery.d.ts +2 -1
  14. package/dist/boot/container-wiring.d.ts +4 -2
  15. package/dist/boot/dispatch-singleshot.d.ts +4 -1
  16. package/dist/boot/dispatch-webui.d.ts +11 -0
  17. package/dist/boot/mcp-config-flag.d.ts +22 -0
  18. package/dist/boot/piped-stdin.d.ts +40 -0
  19. package/dist/boot/restricted-mode.d.ts +15 -0
  20. package/dist/boot/safe-mode.d.ts +30 -0
  21. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  22. package/dist/boot/single-shot-budget.d.ts +30 -0
  23. package/dist/boot/stream-json.d.ts +36 -0
  24. package/dist/boot/structured-output.d.ts +16 -0
  25. package/dist/boot/system-prompt-builder.d.ts +2 -0
  26. package/dist/boot/tool-restriction-flags.d.ts +36 -0
  27. package/dist/boot/tui-project-picker-callback.d.ts +1 -1
  28. package/dist/boot/tui-settings-adapter.d.ts +15 -2
  29. package/dist/boot/worktree-sessions.d.ts +21 -0
  30. package/dist/{boot-auto-thin-MANHOYHE.js → boot-auto-thin-6Q56FY3F.js} +3 -2
  31. package/dist/boot-provider-selection.d.ts +67 -0
  32. package/dist/boot.d.ts +1 -38
  33. package/dist/{chunk-JY52HWL6.js → chunk-2EBVTYJR.js} +2 -2
  34. package/dist/{chunk-RDHFXOJM.js → chunk-2ERX3RPN.js} +112 -65
  35. package/dist/chunk-4TVYGG6G.js +62 -0
  36. package/dist/chunk-5JYDKG5B.js +154 -0
  37. package/dist/{chunk-KEPABQYT.js → chunk-5SEYGOCH.js} +8 -82
  38. package/dist/{chunk-3VXYY5JC.js → chunk-5UZBUV2H.js} +3 -19
  39. package/dist/chunk-BBHWW6LR.js +549 -0
  40. package/dist/chunk-BEHGRNOQ.js +58 -0
  41. package/dist/chunk-CZTXF6HY.js +140 -0
  42. package/dist/{chunk-JX6KL7OF.js → chunk-EPR42SWM.js} +39 -8
  43. package/dist/chunk-F5DCFAKI.js +36 -0
  44. package/dist/chunk-HLSHFXTO.js +97 -0
  45. package/dist/{chunk-CJTBLTS4.js → chunk-KJS5543T.js} +4 -3
  46. package/dist/{chunk-DE7BZDNK.js → chunk-KOEO4CJG.js} +27 -4
  47. package/dist/{chunk-SIS37L3W.js → chunk-L2RVEQWO.js} +211 -193
  48. package/dist/chunk-LBPLTTZ6.js +105 -0
  49. package/dist/chunk-LDCGZJTC.js +46 -0
  50. package/dist/chunk-LKPEBZBE.js +143 -0
  51. package/dist/chunk-LUMETJFO.js +171 -0
  52. package/dist/{chunk-KK2LB3ZS.js → chunk-OAVBM55Q.js} +9 -5
  53. package/dist/chunk-PZQBGUVZ.js +18 -0
  54. package/dist/{chunk-C3Z4N6A6.js → chunk-Q4INH2DG.js} +51 -3
  55. package/dist/chunk-R4QGL6GB.js +10 -0
  56. package/dist/{chunk-YLQEGYV4.js → chunk-RZ4ZDRYA.js} +14 -4
  57. package/dist/chunk-S4FFHDJG.js +93 -0
  58. package/dist/chunk-SFBFYIOW.js +271 -0
  59. package/dist/{chunk-RMQNCHGO.js → chunk-TI7KLHYX.js} +136 -11
  60. package/dist/{chunk-2ENZU66X.js → chunk-WQV2NP57.js} +5 -5
  61. package/dist/{chunk-B4JLSXZB.js → chunk-WSTVGC2C.js} +73 -45
  62. package/dist/chunk-X756ZS72.js +329 -0
  63. package/dist/{chunk-XJ7K67PP.js → chunk-YHYINL47.js} +63 -24
  64. package/dist/{chunk-2VMJ3E5Z.js → chunk-YTEOAWOJ.js} +6 -2
  65. package/dist/{chunk-GPPRNAKW.js → chunk-ZMX5HRLI.js} +2 -2
  66. package/dist/{cli-context-33F74CSZ.js → cli-context-UVGAN3NO.js} +496 -384
  67. package/dist/cli-entry-point.d.ts +2 -0
  68. package/dist/{cli-main-FNGMKPBA.js → cli-main-TN3KZ2P6.js} +3561 -2724
  69. package/dist/cli-update-notice.d.ts +2 -1
  70. package/dist/config-doctor.d.ts +10 -2
  71. package/dist/{config-transfer-2YF3CRTN.js → config-transfer-RUWLDCNK.js} +34 -13
  72. package/dist/{diag-doctor-ANPRUYFM.js → diag-doctor-BIZAFIAT.js} +2 -2
  73. package/dist/execute-deps.d.ts +2 -1
  74. package/dist/{execution-A6WJLSOC.js → execution-7QIP6GRY.js} +2384 -2055
  75. package/dist/fleet/host-types.d.ts +3 -1
  76. package/dist/goal-commands.d.ts +47 -0
  77. package/dist/goal-host.d.ts +1 -14
  78. package/dist/{hq-XQWQTRDA.js → hq-GLZ7QESM.js} +277 -261
  79. package/dist/hq-command-controller.d.ts +1 -1
  80. package/dist/{hq-server-IIBZQZU4.js → hq-server-YTKDVQPY.js} +2 -2
  81. package/dist/{hq-service-L5INQFM4.js → hq-service-BMMJAHRT.js} +11 -4
  82. package/dist/import-claude-code-32PCSIQI.js +236 -0
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.js +19 -10
  85. package/dist/kanban-supervisor-67ECABTD.js +7 -0
  86. package/dist/live-settings-input.d.ts +7 -0
  87. package/dist/{mailbox-serve-3GFOK2I7.js → mailbox-serve-NW5VZG7R.js} +3 -3
  88. package/dist/{mcp-DC5WSBOO.js → mcp-LBS45HWZ.js} +4 -4
  89. package/dist/modeldiag-36VODVIH.js +828 -0
  90. package/dist/{per-subcommand-help-DHTYU524.js → per-subcommand-help-QDAQASPZ.js} +3 -3
  91. package/dist/permission-prompt-mirror.d.ts +1 -1
  92. package/dist/permission-prompt.d.ts +16 -2
  93. package/dist/permission-rules-view.d.ts +18 -0
  94. package/dist/{permissions-CFDLXETM.js → permissions-PL27UHYD.js} +67 -45
  95. package/dist/plugin-config.d.ts +12 -0
  96. package/dist/plugin-management-types.d.ts +31 -0
  97. package/dist/plugin-management.d.ts +2 -30
  98. package/dist/plugin-package-install.d.ts +3 -0
  99. package/dist/{plugin-usage-M6KET4OZ.js → plugin-usage-CIGOOTX3.js} +6 -5
  100. package/dist/{plugins-WJLW6ULV.js → plugins-HQTXUD6A.js} +6 -3
  101. package/dist/preflight.d.ts +1 -1
  102. package/dist/{projects-LMNAGGEU.js → projects-T4CZCA25.js} +3 -6
  103. package/dist/provider-config-utils.d.ts +1 -6
  104. package/dist/provider-helpers.d.ts +7 -11
  105. package/dist/{providers-models-LFNZ5WI7.js → providers-models-5Z2PJTEW.js} +44 -34
  106. package/dist/release-asset-download.d.ts +13 -0
  107. package/dist/release-attestation.d.ts +28 -0
  108. package/dist/remote/remote-session.d.ts +64 -0
  109. package/dist/remote/remote-target.d.ts +69 -0
  110. package/dist/remote-O5WXHLWV.js +561 -0
  111. package/dist/{replay-Z3FTJEMM.js → replay-DEI566CW.js} +2 -2
  112. package/dist/services/commit-message.d.ts +2 -1
  113. package/dist/services/dispatch-classifier.d.ts +39 -5
  114. package/dist/session-move-P2EC2COA.js +44 -0
  115. package/dist/session-move.d.ts +20 -0
  116. package/dist/session-stats.d.ts +10 -0
  117. package/dist/{sessions-config-UL45XKX7.js → sessions-config-SXTTLNXA.js} +47 -9
  118. package/dist/settings-menu.d.ts +2 -0
  119. package/dist/short-circuit-flags-74Y5N6CF.js +10 -0
  120. package/dist/{simpleui-dist-CXSIDAXZ.js → simpleui-dist-7BQISSEP.js} +7 -3
  121. package/dist/skill-suggest-L2EVWB6R.js +290 -0
  122. package/dist/slash-commands/command-context.d.ts +15 -5
  123. package/dist/slash-commands/effort.d.ts +1 -1
  124. package/dist/slash-commands/fallback.d.ts +1 -1
  125. package/dist/slash-commands/gitid.d.ts +1 -1
  126. package/dist/slash-commands/goal-refiner.d.ts +4 -49
  127. package/dist/slash-commands/jev.d.ts +4 -0
  128. package/dist/slash-commands/mcp.d.ts +2 -1
  129. package/dist/slash-commands/openai-quota.d.ts +15 -0
  130. package/dist/slash-commands/permissions.d.ts +4 -0
  131. package/dist/slash-commands/sdd-task-mutations.d.ts +4 -0
  132. package/dist/slash-commands/settings-context-mutations.d.ts +5 -0
  133. package/dist/slash-commands/settings-keys.d.ts +2 -0
  134. package/dist/slash-commands/settings-limits-mutations.d.ts +12 -0
  135. package/dist/slash-commands/settings-reset.d.ts +6 -0
  136. package/dist/standalone-auto-update-TOTRGCSA.js +249 -0
  137. package/dist/standalone-auto-update.d.ts +65 -0
  138. package/dist/standalone-update-LZO3MNLH.js +24 -0
  139. package/dist/standalone-update.d.ts +55 -0
  140. package/dist/subcommands/handlers/hq-alerts.d.ts +3 -0
  141. package/dist/subcommands/handlers/hq-audit.d.ts +46 -0
  142. package/dist/subcommands/handlers/hq-data-dir.d.ts +13 -0
  143. package/dist/subcommands/handlers/import-claude-code.d.ts +42 -0
  144. package/dist/subcommands/handlers/permissions.d.ts +9 -3
  145. package/dist/subcommands/handlers/remote.d.ts +6 -0
  146. package/dist/subcommands/handlers/skill-suggest.d.ts +21 -0
  147. package/dist/subcommands/handlers/typesafe-brain-replay.d.ts +26 -0
  148. package/dist/subcommands/handlers/typesafe-judgment-check.d.ts +3 -0
  149. package/dist/subcommands/handlers/typesafe-topic-replay.d.ts +19 -0
  150. package/dist/subcommands/handlers/typesafe-triage-replay.d.ts +18 -0
  151. package/dist/subcommands/handlers/typesafe.d.ts +23 -0
  152. package/dist/subcommands/handlers/version-help.d.ts +5 -0
  153. package/dist/{subcommands-XSLXMIDP.js → subcommands-Q6ORSB2E.js} +2 -2
  154. package/dist/tui-resume-callback.d.ts +18 -0
  155. package/dist/typesafe-U7YB2RRV.js +316 -0
  156. package/dist/typesafe-brain-replay-C5276FVR.js +222 -0
  157. package/dist/typesafe-judgment-check-GGYYV5UF.js +29 -0
  158. package/dist/typesafe-topic-replay-ZILIU3WS.js +234 -0
  159. package/dist/typesafe-triage-replay-FGAW7QM7.js +215 -0
  160. package/dist/{update-5DPB4YD4.js → update-TDZX4IL2.js} +4 -3
  161. package/dist/{update-check-BS3DHTSI.js → update-check-J5ZVKS73.js} +3 -2
  162. package/dist/update-check.d.ts +1 -1
  163. package/dist/version-JB2UAV2A.js +11 -0
  164. package/dist/version-help-XJJQ7YSH.js +10 -0
  165. package/dist/version.d.ts +3 -2
  166. package/dist/webui-client-observability.d.ts +7 -0
  167. package/dist/webui-server/route-contexts.d.ts +1 -1
  168. package/dist/webui-server/session-start-payload.d.ts +5 -1
  169. package/dist/{webui-server-MRPGTTKL.js → webui-server-YTHLRFD2.js} +577 -370
  170. package/dist/webui-server-lifecycle.d.ts +57 -0
  171. package/dist/webui-server-options.d.ts +11 -0
  172. package/dist/webui-server.d.ts +1 -1
  173. package/dist/wiring/brain-and-orchestration.d.ts +3 -1
  174. package/dist/wiring/cli-prompt-and-tools-setup.d.ts +9 -0
  175. package/dist/wiring/cli-slash-commands-setup.d.ts +1 -0
  176. package/dist/wiring/domain-glossary.d.ts +5 -4
  177. package/dist/wiring/lifecycle-plugins.d.ts +4 -2
  178. package/dist/wiring/metrics.d.ts +9 -1
  179. package/dist/wiring/pipeline.d.ts +2 -7
  180. package/dist/wiring/plugins.d.ts +4 -1
  181. package/dist/wiring/provider-persisters.d.ts +24 -0
  182. package/dist/wiring/provider-runtime.d.ts +9 -1
  183. package/dist/wiring/provider-status.d.ts +1 -0
  184. package/dist/wiring/provider-utility-tools.d.ts +3 -1
  185. package/dist/wiring/runtime-dispatch-state.d.ts +3 -1
  186. package/package.json +28 -28
  187. package/dist/chunk-2CZEORLV.js +0 -54
  188. package/dist/chunk-672UXYL3.js +0 -65
  189. package/dist/chunk-6WRKAACA.js +0 -96
  190. package/dist/chunk-DR2OXU46.js +0 -174
  191. package/dist/chunk-JACOMTIH.js +0 -275
  192. package/dist/chunk-XJXDOF63.js +0 -28
  193. package/dist/modeldiag-CJSFHZ3J.js +0 -1356
  194. package/dist/short-circuit-flags-7GQIGMVD.js +0 -10
  195. package/dist/version-help-WXI42PZ3.js +0 -10
@@ -25,9 +25,9 @@ function bindReplayToContainer(opts) {
25
25
  warn: (m) => logger.warn?.(m)
26
26
  } : void 0
27
27
  });
28
- container.bind(TOKENS.ProviderRunner, () => wrapped);
28
+ container.override(TOKENS.ProviderRunner, () => wrapped);
29
29
  }
30
30
  export {
31
31
  bindReplayToContainer
32
32
  };
33
- //# sourceMappingURL=replay-Z3FTJEMM.js.map
33
+ //# sourceMappingURL=replay-DEI566CW.js.map
@@ -16,7 +16,8 @@ export interface CommitLLMProvider {
16
16
  text: string;
17
17
  }[];
18
18
  }[];
19
- maxTokens: number;
19
+ /** Unset = the model's own output ceiling. */
20
+ maxTokens?: number | undefined;
20
21
  temperature?: number | undefined;
21
22
  }, opts: {
22
23
  signal: AbortSignal;
@@ -1,12 +1,46 @@
1
1
  /**
2
- * LLM-backed classifier for the smart agent dispatcher.
2
+ * Classifier for the smart agent dispatcher.
3
3
  *
4
- * Wraps the session provider in the `complete(prompt) => text` shape that
5
- * `makeLLMClassifier` expects, so `/fleet dispatch` can fall back to the model
6
- * when the heuristic router is ambiguous. Mirrors the one-shot completion
7
- * pattern used by `generateCommitMessageWithLLM`.
4
+ * Two implementations behind one seam:
5
+ *
6
+ * - `makeTypeSafeDispatchClassifier` — one typed `Choice` over the candidate
7
+ * roles plus a `Noul` that can decline. Used when `fleet.dispatch
8
+ * .typesafeClassifier` is on and a `typesafe` account resolves.
9
+ * - `makeLLMClassifier` — the historical path: render a prompt, ask the
10
+ * session provider for prose, regex out the first `{...}`. Still the
11
+ * default, and still the fallback when TypeSafe is unconfigured.
12
+ *
13
+ * Either way the dispatcher only reaches a classifier when its keyword
14
+ * heuristic is ambiguous, so this runs on a minority of dispatches.
8
15
  */
9
16
  import type { DispatchClassifier } from '@wrongstack/core/coordination';
17
+ import type { Config } from '@wrongstack/core/types';
18
+ import { type WarnSink } from '@wrongstack/core/typesafe';
10
19
  import type { CommitLLMProvider } from './commit-message.js';
20
+ /**
21
+ * Wrap the session provider in the `complete(prompt) => text` shape
22
+ * `makeLLMClassifier` expects. Mirrors `generateCommitMessageWithLLM`.
23
+ */
11
24
  export declare function makeProviderClassifier(provider: CommitLLMProvider, model: string): DispatchClassifier;
25
+ /**
26
+ * Pick the classifier this config asks for.
27
+ *
28
+ * Falls back to the provider classifier — never to nothing — when TypeSafe is
29
+ * requested but unconfigured. A missing API key is a setup problem, not a
30
+ * reason to lose the routing the user already had.
31
+ */
32
+ export declare function makeDispatchClassifier(deps: {
33
+ config: Config;
34
+ provider: CommitLLMProvider;
35
+ model: string;
36
+ env?: NodeJS.ProcessEnv | undefined;
37
+ /**
38
+ * Where the one-time "you asked for this and it is not running" line goes.
39
+ * Only `warn` is required; `debug` carries per-request token accounting when
40
+ * the host has somewhere to put it.
41
+ */
42
+ logger?: (WarnSink & {
43
+ debug?(message: string): void;
44
+ }) | undefined;
45
+ }): DispatchClassifier;
12
46
  //# sourceMappingURL=dispatch-classifier.d.ts.map
@@ -0,0 +1,44 @@
1
+
2
+ // src/session-move.ts
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { DefaultSessionStore } from "@wrongstack/core/storage";
6
+ import { resolveWstackPaths } from "@wrongstack/core/utils";
7
+ async function moveSessionTo(opts) {
8
+ const { store } = opts;
9
+ if (!store.move || store.sessionsDir === void 0) {
10
+ throw new Error("This session store cannot move sessions.");
11
+ }
12
+ const checkout = path.resolve(opts.targetPath);
13
+ const stat2 = await fs.stat(checkout).catch(() => null);
14
+ if (!stat2?.isDirectory()) throw new Error(`Not a directory: ${checkout}`);
15
+ const targetDir = resolveWstackPaths({
16
+ projectRoot: checkout,
17
+ ...opts.globalRoot ? { globalRoot: opts.globalRoot } : {}
18
+ }).projectSessions;
19
+ const adopt = store.adoptMovedSession?.bind(store);
20
+ if (path.resolve(targetDir) === path.resolve(store.sessionsDir) && adopt) {
21
+ return store.move(opts.sessionId, {
22
+ store: { sessionsDir: store.sessionsDir, adoptMovedSession: adopt },
23
+ checkout
24
+ });
25
+ }
26
+ await fs.mkdir(targetDir, { recursive: true });
27
+ const targetStore = new DefaultSessionStore({ dir: targetDir, projectRoot: checkout });
28
+ try {
29
+ return await store.move(opts.sessionId, { store: targetStore, checkout });
30
+ } finally {
31
+ await targetStore.dispose().catch(() => void 0);
32
+ }
33
+ }
34
+ function describeSessionMove(result) {
35
+ if (result.kind === "worktree") {
36
+ return `Moved ${result.id} to the worktree at ${result.checkout}; /resume lists it there.`;
37
+ }
38
+ return `Moved ${result.id} to the project at ${result.checkout}${result.fromProject ? ` (from ${result.fromProject})` : ""}. Open it there with: cd "${result.checkout}" && wstack resume ${result.id}`;
39
+ }
40
+ export {
41
+ describeSessionMove,
42
+ moveSessionTo
43
+ };
44
+ //# sourceMappingURL=session-move-P2EC2COA.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `sessions move` for the CLI subcommand and the `/sessions move` slash
3
+ * command: resolve where a session goes and hand both stores to
4
+ * `SessionStore.move`.
5
+ *
6
+ * A path inside another git worktree of this repository resolves to this
7
+ * store (all worktrees share one), so the move only re-stamps the session's
8
+ * checkout. Any other path is a project of its own: its store is opened here,
9
+ * which connects to that project's session catalog.
10
+ */
11
+ import type { SessionMoveResult, SessionStore } from '@wrongstack/core/types';
12
+ export declare function moveSessionTo(opts: {
13
+ store: SessionStore;
14
+ sessionId: string;
15
+ targetPath: string;
16
+ globalRoot?: string | undefined;
17
+ }): Promise<SessionMoveResult>;
18
+ /** One line for the user: where the session went and how to open it there. */
19
+ export declare function describeSessionMove(result: SessionMoveResult): string;
20
+ //# sourceMappingURL=session-move.d.ts.map
@@ -21,6 +21,16 @@ export declare class SessionStats {
21
21
  private bytesWritten;
22
22
  private bashCommands;
23
23
  private fetches;
24
+ /**
25
+ * First token after submit: from a leader turn's start to its first
26
+ * streamed text, thinking or tool call — what the user actually waits for,
27
+ * the provider's latency plus everything the agent does before the request.
28
+ * The leader is the context of the first run; subagent runs are not turns
29
+ * anyone typed.
30
+ */
31
+ private leaderCtx;
32
+ private turnStartedAt;
33
+ private readonly firstTokenMs;
24
34
  private readonly _handlers;
25
35
  constructor(events: EventBus, tokenCounter: TokenCounter);
26
36
  /** Remove all event listeners. Call this when the session ends. */
@@ -1,17 +1,19 @@
1
1
  import {
2
- getHistoryEntry,
3
- listHistory,
4
- restoreFromHistory,
5
- restoreLast
6
- } from "./chunk-B4JLSXZB.js";
2
+ activeProfileConfigPath
3
+ } from "./chunk-YMXXOOFN.js";
7
4
  import {
8
5
  restoreFlags
9
6
  } from "./chunk-CSAPOCBP.js";
10
7
  import {
11
- activeProfileConfigPath
12
- } from "./chunk-YMXXOOFN.js";
8
+ backupCurrent,
9
+ getHistoryEntry,
10
+ listHistory,
11
+ restoreFromHistory,
12
+ restoreLast
13
+ } from "./chunk-WSTVGC2C.js";
13
14
 
14
15
  // src/subcommands/handlers/sessions-config.ts
16
+ import * as path2 from "node:path";
15
17
  import { color as color2, expectDefined } from "@wrongstack/core/utils";
16
18
 
17
19
  // src/subcommands/handlers/helpers.ts
@@ -295,6 +297,35 @@ var sessionsCmd = async (args, deps) => {
295
297
  } catch (err) {
296
298
  deps.renderer.writeError(
297
299
  `Fork failed: ${err instanceof Error ? err.message : String(err)}
300
+ `
301
+ );
302
+ return 1;
303
+ }
304
+ }
305
+ if (sub === "move") {
306
+ const moveArgs = args.slice(1);
307
+ const sessionId = moveArgs[0] && !moveArgs[0].startsWith("-") ? moveArgs[0] : void 0;
308
+ const targetPath = extractArg(moveArgs, "--to");
309
+ if (!sessionId || !targetPath) {
310
+ deps.renderer.writeError(
311
+ "Usage: wstack sessions move <id> --to <project or worktree path>\n"
312
+ );
313
+ return 1;
314
+ }
315
+ try {
316
+ const { moveSessionTo, describeSessionMove } = await import("./session-move-P2EC2COA.js");
317
+ const result = await moveSessionTo({
318
+ store: deps.sessionStore,
319
+ sessionId,
320
+ targetPath: path2.resolve(deps.cwd, targetPath),
321
+ globalRoot: deps.paths.globalRoot
322
+ });
323
+ deps.renderer.write(`${describeSessionMove(result)}
324
+ `);
325
+ return 0;
326
+ } catch (err) {
327
+ deps.renderer.writeError(
328
+ `Move failed: ${err instanceof Error ? err.message : String(err)}
298
329
  `
299
330
  );
300
331
  return 1;
@@ -307,7 +338,7 @@ var sessionsCmd = async (args, deps) => {
307
338
  }
308
339
  for (const s of list)
309
340
  deps.renderer.write(
310
- ` ${s.id} ${color2.dim(s.startedAt)} ${color2.dim(`${s.tokenTotal} tok`)} ${s.title}
341
+ ` ${s.id} ${color2.dim(s.startedAt)} ${color2.dim(`${s.tokenTotal} tok`)} ${s.name ? `${color2.cyan(s.name)} ${color2.dim(s.title)}` : s.title}
311
342
  `
312
343
  );
313
344
  return 0;
@@ -322,6 +353,13 @@ var configCmd = async (args, deps) => {
322
353
  if (sub === "edit") {
323
354
  const editor = process.env["EDITOR"] ?? "vi";
324
355
  deps.renderer.write(`Run: ${editor} ${activeProfileConfigPath(deps.paths, deps.config)}
356
+ `);
357
+ return 0;
358
+ }
359
+ if (sub === "backup") {
360
+ const profileConfigPath = activeProfileConfigPath(deps.paths, deps.config);
361
+ await backupCurrent(void 0, profileConfigPath);
362
+ deps.renderer.write(`Backed up active profile config: ${profileConfigPath}.last
325
363
  `);
326
364
  return 0;
327
365
  }
@@ -418,4 +456,4 @@ export {
418
456
  configCmd,
419
457
  sessionsCmd
420
458
  };
421
- //# sourceMappingURL=sessions-config-UL45XKX7.js.map
459
+ //# sourceMappingURL=sessions-config-SXTTLNXA.js.map
@@ -22,6 +22,8 @@ interface PersistSettingDeps {
22
22
  * from landing in the wrong profile when the mutator changes activeProfile.
23
23
  */
24
24
  resolveProfilePath?: ((profileName: string) => string) | undefined;
25
+ /** Skip the live ConfigStore mirror when a caller is persisting a secondary split target. */
26
+ updateStore?: boolean | undefined;
25
27
  }
26
28
  export declare function resolvePersistPath(deps: PersistSettingDeps): string;
27
29
  /**
@@ -0,0 +1,10 @@
1
+ import {
2
+ handleHelpVersionShortCircuit
3
+ } from "./chunk-WQV2NP57.js";
4
+ import "./chunk-5JYDKG5B.js";
5
+ import "./chunk-F5DCFAKI.js";
6
+ import "./chunk-Q4INH2DG.js";
7
+ export {
8
+ handleHelpVersionShortCircuit
9
+ };
10
+ //# sourceMappingURL=short-circuit-flags-74Y5N6CF.js.map
@@ -4,9 +4,13 @@ import { spawn } from "node:child_process";
4
4
  import { existsSync } from "node:fs";
5
5
  import { createRequire } from "node:module";
6
6
  import * as path from "node:path";
7
+ import { wrongstackPackageJsonPath } from "@wrongstack/core/utils";
8
+ function resolveSimpleUiPackageJson(id, req) {
9
+ return wrongstackPackageJsonPath(id.replace(/\/package\.json$/u, ""), (x) => req.resolve(x));
10
+ }
7
11
  function resolveSimpleUiDistDir(deps = {}) {
8
12
  const requireFromHere = createRequire(import.meta.url);
9
- const resolvePackageJson = deps.resolvePackageJson ?? ((id) => requireFromHere.resolve(id));
13
+ const resolvePackageJson = deps.resolvePackageJson ?? ((id) => resolveSimpleUiPackageJson(id, requireFromHere));
10
14
  const exists = deps.exists ?? existsSync;
11
15
  let packageJson;
12
16
  try {
@@ -30,7 +34,7 @@ async function ensureSimpleUiDistDir(deps = {}) {
30
34
  } catch {
31
35
  }
32
36
  const requireFromHere = createRequire(import.meta.url);
33
- const resolvePackageJson = deps.resolvePackageJson ?? ((id) => requireFromHere.resolve(id));
37
+ const resolvePackageJson = deps.resolvePackageJson ?? ((id) => resolveSimpleUiPackageJson(id, requireFromHere));
34
38
  let packageDir;
35
39
  try {
36
40
  packageDir = path.dirname(resolvePackageJson("@wrongstack/simpleui/package.json"));
@@ -96,4 +100,4 @@ export {
96
100
  ensureSimpleUiDistDir,
97
101
  resolveSimpleUiDistDir
98
102
  };
99
- //# sourceMappingURL=simpleui-dist-CXSIDAXZ.js.map
103
+ //# sourceMappingURL=simpleui-dist-7BQISSEP.js.map
@@ -0,0 +1,290 @@
1
+
2
+ // src/subcommands/handlers/skill-suggest.ts
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import {
6
+ buildSuggesterFromConfig,
7
+ parseEvalJsonl,
8
+ scoreSuggestions,
9
+ sweepThresholds,
10
+ unknownGoldLabels
11
+ } from "@wrongstack/core/skills";
12
+ import { estimateTypeSafeCostUsd } from "@wrongstack/core/typesafe";
13
+ import { color } from "@wrongstack/core/utils";
14
+ var SWEEP_STEPS = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6];
15
+ var EVAL_WORKERS = 4;
16
+ var USAGE = [
17
+ "Usage:",
18
+ ' wstack skill-suggest "<request>" preview one request',
19
+ " wstack skill-suggest --eval <file.jsonl> score a labeled set",
20
+ " wstack skill-suggest --eval <file.jsonl> --sweep \u2026and sweep thresholds",
21
+ "",
22
+ "Eval file: one JSON object per line.",
23
+ ' {"text": "cut a release branch for 1.2.0", "gold": "git-flow"}',
24
+ ' {"text": "explain what a monad is"} // nothing covers it',
25
+ "",
26
+ "Both modes send request text to the configured TypeSafe/OpenRouter route.",
27
+ "Configure its key with `wstack typesafe login` and verify with `wstack typesafe test`."
28
+ ].join("\n");
29
+ var skillSuggestCmd = async (args, deps) => {
30
+ const write = (line) => deps.renderer.write(`${line}
31
+ `);
32
+ const flags = deps.flags ?? {};
33
+ const evalFile = typeof flags["eval"] === "string" ? flags["eval"] : void 0;
34
+ const sweep = flags["sweep"] === true || flags["sweep"] === "true";
35
+ const positional = args.filter((a) => !a.startsWith("-"));
36
+ if (flags["help"] === true || flags["h"] === true) {
37
+ write(USAGE);
38
+ return 0;
39
+ }
40
+ if (!evalFile && positional.length === 0) {
41
+ write(USAGE);
42
+ return 1;
43
+ }
44
+ const built = buildSuggesterFromConfig({
45
+ config: deps.config,
46
+ skillLoader: deps.skillLoader
47
+ });
48
+ if ("error" in built) {
49
+ write(color.red(`skill-suggest: ${built.error}`));
50
+ return 1;
51
+ }
52
+ const { suggester } = built;
53
+ if (evalFile) {
54
+ return runEval({
55
+ file: path.resolve(deps.cwd, evalFile),
56
+ sweep,
57
+ suggester,
58
+ rosterNames: (await deps.skillLoader?.list())?.map((s) => s.name) ?? [],
59
+ write
60
+ });
61
+ }
62
+ const request = positional.join(" ").trim();
63
+ if (!request) {
64
+ write(color.red("skill-suggest: give a request to preview, or --eval <file>"));
65
+ return 1;
66
+ }
67
+ return runPreview({ request, suggester, write, config: deps.config });
68
+ };
69
+ async function runPreview(input) {
70
+ const { write } = input;
71
+ const gateThreshold = input.config.skills?.suggest?.gateThreshold ?? 0.3;
72
+ const fitsThreshold = input.config.skills?.suggest?.fitsThreshold ?? 0.3;
73
+ const started = Date.now();
74
+ const trace = await input.suggester.explain(input.request);
75
+ const elapsed = Date.now() - started;
76
+ write("");
77
+ write(color.dim(` "${truncate(input.request, 72)}"`));
78
+ write("");
79
+ if (trace.stop === "error") {
80
+ write(color.red(" the suggester failed \u2014 no answer to show"));
81
+ write(color.dim(" check the API key, the endpoint, and network reachability"));
82
+ return 1;
83
+ }
84
+ if (trace.stop === "roster-too-small") {
85
+ write(color.yellow(" roster has fewer than 2 visible skills \u2014 nothing to choose between"));
86
+ return 0;
87
+ }
88
+ write(
89
+ ` ${label("gate")} ${bar(trace.gate)} ${pct(trace.gate)} ${verdictWord(trace.gate >= gateThreshold, gateThreshold)}`
90
+ );
91
+ for (const [key, value] of Object.entries(trace.gateValues)) {
92
+ const inverted = key === "prose_suffices";
93
+ write(
94
+ color.dim(` ${key.padEnd(34)} ${pct(value)}${inverted ? " (counts inverted)" : ""}`)
95
+ );
96
+ }
97
+ write("");
98
+ if (trace.ranked.length > 0) {
99
+ write(` ${label("pass 1 \u2014 ranked")}`);
100
+ for (const entry of trace.ranked.slice(0, 5)) {
101
+ const shortlisted = trace.shortlist.includes(entry.name);
102
+ const line = ` ${pct(entry.probability).padStart(4)} ${entry.name}`;
103
+ write(shortlisted ? line : color.dim(line));
104
+ }
105
+ write("");
106
+ }
107
+ if (trace.shortlist.length > 0 && Object.keys(trace.fits).length > 0) {
108
+ write(` ${label("pass 2 \u2014 fits")}`);
109
+ for (const name of trace.shortlist) {
110
+ const value = trace.fits[name];
111
+ const marker = name === trace.winner ? color.cyan(" \u2190 choice") : "";
112
+ write(` ${(value === void 0 ? "\u2014" : pct(value)).padStart(4)} ${name}${marker}`);
113
+ }
114
+ write("");
115
+ }
116
+ const suggestion = trace.suggestion;
117
+ if (suggestion) {
118
+ write(` ${color.green("suggests")} ${suggestion.name}`);
119
+ } else {
120
+ write(
121
+ ` ${color.yellow("suggests nothing")} ${color.dim(`(${stopReason(trace, gateThreshold, fitsThreshold)})`)}`
122
+ );
123
+ }
124
+ write(
125
+ color.dim(
126
+ ` ${trace.requests} request(s), ${elapsed}ms, ${trace.inputTokens} input tokens (~$${estimateTypeSafeCostUsd(trace.inputTokens).toFixed(6)})` + (trace.models.length > 0 ? ` \xB7 answered by ${trace.models.join(", ")}` : "")
127
+ )
128
+ );
129
+ write("");
130
+ return 0;
131
+ }
132
+ function stopReason(trace, gateThreshold, fitsThreshold) {
133
+ switch (trace.stop) {
134
+ case "gate":
135
+ return `gate ${pct(trace.gate)} below ${pct(gateThreshold)}`;
136
+ case "fits": {
137
+ const best = Math.max(...Object.values(trace.fits), 0);
138
+ return `best fit ${pct(best)} below ${pct(fitsThreshold)}`;
139
+ }
140
+ case "wide-failed":
141
+ case "rerank-failed":
142
+ return "the model returned no usable answer for that pass";
143
+ default:
144
+ return trace.stop;
145
+ }
146
+ }
147
+ async function runEval(input) {
148
+ const { write } = input;
149
+ let source;
150
+ try {
151
+ source = await fs.readFile(input.file, "utf8");
152
+ } catch {
153
+ write(color.red(`skill-suggest: cannot read ${input.file}`));
154
+ return 1;
155
+ }
156
+ const { requests, errors } = parseEvalJsonl(source);
157
+ for (const error of errors) {
158
+ write(color.yellow(` line ${error.line}: ${error.reason}`));
159
+ }
160
+ if (requests.length === 0) {
161
+ write(color.red("skill-suggest: no usable cases in that file"));
162
+ return 1;
163
+ }
164
+ const unknown = unknownGoldLabels(requests, input.rosterNames);
165
+ if (unknown.length > 0) {
166
+ write(color.yellow(` gold labels not in this roster: ${unknown.join(", ")}`));
167
+ write(color.yellow(" those cases can never be scored correct \u2014 fix or remove them"));
168
+ write("");
169
+ }
170
+ const covered = requests.filter((r) => r.gold).length;
171
+ write(
172
+ color.dim(
173
+ ` ${requests.length} cases (${covered} covered, ${requests.length - covered} uncovered) \u2192 up to ${requests.length * 2} TypeSafe requests`
174
+ )
175
+ );
176
+ write("");
177
+ const traces = await mapWithConcurrency(requests, EVAL_WORKERS, async (request) => ({
178
+ request,
179
+ // A sweep has to know what pass 2 WOULD have said below the configured
180
+ // gate, and a trace that stopped at the gate cannot answer that.
181
+ trace: await input.suggester.explain(request.text, void 0, { alwaysRerank: input.sweep })
182
+ }));
183
+ const inputTokens = traces.reduce((sum, row) => sum + row.trace.inputTokens, 0);
184
+ const models = [...new Set(traces.flatMap((row) => row.trace.models))];
185
+ write(
186
+ color.dim(
187
+ ` spent ${inputTokens} input tokens (~$${estimateTypeSafeCostUsd(inputTokens).toFixed(4)})` + (models.length > 0 ? ` \xB7 answered by ${models.join(", ")}` : "")
188
+ )
189
+ );
190
+ if (models.length > 1) {
191
+ write(
192
+ color.yellow(
193
+ " Two model versions answered this run \u2014 the alias moved mid-run; re-run before trusting the sweep."
194
+ )
195
+ );
196
+ }
197
+ write("");
198
+ const failed = traces.filter((row) => row.trace.stop === "error").length;
199
+ if (failed > 0) {
200
+ write(color.yellow(` ${failed} case(s) failed outright and count as "suggested nothing"`));
201
+ write("");
202
+ }
203
+ const byText = new Map(traces.map((row) => [row.request.text, row.trace]));
204
+ const { score, cases } = scoreSuggestions(
205
+ requests,
206
+ (request) => byText.get(request.text)?.suggestion?.name
207
+ );
208
+ writeScore(write, score);
209
+ const misses = cases.filter((c) => c.outcome === "wrong" || c.outcome === "needless");
210
+ if (misses.length > 0) {
211
+ write("");
212
+ write(` ${label("worst cases")}`);
213
+ for (const miss of misses.slice(0, 10)) {
214
+ const wanted = miss.request.gold ?? "(nothing)";
215
+ write(color.dim(` "${truncate(miss.request.text, 52)}"`));
216
+ write(` wanted ${wanted}, got ${color.red(miss.suggested ?? "(nothing)")}`);
217
+ }
218
+ if (misses.length > 10) write(color.dim(` \u2026and ${misses.length - 10} more`));
219
+ }
220
+ if (input.sweep) {
221
+ write("");
222
+ write(` ${label("threshold sweep")}`);
223
+ write(
224
+ color.dim(" gate fits correct wrong missed needless (of covered / uncovered)")
225
+ );
226
+ const rows = sweepThresholds(traces, SWEEP_STEPS, SWEEP_STEPS);
227
+ for (const row of rows) {
228
+ const s = row.score;
229
+ write(
230
+ ` ${row.gateThreshold.toFixed(1)} ${row.fitsThreshold.toFixed(1)} ${pct(s.correct).padStart(6)} ${pct(s.wrongSuggestion).padStart(6)} ${pct(s.missed).padStart(6)} ${pct(s.needless).padStart(8)}`
231
+ );
232
+ }
233
+ write("");
234
+ write(
235
+ color.dim(
236
+ " These score the SUGGESTER against your labels, not what the agent then loads."
237
+ )
238
+ );
239
+ write(
240
+ color.dim(
241
+ " Raising gate cuts needless suggestions and adds misses. Pick the one that costs you more."
242
+ )
243
+ );
244
+ }
245
+ write("");
246
+ return 0;
247
+ }
248
+ function writeScore(write, score) {
249
+ write(` ${label("covered")} ${color.dim(`(${score.covered} cases)`)}`);
250
+ write(` correct ${pct(score.correct)}`);
251
+ write(` wrong suggestion ${pct(score.wrongSuggestion)}`);
252
+ write(` suggested nothing ${pct(score.missed)}`);
253
+ write(` ${label("uncovered")} ${color.dim(`(${score.uncovered} cases)`)}`);
254
+ write(` needless ${pct(score.needless)}`);
255
+ }
256
+ async function mapWithConcurrency(items, limit, fn) {
257
+ const results = new Array(items.length);
258
+ let cursor = 0;
259
+ const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
260
+ for (; ; ) {
261
+ const index = cursor++;
262
+ const item = items[index];
263
+ if (item === void 0) return;
264
+ results[index] = await fn(item);
265
+ }
266
+ });
267
+ await Promise.all(workers);
268
+ return results;
269
+ }
270
+ function pct(value) {
271
+ return `${(value * 100).toFixed(0)}%`;
272
+ }
273
+ function bar(value) {
274
+ const filled = Math.round(value * 10);
275
+ return color.dim(`[${"#".repeat(filled)}${".".repeat(10 - filled)}]`);
276
+ }
277
+ function label(text) {
278
+ return color.bold(text);
279
+ }
280
+ function verdictWord(passed, threshold) {
281
+ return passed ? color.green(`\u2265 ${pct(threshold)} \u2014 continue`) : color.yellow(`< ${pct(threshold)} \u2014 stop here`);
282
+ }
283
+ function truncate(text, max) {
284
+ const flat = text.replace(/\s+/g, " ").trim();
285
+ return flat.length <= max ? flat : `${flat.slice(0, max - 1)}\u2026`;
286
+ }
287
+ export {
288
+ skillSuggestCmd
289
+ };
290
+ //# sourceMappingURL=skill-suggest-L2EVWB6R.js.map
@@ -1,7 +1,7 @@
1
1
  import type { Context } from '@wrongstack/core/agent';
2
2
  import type { EventBus } from '@wrongstack/core/kernel';
3
3
  import type { SlashCommandRegistry, ToolRegistry } from '@wrongstack/core/registry';
4
- import type { CompactReport, HealthRegistry, MemoryPort, MetricsRuntimeStatus, MetricsSink, ModeStore, Renderer, SessionStore, SkillLoader, TokenCounter } from '@wrongstack/core/types';
4
+ import type { CompactOptions, CompactReport, HealthRegistry, MemoryPort, MetricsRuntimeStatus, MetricsSink, ModeStore, PermissionPolicy, Renderer, SessionStore, SkillLoader, TokenCounter } from '@wrongstack/core/types';
5
5
  import type { WstackPaths } from '@wrongstack/core/utils';
6
6
  import type { SummarizerPort } from '@wrongstack/tools';
7
7
  import type { VectorMemoryStore } from '@wrongstack/vector-memory';
@@ -9,6 +9,12 @@ import type { VectorMemoryStore } from '@wrongstack/vector-memory';
9
9
  export interface SlashCommandContext {
10
10
  registry: SlashCommandRegistry;
11
11
  toolRegistry: ToolRegistry;
12
+ /**
13
+ * The agent's permission policy: `/permissions rules|explain` read it, and
14
+ * it reads each session's `/permissions allow|deny` rules from that
15
+ * session's context.
16
+ */
17
+ permissionPolicy?: PermissionPolicy | undefined;
12
18
  /** Run one tool through the active ToolExecutor and its permission policy. */
13
19
  executeTool?: ((name: string, input: Record<string, unknown>, ctx: Context) => Promise<{
14
20
  detail: string;
@@ -19,9 +25,7 @@ export interface SlashCommandContext {
19
25
  /** Explicit legacy SDD session codec for compatibility tests/old hosts. */
20
26
  sddSessionTransport?: 'kanban' | 'legacy-file' | undefined;
21
27
  compactor?: {
22
- compact(ctx: Context, opts?: {
23
- aggressive?: boolean | undefined;
24
- }): Promise<CompactReport>;
28
+ compact(ctx: Context, opts?: CompactOptions): Promise<CompactReport>;
25
29
  };
26
30
  sessionStore?: SessionStore | undefined;
27
31
  skillLoader?: SkillLoader | undefined;
@@ -536,7 +540,13 @@ export interface SlashCommandContext {
536
540
  * Resume a persisted PhaseGraph. The host creates a new orchestrator for
537
541
  * the loaded graph and starts executing pending tasks.
538
542
  */
539
- onGoalResumeFromGraph?: ((graph: import('@wrongstack/core/goal').PhaseGraph) => Promise<void>) | undefined;
543
+ onGoalResumeFromGraph?: ((graph: import('@wrongstack/core/goal').PhaseGraph) => Promise<{
544
+ ok: true;
545
+ graph: import('@wrongstack/core/goal').PhaseGraph;
546
+ } | {
547
+ ok: false;
548
+ error: string;
549
+ }>) | undefined;
540
550
  /** Live, read-only view of the running Goal (null when idle). */
541
551
  getGoalRunner?: () => {
542
552
  graph: import('@wrongstack/core/goal').PhaseGraph;
@@ -1,6 +1,6 @@
1
1
  import { type ReasoningEffort, type SlashCommand } from '@wrongstack/core/types';
2
- import type { SlashCommandContext } from './command-context.js';
3
2
  import type { WstackPaths } from '@wrongstack/core/utils';
3
+ import type { SlashCommandContext } from './command-context.js';
4
4
  /**
5
5
  * `/effort` — view or set the SESSION-WIDE reasoning effort applied to the
6
6
  * active leader model. This is the quick, discoverable front-end for
@@ -1,4 +1,4 @@
1
- import { type SlashCommand } from '@wrongstack/core/types';
1
+ import type { SlashCommand } from '@wrongstack/core/types';
2
2
  import type { SlashCommandContext } from './command-context.js';
3
3
  /**
4
4
  * `/fallback` — view or change the cross-provider fallback chain that the
@@ -1,4 +1,4 @@
1
- import { type SlashCommand } from '@wrongstack/core/types';
1
+ import type { SlashCommand } from '@wrongstack/core/types';
2
2
  import type { SlashCommandContext } from './command-context.js';
3
3
  /**
4
4
  * `/gitid` — view or change the commit identity (author/committer name +