@wrongstack/cli 0.63.4 → 0.66.13

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,12 +2,13 @@
2
2
  import * as path8 from 'path';
3
3
  import { join } from 'path';
4
4
  import * as fsp3 from 'fs/promises';
5
- import { color, writeErr, DefaultTaskStore, TaskTracker, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, renderTaskGraph, SpecVersioning, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
5
+ import { color, writeErr, DefaultTaskStore, TaskTracker, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, renderTaskGraph, SpecVersioning, DefaultSecretScrubber, atomicWrite, DefaultPathResolver, TOKENS, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, ToolRegistry, createContextManagerTool, EventBus, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, DefaultBrainArbiter, createDelegateTool, FLEET_ROSTER, createMcpControlTool, DefaultLogger, DefaultModelsRegistry, isStdinTTY, writeOut, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, ProviderRegistry, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, RecoveryLock, DefaultAttachmentStore, QueueStore, Context, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, loadPlugins, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, bootConfig as bootConfig$1, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, DefaultPluginAPI, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENTS_BY_PHASE, dispatchAgent, formatTodosList, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, emptyGoal, buildGoalPreamble, formatGoal, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, AGENT_CATALOG, matrixKeyKind, onResize, ERROR_CODES, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, InputBuilder, FsError } from '@wrongstack/core';
6
6
  import { createRequire } from 'module';
7
7
  import * as os2 from 'os';
8
8
  import os2__default from 'os';
9
9
  import * as crypto2 from 'crypto';
10
10
  import { randomUUID } from 'crypto';
11
+ import { findFreePort, createHttpServer, openBrowser, registerInstance, unregisterInstance } from '@wrongstack/webui/server';
11
12
  import { DefaultSecretVault, decryptConfigSecrets, encryptConfigSecrets, isSecretField } from '@wrongstack/core/security';
12
13
  import { WebSocketServer, WebSocket } from 'ws';
13
14
  import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
@@ -1694,13 +1695,63 @@ __export(webui_server_exports, {
1694
1695
  runWebUI: () => runWebUI
1695
1696
  });
1696
1697
  async function runWebUI(opts) {
1697
- const port = opts.port ?? 3457;
1698
+ const host = "127.0.0.1";
1699
+ const requestedWsPort = opts.port ?? 3457;
1700
+ const requestedHttpPort = opts.httpPort ?? 3456;
1701
+ const strictPort = process.env["WEBUI_STRICT_PORT"] === "1" || process.env["WEBUI_STRICT_PORT"] === "true";
1702
+ let httpPort = requestedHttpPort;
1703
+ let wsPort = requestedWsPort;
1704
+ if (!strictPort) {
1705
+ httpPort = await findFreePort(host, requestedHttpPort);
1706
+ wsPort = await findFreePort(host, requestedWsPort, { exclude: /* @__PURE__ */ new Set([httpPort]) });
1707
+ }
1708
+ const port = wsPort;
1709
+ const rateLimitMax = Number.parseInt(process.env["WEBUI_RATE_LIMIT"] ?? "0", 10);
1698
1710
  const clients = /* @__PURE__ */ new Map();
1711
+ const pendingConfirms = /* @__PURE__ */ new Map();
1699
1712
  const secretScrubber = new DefaultSecretScrubber();
1700
1713
  let abortController = null;
1701
1714
  const authToken = crypto2.randomBytes(16).toString("hex");
1702
- const wss = new WebSocketServer({ port, host: "127.0.0.1", maxPayload: 1 * 1024 * 1024 });
1703
- console.log(`[WebUI] WebSocket server starting on ws://127.0.0.1:${port}`);
1715
+ const wss = new WebSocketServer({ port, host, maxPayload: 1 * 1024 * 1024 });
1716
+ console.log(`[WebUI] WebSocket server starting on ws://${host}:${port}`);
1717
+ let httpServer = null;
1718
+ try {
1719
+ const requireFromHere = createRequire(import.meta.url);
1720
+ const serverEntry = requireFromHere.resolve("@wrongstack/webui/server");
1721
+ const distDir = path8.resolve(path8.dirname(serverEntry), "..");
1722
+ httpServer = createHttpServer({ host, distDir, wsPort });
1723
+ const openUrl = `http://${host}:${httpPort}`;
1724
+ httpServer.listen(httpPort, host, () => {
1725
+ console.log(
1726
+ `
1727
+ \u25B8 WebUI ready \u2014 open \x1B[1m${openUrl}\x1B[0m in your browser
1728
+ (same agent as this terminal \xB7 ws:${wsPort})
1729
+ `
1730
+ );
1731
+ if (opts.open) openBrowser(openUrl);
1732
+ });
1733
+ } catch (err) {
1734
+ console.warn(
1735
+ `[WebUI] Frontend not served (run \`pnpm --filter @wrongstack/webui build\`): ${err instanceof Error ? err.message : String(err)}. WS bridge still active on ws://${host}:${wsPort}.`
1736
+ );
1737
+ }
1738
+ const registryBaseDir = opts.globalConfigPath ? path8.dirname(opts.globalConfigPath) : void 0;
1739
+ if (opts.projectRoot) {
1740
+ void registerInstance(
1741
+ {
1742
+ pid: process.pid,
1743
+ httpPort,
1744
+ wsPort,
1745
+ host,
1746
+ projectRoot: opts.projectRoot,
1747
+ projectName: path8.basename(opts.projectRoot) || opts.projectRoot,
1748
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1749
+ url: `http://${host}:${httpPort}`
1750
+ },
1751
+ registryBaseDir
1752
+ ).catch(() => {
1753
+ });
1754
+ }
1704
1755
  const eventUnsubscribers = [];
1705
1756
  function setupEvents() {
1706
1757
  for (const unsub of eventUnsubscribers) unsub();
@@ -1794,6 +1845,88 @@ async function runWebUI(opts) {
1794
1845
  });
1795
1846
  })
