@wrongstack/cli 0.236.0 → 0.250.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
@@ -2,7 +2,7 @@
2
2
  import * as fsp5 from 'fs/promises';
3
3
  import * as path24 from 'path';
4
4
  import { join } from 'path';
5
- import { color, writeErr, expectDefined, atomicWrite, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, DefaultSecretScrubber, resolveProjectDir, GlobalMailbox, recentTextTurns, enhanceUserPrompt, projectSlug, wstackGlobalRoot, mutateTasks, TOKENS, DEFAULT_CONTEXT_WINDOW_MODE_ID, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, DefaultPathResolver, EventBus, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, SpecVersioning, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, noOpVault, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, setQueuedMessagesSnapshot, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore as DefaultSessionStore$1, DefaultPluginAPI, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, getContextWindowMode, AGENT_CATALOG, dispatchAgent, formatTodosList, loadTasks, formatTaskList, formatTaskProgress, emptyPlan, addPlanItem, savePlan, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, FsError, ConfigError, InputBuilder, estimateMessageTokens, AGENTS_BY_PHASE, resolveMailboxIdentity } from '@wrongstack/core';
5
+ import { color, writeErr, expectDefined, atomicWrite, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, DefaultSecretScrubber, resolveProjectDir, GlobalMailbox, recentTextTurns, enhanceUserPrompt, projectSlug, wstackGlobalRoot, mutateTasks, TOKENS, DEFAULT_CONTEXT_WINDOW_MODE_ID, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, DefaultPathResolver, EventBus, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, SpecVersioning, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, noOpVault, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, setQueuedMessagesSnapshot, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore as DefaultSessionStore$1, truncate, DefaultPluginAPI, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, getContextWindowMode, AGENT_CATALOG, dispatchAgent, formatTodosList, loadTasks, formatTaskList, formatTaskProgress, emptyPlan, addPlanItem, savePlan, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, FsError, ConfigError, InputBuilder, estimateMessageTokens, AGENTS_BY_PHASE, resolveMailboxIdentity } from '@wrongstack/core';
6
6
  import { decryptConfigSecrets, encryptConfigSecrets, DefaultSecretVault, isSecretField } from '@wrongstack/core/security';
7
7
  import * as crypto2 from 'crypto';
8
8
  import { createHash, randomUUID } from 'crypto';
@@ -16,8 +16,9 @@ import { spawn, exec, execFileSync } from 'child_process';
16
16
  import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
