@wrongstack/cli 0.282.1 → 0.282.2

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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { CODEX_MODELS, color, ToolCapabilities, PHASE_EVENT_NAMES, readBundledInstructionText, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, ConfigError, resolveHqDataDir, ensureHqFirstRunAuthFile, DEFAULT_HQ_REDACTION_POLICY, createHqPersistence, HqCommandAuditLog, HqAlertEngine, toAlertMessage, validateHqCommand, watchHqAuthFile, parseHqFrame, HQ_PROTOCOL_VERSION, parseHqEventPayload, scrubAndTruncateHqPreview, FetchError, removeColumn, addColumn, getTask, removeTask, getBoard, assignTask, updateTaskAssignment, listBoards, updateGoalMetricOnTask, addGoalMetricToTask, releaseTaskClaim, claimReadyTask, getTaskChain, setTaskChain, copyTaskToBoard, transferTaskToBoard, moveTask, updateTask, mergeTasks, splitTask, addTask, syncBoardFromTaskGraph, deserializeTaskGraph, exportBoardToTaskGraph, serializeTaskGraph, getKanbanOrchestrationSnapshot, listReadyTasks, generateBoardFromDescription, createBoard, parseLinesIntoTasks, removeBoard, duplicateBoard, updateBoard, wstackGlobalRoot, DefaultSecretScrubber, resolveWstackPaths, watchProviderConfig, PromptUsageStore, TOKENS, ToolRegistry, GlobalMailbox, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, shellHooksEqual, countShellHooks, normalizeTokenSavingTier, allServers as allServers$1, SlashCommandRegistry, attachDepWatcherBridge, createFallbackModelExtension, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, SddRunRegistry, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, buildTranscriptFromEvents, DefaultLogger, DefaultModelsRegistry, isStdinTTY, FsError, atomicWrite, EventBus, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, sessionScopedPath as sessionScopedPath$1, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, makeFleetStatusTool, applyToolDescriptionModes, applyToolResultRenderModes, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, createHqPublisherFromEnv, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, Context, QueueStore, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, applyModelRuntime, installDesignStudioMiddleware, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, WorktreeManager, Director, makeFleetEmitTool, AdaptiveConcurrencyController, resolveSubagentModelTarget, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, mergeModelRuntime, ToolValidationError, WIDE_SUBAGENT_CAPABILITIES, resolveProjectDir, FleetSupervisor, AgentError, PhaseStore, PhaseOrchestrator, assignNickname, AutoPhasePlanner, PhaseGraphBuilder, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, CHIMERA_REVIEW_PROMPT, setQueuedMessagesSnapshot, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, ProviderRegistry, makePreferSideConflictResolver, makeAgentSubagentRunner, NULL_FLEET_BUS, ERROR_CODES, buildChildEnv, exportBoardAsMarkdown, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENT_CATALOG, dispatchAgent, normalizeToolDescriptionMode, getToolDescriptionMode, noOpVault, formatTodosList, loadTasks, formatTaskList, formatTaskProgress, mutateTasks, emptyPlan, addPlanItem, savePlan, formatPlan, recordCompletedWorkEvidence, saveCompletedWorkCheckpoint, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, getDesignKitLoader, getDesignState, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, applyTokenOverrides, materializeTokens, setActiveKit, readHqRuntimeFileSync, resolveHqConfig, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, resolveModelMatrix, resolveModelTargetFromEntry, fallbackProfileChain, parseModelRef, normalizeModelRef, onResize, hasOpenTodos, InputBuilder, DefaultSecretVault as DefaultSecretVault$1, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, DEFAULT_CONTEXT_WINDOW_MODE_ID, HQ_AUTH_FILE_VERSION, truncate, createBoardFromTaskGraph, addDependency, addNoteToTask, addCheckToTask, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, normalizeToolResultRenderMode, getToolResultRenderMode, setToolResultRenderMode, resolveMailboxIdentity, smartDefaultFallbackChain, AutonomousCoordinator, mutateHqAuthFile, mintHqToken, readHqAuthFile, areDependenciesMet, findBlockedTasks, renderInstructionTemplate, recentTextTurns, gatedEnhancerReasoning, enhanceUserPrompt, mutatePlan, setPlanItemStatus, getPlanTemplate, resolveProviderModelList, ParseError, startSessionTelemetryBridge, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge } from '@wrongstack/core';
2
+ import { CODEX_MODELS, color, ToolCapabilities, PHASE_EVENT_NAMES, readBundledInstructionText, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, ConfigError, resolveHqDataDir, ensureHqFirstRunAuthFile, DEFAULT_HQ_REDACTION_POLICY, createHqPersistence, HqCommandAuditLog, HqAlertEngine, toAlertMessage, validateHqCommand, watchHqAuthFile, parseHqFrame, HQ_PROTOCOL_VERSION, parseHqEventPayload, scrubAndTruncateHqPreview, FetchError, removeColumn, addColumn, getTask, removeTask, getBoard, assignTask, updateTaskAssignment, listBoards, updateGoalMetricOnTask, addGoalMetricToTask, releaseTaskClaim, claimReadyTask, getTaskChain, setTaskChain, copyTaskToBoard, transferTaskToBoard, moveTask, updateTask, mergeTasks, splitTask, addTask, syncBoardFromTaskGraph, deserializeTaskGraph, exportBoardToTaskGraph, serializeTaskGraph, getKanbanOrchestrationSnapshot, listReadyTasks, generateBoardFromDescription, createBoard, parseLinesIntoTasks, removeBoard, duplicateBoard, updateBoard, wstackGlobalRoot, DefaultSecretScrubber, resolveWstackPaths, watchProviderConfig, TOKENS, PromptUsageStore, ToolRegistry, GlobalMailbox, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, shellHooksEqual, countShellHooks, normalizeTokenSavingTier, allServers as allServers$1, SlashCommandRegistry, attachDepWatcherBridge, createFallbackModelExtension, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, SddRunRegistry, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, buildTranscriptFromEvents, DefaultLogger, DefaultModelsRegistry, isStdinTTY, FsError, atomicWrite, EventBus, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, mergeCustomModelDefs, DefaultSystemPromptBuilder, makeAutonomyPromptContributor, sessionScopedPath as sessionScopedPath$1, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, makeFleetStatusTool, applyToolDescriptionModes, applyToolResultRenderModes, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, createHqPublisherFromEnv, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, Context, QueueStore, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, loadPlan, createDefaultPipelines, applyModelRuntime, installDesignStudioMiddleware, resolveContextWindowPolicy, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, WorktreeManager, Director, makeFleetEmitTool, AdaptiveConcurrencyController, resolveSubagentModelTarget, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, mergeModelRuntime, ToolValidationError, WIDE_SUBAGENT_CAPABILITIES, resolveProjectDir, FleetSupervisor, AgentError, PhaseStore, PhaseOrchestrator, assignNickname, AutoPhasePlanner, PhaseGraphBuilder, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, CHIMERA_REVIEW_PROMPT, setQueuedMessagesSnapshot, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, ToolAuditLog, DefaultSessionRewinder, DefaultSessionStore, ProviderRegistry, makePreferSideConflictResolver, makeAgentSubagentRunner, NULL_FLEET_BUS, ERROR_CODES, buildChildEnv, exportBoardAsMarkdown, formatContextWindowModeList, repairToolUseAdjacency, getContextWindowMode, AGENT_CATALOG, dispatchAgent, normalizeToolDescriptionMode, getToolDescriptionMode, noOpVault, formatTodosList, loadTasks, formatTaskList, formatTaskProgress, mutateTasks, emptyPlan, addPlanItem, savePlan, formatPlan, recordCompletedWorkEvidence, saveCompletedWorkCheckpoint, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, getDesignKitLoader, getDesignState, clearActiveKit, clearPersistedActiveKit, recordOverrides, setDesignOverrides, loadActiveKit, isDesignStack, applyTokenOverrides, materializeTokens, setActiveKit, readHqRuntimeFileSync, resolveHqConfig, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, resolveModelMatrix, resolveModelTargetFromEntry, fallbackProfileChain, parseModelRef, normalizeModelRef, onResize, hasOpenTodos, InputBuilder, DefaultSecretVault as DefaultSecretVault$1, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, DEFAULT_CONTEXT_WINDOW_MODE_ID, HQ_AUTH_FILE_VERSION, truncate, createBoardFromTaskGraph, addDependency, addNoteToTask, addCheckToTask, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, normalizeToolResultRenderMode, getToolResultRenderMode, setToolResultRenderMode, resolveMailboxIdentity, smartDefaultFallbackChain, AutonomousCoordinator, mutateHqAuthFile, mintHqToken, readHqAuthFile, areDependenciesMet, findBlockedTasks, renderInstructionTemplate, recentTextTurns, gatedEnhancerReasoning, enhanceUserPrompt, mutatePlan, setPlanItemStatus, getPlanTemplate, resolveProviderModelList, ParseError, startSessionTelemetryBridge, startFleetTelemetryBridge, startBrainTelemetryBridge, startWorktreeTelemetryBridge, startToolTelemetryBridge, startCostTelemetryBridge } from '@wrongstack/core';
3
3
  import * as fs2 from 'fs/promises';
