@wrongstack/cli 1.0.26 → 1.0.27

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 (44) hide show
  1. package/dist/{acp-LI665LO2.js → acp-M4565YUW.js} +30 -17
  2. package/dist/boot/dispatch-singleshot.d.ts +8 -0
  3. package/dist/boot/dispatch-webui.d.ts +2 -0
  4. package/dist/boot/goal-tui-default.d.ts +10 -0
  5. package/dist/{chunk-OAVBM55Q.js → chunk-ENRYW73H.js} +525 -379
  6. package/dist/chunk-HDMFKTT3.js +157 -0
  7. package/dist/{chunk-WQV2NP57.js → chunk-HFZH2XJN.js} +2 -2
  8. package/dist/{chunk-BEHGRNOQ.js → chunk-N57IU5FG.js} +9 -9
  9. package/dist/{chunk-2EBVTYJR.js → chunk-NRXWOMK7.js} +17 -3
  10. package/dist/{chunk-5SEYGOCH.js → chunk-RDGGWMTI.js} +2 -2
  11. package/dist/{chunk-KJS5543T.js → chunk-RGFWGUAB.js} +26 -14
  12. package/dist/{chunk-S4FFHDJG.js → chunk-SDJCLEK6.js} +6 -2
  13. package/dist/{cli-context-UVGAN3NO.js → cli-context-C7RBSWHF.js} +33 -6
  14. package/dist/{cli-main-TN3KZ2P6.js → cli-main-TQTH73ZK.js} +304 -345
  15. package/dist/{execution-7QIP6GRY.js → execution-3STBD2U7.js} +87 -33
  16. package/dist/execution-chimera-review.d.ts +18 -1
  17. package/dist/{hq-GLZ7QESM.js → hq-44F4OQH2.js} +5 -4
  18. package/dist/hq-fleet-control.d.ts +36 -0
  19. package/dist/hq-live-status.d.ts +22 -0
  20. package/dist/hq-publisher.d.ts +18 -0
  21. package/dist/hq-server/routes/command-handlers.d.ts +12 -1
  22. package/dist/hq-server/routes/data-handlers.d.ts +1 -1
  23. package/dist/hq-server/socket-credentials.d.ts +63 -0
  24. package/dist/hq-server/upgrade-handler.d.ts +2 -0
  25. package/dist/hq-server/ws.d.ts +24 -0
  26. package/dist/{hq-server-YTKDVQPY.js → hq-server-UIB24LU6.js} +2 -2
  27. package/dist/{import-claude-code-32PCSIQI.js → import-claude-code-AYG24RG2.js} +36 -4
  28. package/dist/index.js +3 -3
  29. package/dist/live-settings-input.d.ts +1 -0
  30. package/dist/{mailbox-serve-NW5VZG7R.js → mailbox-serve-GNGXEQ2R.js} +2 -2
  31. package/dist/{modeldiag-36VODVIH.js → modeldiag-W7XAE625.js} +2 -2
  32. package/dist/{remote-O5WXHLWV.js → remote-GB5VXCCT.js} +38 -23
  33. package/dist/{sessions-config-SXTTLNXA.js → sessions-config-XHLXJ5C3.js} +75 -6
  34. package/dist/{short-circuit-flags-74Y5N6CF.js → short-circuit-flags-5TNTJPQR.js} +2 -2
  35. package/dist/slash-commands/theme.d.ts +15 -1
  36. package/dist/subcommands/handlers/import-claude-code.d.ts +10 -0
  37. package/dist/subcommands/handlers/sessions-fleet.d.ts +0 -12
  38. package/dist/{subcommands-Q6ORSB2E.js → subcommands-BHQYLDSD.js} +2 -2
  39. package/dist/{webui-server-YTHLRFD2.js → webui-server-GCXIO3JY.js} +37 -30
  40. package/dist/webui-server-options.d.ts +10 -0
  41. package/dist/wiring/command-host-state.d.ts +2 -0
  42. package/dist/wiring/hq-telemetry.d.ts +12 -0
  43. package/package.json +29 -28
  44. package/dist/chunk-OWNC7LMD.js +0 -78
@@ -15,12 +15,16 @@ import {
15
15
  MAX_TUI_THINKING_WORD_LENGTH,
16
16
  clearSuggestions,
17
17
  getSuggestions,
18
+ killHqSessionFleet,
18
19
  normalizeTuiThinkingWord,
19
20
  removeSuggestions,
21
+ resolveExecutionMode,
20
22
  runGit,
21
23
  setAutoSuggestions,
22
- setSuggestions
23
- } from "./chunk-OWNC7LMD.js";
24
+ setSuggestions,
25
+ spawnHqAgent,
26
+ terminateHqAgent
27
+ } from "./chunk-HDMFKTT3.js";
24
28
  import {
25
29
  deriveFsAccessPair,
26
30
  filterSafeForProject,
@@ -95,20 +99,20 @@ import {
95
99
  loadCachedAcpRegistry,
96
100
  refreshAcpRegistry,
97
101
  setupProvider
98
- } from "./chunk-5SEYGOCH.js";
102
+ } from "./chunk-RDGGWMTI.js";
99
103
  import {
100
104
  createHqCommandDispatcher,
101
105
  createProjectKanbanAssignHandler,
102
106
  createProjectKanbanTransitionHandler
103
- } from "./chunk-2EBVTYJR.js";
107
+ } from "./chunk-NRXWOMK7.js";
104
108
  import {
105
109
  startCliHqConnection
106
- } from "./chunk-KJS5543T.js";
110
+ } from "./chunk-RGFWGUAB.js";
107
111
  import {
108
112
  buildProviderForId,
109
113
  resolveProviderCfg,
110
114
  resolveRawProviderConnection
111
- } from "./chunk-S4FFHDJG.js";
115
+ } from "./chunk-SDJCLEK6.js";
112
116
  import {
113
117
  buildWin32CmdShimInvocation
114
118
  } from "./chunk-U3SS4NRH.js";