1796
1847
  );
1848
+ eventUnsubscribers.push(
1849
+ opts.events.on("tool.confirm_needed", (e) => {
1850
+ const id = e.toolUseId ?? `confirm_${Date.now()}`;
1851
+ pendingConfirms.set(id, e.resolve);
1852
+ broadcast({
1853
+ type: "tool.confirm_needed",
1854
+ payload: {
1855
+ id,
1856
+ toolName: e.tool?.name ?? "unknown",
1857
+ input: secretScrubber.scrubObject(e.input),
1858
+ suggestedPattern: e.suggestedPattern
1859
+ }
1860
+ });
1861
+ })
1862
+ );
1863
+ const forwardSubagent = (kind, payload) => broadcast({ type: "subagent.event", payload: { kind, ...payload } });
1864
+ eventUnsubscribers.push(
1865
+ opts.events.on(
1866
+ "subagent.spawned",
1867
+ (e) => forwardSubagent("spawned", {
1868
+ subagentId: e.subagentId,
1869
+ taskId: e.taskId,
1870
+ name: e.name,
1871
+ provider: e.provider,
1872
+ model: e.model,
1873
+ description: e.description
1874
+ })
1875
+ ),
1876
+ opts.events.on(
1877
+ "subagent.task_started",
1878
+ (e) => forwardSubagent("task_started", {
1879
+ subagentId: e.subagentId,
1880
+ taskId: e.taskId,
1881
+ description: e.description
1882
+ })
1883
+ ),
1884
+ opts.events.on(
1885
+ "subagent.tool_executed",
1886
+ (e) => forwardSubagent("tool_executed", {
1887
+ subagentId: e.subagentId,
1888
+ toolName: e.name,
1889
+ durationMs: e.durationMs,
1890
+ ok: e.ok
1891
+ })
1892
+ ),
1893
+ opts.events.on(
1894
+ "subagent.iteration_summary",
1895
+ (e) => forwardSubagent("iteration_summary", {
1896
+ subagentId: e.subagentId,
1897
+ iteration: e.iteration,
1898
+ toolCalls: e.toolCalls,
1899
+ costUsd: e.costUsd,
1900
+ currentTool: e.currentTool
1901
+ })
1902
+ ),
1903
+ opts.events.on(
1904
+ "subagent.budget_extended",
1905
+ (e) => forwardSubagent("budget_extended", {
1906
+ subagentId: e.subagentId,
1907
+ totalExtensions: e.totalExtensions
1908
+ })
1909
+ ),
1910
+ opts.events.on(
1911
+ "subagent.ctx_pct",
1912
+ (e) => forwardSubagent("ctx_pct", {
1913
+ subagentId: e.subagentId,
1914
+ load: e.load,
1915
+ tokens: e.tokens,
1916
+ maxContext: e.maxContext
1917
+ })
1918
+ ),
1919
+ opts.events.on(
1920
+ "subagent.task_completed",
1921
+ (e) => forwardSubagent("task_completed", {
1922
+ subagentId: e.subagentId,
1923
+ status: e.status,
1924
+ iterations: e.iterations,
1925
+ toolCalls: e.toolCalls,
1926
+ error: e.error ? { kind: e.error.kind, message: e.error.message } : void 0
1927
+ })
1928
+ )
1929
+ );
1797
1930
  if (opts.subscribeEternalIteration) {
1798
1931
  eventUnsubscribers.push(
1799
1932
  opts.subscribeEternalIteration((entry) => {
@@ -1814,10 +1947,11 @@ async function runWebUI(opts) {
1814
1947
  );
1815
1948
  }
1816
1949
  }
1817
- return new Promise((resolve3) => {
1950
+ return new Promise((resolve4) => {
1818
1951
  wss.on("listening", () => {
1819
- console.log(`[WebUI] WebSocket server running on ws://127.0.0.1:${port}`);
1952
+ console.log(`[WebUI] WebSocket server running on ws://${host}:${port}`);
1820
1953
  setupEvents();
1954
+ opts.onListening?.({ httpPort, wsPort, host });
1821
1955
  });
1822
1956
  wss.on("connection", (ws, req2) => {
1823
1957
  const isLoopback = (hostname) => hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
@@ -1870,17 +2004,19 @@ async function runWebUI(opts) {
1870
2004
  let msgCount = 0;
1871
2005
  let windowResetAt = Date.now() + 6e4;
1872
2006
  ws.on("message", async (data) => {
1873
- const now = Date.now();
1874
- if (now > windowResetAt) {
1875
- msgCount = 0;
1876
- windowResetAt = now + 6e4;
1877
- }
1878
- if (++msgCount > 60) {
1879
- send(ws, {
1880
- type: "error",
1881
- payload: { phase: "rate_limit", message: "Too many messages. Please wait." }
1882
- });
1883
- return;
2007
+ if (rateLimitMax > 0) {
2008
+ const now = Date.now();
2009
+ if (now > windowResetAt) {
2010
+ msgCount = 0;
2011
+ windowResetAt = now + 6e4;
2012
+ }
2013
+ if (++msgCount > rateLimitMax) {
2014
+ send(ws, {
2015
+ type: "error",
2016
+ payload: { phase: "rate_limit", message: "Too many messages. Please wait." }
2017
+ });
2018
+ return;
2019
+ }
1884
2020
  }
1885
2021
  try {
1886
2022
  const msg = JSON.parse(data.toString());
@@ -1892,6 +2028,12 @@ async function runWebUI(opts) {
1892
2028
  ws.on("close", () => {
1893
2029
  console.log("[WebUI] Client disconnected");
1894
2030
  clients.delete(ws);
2031
+ if (clients.size === 0 && pendingConfirms.size > 0) {
2032
+ for (const [id, resolve5] of pendingConfirms) {
2033
+ resolve5("no");
2034
+ pendingConfirms.delete(id);
2035
+ }
2036
+ }
1895
2037
  });
1896
2038
  send(ws, {
1897
2039
  type: "session.start",
@@ -1913,9 +2055,12 @@ async function runWebUI(opts) {
1913
2055
  ws.close();
1914
2056
  }
1915
2057
  clients.clear();
2058
+ void unregisterInstance(process.pid, registryBaseDir).catch(() => {
2059
+ });
2060
+ httpServer?.close();
1916
2061
  wss.close(() => {
1917
2062
  console.log("[WebUI] Server stopped");
1918
- resolve3();
2063
+ resolve4();
1919
2064
  });
1920
2065
  }
1921
2066
  process.on("SIGINT", shutdown);
@@ -1940,6 +2085,15 @@ async function runWebUI(opts) {
1940
2085
  case "ping":
1941
2086
  send(ws, { type: "pong", payload: {} });
1942
2087
  break;
2088
+ case "tool.confirm_result": {
2089
+ const { id, decision } = msg.payload;
2090
+ const resolve4 = pendingConfirms.get(id);
2091
+ if (resolve4) {
2092
+ pendingConfirms.delete(id);
2093
+ resolve4(decision);
2094
+ }
2095
+ break;
2096
+ }
1943
2097
  case "providers.list":
1944
2098
  await handleProvidersList(ws);
1945
2099
  break;
@@ -2396,6 +2550,7 @@ function positiveNumber(value) {
2396
2550
  var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
2397
2551
  "yolo",
2398
2552
  "yolo-destructive",
2553
+ "confirm-destructive",
2399
2554
  "force-all-yolo",
2400
2555
  "verbose",
2401
2556
  "trace",
@@ -2414,6 +2569,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
2414
2569
  "prompt",
2415
2570
  "metrics",
2416
2571
  "webui",
2572
+ "open",
2417
2573
  "no-check",
2418
2574
  "no-models-refresh",
2419
2575
  "director",
@@ -6529,13 +6685,13 @@ function buildYoloCommand(opts) {
6529
6685
  description: "Toggle or query YOLO (auto-approve) mode.",
6530
6686
  help: [
6531
6687
  "Usage:",
6532
- " /yolo Show current YOLO status",
6533
- " /yolo on Enable YOLO mode (auto-approve normal project work)",
6534
- " /yolo off Disable YOLO mode (restore permission prompts)",
6535
- " /yolo toggle Toggle YOLO mode",
6688
+ " /yolo Show current YOLO status",
6689
+ " /yolo on Enable YOLO mode (auto-approve all tool calls)",
6690
+ " /yolo off Disable YOLO mode (restore permission prompts)",
6691
+ " /yolo destructive Toggle destructive confirmation gate (YOLO mode only)",
6536
6692
  "",
6537
- "YOLO mode auto-approves normal in-project tool calls, including simple shell commands.",
6538
- "Clearly destructive calls may still ask unless --yolo-destructive is enabled."
6693
+ "YOLO mode auto-approves everything, including destructive calls.",
6694
+ "Use /yolo destructive to re-enable confirmation for risky operations."
6539
6695
  ].join("\n"),
6540
6696
  async run(args) {
6541
6697
  const arg = args.trim().toLowerCase();
@@ -6717,10 +6873,10 @@ async function runProjectCheck(opts) {
6717
6873
  if (answer2 === "y" || answer2 === "yes") {
6718
6874
  try {
6719
6875
  const { spawn: spawn3 } = await import('child_process');
6720
- await new Promise((resolve3, reject) => {
6876
+ await new Promise((resolve4, reject) => {
6721
6877
  const child = spawn3("git", ["init"], { cwd: projectRoot });
6722
6878
  child.on("error", reject);
6723
- child.on("close", (code) => code === 0 ? resolve3() : reject(new Error(`git init failed with ${code}`)));
6879
+ child.on("close", (code) => code === 0 ? resolve4() : reject(new Error(`git init failed with ${code}`)));
6724
6880
  });
6725
6881
  renderer.write(` ${color.green("\u2713")} Git repository initialized
6726
6882
  `);
@@ -6864,7 +7020,7 @@ var ReadlineInputReader = class {
6864
7020
  async readLine(prompt) {
6865
7021
  if (this.history.length === 0) await this.loadHistory();
6866
7022
  while (this.pending) {
6867
- await new Promise((resolve3) => setTimeout(resolve3, 50));
7023
+ await new Promise((resolve4) => setTimeout(resolve4, 50));
6868
7024
  }
6869
7025
  this.pending = true;
6870
7026
  try {
@@ -6874,15 +7030,15 @@ var ReadlineInputReader = class {
6874
7030
  this.rl = void 0;
6875
7031
  }
6876
7032
  const fresh = this.ensure();
6877
- return new Promise((resolve3) => {
7033
+ return new Promise((resolve4) => {
6878
7034
  fresh.question(prompt ?? "> ", (line) => {
6879
7035
  if (line.trim()) {
6880
7036
  this.history.push(line);
6881
7037
  void this.saveHistory();
6882
7038
  }
6883
- resolve3(line);
7039
+ resolve4(line);
6884
7040
  });
6885
- fresh.once("close", () => resolve3(""));
7041
+ fresh.once("close", () => resolve4(""));
6886
7042
  }).then((result) => {
6887
7043
  this.rl?.close();
6888
7044
  this.rl = void 0;
@@ -6894,7 +7050,7 @@ var ReadlineInputReader = class {
6894
7050
  }
6895
7051
  async readKey(prompt, options) {
6896
7052
  writeOut(prompt);
6897
- return new Promise((resolve3) => {
7053
+ return new Promise((resolve4) => {
6898
7054
  const stdin = process.stdin;
6899
7055
  const wasRaw = stdin.isRaw;
6900
7056
  const wasPaused = stdin.isPaused();
@@ -6905,7 +7061,7 @@ var ReadlineInputReader = class {
6905
7061
  if (key === "") {
6906
7062
  cleanup();
6907
7063
  writeOut("\n");
6908
- resolve3("");
7064
+ resolve4("");
6909
7065
  return;
6910
7066
  }
6911
7067
  const opt = options.find(
@@ -6915,12 +7071,12 @@ var ReadlineInputReader = class {
6915
7071
  cleanup();
6916
7072
  writeOut(`${opt.key}
6917
7073
  `);
6918
- resolve3(opt.value);
7074
+ resolve4(opt.value);
6919
7075
  }
6920
7076
  };
6921
7077
  const onClose = () => {
6922
7078
  cleanup();
6923
- resolve3("");
7079
+ resolve4("");
6924
7080
  };
6925
7081
  const cleanup = () => {
6926
7082
  stdin.off("data", onData);
@@ -6948,7 +7104,7 @@ var ReadlineInputReader = class {
6948
7104
  this.rl?.close();
6949
7105
  this.rl = void 0;
6950
7106
  writeOut(prompt);
6951
- return new Promise((resolve3) => {
7107
+ return new Promise((resolve4) => {
6952
7108
  let buf = "";
6953
7109
  const wasRaw = stdin.isRaw;
6954
7110
  setRawMode(stdin, true);
@@ -6966,7 +7122,7 @@ var ReadlineInputReader = class {
6966
7122
  cleanup();
6967
7123
  writeOut(` ${dim(`[${buf.length} chars]`)}
6968
7124
  `);
6969
- resolve3(buf);
7125
+ resolve4(buf);
6970
7126
  return;
6971
7127
  }
6972
7128
  if (ch === "") {
@@ -8870,8 +9026,9 @@ var updateCmd = async (args, deps) => {
8870
9026
  deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
8871
9027
  `);
8872
9028
  try {
8873
- const result = await new Promise((resolve3, reject) => {
8874
- const child = spawn("npm", ["install", "-g", "wrongstack@latest"], {
9029
+ const result = await new Promise((resolve4, reject) => {
9030
+ const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
9031
+ const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
8875
9032
  cwd,
8876
9033
  stdio: "pipe"
8877
9034
  });
@@ -8880,7 +9037,7 @@ var updateCmd = async (args, deps) => {
8880
9037
  _stderr += d;
8881
9038
  });
8882
9039
  child.on("error", reject);
8883
- child.on("close", (code) => resolve3({ code: code ?? 0 }));
9040
+ child.on("close", (code) => resolve4({ code: code ?? 0 }));
8884
9041
  });
8885
9042
  if (result.code === 0) {
8886
9043
  deps.renderer.write(`
@@ -9337,8 +9494,8 @@ async function serveMcpStdio(deps) {
9337
9494
  log(
9338
9495
  `wrongstack MCP server ready at ${handle2.url} \u2014 exposing ${allowed.length} tool(s) (${mode})${token ? " [token auth]" : ""}.`
9339
9496
  );
9340
- await new Promise((resolve3) => {
9341
- const stop = () => resolve3();
9497
+ await new Promise((resolve4) => {
9498
+ const stop = () => resolve4();
9342
9499
  process.once("SIGINT", stop);
9343
9500
  process.once("SIGTERM", stop);
9344
9501
  });
@@ -10700,10 +10857,13 @@ var helpCmd = async (_args, deps) => {
10700
10857
  " wstack version Print version",
10701
10858
  "",
10702
10859
  color.bold("Common flags"),
10703
- " --yolo Auto-approve normal in-project tool calls",
10704
- " --yolo-destructive Also auto-approve clearly destructive YOLO-gated calls",
10705
- " --force-all-yolo Deprecated alias for --yolo-destructive",
10860
+ " --yolo Auto-approve all tool calls (including destructive)",
10861
+ " --confirm-destructive In YOLO mode, still prompt for destructive operations",
10862
+ " --yolo-destructive Deprecated \u2014 YOLO now auto-approves everything by default",
10706
10863
  " --tui / --no-tui Force or disable TUI mode",
10864
+ " --webui [--port <n>] [--open] Serve the browser UI + WS bridge (prints a URL,",
10865
+ " --open pops the browser; shares this terminal's",
10866
+ " agent; auto-picks free ports)",
10707
10867
  ' --eternal "<mission>" Start an eternal-autonomy loop',
10708
10868
  " --no-hints Hide launch hints"
10709
10869
  ];
@@ -10932,6 +11092,10 @@ async function boot(argv) {
10932
11092
  return 2;
10933
11093
  }
10934
11094
  }
11095
+ if (flags["webui"]) {
11096
+ flags["tui"] = false;
11097
+ flags["no-tui"] = true;
11098
+ }
10935
11099
  if (isInteractiveTTY) {
10936
11100
  let modePinned;
10937
11101
  if (flags["no-tui"]) modePinned = "repl";
@@ -11370,7 +11534,7 @@ async function runRepl(opts) {
11370
11534
  `[eternal] ${err instanceof Error ? err.message : String(err)}`
11371
11535
  );
11372
11536
  }
11373
- await new Promise((resolve3) => setTimeout(resolve3, 250));
11537
+ await new Promise((resolve4) => setTimeout(resolve4, 250));
11374
11538
  continue;
11375
11539
  }
11376
11540
  } else if (opts.getAutonomy?.() === "eternal-parallel") {
@@ -11416,7 +11580,7 @@ async function runRepl(opts) {
11416
11580
  `[parallel] ${err instanceof Error ? err.message : String(err)}`
11417
11581
  );
11418
11582
  }
11419
- await new Promise((resolve3) => setTimeout(resolve3, 250));
11583
+ await new Promise((resolve4) => setTimeout(resolve4, 250));
11420
11584
  continue;
11421
11585
  }
11422
11586
  }
@@ -12066,7 +12230,7 @@ async function execute(deps) {
12066
12230
  ) + "\n"
12067
12231
  );
12068
12232
  }
12069
- } else if (flags.tui && !flags["no-tui"]) {
12233
+ } else if (flags.tui && !flags["no-tui"] && !flags.webui) {
12070
12234
  agent.disableInteractiveConfirmation();
12071
12235
  const { runTui } = await import('@wrongstack/tui');
12072
12236
  renderer.setSilent(true);
@@ -12255,12 +12419,15 @@ async function execute(deps) {
12255
12419
  renderer.setSilent(false);
12256
12420
  }
12257
12421
  } else if (flags.webui) {
12422
+ agent.disableInteractiveConfirmation();
12258
12423
  const { runWebUI: runWebUI2 } = await Promise.resolve().then(() => (init_webui_server(), webui_server_exports));
12259
12424
  const webuiPromise = runWebUI2({
12260
12425
  agent,
12261
12426
  events,
12262
12427
  session,
12263
12428
  port: Number.parseInt(String(flags.port ?? "3457"), 10),
12429
+ projectRoot,
12430
+ open: !!flags.open,
12264
12431
  modelsRegistry,
12265
12432
  globalConfigPath: wpaths.globalConfig,
12266
12433
  subscribeEternalIteration
@@ -13191,7 +13358,7 @@ function samplePaths(set) {
13191
13358
  }
13192
13359
  var WORKTREE_PHASE_CONCURRENCY = 4;
13193
13360
  function gitText(args, cwd) {
13194
- return new Promise((resolve3) => {
13361
+ return new Promise((resolve4) => {
13195
13362
  let out = "";
13196
13363
  const child = spawn("git", args, {
13197
13364
  cwd,
@@ -13204,8 +13371,8 @@ function gitText(args, cwd) {
13204
13371
  child.stderr?.on("data", (c) => {
13205
13372
  out += c.toString();
13206
13373
  });
13207
- child.on("error", () => resolve3({ code: 1, out }));
13208
- child.on("close", (code) => resolve3({ code: code ?? 1, out: out.trim() }));
13374
+ child.on("error", () => resolve4({ code: 1, out }));
13375
+ child.on("close", (code) => resolve4({ code: code ?? 1, out: out.trim() }));
13209
13376
  });
13210
13377
  }
13211
13378
  async function isGitRepo(cwd) {
@@ -13213,7 +13380,7 @@ async function isGitRepo(cwd) {
13213
13380
  return code === 0 && out.trim() === "true";
13214
13381
  }
13215
13382
  function runCmd(cmd, args, cwd, shell = false) {
13216
- return new Promise((resolve3) => {
13383
+ return new Promise((resolve4) => {
13217
13384
  let out = "";
13218
13385
  const child = spawn(cmd, args, {
13219
13386
  cwd,
@@ -13227,8 +13394,8 @@ function runCmd(cmd, args, cwd, shell = false) {
13227
13394
  child.stderr?.on("data", (c) => {
13228
13395
  out += c.toString();
13229
13396
  });
13230
- child.on("error", (e) => resolve3({ code: 1, out: `${out}${String(e)}` }));
13231
- child.on("close", (code) => resolve3({ code: code ?? 1, out: out.trim() }));
13397
+ child.on("error", (e) => resolve4({ code: 1, out: `${out}${String(e)}` }));
13398
+ child.on("close", (code) => resolve4({ code: code ?? 1, out: out.trim() }));
13232
13399
  });
13233
13400
  }
13234
13401
  function detectPackageManager2(root) {
@@ -13621,13 +13788,6 @@ function renderProgress3(ratio, width) {
13621
13788
  const capped = Math.min(width, filled);
13622
13789
  return FILLED2.repeat(capped) + EMPTY2.repeat(width - capped);
13623
13790
  }
13624
- var createSessionEventBridge = (_writer, level) => ({
13625
- append: async (_e) => {
13626
- },
13627
- level: level ?? "standard",
13628
- allows: () => true
13629
- });
13630
- var resolveAuditLevel = (cfg) => cfg?.session?.auditLevel ?? "standard";
13631
13791
  function setupPipelines(params) {
13632
13792
  const { events, logger } = params;
13633
13793
  const pipelines = createDefaultPipelines();
@@ -14316,21 +14476,6 @@ async function launchEternalFromFlag(deps) {
14316
14476
  }
14317
14477
 
14318
14478
  // src/index.ts
14319
- var createSessionEventBridge2 = (_writer, level, _opts) => ({
14320
- append: async (_e) => {
14321
- },
14322
- level: level ?? "standard",
14323
- allows: () => true
14324
- });
14325
- var resolveAuditLevel2 = (cfg) => cfg?.session?.auditLevel ?? "standard";
14326
- var resolveSessionLoggingConfig = (cfg) => ({
14327
- auditLevel: resolveAuditLevel2(cfg),
14328
- sampling: {
14329
- toolProgress: {
14330
- sampleRate: cfg?.session?.sampling?.toolProgress?.sampleRate ?? 8
14331
- }
14332
- }
14333
- });
14334
14479
  async function main(argv) {
14335
14480
  const ctx = await boot(argv);
14336
14481
  if (typeof ctx === "number") return ctx;
@@ -14358,6 +14503,7 @@ async function main(argv) {
14358
14503
  permission: {
14359
14504
  yolo: config.yolo,
14360
14505
  yoloDestructive: flags["yolo-destructive"] === true || flags["force-all-yolo"] === true,
14506
+ confirmDestructive: flags["confirm-destructive"] === true,
14361
14507
  promptDelegate: makePromptDelegate(reader)
14362
14508
  },
14363
14509
  compactor: {
@@ -14548,9 +14694,13 @@ async function main(argv) {
14548
14694
  const detachTodosCheckpoint = sessResult.detachTodosCheckpoint;
14549
14695
  const priorFleetState = sessResult.priorFleetState;
14550
14696
  const sessionConfig = resolveSessionLoggingConfig(config);
14551
- const sessionBridge = createSessionEventBridge2(
14697
+ const sessionBridge = createSessionEventBridge(
14552
14698
  session,
14553
- sessionConfig.auditLevel);
14699
+ sessionConfig.auditLevel,
14700
+ {
14701
+ sampling: sessionConfig.sampling
14702
+ }
14703
+ );
14554
14704
  const stats = new SessionStats(events, tokenCounter);
14555
14705
  const errorRing = [];
14556
14706
  events.on("error", (e) => {
@@ -15460,7 +15610,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
15460
15610
  const { spawn: spawn3 } = await import('child_process');
15461
15611
  const cwd2 = projectRoot;
15462
15612
  const statusResult = await new Promise(
15463
- (resolve3, reject) => {
15613
+ (resolve4, reject) => {
15464
15614
  const child = spawn3("git", ["status", "--porcelain"], {
15465
15615
  cwd: cwd2,
15466
15616
  stdio: ["ignore", "pipe", "pipe"]
@@ -15470,7 +15620,7 @@ Restart WrongStack to load or unload plugin code in this session.`;
15470
15620
  stdout += d;
15471
15621
  });
15472
15622
  child.on("error", reject);
15473
- child.on("close", (code) => resolve3({ stdout, code: code ?? 0 }));
15623
+ child.on("close", (code) => resolve4({ stdout, code: code ?? 0 }));
15474
15624
  }
15475
15625
  );
15476
15626
  if (statusResult.stdout.trim().length > 0) {