4
4
  import { access, readFile } from 'fs/promises';
5
5
  import { DefaultSecretVault, decryptConfigSecrets, encryptConfigSecrets, isSecretField } from '@wrongstack/core/security';
@@ -34,7 +34,7 @@ import { parseNextSteps } from '@wrongstack/tui';
34
34
  import { WrongStackACPServer, makeACPServerAgentTurn, ACPSessionStore, WsBridgeTransport, ACPProtocolHandler } from '@wrongstack/acp/agent';
35
35
  import { allServers, DefaultPathResolver, DefaultTokenCounter } from '@wrongstack/core/infrastructure';
36
36
  import { ToolExecutor } from '@wrongstack/core/execution';
37
- import { loadBenchConfig, reportHeaderLine, readSummary, renderMarkdownReport, createPolyglotSuite, createSwebenchSuite, runBenchmark, writeJsonArtifacts, collectCellPredictions, writePredictionsJsonl, gradePolyglot, gradeSwebench } from '@wrongstack/bench';
37
+ import { loadBenchConfig, reportHeaderLine, computeToolManifestHash, readSummary, renderMarkdownReport, createPolyglotSuite, createSwebenchSuite, createLocalManifestSuite, runBenchmark, writeJsonArtifacts, collectCellPredictions, writePredictionsJsonl, gradePolyglot, gradeSwebench, gradeLocalManifest } from '@wrongstack/bench';
38
38
  import { createAgentMonitorService, acquireOrJoin, release, finalize, readLiveLock } from '@wrongstack/core/coordination';