@@ -2214,12 +2218,12 @@ function createHostExploreCompanion(input) {
2214
2218
  mailbox: mailbox(),
2215
2219
  leaderSessionId: sessionId,
2216
2220
  leaderAgentId: "leader",
2217
- onProbe: async (probe) => {
2221
+ onProbe: async (probe2) => {
2218
2222
  const subagentId = await ensureResident();
2219
2223
  const taskId = randomUUID2();
2220
2224
  await director.assignInternal({
2221
2225
  id: taskId,
2222
- description: buildProbeTaskText(probe),
2226
+ description: buildProbeTaskText(probe2),
2223
2227
  subagentId
2224
2228
  });
2225
2229
  return { subagentId, taskId };
@@ -3165,6 +3169,7 @@ import { AutoApprovePermissionPolicy } from "@wrongstack/core/security";
3165
3169
  import { createSessionEventBridge, resolveSessionLoggingConfig } from "@wrongstack/core/storage";
3166
3170
 
3167
3171
  // src/fleet/host-context.ts
3172
+ import { fenceIfUntrusted } from "@wrongstack/core/agent";
3168
3173
  import {
3169
3174
  DEFAULT_EAGER_SKILL_LIMIT,
3170
3175
  loadProjectSkillAugmentation,
@@ -3233,9 +3238,14 @@ async function resolveHostSubagentSkillResolution(deps, roster, subCfg, availabl
3233
3238
  const compose = (bodyChars) => [
3234
3239
  `## Skill: ${skillName}`,
3235
3240
  "",
3236
- body.length > bodyChars ? `${body.slice(0, bodyChars).trimEnd()}
3241
+ fenceIfUntrusted(
3242
+ manifest.source,
3243
+ skillName,
3244
+ body.length > bodyChars ? `${body.slice(0, bodyChars).trimEnd()}
3237
3245
 
3238
3246
  _(body trimmed)_` : body,
3247
+ manifest.originTool
3248
+ ),
3239
3249
  ...augmentation ? [
3240
3250
  "",
3241
3251
  `### Project practice for \`${skillName}\``,
@@ -5040,6 +5050,9 @@ function plainMaskedKey(key) {
5040
5050
  if (key.length <= 8) return "\u2022".repeat(key.length);
5041
5051
  return `${key.slice(0, 4)}\u2026${key.slice(-4)}`;
5042
5052
  }
5053
+ function hasEditableModel(provider, modelId) {
5054
+ return provider.models?.includes(modelId) === true || Object.hasOwn(provider.customModels ?? {}, modelId);
5055
+ }
5043
5056
  function createAuthPanelHost(deps) {
5044
5057
  const loadProviders = () => loadConfigProviders(deps.profileConfigPath, deps.vault, {
5045
5058
  warn: (message) => {
@@ -5241,7 +5254,7 @@ function createAuthPanelHost(deps) {
5241
5254
  },
5242
5255
  async getModelEdit(providerId, modelId) {
5243
5256
  const provider = (await loadProviders())[providerId];
5244
- if (!provider?.models?.includes(modelId)) return null;
5257
+ if (!provider || !hasEditableModel(provider, modelId)) return null;
5245
5258
  const details = provider.customModels?.[modelId];
5246
5259
  const modelsDev = details?.modelsDev ?? {};
5247
5260
  const limit = modelsDev["limit"];
@@ -5270,7 +5283,7 @@ function createAuthPanelHost(deps) {
5270
5283
  if (typeof value === "string") return value;
5271
5284
  return mutate((all) => {
5272
5285
  const provider = all[edit.providerId];
5273
- if (!provider?.models?.includes(edit.modelId))
5286
+ if (!provider || !hasEditableModel(provider, edit.modelId))
5274
5287
  return `Model "${edit.modelId}" no longer exists.`;
5275
5288
  const existing = provider.customModels?.[edit.modelId] ?? {};
5276
5289
  const modelsDev = { ...existing.modelsDev ?? {} };
@@ -5279,8 +5292,7 @@ function createAuthPanelHost(deps) {
5279
5292
  const limit = { ...modelsDev["limit"] ?? {} };
5280
5293
  if (context === void 0) delete limit["context"];
5281
5294
  else limit["context"] = context;
5282
- if (output === void 0) delete limit["output"];
5283
- else limit["output"] = output;
5295
+ delete limit["output"];
5284
5296
  if (Object.keys(limit).length) modelsDev["limit"] = limit;
5285
5297
  else delete modelsDev["limit"];
5286
5298
  const cost = { ...modelsDev["cost"] ?? {} };
@@ -5291,8 +5303,10 @@ function createAuthPanelHost(deps) {
5291
5303
  if (Object.keys(cost).length) modelsDev["cost"] = cost;
5292
5304
  else delete modelsDev["cost"];
5293
5305
  if (!provider.customModels) provider.customModels = {};
5306
+ const { modelsDev: _previousModelsDev, maxOutput: _previousMaxOutput, ...kept } = existing;
5294
5307
  provider.customModels[edit.modelId] = {
5295
- ...existing,
5308
+ ...kept,
5309
+ ...typeof output === "number" ? { maxOutput: output } : {},
5296
5310
  ...Object.keys(modelsDev).length ? { modelsDev } : {}
5297
5311
  };
5298
5312
  return null;
@@ -6104,7 +6118,7 @@ async function runCliExecution(params) {
6104
6118
  governanceHandle,
6105
6119
  setConfig
6106
6120
  } = params;
6107
- const { execute } = await import("./execution-7QIP6GRY.js");
6121
+ const { execute } = await import("./execution-3STBD2U7.js");
6108
6122
  return execute(
6109
6123
  toExecuteDeps({
6110
6124
  core: {
@@ -6850,6 +6864,7 @@ ${res.out}` };
6850
6864
  };
6851
6865
  }
6852
6866
  starting = true;
6867
+ const ownerSessionId = deps.getSessionId?.();
6853
6868
  let releaseRunLease;
6854
6869
  try {
6855
6870
  releaseRunLease = await store.acquireRunLease(`cli:${process.pid}:${crypto.randomUUID()}`);
@@ -6890,6 +6905,7 @@ ${res.out}` };
6890
6905
  phases,
6891
6906
  autonomous: true
6892
6907
  }).build();
6908
+ graph.sessionId = ownerSessionId;
6893
6909
  await persist(graph);
6894
6910
  const worktreesEnabled = deps.worktrees !== false && process.env["WRONGSTACK_GOAL_WORKTREES"] !== "0";
6895
6911
  let worktrees;
@@ -6957,6 +6973,7 @@ ${res.out}` };
6957
6973
  return false;
6958
6974
  }
6959
6975
  } : void 0,
6976
+ sessionId: graph.sessionId,
6960
6977
  brain: deps.brain,
6961
6978
  onTaskUpdate: () => {
6962
6979
  void persist(graph);
@@ -7011,6 +7028,7 @@ ${res.out}` };
7011
7028
  };
7012
7029
  }
7013
7030
  starting = true;
7031
+ if (!graph.sessionId) graph.sessionId = deps.getSessionId?.();
7014
7032
  let releaseRunLease;
7015
7033
  try {
7016
7034
  releaseRunLease = await store.acquireRunLease(
@@ -7084,6 +7102,7 @@ ${res.out}` };
7084
7102
  return false;
7085
7103
  }
7086
7104
  } : void 0,
7105
+ sessionId: graph.sessionId,
7087
7106
  brain: deps.brain,
7088
7107
  onTaskUpdate: () => {
7089
7108
  void persist(graph);
@@ -7624,7 +7643,7 @@ import {
7624
7643
  } from "@wrongstack/core/coordination";
7625
7644
  import { loadDirectorState } from "@wrongstack/core/storage";
7626
7645
  import { AgentError as AgentError2 } from "@wrongstack/core/types";
7627
- import { color as color5, expectDefined as expectDefined2 } from "@wrongstack/core/utils";
7646
+ import { color as color5, expectDefined as expectDefined2, isSessionTranscriptFileName } from "@wrongstack/core/utils";
7628
7647
  function createFleetCommandHandlers(input) {
7629
7648
  return {
7630
7649
  onSpawn: async (description, options) => {
@@ -7896,6 +7915,9 @@ async function readFleetLog(fleetRoot, subagentId, mode) {
7896
7915
  }
7897
7916
  return summarizeTranscript(transcript);
7898
7917
  }
7918
+ function isSubagentTranscriptFile(name) {
7919
+ return name.toLowerCase().endsWith(".jsonl") && isSessionTranscriptFileName(name);
7920
+ }
7899
7921
  async function findTranscripts(root) {
7900
7922
  let runIds;
7901
7923
  try {
@@ -7913,7 +7935,7 @@ async function findTranscripts(root) {
7913
7935
  return [];
7914
7936
  }
7915
7937
  const found = await Promise.all(
7916
- files.filter((file) => file.endsWith(".jsonl")).map(async (file) => {
7938
+ files.filter((file) => isSubagentTranscriptFile(file)).map(async (file) => {
7917
7939
  const fullPath = path8.join(directory, file);
7918
7940
  try {
7919
7941
  const stat6 = await fs2.stat(fullPath);
@@ -8077,6 +8099,7 @@ function createSddHandlers(deps) {
8077
8099
  getSddRuntimeState
8078
8100
  } = deps;
8079
8101
  const onSddParallelRun = async (opts) => {
8102
+ const ownerSessionId = sessionRef.current?.id ?? session.id;
8080
8103
  const { tracker, builder, graphId } = await getSddRuntimeState();
8081
8104
  if (!tracker || !builder) {
8082
8105
  return "No active SDD session with tasks. Use /sdd new to start one.";
@@ -8145,6 +8168,7 @@ function createSddHandlers(deps) {
8145
8168
  const boardStore = new sddApi.SddBoardStore({ baseDir: wpaths.projectSddBoards });
8146
8169
  const sddSupervisor = new sddApi.SddSupervisor({
8147
8170
  brain,
8171
+ sessionId: ownerSessionId,
8148
8172
  reassignModels: agentCore.effectiveFallbackChain(config)
8149
8173
  });
8150
8174
  const sddSubagentFactory = multiAgentHost.makeSubagentFactory(config);
@@ -17282,6 +17306,7 @@ var HELP = [
17282
17306
  `/jev features: ${JEV_FEATURES.join(", ")}`,
17283
17307
  "/jev test \u2014 one billed connection probe using saved settings",
17284
17308
  "/jev logs [feature] \u2014 recent process activity and persistent log path",
17309
+ "/jev logcontent on|off \u2014 record full request/response content in the log file",
17285
17310
  "/jev remove-key \u2014 delete the profile key (environment key may still apply)",
17286
17311
  "Changes are saved in the active profile. Restart existing sessions to apply all consumers."
17287
17312
  ].join("\n");
@@ -17306,6 +17331,7 @@ function buildJevCommand(opts) {
17306
17331
  ([key, on]) => `${on ? "on " : "off"} ${key} \xB7 ${s.readiness[key]?.state}: ${s.readiness[key]?.reason}`
17307
17332
  ),
17308
17333
  `Profile compaction: ${s.contextStrategy}. Model tiers: /tier. Conditions do not prove runtime use.`,
17334
+ s.logContent ? "Activity log: FULL content (request/response/error) \u2192 /jev logcontent off to stop" : "Activity log: metadata only \u2192 /jev logcontent on for full content",
17309
17335
  "",
17310
17336
  HELP
17311
17337
  ].join("\n")
@@ -17315,10 +17341,12 @@ function buildJevCommand(opts) {
17315
17341
  if (sub === "logs") {
17316
17342
  const log = jevActivitySnapshot();
17317
17343
  const rows = log.entries.filter((entry) => !arg || entry.feature === arg).slice(0, 30);
17344
+ const content = jevSettingsSnapshot(opts.configStore.get()).logContent;
17318
17345
  return {
17319
17346
  message: [
17320
17347
  `Jev activity \xB7 this process \xB7 ${log.path ?? "no disk entries yet"}`,
17321
17348
  log.writeError ?? "",
17349
+ `Content: ${content ? "request/response recorded in the log file only \u2014 never in this view" : "not recorded \xB7 /jev logcontent on"}`,
17322
17350
  ...rows.map(
17323
17351
  (e) => `${new Date(e.at).toISOString()} ${e.feature} ${e.outcome} ${e.durationMs}ms ${e.route}/${e.model} ${e.inputTokens ?? 0}in ${e.reason ?? ""}
17324
17352
  ${e.project} ${JSON.stringify(e.answers ?? {})}`
@@ -17366,6 +17394,8 @@ function buildJevCommand(opts) {
17366
17394
  patch = { recallTurnContext: arg === "on" };
17367
17395
  else if (sub === "compaction") patch = { contextStrategy: arg };
17368
17396
  else if (sub === "timeout") patch = { requestTimeoutMs: Number(arg) };
17397
+ else if (sub === "logcontent" && ["on", "off"].includes(arg))
17398
+ patch = { logContent: arg === "on" };
17369
17399
  else if (sub === "remove-key") patch = { apiKey: null };
17370
17400
  else if (sub === "feature" && ["on", "off"].includes(value))
17371
17401
  patch = { features: { [arg]: value === "on" } };
@@ -23028,6 +23058,13 @@ ${formatExplainedCall(explained)}` };
23028
23058
  let next;
23029
23059
  let done;
23030
23060
  if (sub === "allow" || sub === "deny") {
23061
+ if (sub === "allow" && isYoloLockedOff()) {
23062
+ return {
23063
+ message: color45.yellow(
23064
+ "Session allow rules are not honoured under --restricted (every write asks). Deny rules still apply."
23065
+ )
23066
+ };
23067
+ }
23031
23068
  const tool = rest.split(/\s+/)[0] ?? "";
23032
23069
  const pattern = rest.slice(tool.length).trim();
23033
23070
  if (!tool) return { message: color45.yellow(`Usage: /permissions ${sub} <tool> [pattern]`) };
@@ -24608,6 +24645,14 @@ function executeSddTaskMutation(cmd, restJoined) {
24608
24645
  }
24609
24646
 
24610
24647
  // src/slash-commands/sdd.ts
24648
+ function dependentFirstView(graph) {
24649
+ return {
24650
+ ...graph,
24651
+ edges: graph.edges.map(
24652
+ (edge) => edge.type === "depends_on" ? { ...edge, from: edge.to, to: edge.from } : edge
24653
+ )
24654
+ };
24655
+ }
24611
24656
  function buildSddCommand(opts) {
24612
24657
  const sessionState = getSessionState(opts.context);
24613
24658
  return {
@@ -25257,7 +25302,7 @@ ${lines.join("\n")}`
25257
25302
  if (!graph) {
25258
25303
  return { message: "Could not load task graph." };
25259
25304
  }
25260
- const analysis = analyzeCriticalPath(graph);
25305
+ const analysis = analyzeCriticalPath(dependentFirstView(graph));
25261
25306
  return { message: formatCriticalPathAnalysis(graph, analysis) };
25262
25307
  } catch {
25263
25308
  return { message: "Could not analyze critical path." };
@@ -27089,153 +27134,13 @@ function buildWebuiCommand() {
27089
27134
  }
27090
27135
 
27091
27136
  // src/slash-commands/theme.ts
27092
- import { THEME_PRESET_IDS } from "@wrongstack/core/types";
27137
+ import { THEME_PRESET_IDS, THEME_PRESET_META } from "@wrongstack/core/types";
27093
27138
  import { color as color54, writeOut as writeOut3 } from "@wrongstack/core/utils";
27094
- var THEME_META = {
27095
- catppuccin: { name: "Catppuccin Mocha", desc: "Soft pastel dark theme (Default)" },
27096
- "tokyo-night": { name: "Tokyo Night", desc: "Deep violet, neon orange & cyan" },
27097
- nord: { name: "Nord", desc: "Cool arctic blue & slate pastels" },
27098
- cyberpunk: { name: "Cyberpunk Neon", desc: "High-contrast magenta, cyan & yellow" },
27099
- dracula: { name: "Dracula", desc: "Vibrant purple, pink & green" },
27100
- "gruvbox-dark": { name: "Gruvbox Dark", desc: "Warm earthy retro \u2014 orange, olive & aqua" },
27101
- "solarized-dark": { name: "Solarized Dark", desc: "Base16 classic \u2014 teal & ochre precision" },
27102
- "one-dark": { name: "One Dark", desc: "Atom's iconic palette \u2014 blue-led, warm accents" },
27103
- monokai: { name: "Monokai", desc: "Sublime classic \u2014 vivid magenta, cyan & lime" },
27104
- "rose-pine": { name: "Ros\xE9 Pine", desc: "Aesthetic pine & foam \u2014 soft evening pastels" },
27105
- kanagawa: { name: "Kanagawa", desc: "Hokusai-inspired waves \u2014 sumi ink on washi" },
27106
- "ayu-dark": { name: "Ayu Dark", desc: "Simple pleasant dark \u2014 warm orange + cool blue" },
27107
- everforest: { name: "Everforest", desc: "Green-based comfort \u2014 forest greens & warm tans" },
27108
- "night-owl": { name: "Night Owl", desc: "Sarah Drasner's night \u2014 deep navy + bold accents" },
27109
- synthwave: { name: "Synthwave '84", desc: "Hot pink + neon cyan on deep purple" },
27110
- "github-dark": { name: "GitHub Dark", desc: "GitHub's default dark \u2014 crisp blue on near-black" },
27111
- "material-ocean": {
27112
- name: "Material Ocean",
27113
- desc: "Deepest Material variant \u2014 ink blue with pastel accents"
27114
- },
27115
- nightfox: { name: "Nightfox", desc: "Balanced slate blue with muted sage and rose" },
27116
- oxocarbon: {
27117
- name: "Oxocarbon",
27118
- desc: "IBM Carbon-derived \u2014 neutral greys, electric blue & pink"
27119
- },
27120
- "catppuccin-macchiato": {
27121
- name: "Catppuccin Macchiato",
27122
- desc: "Warmer, one shade lighter than Mocha"
27123
- },
27124
- "catppuccin-frappe": {
27125
- name: "Catppuccin Frapp\xE9",
27126
- desc: "The lightest Catppuccin dark \u2014 gentle midday contrast"
27127
- },
27128
- "gruvbox-material": {
27129
- name: "Gruvbox Material",
27130
- desc: "Softened Gruvbox \u2014 same warmth, lower eye strain"
27131
- },
27132
- "tokyo-night-storm": {
27133
- name: "Tokyo Night Storm",
27134
- desc: "Tokyo Night on a lifted blue-grey base"
27135
- },
27136
- "rose-pine-moon": {
27137
- name: "Ros\xE9 Pine Moon",
27138
- desc: "Ros\xE9 Pine at dusk \u2014 deeper base, same soft accents"
27139
- },
27140
- zenburn: { name: "Zenburn", desc: "The classic low-contrast grey \u2014 desaturated and calm" },
27141
- palenight: { name: "Palenight", desc: "Material Palenight \u2014 indigo base, candy accents" },
27142
- horizon: { name: "Horizon", desc: "Warm coral and mint on charcoal \u2014 sunset gradient" },
27143
- sonokai: { name: "Sonokai", desc: "Monokai Pro descendant \u2014 punchy on warm graphite" },
27144
- "edge-dark": { name: "Edge Dark", desc: "Clean, evenly-weighted palette on desaturated navy" },
27145
- moonfly: { name: "Moonfly", desc: "Near-black base with high-chroma accents \u2014 max contrast" },
27146
- melange: { name: "Melange", desc: "Warm sepia and clay \u2014 the least blue dark theme here" },
27147
- poimandres: { name: "Poimandres", desc: "Teal-forward, low-saturation \u2014 mint on deep indigo" },
27148
- "vitesse-dark": {
27149
- name: "Vitesse Dark",
27150
- desc: "Anthony Fu's minimal palette \u2014 muted, print-like"
27151
- },
27152
- aura: { name: "Aura Dark", desc: "Vivid purple and spring green on near-black violet" },
27153
- "dark-plus": { name: "VS Code Dark+", desc: "VS Code's default \u2014 familiar blue/orange/teal" },
27154
- monochrome: { name: "Monochrome", desc: "Pure grayscale \u2014 no hue, only luminance" },
27155
- matrix: { name: "Matrix Green", desc: "Phosphor green CRT terminal \u2014 digital rain aesthetic" },
27156
- amber: { name: "Amber CRT", desc: "Warm phosphor CRT terminal \u2014 glowing vintage amber" },
27157
- "cyber-noir": {
27158
- name: "Cyber Noir",
27159
- desc: "Stark white and slate on jet black \u2014 minimalist high contrast"
27160
- },
27161
- "cobalt-mono": {
27162
- name: "Cobalt Monochrome",
27163
- desc: "Luminous cyan on deep abyss blue \u2014 oceanic blueprint"
27164
- },
27165
- "blood-moon": {
27166
- name: "Blood Moon",
27167
- desc: "Crimson & scarlet on obsidian \u2014 brooding dark mode"
27168
- },
27169
- cobalt2: {
27170
- name: "Cobalt2",
27171
- desc: "Wes Bos' signature theme \u2014 deep navy with golden yellow & cyan"
27172
- },
27173
- "shades-of-purple": {
27174
- name: "Shades of Purple",
27175
- desc: "Ahmad Awais' bold purple palette with neon yellow & magenta"
27176
- },
27177
- "flexoki-dark": {
27178
- name: "Flexoki Dark",
27179
- desc: "Steph Ango's inky warm paper palette \u2014 natural earthy accents"
27180
- },
27181
- laserwave: {
27182
- name: "LaserWave",
27183
- desc: "80s retrowave \u2014 neon flamingo and turquoise on violet"
27184
- },
27185
- andromeda: {
27186
- name: "Andromeda",
27187
- desc: "Deep interstellar dark with vibrant neon teal and pink"
27188
- },
27189
- "github-dark-dimmed": {
27190
- name: "GitHub Dark Dimmed",
27191
- desc: "GitHub's softer slate dark theme \u2014 gentle blues and pastels"
27192
- },
27193
- snazzy: {
27194
- name: "Hyper Snazzy",
27195
- desc: "Sindre Sorhus' elegant saturated terminal palette"
27196
- },
27197
- "tokyo-night-moon": {
27198
- name: "Tokyo Night Moon",
27199
- desc: "Tokyo Night on balanced deep indigo \u2014 vibrant accents"
27200
- },
27201
- "gruvbox-dark-hard": {
27202
- name: "Gruvbox Dark Hard",
27203
- desc: "Maximum contrast Gruvbox on deep pitch charcoal"
27204
- },
27205
- "oceanic-next": {
27206
- name: "Oceanic Next",
27207
- desc: "Teal-and-slate classic \u2014 calm blue, warm coral"
27208
- },
27209
- "one-half-dark": {
27210
- name: "One Half Dark",
27211
- desc: "Atom's One Half \u2014 One Dark with cleaner contrast"
27212
- },
27213
- "ayu-mirage": { name: "Ayu Mirage", desc: "Dusk-slate Ayu, between Dark and Light" },
27214
- seti: { name: "Seti", desc: "Long-running VS Code classic \u2014 charcoal, gold, cyan" },
27215
- "paraiso-dark": { name: "Paraiso Dark", desc: "Base16 plum \u2014 warm, muted, low-glare" },
27216
- darcula: { name: "Darcula", desc: "JetBrains' default dark \u2014 grey-green with amber" },
27217
- "slack-dark": { name: "Slack Aubergine", desc: "Deep aubergine with sky blue and lime" },
27218
- "vitesse-black": { name: "Vitesse Black", desc: "Vitesse on true black \u2014 least glare here" },
27219
- "atom-dark": { name: "Atom Dark", desc: "The original Atom grey \u2014 neutral, low-chroma" },
27220
- "github-dark-high-contrast": {
27221
- name: "GitHub Dark High Contrast",
27222
- desc: "Accessible GitHub \u2014 boosted text and borders"
27223
- },
27224
- "contrast-max": {
27225
- name: "Maximum Contrast",
27226
- desc: "Original \u2014 pure black, AAA-targeted text and borders"
27227
- },
27228
- "colorblind-safe": {
27229
- name: "Colorblind Safe",
27230
- desc: "Original \u2014 blue/orange coding, no red-vs-green reliance"
27231
- },
27232
- sandstone: { name: "Sandstone", desc: "Original \u2014 warm stone neutrals with sage and clay" },
27233
- "everforest-hard": {
27234
- name: "Everforest Hard",
27235
- desc: "Everforest on its deepest base \u2014 more depth, same greens"
27236
- }
27237
- };
27238
- var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({ id, ...THEME_META[id] }));
27139
+ var THEME_OPTIONS = THEME_PRESET_IDS.map((id) => ({
27140
+ id,
27141
+ name: THEME_PRESET_META[id].name,
27142
+ desc: THEME_PRESET_META[id].description
27143
+ }));
27239
27144
  function presetHelpLines(perLine = 4) {
27240
27145
  const lines = [];
27241
27146
  for (let i = 0; i < THEME_PRESET_IDS.length; i += perLine) {
@@ -27954,6 +27859,24 @@ ${lines.join("\n")}` };
27954
27859
  import { readHqRuntimeFileSync, resolveHqConfig, resolveHqDataDir } from "@wrongstack/core/hq";
27955
27860
  import { noOpVault as noOpVault5 } from "@wrongstack/core/security";
27956
27861
  import { color as color56 } from "@wrongstack/core/utils";
27862
+
27863
+ // src/hq-live-status.ts
27864
+ var probe;
27865
+ function setHqLiveStatusProbe(next) {
27866
+ probe = next;
27867
+ return () => {
27868
+ if (probe === next) probe = void 0;
27869
+ };
27870
+ }
27871
+ function readHqLiveStatus() {
27872
+ try {
27873
+ return probe?.();
27874
+ } catch {
27875
+ return void 0;
27876
+ }
27877
+ }
27878
+
27879
+ // src/slash-commands/hq.ts
27957
27880
  function maskToken(t) {
27958
27881
  if (t.length <= 10) return `${t.slice(0, 2)}\u2026(${t.length})`;
27959
27882
  return `${t.slice(0, 6)}\u2026${t.slice(-4)} (${t.length} chars)`;
@@ -27972,6 +27895,14 @@ async function probeHq(url) {
27972
27895
  return color56.red("unreachable");
27973
27896
  }
27974
27897
  }
27898
+ function describeLiveConnection() {
27899
+ const live = readHqLiveStatus();
27900
+ if (live === void 0) return color56.dim("no HQ connection in this process");
27901
+ const state = live.connected ? color56.green("connected") : color56.amber("reconnecting");
27902
+ const queued = live.queuedFrames > 0 ? color56.dim(` \xB7 ${live.queuedFrames} frames queued`) : "";
27903
+ const session = live.sessionId ? color56.dim(` \xB7 session ${live.sessionId.slice(-12)}`) : "";
27904
+ return `${state} ${color56.dim(`as ${live.clientId.slice(0, 12)}`)}${session}${queued}`;
27905
+ }
27975
27906
  function buildHqCommand(opts) {
27976
27907
  return {
27977
27908
  name: "hq",
@@ -27992,8 +27923,8 @@ function buildHqCommand(opts) {
27992
27923
  " /hq on | off Enable / disable HQ publishing",
27993
27924
  " /hq clear Remove all HQ settings",
27994
27925
  "",
27995
- "Saved to the active profile config. Telemetry connects on the",
27996
- "NEXT session start (an already-running session keeps its connection).",
27926
+ "Saved to the active profile config. The running terminal session",
27927
+ "follows the change within a few seconds (set/token/on/off/clear).",
27997
27928
  "A locally running `wstack --hq` is auto-discovered with no config.",
27998
27929
  "",
27999
27930
  "/hq is the canonical HQ command. The /settings hq* entries write the same",
@@ -28045,7 +27976,7 @@ function buildHqCommand(opts) {
28045
27976
  return {
28046
27977
  message: `${color56.green("\u2713")} HQ set \u2192 ${color56.cyan(url)}${tokLine}
28047
27978
  status: ${reach}
28048
- ${color56.dim("Connects on the next session start.")}`
27979
+ ${color56.dim("This session re-points within a few seconds.")}`
28049
27980
  };
28050
27981
  }
28051
27982
  if (sub === "token") {
@@ -28114,7 +28045,7 @@ function buildHqCommand(opts) {
28114
28045
  if (runtime) {
28115
28046
  lines.push("");
28116
28047
  lines.push(
28117
- ` ${color56.green("A local HQ is running")} at ${color56.cyan(runtime.url)} ${color56.dim("(start a new session to attach)")}`
28048
+ ` ${color56.green("A local HQ is running")} at ${color56.cyan(runtime.url)} ${color56.dim("(/hq on to attach)")}`
28118
28049
  );
28119
28050
  }
28120
28051
  const message = lines.join("\n");
@@ -28146,6 +28077,7 @@ function buildHqCommand(opts) {
28146
28077
  );
28147
28078
  if (resolved.projectAlias) lines.push(` alias: ${color56.cyan(resolved.projectAlias)}`);
28148
28079
  lines.push(` status: ${await probeHq(resolved.url)}`);
28080
+ lines.push(` this: ${describeLiveConnection()}`);
28149
28081
  return { message: lines.join("\n") };
28150
28082
  }
28151
28083
  return {
@@ -29198,6 +29130,7 @@ var ALL_SETTINGS_KEYS = [
29198
29130
  "memory",
29199
29131
  "skills",
29200
29132
  "models-registry",
29133
+ "tool-coach",
29201
29134
  "max-iterations",
29202
29135
  "limits",
29203
29136
  "auto-proceed-max-iterations",
@@ -29880,6 +29813,20 @@ async function executeSettingsSubcommand(sub, rest, opts) {
29880
29813
  message: `${color61.green("\u2713")} Models registry \u2192 ${on ? color61.cyan("on") : color61.dim("off")} ${color61.dim("restart to apply")}`
29881
29814
  };
29882
29815
  }
29816
+ if (sub === "tool-coach") {
29817
+ const raw = (rest[0] ?? "").toLowerCase();
29818
+ if (!["on", "off"].includes(raw))
29819
+ return { message: `${color61.amber("Usage:")} /settings tool-coach on|off` };
29820
+ const on = raw === "on";
29821
+ await persistConfigSetting(persistDeps, (cfg) => {
29822
+ const feats = cfg.features ?? {};
29823
+ feats.toolCoach = on;
29824
+ cfg.features = feats;
29825
+ });
29826
+ return {
29827
+ message: `${color61.green("\u2713")} Tool Coach \u2192 ${on ? color61.cyan("on") : color61.dim("off")} ${color61.dim("applies to the next task")}`
29828
+ };
29829
+ }
29883
29830
  if (sub === "stream-fleet") {
29884
29831
  const raw = (rest[0] ?? "").toLowerCase();
29885
29832
  const mode = raw === "on" ? "full" : raw === "off" || raw === "full" ? raw : void 0;
@@ -30106,6 +30053,7 @@ var SETTINGS_HELP = [
30106
30053
  " /settings memory on|off Register remember/forget tools",
30107
30054
  " /settings skills on|off Discover and load skills from disk",
30108
30055
  " /settings models-registry on|off Fetch model catalog at startup",
30056
+ " /settings tool-coach on|off Guide tool choice and recovery during tasks",
30109
30057
  " /settings max-concurrent <n> Max concurrent subagents (0 = default)",
30110
30058
  " /settings max-iterations <n> Max agent iterations before pausing (0 = default)",
30111
30059
  " /settings auto-proceed-max-iterations <n> Max auto turns before pausing (0 = unlimited)",
@@ -30225,6 +30173,7 @@ function formatCurrentSettingsView(opts) {
30225
30173
  ` memory features: ${feats?.memory !== false ? color62.cyan("on") : color62.dim("off")} ${color62.dim("change: /settings memory on|off")}`,
30226
30174
  ` skills features: ${feats?.skills !== false ? color62.cyan("on") : color62.dim("off")} ${color62.dim("change: /settings skills on|off")}`,
30227
30175
  ` models registry: ${feats?.modelsRegistry !== false ? color62.cyan("on") : color62.dim("off")} ${color62.dim("change: /settings models-registry on|off")}`,
30176
+ ` Tool Coach: ${feats?.toolCoach !== false ? color62.cyan("on") : color62.dim("off")} ${color62.dim("change: /settings tool-coach on|off")}`,
30228
30177
  ` max concurrent: ${color62.cyan(maxConcurrent === 0 ? "default" : String(maxConcurrent))} ${color62.dim("change: /settings max-concurrent <n>")}`,
30229
30178
  ` max iterations: ${color62.cyan(String(tools?.maxIterations ?? "default"))} ${color62.dim("change: /settings max-iterations <n>")}`,
30230
30179
  ` auto-proceed max iters: ${color62.cyan(String(au?.autoProceedMaxIterations ?? "unlimited"))} ${color62.dim("change: /settings auto-proceed-max-iterations <n>")}`,
@@ -34000,7 +33949,7 @@ var KIND_BLURBS = {
34000
33949
  "git-history": "reset --hard, clean -f, push --force, filter-branch",
34001
33950
  publish: "npm publish, docker push, kubectl delete namespace",
34002
33951
  "download-and-run": "curl | sh, and inline payloads that fetch then execute",
34003
- "bulk-delete": "find -exec rm, inline rmSync across many paths",
33952
+ "bulk-delete": "find -exec rm, inline rmSync, container volume deletes, database drops",
34004
33953
  "agent-state": "writes to WrongStack's own config.json / trust.json / auth.json",
34005
33954
  "credential-bind": "attaching a well-known API key to a chosen provider endpoint"
34006
33955
  };
@@ -34472,7 +34421,6 @@ function setupCliSlashCommands(params) {
34472
34421
  // src/wiring/command-host-state.ts
34473
34422
  import {
34474
34423
  areSubagentsAllowedForSession as areSubagentsAllowedForSession4,
34475
- FLEET_ROSTER as FLEET_ROSTER5,
34476
34424
  mailboxSessionTag as mailboxSessionTag6,
34477
34425
  makeKanbanQueueTool
34478
34426
  } from "@wrongstack/core/coordination";
@@ -34557,9 +34505,11 @@ async function setupCommandHostState(input) {
34557
34505
  const liveSessionId = () => input.sessionRef.current?.id ?? input.session.id;
34558
34506
  input.hqCommandController.sessionId = liveSessionId;
34559
34507
  input.hqCommandController.sessionTag = () => mailboxSessionTag6(liveSessionId());
34560
- input.hqCommandController.killFleet = () => killFleet2(input.getDirector());
34561
- input.hqCommandController.terminateAgent = (subagentId) => terminateAgent(input.getDirector(), subagentId);
34562
- input.hqCommandController.spawnAgent = (role, task, maxIterations) => spawnAgent2(input.getDirector(), liveSessionId(), role, task, maxIterations);
34508
+ input.hqCommandController.killFleet = (sessionId) => killHqSessionFleet(input.getDirector(), sessionId ?? liveSessionId(), {
34509
+ multiConversation: input.hqMultiConversation === true
34510
+ });
34511
+ input.hqCommandController.terminateAgent = (subagentId) => terminateHqAgent(input.getDirector(), subagentId);
34512
+ input.hqCommandController.spawnAgent = (role, task, maxIterations, sessionId) => spawnHqAgent(input.getDirector(), sessionId ?? liveSessionId(), role, task, maxIterations);
34563
34513
  input.hqCommandController.kanbanDispatch = async (request) => {
34564
34514
  const director = input.getDirector();
34565
34515
  const sessionId = request.sessionId ?? liveSessionId();
@@ -34727,49 +34677,6 @@ async function setupCommandHostState(input) {
34727
34677
  sddRunRegistry
34728
34678
  };
34729
34679
  }
34730
- async function killFleet2(director) {
34731
- if (!director) return 0;
34732
- let killed = 0;
34733
- for (const subagent of director.status().subagents) {
34734
- if (subagent.status === "running" || subagent.status === "idle") {
34735
- try {
34736
- await director.remove(subagent.id);
34737
- killed++;
34738
- } catch {
34739
- }
34740
- }
34741
- }
34742
- return killed;
34743
- }
34744
- async function terminateAgent(director, subagentId) {
34745
- if (!director) return false;
34746
- try {
34747
- await director.terminate(subagentId);
34748
- return true;
34749
- } catch {
34750
- return false;
34751
- }
34752
- }
34753
- async function spawnAgent2(director, sessionId, role, task, maxIterations) {
34754
- if (!director) {
34755
- throw new AgentError3({
34756
- message: "Director is not available.",
34757
- code: "AGENT_RUN_FAILED",
34758
- context: { phase: "hq-spawn", role }
34759
- });
34760
- }
34761
- if (!areSubagentsAllowedForSession4(sessionId)) {
34762
- throw new Error("Subagents are disabled for this session.");
34763
- }
34764
- const base = FLEET_ROSTER5[role] ?? {
34765
- id: `manual-${Date.now()}`,
34766
- name: role,
34767
- maxIterations: maxIterations ?? 0,
34768
- maxToolCalls: 200
34769
- };
34770
- const config = task !== void 0 ? { ...base, task } : base;
34771
- return director.spawn({ ...config, originSessionId: sessionId });
34772
- }
34773
34680
 
34774
34681
  // src/wiring/dep-watcher.ts
34775
34682
  import * as path24 from "node:path";
@@ -34902,7 +34809,7 @@ function setupDepWatcherBridge(deps) {
34902
34809
  }
34903
34810
 
34904
34811
  // src/wiring/director-announcement.ts
34905
- import { FLEET_ROSTER as FLEET_ROSTER6 } from "@wrongstack/core/coordination";
34812
+ import { FLEET_ROSTER as FLEET_ROSTER5 } from "@wrongstack/core/coordination";
34906
34813
  async function ensureDirectorAndAnnounce(args) {
34907
34814
  const {
34908
34815
  multiAgentHost,
@@ -34919,7 +34826,7 @@ async function ensureDirectorAndAnnounce(args) {
34919
34826
  if (director) {
34920
34827
  if (priorFleetState) director.setCheckpointState(priorFleetState);
34921
34828
  const directorToolNames = [];
34922
- for (const tool of director.tools(FLEET_ROSTER6)) {
34829
+ for (const tool of director.tools(FLEET_ROSTER5)) {
34923
34830
  toolRegistry.register(tool);
34924
34831
  directorToolNames.push(tool.name);
34925
34832
  }
@@ -34927,10 +34834,10 @@ async function ensureDirectorAndAnnounce(args) {
34927
34834
  const browserSurface = flags.webui === true || flags.simpleui === true;
34928
34835
  if (browserSurface) {
34929
34836
  renderer.writeInfo(
34930
- `Director mode enabled (${Object.keys(FLEET_ROSTER6).length} roles) \u2192 ${fleetRoot}`
34837
+ `Director mode enabled (${Object.keys(FLEET_ROSTER5).length} roles) \u2192 ${fleetRoot}`
34931
34838
  );
34932
34839
  } else {
34933
- renderer.writeInfo(`Director mode enabled. Roster: ${Object.keys(FLEET_ROSTER6).join(", ")}`);
34840
+ renderer.writeInfo(`Director mode enabled. Roster: ${Object.keys(FLEET_ROSTER5).join(", ")}`);
34934
34841
  renderer.writeInfo(` fleet root \u2192 ${fleetRoot}`);
34935
34842
  renderer.writeInfo(` manifest \u2192 ${manifestPath}`);
34936
34843
  renderer.writeInfo(` scratchpad \u2192 ${sharedScratchpadPath}`);
@@ -35234,12 +35141,15 @@ function startGovernanceHqTelemetry(options) {
35234
35141
  };
35235
35142
  }
35236
35143
  if (stopped) return;
35237
- const payload = projectGovernanceHqSnapshot(
35238
- options.publisher.project.projectId,
35239
- now(),
35240
- result
35241
- );
35242
- options.publisher.publishEvent({ type: "governance.snapshot", payload });
35144
+ try {
35145
+ const payload = projectGovernanceHqSnapshot(
35146
+ options.publisher.project.projectId,
35147
+ now(),
35148
+ result
35149
+ );
35150
+ options.publisher.publishEvent({ type: "governance.snapshot", payload });
35151
+ } catch {
35152
+ }
35243
35153
  } finally {
35244
35154
  inFlight = false;
35245
35155
  }
@@ -35264,6 +35174,8 @@ function toHqMcpServers(servers) {
35264
35174
  lastFailureAt: server.lastFailureAt === void 0 ? void 0 : new Date(server.lastFailureAt).toISOString()
35265
35175
  }));
35266
35176
  }
35177
+ var DEFAULT_SCOPE_CHECK_INTERVAL_MS = 1e3;
35178
+ var MCP_HEALTH_KEEPALIVE_MS = 2 * 6e4;
35267
35179
  function setupHqTelemetry(deps) {
35268
35180
  const {
35269
35181
  events,
@@ -35281,13 +35193,15 @@ function setupHqTelemetry(deps) {
35281
35193
  hqPublisherRef,
35282
35194
  mcpRegistry
35283
35195
  } = deps;
35196
+ const liveSession = deps.liveSession ?? (() => session);
35197
+ const liveProjectRoot = deps.liveProjectRoot ?? (() => projectRoot);
35284
35198
  let stopHqSessionBridge;
35285
35199
  const stopHqAuxBridges = [];
35286
35200
  const approvalRegistry = createApprovalRegistry(events);
35287
35201
  teardownHandlers.push(() => approvalRegistry.dispose());
35288
35202
  if (deps.approvalMirror) {
35289
35203
  deps.approvalMirror.current = approvalRegistry;
35290
- deps.approvalMirror.sessionId = () => session.id;
35204
+ deps.approvalMirror.sessionId = () => liveSession().id;
35291
35205
  teardownHandlers.push(() => {
35292
35206
  if (deps.approvalMirror?.current === approvalRegistry) {
35293
35207
  deps.approvalMirror.current = void 0;
@@ -35298,23 +35212,126 @@ function setupHqTelemetry(deps) {
35298
35212
  const hqCommandController = {
35299
35213
  steerMailbox: brainMailbox,
35300
35214
  interruptLeader: () => false,
35301
- sessionTag: () => mailboxSessionTag8(session.id),
35302
- // Boot-session seed. `setupCommandHostState` rebinds both to the LIVE
35303
- // writer ref, because an in-process resume / session.new swaps
35304
- // `ctx.session` for a new writer object and this captured one goes stale.
35305
- sessionId: () => session.id,
35215
+ sessionTag: () => mailboxSessionTag8(liveSession().id),
35216
+ // `setupCommandHostState` rebinds both to the LIVE writer ref too, because
35217
+ // an in-process resume / session.new swaps `ctx.session` for a new writer
35218
+ // object and a captured one goes stale.
35219
+ sessionId: () => liveSession().id,
35306
35220
  allowRunCommand: () => flags["hq-allow-exec"] === true,
35307
35221
  resolveApproval: (toolUseId, decision, commandSessionId) => approvalRegistry.resolve(toolUseId, decision, commandSessionId),
35308
35222
  resolveUserInput: (requestId, response, commandSessionId) => approvalRegistry.resolveUserInput?.(requestId, response, commandSessionId) ?? false,
35309
- kanbanTransition: createProjectKanbanTransitionHandler(projectRoot),
35310
- kanbanAssign: createProjectKanbanAssignHandler(projectRoot)
35223
+ // Resolved per command: an in-place project switch must not leave HQ's
35224
+ // Kanban moves writing into the project this terminal just left.
35225
+ kanbanTransition: (request) => createProjectKanbanTransitionHandler(liveProjectRoot())(request),
35226
+ kanbanAssign: (request) => createProjectKanbanAssignHandler(liveProjectRoot())(request)
35311
35227
  };
35312
35228
  const hqOnCommand = createHqCommandDispatcher(hqCommandController);
35313
- const hqConnection = startCliHqConnection({
35229
+ const stopSessionScope = () => {
35230
+ stopHqSessionBridge?.();
35231
+ stopHqSessionBridge = void 0;
35232
+ for (const stop of stopHqAuxBridges) {
35233
+ try {
35234
+ stop();
35235
+ } catch {
35236
+ }
35237
+ }
35238
+ stopHqAuxBridges.length = 0;
35239
+ };
35240
+ let boundSessionId;
35241
+ const bindSessionScope = (publisher) => {
35242
+ stopSessionScope();
35243
+ const writer = liveSession();
35244
+ const sessionId = writer.id;
35245
+ const root = liveProjectRoot();
35246
+ boundSessionId = sessionId;
35247
+ try {
35248
+ stopHqSessionBridge = startSessionTelemetryBridge({
35249
+ publisher,
35250
+ events,
35251
+ sessionId,
35252
+ projectRoot: root,
35253
+ projectName: path27.basename(root),
35254
+ globalRoot,
35255
+ writer,
35256
+ // biome-ignore lint/suspicious/noExplicitAny: initialAgents shape
35257
+ initialAgents: tracker?.getAgents?.(),
35258
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
35259
+ });
35260
+ } catch {
35261
+ }
35262
+ try {
35263
+ stopHqAuxBridges.push(
35264
+ startFleetTelemetryBridge({ events, publisher, runId: sessionId, sessionId })
35265
+ );
35266
+ } catch {
35267
+ }
35268
+ try {
35269
+ stopHqAuxBridges.push(startGovernanceHqTelemetry({ publisher, projectRoot: root }));
35270
+ } catch {
35271
+ }
35272
+ try {
35273
+ const publishMcpHealth = () => {
35274
+ publisher.publishEvent({
35275
+ type: "mcp.health.snapshot",
35276
+ payload: { servers: toHqMcpServers(mcpRegistry.operationalHealth()) },
35277
+ sessionId
35278
+ });
35279
+ };
35280
+ publishMcpHealth();
35281
+ stopHqAuxBridges.push(publisher.onConnected(publishMcpHealth));
35282
+ const mcpKeepAlive = setInterval(publishMcpHealth, MCP_HEALTH_KEEPALIVE_MS);
35283
+ mcpKeepAlive.unref?.();
35284
+ stopHqAuxBridges.push(() => clearInterval(mcpKeepAlive));
35285
+ stopHqAuxBridges.push(
35286
+ mcpRegistry.onOperation((operation) => {
35287
+ publisher.publishEvent({
35288
+ type: "mcp.operation",
35289
+ payload: {
35290
+ operation,
35291
+ servers: toHqMcpServers(mcpRegistry.operationalHealth())
35292
+ },
35293
+ sessionId
35294
+ });
35295
+ })
35296
+ );
35297
+ } catch {
35298
+ }
35299
+ try {
35300
+ stopHqAuxBridges.push(startBrainTelemetryBridge({ events, publisher, sessionId }));
35301
+ } catch {
35302
+ }
35303
+ try {
35304
+ stopHqAuxBridges.push(startWorktreeTelemetryBridge({ events, publisher, sessionId }));
35305
+ } catch {
35306
+ }
35307
+ try {
35308
+ stopHqAuxBridges.push(
35309
+ startToolTelemetryBridge({ events, publisher, projectRoot: root, sessionId })
35310
+ );
35311
+ } catch {
35312
+ }
35313
+ try {
35314
+ stopHqAuxBridges.push(startCostTelemetryBridge({ events, publisher, sessionId }));
35315
+ } catch {
35316
+ }
35317
+ try {
35318
+ stopHqAuxBridges.push(
35319
+ startApprovalTelemetryBridge({
35320
+ registry: approvalRegistry,
35321
+ publisher,
35322
+ projectRoot: root,
35323
+ sessionId
35324
+ })
35325
+ );
35326
+ } catch {
35327
+ }
35328
+ };
35329
+ const connect = (root) => startCliHqConnection({
35314
35330
  clientKind: tuiOwnsScreen ? "tui" : "cli",
35315
- projectRoot,
35316
- projectName: path27.basename(projectRoot),
35331
+ projectRoot: root,
35332
+ projectName: path27.basename(root),
35317
35333
  appConfig: config,
35334
+ ...deps.getConfig !== void 0 ? { getAppConfig: deps.getConfig } : {},
35318
35335
  onCommand: hqOnCommand,
35319
35336
  capabilities: [
35320
35337
  "telemetry.publish",
@@ -35327,118 +35344,54 @@ function setupHqTelemetry(deps) {
35327
35344
  ],
35328
35345
  onConnect: (publisher) => {
35329
35346
  hqPublisherRef.current = publisher;
35330
- stopHqSessionBridge?.();
35331
- stopHqSessionBridge = void 0;
35332
- for (const stop of stopHqAuxBridges) {
35333
- try {
35334
- stop();
35335
- } catch {
35336
- }
35337
- }
35338
- stopHqAuxBridges.length = 0;
35339
- try {
35340
- stopHqSessionBridge = startSessionTelemetryBridge({
35341
- publisher,
35342
- events,
35343
- sessionId: session.id,
35344
- projectRoot,
35345
- projectName: path27.basename(projectRoot),
35346
- globalRoot,
35347
- writer: session,
35348
- // biome-ignore lint/suspicious/noExplicitAny: initialAgents shape
35349
- initialAgents: tracker?.getAgents?.(),
35350
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
35351
- });
35352
- } catch {
35353
- }
35354
- try {
35355
- stopHqAuxBridges.push(
35356
- startFleetTelemetryBridge({
35357
- events,
35358
- publisher,
35359
- runId: session.id,
35360
- sessionId: session.id
35361
- })
35362
- );
35363
- } catch {
35364
- }
35365
- try {
35366
- stopHqAuxBridges.push(startGovernanceHqTelemetry({ publisher, projectRoot }));
35367
- } catch {
35368
- }
35369
- try {
35370
- publisher.publishEvent({
35371
- type: "mcp.health.snapshot",
35372
- payload: { servers: toHqMcpServers(mcpRegistry.operationalHealth()) },
35373
- sessionId: session.id
35374
- });
35375
- stopHqAuxBridges.push(
35376
- mcpRegistry.onOperation((operation) => {
35377
- publisher.publishEvent({
35378
- type: "mcp.operation",
35379
- payload: {
35380
- operation,
35381
- servers: toHqMcpServers(mcpRegistry.operationalHealth())
35382
- },
35383
- sessionId: session.id
35384
- });
35385
- })
35386
- );
35387
- } catch {
35388
- }
35389
- try {
35390
- stopHqAuxBridges.push(
35391
- startBrainTelemetryBridge({ events, publisher, sessionId: session.id })
35392
- );
35393
- } catch {
35394
- }
35395
- try {
35396
- stopHqAuxBridges.push(
35397
- startWorktreeTelemetryBridge({ events, publisher, sessionId: session.id })
35398
- );
35399
- } catch {
35400
- }
35401
- try {
35402
- stopHqAuxBridges.push(
35403
- startToolTelemetryBridge({
35404
- events,
35405
- publisher,
35406
- projectRoot,
35407
- sessionId: session.id
35408
- })
35409
- );
35410
- } catch {
35411
- }
35412
- try {
35413
- stopHqAuxBridges.push(
35414
- startCostTelemetryBridge({ events, publisher, sessionId: session.id })
35415
- );
35416
- } catch {
35417
- }
35418
- try {
35419
- stopHqAuxBridges.push(
35420
- startApprovalTelemetryBridge({
35421
- registry: approvalRegistry,
35422
- publisher,
35423
- projectRoot,
35424
- sessionId: session.id
35425
- })
35426
- );
35427
- } catch {
35428
- }
35347
+ bindSessionScope(publisher);
35348
+ },
35349
+ // `/hq off` (or clearing the endpoint) retired the publisher: stop the
35350
+ // bridges bound to it so nothing keeps queueing into a closed socket.
35351
+ onDisconnect: () => {
35352
+ stopSessionScope();
35353
+ boundSessionId = void 0;
35354
+ hqPublisherRef.current = void 0;
35429
35355
  }
35430
35356
  });
35357
+ let boundProjectRoot = projectRoot;
35358
+ let hqConnection = connect(boundProjectRoot);
35431
35359
  hqPublisherRef.getKanbanSyncStats = () => hqConnection.getKanbanSyncStats();
35432
35360
  hqPublisherRef.current = hqConnection.getPublisher();
35433
- teardownHandlers.push(() => stopHqSessionBridge?.());
35434
- teardownHandlers.push(() => {
35435
- for (const stop of stopHqAuxBridges) {
35436
- try {
35437
- stop();
35438
- } catch {
35361
+ const scopeWatcher = setInterval(() => {
35362
+ try {
35363
+ const root = liveProjectRoot();
35364
+ if (root !== boundProjectRoot) {
35365
+ boundProjectRoot = root;
35366
+ stopSessionScope();
35367
+ hqConnection.stop();
35368
+ hqConnection = connect(root);
35369
+ hqPublisherRef.current = hqConnection.getPublisher();
35370
+ return;
35371
+ }
35372
+ const publisher = hqPublisherRef.current;
35373
+ if (publisher !== void 0 && liveSession().id !== boundSessionId) {
35374
+ bindSessionScope(publisher);
35439
35375
  }
35376
+ } catch {
35440
35377
  }
35441
- });
35378
+ }, deps.scopeCheckIntervalMs ?? DEFAULT_SCOPE_CHECK_INTERVAL_MS);
35379
+ scopeWatcher.unref?.();
35380
+ teardownHandlers.push(() => clearInterval(scopeWatcher));
35381
+ teardownHandlers.push(
35382
+ setHqLiveStatusProbe(() => {
35383
+ const publisher = hqPublisherRef.current;
35384
+ if (publisher === void 0) return void 0;
35385
+ return {
35386
+ clientId: publisher.identity.clientId,
35387
+ projectId: publisher.project.projectId,
35388
+ connected: publisher.connected,
35389
+ queuedFrames: publisher.getQueueStats().entries,
35390
+ sessionId: boundSessionId
35391
+ };
35392
+ })
35393
+ );
35394
+ teardownHandlers.push(() => stopSessionScope());
35442
35395
  teardownHandlers.push(() => {
35443
35396
  hqPublisherRef.getKanbanSyncStats = void 0;
35444
35397
  hqConnection.stop();
@@ -37758,6 +37711,7 @@ import {
37758
37711
  } from "@wrongstack/core/coordination";
37759
37712
  import { ProviderCacheLedger } from "@wrongstack/core/infrastructure";
37760
37713
  import { restoreSessionPermissionOverrides } from "@wrongstack/core/security";
37714
+ import { restoreRequiredSkillsFromEvents } from "@wrongstack/core/skills";
37761
37715
  import {
37762
37716
  attachTodosCheckpoint,
37763
37717
  cleanOrphanLocks,
@@ -37997,6 +37951,7 @@ async function setupSession(params) {
37997
37951
  restoreSessionSubagentPolicy(context, restoredEvents, restoredSubagentsAllowed);
37998
37952
  restoreSessionSubagentModelPlan(context, restoredEvents);
37999
37953
  } else seedSessionSubagentPolicy(context);
37954
+ restoreRequiredSkillsFromEvents(context, restoredEvents);
38000
37955
  restoreSessionPermissionOverrides(context.meta, {
38001
37956
  events: restoredEvents,
38002
37957
  permissionOverrides: restoredPermissionOverrides
@@ -39626,7 +39581,10 @@ async function runInteractive(cliCtx) {
39626
39581
  mailboxSessionTag: mailboxSessionTag7,
39627
39582
  hqPublisherRef,
39628
39583
  approvalMirror,
39629
- mcpRegistry
39584
+ mcpRegistry,
39585
+ liveSession: () => context.session ?? session,
39586
+ liveProjectRoot: () => context.projectRoot ?? projectRoot,
39587
+ getConfig: () => configStore.get()
39630
39588
  });
39631
39589
  setupDepWatcherConsumers({
39632
39590
  dwCfg,
@@ -39683,6 +39641,7 @@ async function runInteractive(cliCtx) {
39683
39641
  },
39684
39642
  getDirector: () => director,
39685
39643
  hqCommandController,
39644
+ hqMultiConversation: resolveExecutionMode(positional, flags) === "webui",
39686
39645
  multiAgentHost,
39687
39646
  events,
39688
39647
  sessionRef,
@@ -39966,4 +39925,4 @@ export {
39966
39925
  CLI_VERSION,
39967
39926
  runInteractive
39968
39927
  };
39969
- //# sourceMappingURL=cli-main-TN3KZ2P6.js.map
39928
+ //# sourceMappingURL=cli-main-TQTH73ZK.js.map