@wrongstack/cli 0.6.6 → 0.7.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.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import * as path23 from 'path';
3
3
  import { join } from 'path';
4
4
  import * as fsp2 from 'fs/promises';
5
5
  import { readdir, readFile } from 'fs/promises';
6
- import { color, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, SlashCommandRegistry, createDelegateTool, FLEET_ROSTER, createMcpControlTool, EternalAutonomyEngine, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeAgentSubagentRunner, NULL_FLEET_BUS, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, AutoApprovePermissionPolicy, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderProgress, renderTaskGraph, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, InputBuilder, projectHash, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, SpecVersioning, ParallelEternalEngine, allServers as allServers$1 } from '@wrongstack/core';
6
+ import { color, DefaultPathResolver, TOKENS, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, SlashCommandRegistry, createDelegateTool, FLEET_ROSTER, createMcpControlTool, EternalAutonomyEngine, DefaultLogger, DefaultModelsRegistry, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, AutoCompactionMiddleware, estimateRequestTokens, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeAgentSubagentRunner, NULL_FLEET_BUS, resolveWstackPaths, DefaultSecretVault, migratePlaintextSecrets, DefaultConfigLoader, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, atomicWrite, DefaultPluginAPI, AutoApprovePermissionPolicy, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, resolveContextWindowPolicy, formatTodosList, emptyPlan, clearPlan, savePlan, formatPlanTemplates, getPlanTemplate, addPlanItem, formatPlan, deriveTodosFromPlanItem, removePlanItem, setPlanItemStatus, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderProgress, renderTaskGraph, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, InputBuilder, FsError, ERROR_CODES, projectHash, WrongStackError, defaultOrchestrator, decryptConfigSecrets, encryptConfigSecrets as encryptConfigSecrets$1, SpecVersioning, ParallelEternalEngine, allServers as allServers$1 } from '@wrongstack/core';
7
7
  import { createRequire } from 'module';
8
8
  import * as os6 from 'os';
9
9
  import os6__default from 'os';
@@ -372,7 +372,7 @@ function getActiveBuilder() {
372
372
  return sddState.getBuilder();
373
373
  }