39
39
  import * as net from 'net';
40
40
  import { createToolVisionAdapters } from '@wrongstack/runtime/vision';
@@ -7388,6 +7388,29 @@ var init_cost_helpers = __esm({
7388
7388
  function currentSessionId2(ctx) {
7389
7389
  return ctx.agent.ctx.session?.id ?? ctx.sessionId;
7390
7390
  }
7391
+ function toolEntries(ctx) {
7392
+ const registry = ctx.agent.tools;
7393
+ if (typeof registry.listWithOwner === "function") {
7394
+ return [
7395
+ ...registry.listWithOwner(),
7396
+ ...typeof registry.listDisabled === "function" ? registry.listDisabled() : []
7397
+ ];
7398
+ }
7399
+ return (registry.list?.() ?? []).map((tool) => ({ tool, owner: "core" }));
7400
+ }
7401
+ function persistDisabledTool(ctx, name, disabled) {
7402
+ const configStore = ctx.configStore;
7403
+ if (!configStore) return;
7404
+ const currentTools = configStore.get().tools ?? {};
7405
+ const disabledTools = new Set(currentTools.disabledTools ?? []);
7406
+ if (disabled) disabledTools.add(name);
7407
+ else disabledTools.delete(name);
7408
+ configStore.update({ tools: { ...currentTools, disabledTools: Array.from(disabledTools) } });
7409
+ }
7410
+ function toolNameFromPayload(payload) {
7411
+ const name = payload?.name;
7412
+ return typeof name === "string" && name.trim().length > 0 ? name.trim() : void 0;
7413
+ }
7391
7414
  async function handleSkillsList(ctx, ws) {
7392
7415
  if (!ctx.skillLoader) {
7393
7416
  ctx.send(ws, { type: "skills.list", payload: { skills: [], enabled: false } });
@@ -7424,17 +7447,42 @@ async function handleSkillsList(ctx, ws) {
7424
7447
  }
7425
7448
  }
7426
7449
  function handleToolsList(ctx, ws) {
7427
- const list = ctx.agent.tools.list().map((t) => {
7428
- const schema = t.inputSchema ?? {};
7450
+ const registry = ctx.agent.tools;
7451
+ const list = toolEntries(ctx).map(({ tool, owner }) => {
7452
+ const schema = tool.inputSchema ?? {};
7429
7453
  const params = schema.properties ? Object.keys(schema.properties) : [];
7430
7454
  return {
7431
- name: t.name,
7432
- description: t.description ?? "",
7433
- params
7455
+ name: tool.name,
7456
+ owner,
7457
+ description: tool.description ?? "",
7458
+ params,
7459
+ disabled: registry.isDisabled?.(tool.name) ?? false,
7460
+ mutating: !!tool.mutating,
7461
+ permission: tool.permission ?? "auto"
7434
7462
  };
7435
7463
  });
7436
7464
  ctx.send(ws, { type: "tools.list", payload: { tools: list } });
7437
7465
  }
7466
+ function handleToolDisable(ctx, ws, payload) {
7467
+ const name = toolNameFromPayload(payload);
7468
+ if (!name) {
7469
+ ctx.send(ws, { type: "error", payload: { message: "tool.disable requires a name" } });
7470
+ return;
7471
+ }
7472
+ const ok2 = ctx.agent.tools.disable(name);
7473
+ if (ok2) persistDisabledTool(ctx, name, true);
7474
+ ctx.send(ws, { type: "tool.disabled", payload: { name, ok: ok2 } });
7475
+ }
7476
+ function handleToolEnable(ctx, ws, payload) {
7477
+ const name = toolNameFromPayload(payload);
7478
+ if (!name) {
7479
+ ctx.send(ws, { type: "error", payload: { message: "tool.enable requires a name" } });
7480
+ return;
7481
+ }
7482
+ const ok2 = ctx.agent.tools.enable(name);
7483
+ if (ok2) persistDisabledTool(ctx, name, false);
7484
+ ctx.send(ws, { type: "tool.enabled", payload: { name, ok: ok2 } });
7485
+ }
7438
7486
  function handleDiagGet(ctx, ws) {
7439
7487
  const actx = ctx.agent.ctx;
7440
7488
  const tools = ctx.agent.tools.list();
@@ -9901,6 +9949,8 @@ function createMessageRouter(deps) {
9901
9949
  });
9902
9950
  },
9903
9951
  "tools.list": (_msg, ws) => handleToolsList(introspectionCtx, ws),
9952
+ "tool.disable": (msg, ws) => handleToolDisable(introspectionCtx, ws, msg.payload),
9953
+ "tool.enable": (msg, ws) => handleToolEnable(introspectionCtx, ws, msg.payload),
9904
9954
  // ── Autonomy ──
9905
9955
  "autonomy.switch": (msg, ws) => handleAutonomySwitch(prefsCtx, ws, msg.payload.mode),
9906
9956
  // ── Brain ──
@@ -11554,6 +11604,7 @@ async function runWebUI(opts) {
11554
11604
  projectRoot: opts.projectRoot,
11555
11605
  sessionId: opts.session.id,
11556
11606
  sessionStartedAt,
11607
+ configStore: opts.agent.container?.safeResolve?.(TOKENS.ConfigStore),
11557
11608
  send: send2,
11558
11609
  broadcast,
11559
11610
  log: (m) => console.log(m)
@@ -17143,6 +17194,10 @@ function buildBrainCommand(opts) {
17143
17194
  const trimmed = args.trim();
17144
17195
  const [sub, ...rest] = trimmed.split(/\s+/);
17145
17196
  const subcommand = (sub ?? "").toLowerCase();
17197
+ if ((subcommand === "" || subcommand === "status") && opts.onPanelOpen?.current) {
17198
+ const opened = opts.onPanelOpen.current("brainOpen");
17199
+ if (opened) return { message: "" };
17200
+ }
17146
17201
  if (subcommand === "risk") {
17147
17202
  if (!opts.brainSettings) {
17148
17203
  const msg3 = "Brain settings are not available in this session.";
@@ -17949,6 +18004,10 @@ ${description}`
17949
18004
  return { message: `Task ${taskId.slice(0, 8)} marked failed: ${reason}` };
17950
18005
  }
17951
18006
  if (verb === "status") {
18007
+ if (opts.onPanelOpen?.current) {
18008
+ const opened = opts.onPanelOpen.current("toggleCoordinatorMonitor");
18009
+ if (opened) return { message: "" };
18010
+ }
17952
18011
  const statusFn = getStatus();
17953
18012
  if (statusFn) {
17954
18013
  const stats = await statusFn();
@@ -21128,6 +21187,10 @@ function buildGoalCommand(opts) {
21128
21187
  "every iteration to decide what to do next."
21129
21188
  ].join("\n"),
21130
21189
  async run(args) {
21190
+ if (!args.trim() && opts.onPanelOpen?.current) {
21191
+ const opened = opts.onPanelOpen.current("toggleGoalPanel");
21192
+ if (opened) return { message: "" };
21193
+ }
21131
21194
  const trimmed = args.trim();
21132
21195
  const [verbRaw, ...rest] = trimmed.split(/\s+/);
21133
21196
  const verb = (verbRaw ?? "").toLowerCase();
@@ -21346,6 +21409,10 @@ function buildHelpCommand(opts) {
21346
21409
  ].join("\n"),
21347
21410
  async run(args) {
21348
21411
  const query = args.trim();
21412
+ if (!query && opts.onPanelOpen?.current) {
21413
+ opts.onPanelOpen.current("helpOpen");
21414
+ return { message: "" };
21415
+ }
21349
21416
  if (query) {
21350
21417
  const needle = query.startsWith("/") ? query.slice(1) : query;
21351
21418
  let match;
@@ -23343,7 +23410,7 @@ function buildMcpSlashCommand(opts) {
23343
23410
  argsHint: "[list|add <name>|remove <name>|enable <name>|disable <name>|restart <name>]",
23344
23411
  help: [
23345
23412
  "Usage:",
23346
- " /mcp List available and configured servers.",
23413
+ " /mcp Open interactive server picker (TUI) or list servers.",
23347
23414
  " /mcp list Same.",
23348
23415
  " /mcp add <name> Add server preset to config (disabled).",
23349
23416
  " /mcp add <name> --enable Add and immediately enable.",
@@ -23359,10 +23426,15 @@ function buildMcpSlashCommand(opts) {
23359
23426
  " /mcp restart brave-search"
23360
23427
  ].join("\n"),
23361
23428
  async run(args) {
23429
+ const trimmed = args.trim();
23430
+ if ((trimmed === "" || trimmed === "list") && opts.onPanelOpen?.current) {
23431
+ const opened = opts.onPanelOpen.current("mcpPickerOpen");
23432
+ if (opened) return { message: "" };
23433
+ }
23362
23434
  if (!opts.onMcp) {
23363
23435
  return { message: "MCP management is not available in this session." };
23364
23436
  }
23365
- const result = await opts.onMcp(args.trim());
23437
+ const result = await opts.onMcp(trimmed);
23366
23438
  return { message: result };
23367
23439
  }
23368
23440
  };
@@ -25797,6 +25869,10 @@ function buildAgentsCommand(opts) {
25797
25869
  category: "Agent",
25798
25870
  description: "Monitor subagent activity: /agents [stream on|off|status|list|show <id>]",
25799
25871
  async run(args) {
25872
+ if ((!args.trim() || args.trim() === "list") && opts.onPanelOpen?.current) {
25873
+ const opened = opts.onPanelOpen.current("toggleAgentsMonitor");
25874
+ if (opened) return { message: "" };
25875
+ }
25800
25876
  const monitor = opts.agentMonitor;
25801
25877
  const { cmd, rest } = parseSubcommand(args);
25802
25878
  const restJoined = rest.join(" ").trim();
@@ -27482,6 +27558,13 @@ function buildShadowCommand(opts) {
27482
27558
  async run(args, _ctx) {
27483
27559
  const [action, ...rest] = args.trim().split(/\s+/);
27484
27560
  switch (action) {
27561
+ case void 0:
27562
+ case "":
27563
+ if (opts.onPanelOpen?.current) {
27564
+ const opened = opts.onPanelOpen.current("shadowOpen");
27565
+ if (opened) return { message: "" };
27566
+ }
27567
+ return { message: this.help ?? "/shadow \u2014 use /shadow help for usage" };
27485
27568
  case "start": {
27486
27569
  if (!opts.onSpawn) {
27487
27570
  return { message: "/shadow requires a running director with subagent support." };
@@ -29461,6 +29544,10 @@ function buildToolsCommand(opts) {
29461
29544
  ({ tool, owner }) => tool.name.toLowerCase().includes(filter) || owner.toLowerCase().includes(filter)
29462
29545
  ) : allTools;
29463
29546
  const disabled = reg.listDisabled();
29547
+ if (opts.onPanelOpen?.current) {
29548
+ const opened = opts.onPanelOpen.current("toolsPickerOpen");
29549
+ if (opened) return { message: "" };
29550
+ }
29464
29551
  if (filter && all.length === 0) {
29465
29552
  const msg2 = `${color.bold("Tools")} \u2014 no tool name or owner matched "${filter}".`;
29466
29553
  opts.renderer.write(msg2);
@@ -32074,6 +32161,9 @@ function printUsage(deps) {
32074
32161
  color.dim(
32075
32162
  " wstack bench run --suite polyglot --polyglot-dir ./polyglot --models bench.config.json --limit 5"
32076
32163
  ),
32164
+ color.dim(
32165
+ " wstack bench run --suite local --suite-dir ./evals --models bench.config.json"
32166
+ ),
32077
32167
  color.dim(" wstack bench report ./bench-results/2026-06-14T10-00-00"),
32078
32168
  ""
32079
32169
  ].join("\n") + "\n"
@@ -32141,11 +32231,26 @@ async function benchRun(_args, deps) {
32141
32231
  docker
32142
32232
  });
32143
32233
  grade = (a) => gradeSwebench({ ...a, predictionsDir });
32234
+ } else if (suiteId === "local" || suiteId === "manifest") {
32235
+ const suiteDirRaw = flagStr(deps, "suite-dir");
32236
+ const manifestRaw = flagStr(deps, "manifest");
32237
+ if (!suiteDirRaw && !manifestRaw) {
32238
+ deps.renderer.writeError(
32239
+ "--suite-dir <path> or --manifest <file> is required for the local suite."
32240
+ );
32241
+ return 1;
32242
+ }
32243
+ const manifestFile = manifestRaw ? path5.resolve(deps.cwd, manifestRaw) : void 0;
32244
+ const suiteDir = suiteDirRaw ? path5.resolve(deps.cwd, suiteDirRaw) : path5.dirname(manifestFile);
32245
+ suite = createLocalManifestSuite({ suiteDir, manifestFile });
32246
+ grade = (a) => gradeLocalManifest(a);
32144
32247
  } else {
32145
- deps.renderer.writeError(`unknown suite "${suiteId}" (expected: polyglot | swebench)`);
32248
+ deps.renderer.writeError(`unknown suite "${suiteId}" (expected: polyglot | swebench | local)`);
32146
32249
  return 1;
32147
32250
  }
32148
- const toolNames = deps.toolRegistry?.list().map((t) => t.name) ?? [];
32251
+ const tools = deps.toolRegistry?.list() ?? [];
32252
+ const toolNames = tools.map((t) => t.name);
32253
+ const toolManifestHash = computeToolManifestHash(tools);
32149
32254
  const wstackEntry = await resolveWstackEntry();
32150
32255
  deps.renderer.writeInfo(`Running ${suiteId} across ${config.cells.length} model(s)\u2026`);
32151
32256
  let report;
@@ -32156,6 +32261,7 @@ async function benchRun(_args, deps) {
32156
32261
  config,
32157
32262
  cliVersion: CLI_VERSION,
32158
32263
  toolNames,
32264
+ toolManifestHash,
32159
32265
  nodeBin: process.execPath,
32160
32266
  wstackEntry,
32161
32267
  limit,
@@ -32212,6 +32318,9 @@ async function benchList(_args, deps) {
32212
32318
  deps.renderer.write(
32213
32319
  " swebench " + color.dim("SWE-bench Verified (end-to-end) \u2014 Phase 2, Docker-gated\n")
32214
32320
  );
32321
+ deps.renderer.write(
32322
+ " local " + color.dim("Project-defined manifest tasks with command/file graders\n")
32323
+ );
32215
32324
  const modelsPath = flagStr(deps, "models");
32216
32325
  if (modelsPath) {
32217
32326
  try {
@@ -32223,12 +32332,14 @@ async function benchList(_args, deps) {
32223
32332
  `
32224
32333
  );
32225
32334
  }
32335
+ const tools = deps.toolRegistry?.list() ?? [];
32226
32336
  const fp = reportHeaderLine({
32227
32337
  cliVersion: CLI_VERSION,
32228
- toolNames: deps.toolRegistry?.list().map((t) => t.name) ?? [],
32338
+ toolNames: tools.map((t) => t.name),
32229
32339
  maxIterations: config.maxIterations,
32230
32340
  yolo: true,
32231
32341
  subsetId: "(computed at run time)",
32342
+ toolManifestHash: computeToolManifestHash(tools),
32232
32343
  hash: "(computed at run time)"
32233
32344
  });
32234
32345
  deps.renderer.write("\n" + color.dim(`Harness: ${fp}`) + "\n");
@@ -39347,6 +39458,16 @@ async function execute(deps) {
39347
39458
  saveStatuslineHiddenItems,
39348
39459
  getPluginItems,
39349
39460
  onPluginToggle,
39461
+ getMcpServers,
39462
+ onMcpToggle,
39463
+ onMcpRestart,
39464
+ getToolsItems,
39465
+ onToolToggle,
39466
+ getBrainData,
39467
+ onBrainRiskLevel,
39468
+ getShadowData,
39469
+ onShadowStart,
39470
+ onShadowStop,
39350
39471
  authHost,
39351
39472
  agentsMonitorController,
39352
39473
  onPanelOpen,
@@ -39833,6 +39954,16 @@ async function execute(deps) {
39833
39954
  saveStatuslineHiddenItems,
39834
39955
  getPluginItems,
39835
39956
  onPluginToggle,
39957
+ getMcpServers,
39958
+ onMcpToggle,
39959
+ onMcpRestart,
39960
+ getToolsItems,
39961
+ onToolToggle,
39962
+ getBrainData,
39963
+ onBrainRiskLevel,
39964
+ getShadowData,
39965
+ onShadowStart,
39966
+ onShadowStop,
39836
39967
  authHost,
39837
39968
  agentsMonitorController,
39838
39969
  getLiveSessions: () => getLiveSessions({ state }),
@@ -45045,6 +45176,114 @@ Restart WrongStack to load or unload plugin code in this session.`;
45045
45176
  saveStatuslineHiddenItems,
45046
45177
  getPluginItems: getPluginPickerItems,
45047
45178
  onPluginToggle: togglePluginFromPicker,
45179
+ getMcpServers: () => {
45180
+ const servers = config.mcpServers ?? {};
45181
+ const liveStatus = mcpRegistry.list();
45182
+ const liveMap = new Map(liveStatus.map((s) => [s.name, s]));
45183
+ return Object.entries(servers).map(([name, cfg]) => {
45184
+ const live = liveMap.get(name);
45185
+ return {
45186
+ name,
45187
+ enabled: cfg.enabled !== false,
45188
+ status: live ? live.state : "stopped",
45189
+ transport: cfg.transport ?? "stdio",
45190
+ description: cfg.description,
45191
+ toolCount: live?.toolCount ?? 0,
45192
+ lazy: cfg.lazy
45193
+ };
45194
+ });
45195
+ },
45196
+ onMcpToggle: async (name) => {
45197
+ const { enableMcp, disableMcp, listMcp } = await import('@wrongstack/mcp');
45198
+ const deps = { configPath: wpaths.globalConfig, registry: mcpRegistry, presets: allServers$1() };
45199
+ const live = mcpRegistry.list().find((s) => s.name === name);
45200
+ const isCurrentlyEnabled = live !== void 0 && live.state !== "idle";
45201
+ const result = isCurrentlyEnabled ? await disableMcp(name, deps) : await enableMcp(name, deps);
45202
+ const items = await listMcp(deps);
45203
+ return {
45204
+ items: items.map((s) => ({ name: s.name, enabled: s.enabled, status: s.status, transport: s.transport, description: s.description, toolCount: s.tools.length, lazy: s.lazy })),
45205
+ message: result.ok ? result.server ? `${result.server.status === "connected" ? "\u25CF" : "\u25CB"} ${name}` : result.message : void 0,
45206
+ error: result.ok ? void 0 : result.message
45207
+ };
45208
+ },
45209
+ onMcpRestart: async (name) => {
45210
+ const { listMcp } = await import('@wrongstack/mcp');
45211
+ const deps = { configPath: wpaths.globalConfig, registry: mcpRegistry, presets: allServers$1() };
45212
+ try {
45213
+ await mcpRegistry.restart(name);
45214
+ } catch (err) {
45215
+ const message = err instanceof Error ? err.message : String(err);
45216
+ const items2 = await listMcp(deps);
45217
+ return { items: items2.map((s) => ({ name: s.name, enabled: s.enabled, status: s.status, transport: s.transport, description: s.description, toolCount: s.tools.length, lazy: s.lazy })), message: void 0, error: message };
45218
+ }
45219
+ const items = await listMcp(deps);
45220
+ return { items: items.map((s) => ({ name: s.name, enabled: s.enabled, status: s.status, transport: s.transport, description: s.description, toolCount: s.tools.length, lazy: s.lazy })), message: `Restarted "${name}".`, error: void 0 };
45221
+ },
45222
+ getToolsItems: () => {
45223
+ const all = toolRegistry.listWithOwner().map(({ tool, owner }) => {
45224
+ const descMode = getToolDescriptionMode(toolRegistry, tool.name);
45225
+ return {
45226
+ name: tool.name,
45227
+ owner,
45228
+ category: tool.category ?? "Other",
45229
+ enabled: !toolRegistry.isDisabled(tool.name),
45230
+ mutating: tool.mutating,
45231
+ permission: tool.permission,
45232
+ descMode,
45233
+ description: tool.description
45234
+ };
45235
+ });
45236
+ return all;
45237
+ },
45238
+ onToolToggle: async (name) => {
45239
+ const disabled = new Set(config.tools?.disabledTools ?? []);
45240
+ const isCurrentlyDisabled = toolRegistry.isDisabled(name);
45241
+ if (isCurrentlyDisabled) {
45242
+ toolRegistry.enable(name);
45243
+ disabled.delete(name);
45244
+ } else {
45245
+ toolRegistry.disable(name);
45246
+ disabled.add(name);
45247
+ }
45248
+ const nextTools = { ...config.tools ?? {}, disabledTools: Array.from(disabled) };
45249
+ config = patchConfig(config, { tools: nextTools });
45250
+ configStore.update({ tools: nextTools });
45251
+ const items = toolRegistry.listWithOwner().map(({ tool, owner }) => ({
45252
+ name: tool.name,
45253
+ owner,
45254
+ category: tool.category ?? "Other",
45255
+ enabled: !toolRegistry.isDisabled(tool.name),
45256
+ mutating: tool.mutating,
45257
+ permission: tool.permission,
45258
+ descMode: getToolDescriptionMode(toolRegistry, tool.name),
45259
+ description: tool.description
45260
+ }));
45261
+ return {
45262
+ items,
45263
+ message: isCurrentlyDisabled ? `Enabled "${name}".` : `Disabled "${name}".`,
45264
+ error: void 0
45265
+ };
45266
+ },
45267
+ getBrainData: () => {
45268
+ const ceiling = brainSettings?.maxAutoRisk ?? "medium";
45269
+ const log = brainLog.slice(-20).map((entry) => ({
45270
+ kind: entry.kind,
45271
+ question: entry.question,
45272
+ outcome: entry.outcome,
45273
+ age: typeof entry.at === "number" ? (() => {
45274
+ const s = Math.max(0, Math.round((Date.now() - entry.at) / 1e3));
45275
+ if (s < 60) return `${s}s`;
45276
+ if (s < 3600) return `${Math.round(s / 60)}m`;
45277
+ return `${Math.round(s / 3600)}h`;
45278
+ })() : ""
45279
+ }));
45280
+ return { riskLevel: ceiling, log };
45281
+ },
45282
+ onBrainRiskLevel: (level) => {
45283
+ if (!brainSettings) return "Brain settings not available.";
45284
+ brainSettings.maxAutoRisk = level;
45285
+ return void 0;
45286
+ },
45048
45287
  // Interactive /auth panel host — provider/key CRUD, catalog/local adds
45049
45288
  // and OAuth sign-in, all executed CLI-side against the encrypted config
45050
45289
  // (secrets never enter the TUI; key values arrive pre-masked).