17
17
  import { capabilitiesFor, buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';
18
18
  import { createDefaultContainer, routeImagesForModel, readClipboardImage } from '@wrongstack/runtime';
19
- import { builtinToolsPack, rememberTool, forgetTool, searchMemoryTool, relatedMemoryTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes } from '@wrongstack/tools';
19
+ import { builtinToolsPack, rememberTool, forgetTool, searchMemoryTool, relatedMemoryTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes, shutdownCodebaseIndexHost, resetIndexCircuitBreaker } from '@wrongstack/tools';
20
20
  import { fileURLToPath } from 'url';
21
+ import { parseNextSteps } from '@wrongstack/tui';
21
22
  import * as readline from 'readline';
22
23
  import * as fs18 from 'fs';
23
24
  import { writeFileSync, existsSync, readFileSync } from 'fs';
@@ -4376,7 +4377,7 @@ async function runWebUI(opts) {
4376
4377
  const { spawn: spawn6 } = await import('child_process');
4377
4378
  const platform3 = process.platform;
4378
4379
  const launch = (cmd, args, onError) => {
4379
- const child = spawn6(cmd, args, { detached: true, stdio: "ignore" });
4380
+ const child = spawn6(cmd, args, { detached: true, stdio: "ignore", windowsHide: true });
4380
4381
  child.on("error", () => onError?.());
4381
4382
  child.unref();
4382
4383
  };
@@ -5840,6 +5841,7 @@ function buildClearCommand(opts) {
5840
5841
  }
5841
5842
  await opts.memoryStore?.clear();
5842
5843
  opts.onClear?.();
5844
+ await opts.onNewSession?.();
5843
5845
  opts.renderer.clear();
5844
5846
  const msg = "Session cleared (context, memory, and history reset).";
5845
5847
  opts.renderer.writeInfo(msg);
@@ -5868,6 +5870,7 @@ function buildCodebaseReindexCommand(opts) {
5868
5870
  opts.renderer.write(color.dim(`${force ? "Rebuilding" : "Reindexing"} codebase index\u2026
5869
5871
  `));
5870
5872
  try {
5873
+ resetIndexCircuitBreaker();
5871
5874
  const r = await runStartupIndex({ projectRoot: opts.projectRoot, force });
5872
5875
  const summary = `${color.green("\u2713")} codebase index ${force ? "rebuilt" : "updated"} ` + color.dim(`\u2014 ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`) + (r.errors.length ? `
5873
5876
  ${color.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
@@ -6051,10 +6054,6 @@ function summarise(ev) {
6051
6054
  }
6052
6055
  }
6053
6056
  }
6054
- function truncate(s, n) {
6055
- if (s.length <= n) return s;
6056
- return `${s.slice(0, n - 1)}\u2026`;
6057
- }
6058
6057
  function helpCommand() {
6059
6058
  const lines = [
6060
6059
  color.bold("/collab \u2014 live collaboration (read-only observers)"),
@@ -6638,6 +6637,15 @@ function buildStatsCommand(opts) {
6638
6637
  }
6639
6638
  };
6640
6639
  }
6640
+
6641
+ // src/utils/delay-format.ts
6642
+ function formatDelay(ms) {
6643
+ if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
6644
+ if (ms === 0) return "disabled";
6645
+ return `${Math.round(ms / 1e3)}s`;
6646
+ }
6647
+
6648
+ // src/settings-menu.ts
6641
6649
  function resolvePersistPath(deps) {
6642
6650
  const scope = deps.configStore.get().configScope;
6643
6651
  if (scope === "project" && deps.inProjectConfigPath) {
@@ -11227,12 +11235,9 @@ function buildSuggestCommand(opts) {
11227
11235
  };
11228
11236
  }
11229
11237
  function parseSuggestions(raw) {
11230
- const lines = raw.split("\n").map((l) => l.trim()).filter(Boolean);
11231
- const numbered = lines.filter((l) => /^\d+[.)]\s/.test(l)).map((l) => l.replace(/^\d+[.)]\s*/, "").trim());
11232
- if (numbered.length > 0) return numbered.slice(0, 5);
11233
- const bullets = lines.filter((l) => /^[-*•]\s/.test(l)).map((l) => l.replace(/^[-*•]\s*/, "").trim());
11234
- if (bullets.length > 0) return bullets.slice(0, 5);
11235
- return lines.filter((l) => l.length > 10 && !l.startsWith("#") && !l.startsWith("```")).slice(0, 5);
11238
+ const { texts } = parseNextSteps(raw, false, false);
11239
+ if (texts.length > 0) return texts;
11240
+ return raw.split("\n").map((l) => l.trim()).filter((l) => l.length > 10 && !l.startsWith("#") && !l.startsWith("```")).slice(0, 5);
11236
11241
  }
11237
11242
  function generateHeuristicSuggestions(opts) {
11238
11243
  const suggestions = [];
@@ -11282,11 +11287,6 @@ function formatSuggestions(suggestions) {
11282
11287
  return lines.join("\n");
11283
11288
  }
11284
11289
  init_helpers();
11285
- function formatDelay(ms) {
11286
- if (ms >= 6e4) return `${Math.round(ms / 6e4)}m`;
11287
- if (ms === 0) return "disabled";
11288
- return `${Math.round(ms / 1e3)}s`;
11289
- }
11290
11290
  function buildSettingsCommand(opts) {
11291
11291
  const help = [
11292
11292
  "Usage:",
@@ -13068,7 +13068,7 @@ function buildMouseCommand(_opts) {
13068
13068
  }
13069
13069
  async function runGit(args, cwd) {
13070
13070
  return new Promise((resolve9) => {
13071
- const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], signal: AbortSignal.timeout(1e4) });
13071
+ const child = spawn("git", args, { cwd, stdio: ["ignore", "pipe", "pipe"], signal: AbortSignal.timeout(1e4), windowsHide: true });
13072
13072
  let stdout = "";
13073
13073
  child.stdout?.on("data", (d) => {
13074
13074
  stdout += d;
@@ -13315,7 +13315,7 @@ async function runProjectCheck(opts) {
13315
13315
  try {
13316
13316
  const { spawn: spawn6 } = await import('child_process');
13317
13317
  await new Promise((resolve9, reject) => {
13318
- const child = spawn6("git", ["init"], { cwd, signal: AbortSignal.timeout(1e4) });
13318
+ const child = spawn6("git", ["init"], { cwd, signal: AbortSignal.timeout(1e4), windowsHide: true });
13319
13319
  child.on("error", reject);
13320
13320
  child.on("close", (code) => code === 0 ? resolve9() : reject(new Error(`git init failed with ${code}`)));
13321
13321
  });
@@ -15924,7 +15924,8 @@ var updateCmd = async (args, deps) => {
15924
15924
  const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
15925
15925
  cwd,
15926
15926
  stdio: "pipe",
15927
- signal: AbortSignal.timeout(12e4)
15927
+ signal: AbortSignal.timeout(12e4),
15928
+ windowsHide: true
15928
15929
  });
15929
15930
  let _stderr = "";
15930
15931
  child.stderr?.on("data", (d) => {
@@ -18965,7 +18966,8 @@ async function checkGitInCwd(opts) {
18965
18966
  await new Promise((resolve9, reject) => {
18966
18967
  const child = spawn6("git", ["init"], {
18967
18968
  cwd,
18968
- signal: AbortSignal.timeout(1e4)
18969
+ signal: AbortSignal.timeout(1e4),
18970
+ windowsHide: true
18969
18971
  });
18970
18972
  child.on("error", reject);
18971
18973
  child.on(
@@ -19319,21 +19321,8 @@ async function predictNextTasks(input, opts) {
19319
19321
  init_sdd();
19320
19322
  var DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED = 50;
19321
19323
  function parseSuggestionsFromOutput(finalText) {
19322
- const patterns = [
19323
- /💡\s*Next\s+steps?\s*\n((?:\d+\.\s+.+\n?)+)/i,
19324
- /##?\s*Next\s+steps?\s*\n((?:\d+\.\s+.+\n?)+)/i,
19325
- /Next\s+steps?\s*\n((?:\d+\.\s+.+\n?)+)/i
19326
- ];
19327
- for (const pat of patterns) {
19328
- const m = pat.exec(finalText);
19329
- if (m?.[1]) {
19330
- const block = m[1].trim();
19331
- const lines = block.split("\n").filter(Boolean);
19332
- const suggestions = lines.map((l) => l.replace(/^\d+\.\s*/, "").trim()).filter((s) => s.length > 3);
19333
- if (suggestions.length > 0) return suggestions.slice(0, 5);
19334
- }
19335
- }
19336
- return null;
19324
+ const { texts } = parseNextSteps(finalText, false);
19325
+ return texts.length > 0 ? texts : null;
19337
19326
  }
19338
19327
  async function runRepl(opts) {
19339
19328
  if (opts.banner !== false) printBanner(opts.renderer, opts.projectName);
@@ -20519,6 +20508,9 @@ async function execute(deps) {
20519
20508
  },
20520
20509
  // Retrieve current suggestions for next-steps auto-submit countdown.
20521
20510
  getSuggestions: () => getSuggestions2?.() ?? [],
20511
+ // Store parsed next steps so the /next command and auto-submit countdown
20512
+ // can access them (entry.tsx parses from rendered messages).
20513
+ setSuggestions,
20522
20514
  getEternalEngine,
20523
20515
  subscribeEternalIteration,
20524
20516
  subscribeEternalStage,
@@ -20703,6 +20695,9 @@ async function execute(deps) {
20703
20695
  confirmExit: config.autonomy?.["confirmExit"] ?? true,
20704
20696
  director,
20705
20697
  fleetRoster,
20698
+ // /clear: signal the TUI to wipe entries and reset fleet/leader stats
20699
+ // AND bump the context chip version — so the display reflects a
20700
+ // completely fresh session after the backend has been cleared.
20706
20701
  onClearHistory: (dispatch) => {
20707
20702
  dispatch({ type: "clearHistory" });
20708
20703
  dispatch({ type: "resetContextChip" });
@@ -21894,10 +21889,7 @@ function makeConfirmAwaiter(reader) {
21894
21889
  function stringifyInput(input) {
21895
21890
  if (!input || typeof input !== "object") return "";
21896
21891
  const obj = input;
21897
- return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string").map(([k, v]) => `${k}: ${truncate2(JSON.stringify(v), 80)}`).join(" ");
21898
- }
21899
- function truncate2(s, max) {
21900
- return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
21892
+ return Object.entries(obj).filter(([k]) => k !== "content" && k !== "new_string").map(([k, v]) => `${k}: ${truncate(JSON.stringify(v), 80)}`).join(" ");
21901
21893
  }
21902
21894
  function hasDiff(input) {
21903
21895
  return Boolean(
@@ -22075,7 +22067,8 @@ function gitText(args, cwd) {
22075
22067
  cwd,
22076
22068
  env: buildChildEnv(),
22077
22069
  stdio: ["ignore", "pipe", "pipe"],
22078
- signal: AbortSignal.timeout(1e4)
22070
+ signal: AbortSignal.timeout(1e4),
22071
+ windowsHide: true
22079
22072
  });
22080
22073
  } catch (err) {
22081
22074
  reject(err);
@@ -22141,7 +22134,8 @@ function runCmd(cmd, args, cwd, shell = false) {
22141
22134
  // Pass through explicitly — allowlist validation already runs above,
22142
22135
  // so the caller's shell preference is authoritative.
22143
22136
  shell,
22144
- signal: AbortSignal.timeout(3e4)
22137
+ signal: AbortSignal.timeout(3e4),
22138
+ windowsHide: true
22145
22139
  });
22146
22140
  } catch (err) {
22147
22141
  reject(err);
@@ -22889,7 +22883,7 @@ async function setupCodebaseIndexing(deps) {
22889
22883
  const debounceMs = idx.debounceMs ?? 400;
22890
22884
  const onError = (err) => logger.debug(`codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`);
22891
22885
  if (idx.onSessionStart) {
22892
- void runStartupIndex({ projectRoot, signal: context.signal }).then((r) => {
22886
+ void runStartupIndex({ projectRoot, signal: context.signal, timeoutMs: idx.indexTimeoutMs }).then((r) => {
22893
22887
  logger.info(
22894
22888
  `codebase index ready: ${r.symbolsIndexed} symbols \xB7 ${r.filesIndexed} files \xB7 ${r.durationMs}ms`
22895
22889
  );
@@ -22948,6 +22942,7 @@ async function setupCodebaseIndexing(deps) {
22948
22942
  } catch {
22949
22943
  }
22950
22944
  cancelPendingReindexes();
22945
+ shutdownCodebaseIndexHost();
22951
22946
  };
22952
22947
  }
22953
22948
  function createApi(ownerName, base) {
@@ -23223,7 +23218,9 @@ async function setupSession(params) {
23223
23218
  });
23224
23219
  }
23225
23220
  const sessionRef = { current: session };
23226
- await recoveryLock.write(session?.id).catch(() => void 0);
23221
+ await recoveryLock.write(session?.id).catch((err) => {
23222
+ console.error(JSON.stringify({ level: "error", event: "recovery_lock_write_failed", error: String(err), sessionId: session?.id }));
23223
+ });
23227
23224
  const attachments = new DefaultAttachmentStore({
23228
23225
  spoolDir: path24.join(wpaths.projectSessions, session?.id, "attachments")
23229
23226
  });
@@ -23664,7 +23661,8 @@ async function main(argv) {
23664
23661
  gitBranch = execSync("git rev-parse --abbrev-ref HEAD", {
23665
23662
  cwd: projectRoot,
23666
23663
  timeout: 3e3,
23667
- stdio: ["ignore", "pipe", "ignore"]
23664
+ stdio: ["ignore", "pipe", "ignore"],
23665
+ windowsHide: true
23668
23666
  }).toString().trim();
23669
23667
  if (gitBranch === "HEAD") gitBranch = void 0;
23670
23668
  } catch {
@@ -24872,7 +24870,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
24872
24870
  const child = spawn("git", ["status", "--porcelain"], {
24873
24871
  cwd: cwd2,
24874
24872
  stdio: ["ignore", "pipe", "pipe"],
24875
- signal: AbortSignal.timeout(5e3)
24873
+ signal: AbortSignal.timeout(5e3),
24874
+ windowsHide: true
24876
24875
  });
24877
24876
  let stdout = "";
24878
24877
  child.stdout?.on("data", (d) => {
@@ -24899,6 +24898,8 @@ Restart WrongStack to load or unload plugin code in this session.`;
24899
24898
  } catch {
24900
24899
  }
24901
24900
  },
24901
+ onNewSession: async () => {
24902
+ },
24902
24903
  onDiag: () => {
24903
24904
  const u = tokenCounter.total();
24904
24905
  const cost = tokenCounter.estimateCost();