374
374
  function buildSddCommand(opts) {
375
- getSessionState(opts.context);
375
+ const sessionState = getSessionState(opts.context);
376
376
  return {
377
377
  name: "sdd",
378
378
  description: "AI-driven SDD: /sdd [new|approve|execute|cancel|status|list|show|templates]",
@@ -395,7 +395,7 @@ function buildSddCommand(opts) {
395
395
  case "create": {
396
396
  const forceFlag = rest.includes("--force") || rest.includes("-f");
397
397
  const title = rest.filter((a) => !a.startsWith("-")).join(" ").trim() || "Untitled Feature";
398
- if (!sddState.getBuilder() && !forceFlag) {
398
+ if (!sessionState.getBuilder() && !forceFlag) {
399
399
  const sessionPath = path23.join(projectRoot, ".wrongstack", "sdd-session.json");
400
400
  try {
401
401
  await fsp2.access(sessionPath);
@@ -1030,6 +1030,14 @@ Start executing the tasks one by one.`
1030
1030
  deletedFromDisk = true;
1031
1031
  } catch {
1032
1032
  }
1033
+ try {
1034
+ await fsp2.rm(path23.join(projectRoot, ".wrongstack", "specs"), { recursive: true, force: true });
1035
+ } catch {
1036
+ }
1037
+ try {
1038
+ await fsp2.rm(path23.join(projectRoot, ".wrongstack", "task-graphs"), { recursive: true, force: true });
1039
+ } catch {
1040
+ }
1033
1041
  const cancelBuilder = sddState.getBuilder();
1034
1042
  if (cancelBuilder) {
1035
1043
  const title = cancelBuilder.getSession().title;
@@ -2745,7 +2753,16 @@ function entryId(ts) {
2745
2753
  return ts.replace(/[:.]/g, "-").slice(0, 19);
2746
2754
  }
2747
2755
  async function ensureHistoryDir(homeFn = defaultHomeDir) {
2748
- await fsp2.mkdir(historyDir(homeFn), { recursive: true });
2756
+ try {
2757
+ await fsp2.mkdir(historyDir(homeFn), { recursive: true });
2758
+ } catch (err) {
2759
+ throw new FsError({
2760
+ message: err instanceof Error ? err.message : String(err),
2761
+ code: ERROR_CODES.FS_MKDIR_FAILED,
2762
+ path: historyDir(homeFn),
2763
+ cause: err
2764
+ });
2765
+ }
2749
2766
  }
2750
2767
  async function readIndex(homeFn = defaultHomeDir) {
2751
2768
  try {
@@ -2757,7 +2774,16 @@ async function readIndex(homeFn = defaultHomeDir) {
2757
2774
  }
2758
2775
  async function writeIndex(idx, homeFn = defaultHomeDir) {
2759
2776
  await ensureHistoryDir(homeFn);
2760
- await atomicWrite(historyIndexPath(homeFn), JSON.stringify(idx, null, 2));
2777
+ try {
2778
+ await atomicWrite(historyIndexPath(homeFn), JSON.stringify(idx, null, 2));
2779
+ } catch (err) {
2780
+ throw new FsError({
2781
+ message: err instanceof Error ? err.message : String(err),
2782
+ code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
2783
+ path: historyIndexPath(homeFn),
2784
+ cause: err
2785
+ });
2786
+ }
2761
2787
  }
2762
2788
  async function backupCurrent(homeFn = defaultHomeDir) {
2763
2789
  const cfg = configPath(homeFn);
@@ -2802,11 +2828,20 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
2802
2828
  snapshotMasked: maskConfigSecrets(newCfg),
2803
2829
  diffSummary: diffSummary(oldCfg, newCfg)
2804
2830
  };
2805
- await fsp2.writeFile(
2806
- path23.join(historyDir(homeFn), `${id}.json`),
2807
- JSON.stringify(entry, null, 2),
2808
- "utf8"
2809
- );
2831
+ try {
2832
+ await fsp2.writeFile(
2833
+ path23.join(historyDir(homeFn), `${id}.json`),
2834
+ JSON.stringify(entry, null, 2),
2835
+ "utf8"
2836
+ );
2837
+ } catch (err) {
2838
+ throw new FsError({
2839
+ message: err instanceof Error ? err.message : String(err),
2840
+ code: ERROR_CODES.FS_WRITE_FAILED,
2841
+ path: path23.join(historyDir(homeFn), `${id}.json`),
2842
+ cause: err
2843
+ });
2844
+ }
2810
2845
  const idx = await readIndex(homeFn);
2811
2846
  idx.entries.unshift({ id, timestamp, description });
2812
2847
  await writeIndex(idx, homeFn);
@@ -3468,17 +3503,37 @@ function buildClearCommand(opts) {
3468
3503
  };
3469
3504
  }
3470
3505
  async function runGit(args, cwd) {
3471
- return new Promise((resolve4) => {
3472
- const child = spawn("git", args, {
3473
- cwd,
3474
- stdio: ["ignore", "pipe", "pipe"]
3506
+ try {
3507
+ return await new Promise((resolve4, reject) => {
3508
+ const child = spawn("git", args, {
3509
+ cwd,
3510
+ stdio: ["ignore", "pipe", "pipe"]
3511
+ });
3512
+ let stdout = "";
3513
+ let stderr = "";
3514
+ child.stdout?.on("data", (d) => stdout += d);
3515
+ child.stderr?.on("data", (d) => stderr += d);
3516
+ child.on("error", (err) => {
3517
+ reject(new WrongStackError({
3518
+ message: `Failed to run git: ${err.message}`,
3519
+ code: ERROR_CODES.TOOL_EXECUTION_FAILED,
3520
+ subsystem: "tool",
3521
+ context: { command: "git", args, cwd },
3522
+ cause: err
3523
+ }));
3524
+ });
3525
+ child.on("close", (code) => resolve4({ stdout, stderr, code: code ?? 0 }));
3475
3526
  });
3476
- let stdout = "";
3477
- let stderr = "";
3478
- child.stdout?.on("data", (d) => stdout += d);
3479
- child.stderr?.on("data", (d) => stderr += d);
3480
- child.on("close", (code) => resolve4({ stdout, stderr, code: code ?? 0 }));
3481
- });
3527
+ } catch (err) {
3528
+ if (err instanceof WrongStackError) throw err;
3529
+ throw new WrongStackError({
3530
+ message: err instanceof Error ? err.message : String(err),
3531
+ code: ERROR_CODES.TOOL_EXECUTION_FAILED,
3532
+ subsystem: "tool",
3533
+ context: { command: "git", args, cwd },
3534
+ cause: err
3535
+ });
3536
+ }
3482
3537
  }
3483
3538
  function detectCommitType(stats) {
3484
3539
  const lines = stats.split("\n");
@@ -5497,8 +5552,17 @@ async function loadStatuslineConfig() {
5497
5552
  }
5498
5553
  async function saveStatuslineConfig(cfg) {
5499
5554
  const p = resolveConfigPath();
5500
- await fsp2.mkdir(path23.dirname(p), { recursive: true });
5501
- await atomicWrite(p, JSON.stringify(cfg, null, 2));
5555
+ try {
5556
+ await fsp2.mkdir(path23.dirname(p), { recursive: true });
5557
+ await atomicWrite(p, JSON.stringify(cfg, null, 2));
5558
+ } catch (err) {
5559
+ throw new FsError({
5560
+ message: err instanceof Error ? err.message : String(err),
5561
+ code: err instanceof Error && err.message.includes("mkdir") ? ERROR_CODES.FS_MKDIR_FAILED : ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
5562
+ path: p,
5563
+ cause: err
5564
+ });
5565
+ }
5502
5566
  }
5503
5567
  function buildStatuslineCommand(deps) {
5504
5568
  return {
@@ -6700,6 +6764,7 @@ async function runProjectCheck(opts) {
6700
6764
  const { spawn: spawn3 } = await import('child_process');
6701
6765
  await new Promise((resolve4, reject) => {
6702
6766
  const child = spawn3("git", ["init"], { cwd: projectRoot });
6767
+ child.on("error", reject);
6703
6768
  child.on("close", (code) => code === 0 ? resolve4() : reject(new Error(`git init failed with ${code}`)));
6704
6769
  });
6705
6770
  renderer.write(` ${color.green("\u2713")} Git repository initialized
@@ -6915,6 +6980,85 @@ var TerminalRenderer = class {
6915
6980
  this.out.write("\x1B[2J\x1B[H");
6916
6981
  this.lineStart = true;
6917
6982
  }
6983
+ /**
6984
+ * Write a flashy agent completion banner for delegate tool results.
6985
+ * Renders a box like:
6986
+ * ┌─────────────────────────────────────┐
6987
+ * │ ✓ [role] done in 4m 32s │
6988
+ * │ 127 iterations · 341 tools │
6989
+ * │ Found 14 bugs across 6 files... │
6990
+ * └─────────────────────────────────────┘
6991
+ */
6992
+ writeAgentSummary(summary, ok) {
6993
+ if (this.silent) return;
6994
+ if (!this.lineStart) this.out.write("\n");
6995
+ const lines = summary.split("\n");
6996
+ const icon = ok ? theme2.success("\u2713") : theme2.error("\u2718");
6997
+ const firstLine = `${icon} ${lines[0] ?? summary}`;
6998
+ const body = lines.slice(1);
6999
+ const maxWidth = Math.min(process.stdout.columns ?? 80, 120);
7000
+ const contentWidth = Math.max(
7001
+ firstLine.length,
7002
+ body.reduce((a, l) => Math.max(a, l.length), 0)
7003
+ );
7004
+ const boxWidth = Math.min(Math.max(contentWidth + 4, 44), maxWidth);
7005
+ const thick = "\u2501".repeat(boxWidth - 2);
7006
+ const thin = "\u2500".repeat(boxWidth - 2);
7007
+ this.out.write(`
7008
+ ${theme2.primary("\u250C")}${thick}${theme2.primary("\u2510")}
7009
+ `);
7010
+ const centre = (s) => {
7011
+ const inner = ` ${s} `;
7012
+ const padLen = Math.max(0, boxWidth - 2 - s.length);
7013
+ const left = Math.floor(padLen / 2);
7014
+ const right = padLen - left;
7015
+ return `${" ".repeat(left)}${inner}${" ".repeat(right)}`;
7016
+ };
7017
+ this.out.write(` ${theme2.primary("\u2502")}${centre(firstLine)}${theme2.primary("\u2502")}
7018
+ `);
7019
+ for (const l of body) {
7020
+ this.out.write(
7021
+ ` ${theme2.primary("\u2502")} ${l}${" ".repeat(Math.max(0, boxWidth - 3 - l.length))}${theme2.primary("\u2502")}
7022
+ `
7023
+ );
7024
+ }
7025
+ this.out.write(` ${theme2.primary("\u2514")}${thin}${theme2.primary("\u2518")}
7026
+ `);
7027
+ this.lineStart = true;
7028
+ }
7029
+ /**
7030
+ * Render subagent completion banners from a RunResult.
7031
+ * Uses `delegateSummaries` when available (populated by delegate tool),
7032
+ * otherwise falls back to scanning message history.
7033
+ */
7034
+ writeDelegateSummaries(result) {
7035
+ if (this.silent) return;
7036
+ if (result.delegateSummaries) {
7037
+ for (const { summary, ok } of result.delegateSummaries) {
7038
+ this.writeAgentSummary(summary, ok);
7039
+ }
7040
+ return;
7041
+ }
7042
+ if (!result.messages) return;
7043
+ for (const msg of result.messages) {
7044
+ const m = msg;
7045
+ if (!Array.isArray(m.content)) continue;
7046
+ for (const block of m.content) {
7047
+ const b = block;
7048
+ if (b.type !== "tool_result" || b.name !== "delegate") continue;
7049
+ let obj;
7050
+ try {
7051
+ obj = typeof b.content === "string" ? JSON.parse(b.content) : b.content;
7052
+ } catch {
7053
+ continue;
7054
+ }
7055
+ const o = obj;
7056
+ if (o.summary) {
7057
+ this.writeAgentSummary(o.summary, o.ok ?? true);
7058
+ }
7059
+ }
7060
+ }
7061
+ }
6918
7062
  };
6919
7063
  function renderMarkdown(s) {
6920
7064
  let out = s;
@@ -7699,7 +7843,7 @@ var updateCmd = async (args, deps) => {
7699
7843
  deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
7700
7844
  `);
7701
7845
  try {
7702
- const result = await new Promise((resolve4) => {
7846
+ const result = await new Promise((resolve4, reject) => {
7703
7847
  const child = spawn("npm", ["install", "-g", "wrongstack@latest"], {
7704
7848
  cwd,
7705
7849
  stdio: "pipe"
@@ -7708,6 +7852,7 @@ var updateCmd = async (args, deps) => {
7708
7852
  child.stderr?.on("data", (d) => {
7709
7853
  stderr += d;
7710
7854
  });
7855
+ child.on("error", reject);
7711
7856
  child.on("close", (code) => resolve4({ code: code ?? 0 }));
7712
7857
  });
7713
7858
  if (result.code === 0) {
@@ -9225,11 +9370,13 @@ async function runRepl(opts) {
9225
9370
  await renderGoalBanner(opts);
9226
9371
  let activeCtrl;
9227
9372
  let interrupts = 0;
9373
+ let exiting = false;
9228
9374
  const onSigint = () => {
9229
9375
  interrupts++;
9230
9376
  if (interrupts >= 2) {
9231
9377
  opts.renderer.writeWarning("Exiting.");
9232
- process.exit(130);
9378
+ exiting = true;
9379
+ return;
9233
9380
  }
9234
9381
  if (opts.getAutonomy?.() === "eternal" || opts.getAutonomy?.() === "eternal-parallel") {
9235
9382
  opts.getEternalEngine?.()?.stop();
@@ -9250,6 +9397,7 @@ async function runRepl(opts) {
9250
9397
  const builder = new InputBuilder({ store: opts.attachments });
9251
9398
  try {
9252
9399
  for (; ; ) {
9400
+ if (exiting) break;
9253
9401
  if (opts.getAutonomy?.() === "eternal") {
9254
9402
  const engine = opts.getEternalEngine?.();
9255
9403
  if (!engine) {
@@ -9292,9 +9440,15 @@ async function runRepl(opts) {
9292
9440
  } else {
9293
9441
  const beforeGoal = await loadGoalSafe(opts);
9294
9442
  const beforeIter = beforeGoal?.iterations ?? 0;
9443
+ const coord = engine.getCoordinator();
9444
+ if (coord) {
9445
+ const stats = coord.getStats();
9446
+ opts.renderer.write(
9447
+ color.dim(` \u250C\u2500 Fleet: ${stats.running} running, ${stats.idle} idle, ${stats.pending} pending, ${stats.completed} done`) + "\n"
9448
+ );
9449
+ }
9295
9450
  opts.renderer.write(
9296
- color.magenta(`
9297
- \u21B3 [parallel #${beforeIter + 1}] launching fan-out\u2026
9451
+ color.magenta(` \u21B3 [parallel #${beforeIter + 1}] launching fan-out\u2026
9298
9452
  `)
9299
9453
  );
9300
9454
  interrupts = 0;
@@ -9302,6 +9456,13 @@ async function runRepl(opts) {
9302
9456
  const ok = await engine.runOneIteration();
9303
9457
  const afterGoal = await loadGoalSafe(opts);
9304
9458
  const last = afterGoal?.journal[afterGoal.journal.length - 1];
9459
+ if (coord) {
9460
+ const stats = coord.getStats();
9461
+ opts.renderer.write(
9462
+ color.dim(` \u2514\u2500 Fleet: ${stats.running} running, ${stats.idle} idle, ${stats.completed} done
9463
+ `)
9464
+ );
9465
+ }
9305
9466
  if (last) {
9306
9467
  const mark = last.status === "success" ? color.green("\u2713") : last.status === "failure" ? color.red("\u2717") : color.amber("\u2298");
9307
9468
  const tail = last.note ? color.dim(` \u2014 ${last.note.slice(0, 80)}`) : "";
@@ -9653,9 +9814,17 @@ async function renderGoalBanner(opts) {
9653
9814
  const goal = await loadGoalSafe(opts);
9654
9815
  if (!goal) return;
9655
9816
  const summary = goal.goal.length > 80 ? `${goal.goal.slice(0, 77)}\u2026` : goal.goal;
9817
+ const stateColor = goal.goalState === "active" ? color.green : goal.goalState === "paused" ? color.amber : goal.goalState === "completed" ? color.green : goal.goalState === "abandoned" ? color.dim : color.dim;
9656
9818
  opts.renderer.write(
9657
- color.dim("Goal: ") + color.bold(summary) + color.dim(` (iter ${goal.iterations})`) + "\n"
9819
+ color.dim("Goal: ") + stateColor(summary) + color.dim(` [${goal.goalState}] (iter ${goal.iterations})`) + "\n"
9658
9820
  );
9821
+ if (goal.journal.length > 0) {
9822
+ const lastEntry = goal.journal[goal.journal.length - 1];
9823
+ const statusIcon2 = lastEntry.status === "success" ? "\u2713" : lastEntry.status === "failure" ? "\u2717" : lastEntry.status === "aborted" ? "\u2298" : lastEntry.status === "skipped" ? "\u229D" : "\xB7";
9824
+ opts.renderer.write(
9825
+ color.dim(` Last: ${statusIcon2} ${lastEntry.task} (${lastEntry.status})`) + "\n"
9826
+ );
9827
+ }
9659
9828
  if (goal.engineState === "running") {
9660
9829
  opts.renderer.write(
9661
9830
  color.amber(" \u21BA Eternal engine was running when last session ended.") + "\n"
@@ -9680,6 +9849,18 @@ async function renderGoalBanner(opts) {
9680
9849
  color.dim(" Use `/autonomy eternal` to resume.") + "\n"
9681
9850
  );
9682
9851
  }
9852
+ } else if (goal.goalState === "paused") {
9853
+ opts.renderer.write(
9854
+ color.amber(" \u23F8 Goal is paused. Use `/goal resume` to continue.") + "\n"
9855
+ );
9856
+ } else if (goal.goalState === "completed") {
9857
+ opts.renderer.write(
9858
+ color.green(" \u2713 Goal completed! Use `/goal clear` to set a new goal.") + "\n"
9859
+ );
9860
+ } else if (goal.goalState === "abandoned") {
9861
+ opts.renderer.write(
9862
+ color.dim(" Use `/goal clear` to set a new goal.") + "\n"
9863
+ );
9683
9864
  }
9684
9865
  opts.renderer.write("\n");
9685
9866
  }
@@ -9855,6 +10036,8 @@ async function execute(deps) {
9855
10036
  renderer.writeWarning(`Hit max iterations (${result.iterations}).`);
9856
10037
  }
9857
10038
  if (result.finalText) renderer.write("\n" + result.finalText + "\n");
10039
+ const r = result;
10040
+ renderer.writeDelegateSummaries(r);
9858
10041
  renderer.write(
9859
10042
  "\n" + color.dim(
9860
10043
  `[in: ${fmtTok(usage.input)} out: ${fmtTok(usage.output)} iters: ${usage.iterations} cost: ${usage.cost.toFixed(4)} ${(usage.elapsedMs / 1e3).toFixed(1)}s]`
@@ -9919,6 +10102,7 @@ async function execute(deps) {
9919
10102
  setStatuslineHiddenItems,
9920
10103
  initialGoal: goalFlag,
9921
10104
  initialAsk: askFlag,
10105
+ projectRoot,
9922
10106
  getSDDContext: () => {
9923
10107
  const { getActiveSDDContext: getActiveSDDContext2 } = (init_sdd(), __toCommonJS(sdd_exports));
9924
10108
  return getActiveSDDContext2();
@@ -10258,8 +10442,7 @@ var MultiAgentHost = class {
10258
10442
  }
10259
10443
  subagentToolRegistry(allow) {
10260
10444
  if (!allow || allow.length === 0) return this.deps.toolRegistry;
10261
- const cloneCtor = this.deps.toolRegistry.constructor;
10262
- const sub = new cloneCtor();
10445
+ const sub = this.deps.toolRegistry.clone();
10263
10446
  for (const t of this.filterTools(allow)) sub.register(t);
10264
10447
  return sub;
10265
10448
  }
@@ -12004,10 +12187,11 @@ Restart WrongStack to load or unload plugin code in this session.`;
12004
12187
  onBeforeExit: async () => {
12005
12188
  const { spawn: spawn3 } = await import('child_process');
12006
12189
  const cwd2 = projectRoot;
12007
- const statusResult = await new Promise((resolve4) => {
12190
+ const statusResult = await new Promise((resolve4, reject) => {
12008
12191
  const child = spawn3("git", ["status", "--porcelain"], { cwd: cwd2, stdio: ["ignore", "pipe", "pipe"] });
12009
12192
  let stdout = "";
12010
12193
  child.stdout?.on("data", (d) => stdout += d);
12194
+ child.on("error", reject);
12011
12195
  child.on("close", (code) => resolve4({ stdout, code: code ?? 0 }));
12012
12196
  });
12013
12197
  if (statusResult.stdout.trim().length > 0) {
@@ -12171,12 +12355,12 @@ if (isMain) {
12171
12355
  main(process.argv.slice(2)).then(
12172
12356
  (c) => {
12173
12357
  process.exitCode = c;
12174
- setTimeout(() => process.exit(c), 200).unref();
12358
+ setTimeout(() => process.exit(c), 500).unref();
12175
12359
  },
12176
12360
  (err) => {
12177
12361
  process.stderr.write((err instanceof Error ? err.stack : String(err)) + "\n");
12178
12362
  process.exitCode = 1;
12179
- setTimeout(() => process.exit(1), 200).unref();
12363
+ setTimeout(() => process.exit(1), 500).unref();
12180
12364
  }
12181
12365
  );
12182
12366
  }