@wrongstack/cli 0.282.1 → 0.283.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
@@ -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, detectContinueIntent, resolveContinuation, 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
  };
@@ -23844,15 +23916,15 @@ function buildModeCommand(opts) {
23844
23916
  " /mode Show current mode and available modes",
23845
23917
  " /mode <id> Switch to a different mode",
23846
23918
  "",
23847
- "Available modes:",
23848
- " default General-purpose coding assistant",
23849
- " brief Fast, no-nonsense \u2014 get to the point",
23850
- " teach Mentor mode \u2014 explains why, not just what",
23851
- " code-reviewer, code-auditor, architect, debugger, tester, devops, refactorer",
23919
+ "Available mode families:",
23920
+ " Token-saving: brief, review-lite, audit-lite, plan-lite, debug-lite, test-lite, refactor-lite, research-lite",
23921
+ " Deep/full: code-reviewer, code-auditor, architect, debugger, tester, devops, refactorer, ui-design, teach, research-web",
23852
23922
  "",
23853
- "Example:",
23854
- " /mode brief Switch to brief mode",
23855
- " /mode teach Switch to teach mode"
23923
+ "Examples:",
23924
+ " /mode brief Ultra-compact responses",
23925
+ " /mode review-lite Narrow changed-file review",
23926
+ " /mode code-reviewer Full correctness/security review",
23927
+ " /mode teach Mentor-style explanations"
23856
23928
  ].join("\n"),
23857
23929
  async run(args, ctx) {
23858
23930
  const modeStore = opts.modeStore;
@@ -25775,6 +25847,64 @@ function formatSuggestions(suggestions) {
25775
25847
  return lines.join("\n");
25776
25848
  }
25777
25849
 
25850
+ // src/slash-commands/surfaces.ts
25851
+ var DESKTOP_MESSAGE = [
25852
+ "WrongStack Desktop",
25853
+ "\u2500".repeat("WrongStack Desktop".length),
25854
+ "The desktop app is the local graphical shell for WrongStack sessions, project state, and agent coordination.",
25855
+ "",
25856
+ "Recommended path:",
25857
+ " Start it from your desktop launcher or from the platform-specific package you installed.",
25858
+ "",
25859
+ "Why this command only explains:",
25860
+ " A slash command runs inside the current CLI/TUI process, so silently launching a GUI is platform- and install-dependent. Keeping this informational avoids surprising side effects."
25861
+ ].join("\n");
25862
+ var WEBUI_MESSAGE = [
25863
+ "WrongStack Web UI",
25864
+ "\u2500".repeat("WrongStack Web UI".length),
25865
+ "The Web UI is the browser-based view for sessions, agents, mailbox coordination, and project activity.",
25866
+ "",
25867
+ "Recommended path:",
25868
+ " Start the Web UI/HQ server with the project command you normally use, then open the printed local URL in your browser.",
25869
+ "",
25870
+ "Why this command only explains:",
25871
+ " The active slash-command surface may not know which port, host, or Web UI package is running. Showing guidance is more reliable than guessing and opening the wrong target."
25872
+ ].join("\n");
25873
+ function buildDesktopCommand() {
25874
+ return {
25875
+ name: "desktop",
25876
+ category: "App",
25877
+ description: "Explain how to access the WrongStack Desktop app.",
25878
+ help: [
25879
+ "Usage:",
25880
+ " /desktop",
25881
+ "",
25882
+ "Shows where the Desktop app fits and why the CLI/TUI does not automatically launch it."
25883
+ ].join("\n"),
25884
+ async run() {
25885
+ return { message: DESKTOP_MESSAGE };
25886
+ }
25887
+ };
25888
+ }
25889
+ function buildWebuiCommand() {
25890
+ return {
25891
+ name: "webui",
25892
+ aliases: ["web"],
25893
+ category: "App",
25894
+ description: "Explain how to access the WrongStack browser UI.",
25895
+ help: [
25896
+ "Usage:",
25897
+ " /webui",
25898
+ " /web",
25899
+ "",
25900
+ "Shows Web UI access guidance without guessing whether a local server is already running."
25901
+ ].join("\n"),
25902
+ async run() {
25903
+ return { message: WEBUI_MESSAGE };
25904
+ }
25905
+ };
25906
+ }
25907
+
25778
25908
  // src/slash-commands/agents.ts
25779
25909
  init_helpers();
25780
25910
  function formatAgentLine(a) {
@@ -25797,6 +25927,10 @@ function buildAgentsCommand(opts) {
25797
25927
  category: "Agent",
25798
25928
  description: "Monitor subagent activity: /agents [stream on|off|status|list|show <id>]",
25799
25929
  async run(args) {
25930
+ if ((!args.trim() || args.trim() === "list") && opts.onPanelOpen?.current) {
25931
+ const opened = opts.onPanelOpen.current("toggleAgentsMonitor");
25932
+ if (opened) return { message: "" };
25933
+ }
25800
25934
  const monitor = opts.agentMonitor;
25801
25935
  const { cmd, rest } = parseSubcommand(args);
25802
25936
  const restJoined = rest.join(" ").trim();
@@ -27482,6 +27616,13 @@ function buildShadowCommand(opts) {
27482
27616
  async run(args, _ctx) {
27483
27617
  const [action, ...rest] = args.trim().split(/\s+/);
27484
27618
  switch (action) {
27619
+ case void 0:
27620
+ case "":
27621
+ if (opts.onPanelOpen?.current) {
27622
+ const opened = opts.onPanelOpen.current("shadowOpen");
27623
+ if (opened) return { message: "" };
27624
+ }
27625
+ return { message: this.help ?? "/shadow \u2014 use /shadow help for usage" };
27485
27626
  case "start": {
27486
27627
  if (!opts.onSpawn) {
27487
27628
  return { message: "/shadow requires a running director with subagent support." };
@@ -29002,7 +29143,7 @@ ${color.dim("No default chat set. You can add it later: /telegram-setup <token>
29002
29143
  `${color.amber("\u26A0")} Restart WrongStack for the plugin to pick up the new config.`,
29003
29144
  "",
29004
29145
  "After restart, try:",
29005
- ` ${color.cyan("/telegram:status")} \u2014 check bot connection`,
29146
+ ` ${color.cyan("/telegram")} \u2014 check bot connection`,
29006
29147
  ` ${color.cyan("/telegram:send")} \u2014 send a test message`
29007
29148
  ].join("\n")
29008
29149
  };
@@ -29138,6 +29279,7 @@ function buildToolCommand(opts) {
29138
29279
  " /tool <name> result simple|extend Set ONLY the on-screen result mode",
29139
29280
  " /tool disable <name> Hide a tool from the registry and system prompt",
29140
29281
  " /tool enable <name> Restore a disabled tool",
29282
+ " /tool <name> disable|enable Same as above, noun-first alias",
29141
29283
  " /tool enable-all Restore all disabled tools",
29142
29284
  "",
29143
29285
  "Modes:",
@@ -29376,6 +29518,19 @@ function buildToolCommand(opts) {
29376
29518
  return { message: `${color.red("Error")}: ${toErrorMessage$1(err)}` };
29377
29519
  }
29378
29520
  }
29521
+ const action = parts[1]?.toLowerCase();
29522
+ if (action === "disable" || action === "enable") {
29523
+ if (parts.length > 2) {
29524
+ return {
29525
+ message: `${color.amber("Usage:")} /tool ${name} ${action}`
29526
+ };
29527
+ }
29528
+ try {
29529
+ return { message: action === "disable" ? await cmdDisable(name) : await cmdEnable(name) };
29530
+ } catch (err) {
29531
+ return { message: `${color.red("Error")}: ${toErrorMessage$1(err)}` };
29532
+ }
29533
+ }
29379
29534
  if (!opts.toolRegistry.get(name) && !opts.toolRegistry.isDisabled(name)) {
29380
29535
  return {
29381
29536
  message: `${color.red("Unknown tool")}: ${name}. Use ${color.dim("/tools")} to list registered tools.`
@@ -29456,11 +29611,15 @@ function buildToolsCommand(opts) {
29456
29611
  async run(args) {
29457
29612
  const reg = opts.toolRegistry;
29458
29613
  const filter = args.trim().toLowerCase();
29459
- const allTools = reg.listWithOwner();
29614
+ const allTools = [...reg.listWithOwner(), ...reg.listDisabled()];
29460
29615
  const all = filter ? allTools.filter(
29461
29616
  ({ tool, owner }) => tool.name.toLowerCase().includes(filter) || owner.toLowerCase().includes(filter)
29462
29617
  ) : allTools;
29463
29618
  const disabled = reg.listDisabled();
29619
+ if (opts.onPanelOpen?.current) {
29620
+ const opened = opts.onPanelOpen.current("toolsPickerOpen");
29621
+ if (opened) return { message: "" };
29622
+ }
29464
29623
  if (filter && all.length === 0) {
29465
29624
  const msg2 = `${color.bold("Tools")} \u2014 no tool name or owner matched "${filter}".`;
29466
29625
  opts.renderer.write(msg2);
@@ -29682,6 +29841,8 @@ function buildYoloCommand(opts) {
29682
29841
  function buildBuiltinSlashCommands(opts) {
29683
29842
  return [
29684
29843
  buildHelpCommand(opts),
29844
+ buildDesktopCommand(),
29845
+ buildWebuiCommand(),
29685
29846
  buildInitCommand(opts),
29686
29847
  buildClearCommand(opts),
29687
29848
  buildInterruptCommand(opts),
@@ -32074,6 +32235,9 @@ function printUsage(deps) {
32074
32235
  color.dim(
32075
32236
  " wstack bench run --suite polyglot --polyglot-dir ./polyglot --models bench.config.json --limit 5"
32076
32237
  ),
32238
+ color.dim(
32239
+ " wstack bench run --suite local --suite-dir ./evals --models bench.config.json"
32240
+ ),
32077
32241
  color.dim(" wstack bench report ./bench-results/2026-06-14T10-00-00"),
32078
32242
  ""
32079
32243
  ].join("\n") + "\n"
@@ -32141,11 +32305,26 @@ async function benchRun(_args, deps) {
32141
32305
  docker
32142
32306
  });
32143
32307
  grade = (a) => gradeSwebench({ ...a, predictionsDir });
32308
+ } else if (suiteId === "local" || suiteId === "manifest") {
32309
+ const suiteDirRaw = flagStr(deps, "suite-dir");
32310
+ const manifestRaw = flagStr(deps, "manifest");
32311
+ if (!suiteDirRaw && !manifestRaw) {
32312
+ deps.renderer.writeError(
32313
+ "--suite-dir <path> or --manifest <file> is required for the local suite."
32314
+ );
32315
+ return 1;
32316
+ }
32317
+ const manifestFile = manifestRaw ? path5.resolve(deps.cwd, manifestRaw) : void 0;
32318
+ const suiteDir = suiteDirRaw ? path5.resolve(deps.cwd, suiteDirRaw) : path5.dirname(manifestFile);
32319
+ suite = createLocalManifestSuite({ suiteDir, manifestFile });
32320
+ grade = (a) => gradeLocalManifest(a);
32144
32321
  } else {
32145
- deps.renderer.writeError(`unknown suite "${suiteId}" (expected: polyglot | swebench)`);
32322
+ deps.renderer.writeError(`unknown suite "${suiteId}" (expected: polyglot | swebench | local)`);
32146
32323
  return 1;
32147
32324
  }
32148
- const toolNames = deps.toolRegistry?.list().map((t) => t.name) ?? [];
32325
+ const tools = deps.toolRegistry?.list() ?? [];
32326
+ const toolNames = tools.map((t) => t.name);
32327
+ const toolManifestHash = computeToolManifestHash(tools);
32149
32328
  const wstackEntry = await resolveWstackEntry();
32150
32329
  deps.renderer.writeInfo(`Running ${suiteId} across ${config.cells.length} model(s)\u2026`);
32151
32330
  let report;
@@ -32156,6 +32335,7 @@ async function benchRun(_args, deps) {
32156
32335
  config,
32157
32336
  cliVersion: CLI_VERSION,
32158
32337
  toolNames,
32338
+ toolManifestHash,
32159
32339
  nodeBin: process.execPath,
32160
32340
  wstackEntry,
32161
32341
  limit,
@@ -32212,6 +32392,9 @@ async function benchList(_args, deps) {
32212
32392
  deps.renderer.write(
32213
32393
  " swebench " + color.dim("SWE-bench Verified (end-to-end) \u2014 Phase 2, Docker-gated\n")
32214
32394
  );
32395
+ deps.renderer.write(
32396
+ " local " + color.dim("Project-defined manifest tasks with command/file graders\n")
32397
+ );
32215
32398
  const modelsPath = flagStr(deps, "models");
32216
32399
  if (modelsPath) {
32217
32400
  try {
@@ -32223,12 +32406,14 @@ async function benchList(_args, deps) {
32223
32406
  `
32224
32407
  );
32225
32408
  }
32409
+ const tools = deps.toolRegistry?.list() ?? [];
32226
32410
  const fp = reportHeaderLine({
32227
32411
  cliVersion: CLI_VERSION,
32228
- toolNames: deps.toolRegistry?.list().map((t) => t.name) ?? [],
32412
+ toolNames: tools.map((t) => t.name),
32229
32413
  maxIterations: config.maxIterations,
32230
32414
  yolo: true,
32231
32415
  subsetId: "(computed at run time)",
32416
+ toolManifestHash: computeToolManifestHash(tools),
32232
32417
  hash: "(computed at run time)"
32233
32418
  });
32234
32419
  deps.renderer.write("\n" + color.dim(`Harness: ${fp}`) + "\n");
@@ -37900,6 +38085,7 @@ function createSettingsAdapter(ctx) {
37900
38085
  restrictFsToRoot: resolvedRestrict,
37901
38086
  autoProceedMaxIterations: cfg.autonomy?.autoProceedMaxIterations ?? 50,
37902
38087
  debugStream: cfg.debugStream ?? false,
38088
+ shellBangWarningDontShowAgain: autonomy?.shellBangWarningDontShowAgain === true,
37903
38089
  statuslineMode: autonomy?.statuslineMode === "minimum" ? "minimum" : "detailed",
37904
38090
  thinkingWord: normalizeTuiThinkingWord(autonomy?.thinkingWord),
37905
38091
  animationStyle: normalizeAnimationStyle(autonomy?.animationStyle),
@@ -37920,7 +38106,7 @@ function createSettingsAdapter(ctx) {
37920
38106
  }
37921
38107
  async function saveSettings(s) {
37922
38108
  try {
37923
- if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.streamFleet !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0) {
38109
+ if (s.mode !== void 0 || s.delayMs !== void 0 || s.titleAnimation !== void 0 || s.yolo !== void 0 || s.streamFleet !== void 0 || s.chime !== void 0 || s.confirmExit !== void 0 || s.mouseMode !== void 0 || s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.contextMode !== void 0 || s.maxConcurrent !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.restrictFsToRoot !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.shellBangWarningDontShowAgain !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0 || s.enhanceEnabled !== void 0 || s.enhanceLanguage !== void 0 || s.midRunSendPicker !== void 0 || s.statuslineMode !== void 0 || s.thinkingWord !== void 0 || s.animationStyle !== void 0 || s.autonomyNextPrompt !== void 0 || s.autoProceedMaxIterations !== void 0 || s.reasoningMode !== void 0 || s.reasoningEffort !== void 0 || s.reasoningPreserve !== void 0 || s.cacheTtl !== void 0) {
37924
38110
  const configScope = s.configScope ?? configStore.get().configScope ?? "global";
37925
38111
  const targetPath = configScope === "project" && wpaths.inProjectConfig ? wpaths.inProjectConfig : wpaths.globalConfig;
37926
38112
  let raw;
@@ -37950,6 +38136,8 @@ function createSettingsAdapter(ctx) {
37950
38136
  if (s.enhanceEnabled !== void 0) autonomy.enhance = s.enhanceEnabled;
37951
38137
  if (s.enhanceLanguage !== void 0) autonomy.enhanceLanguage = s.enhanceLanguage;
37952
38138
  if (s.midRunSendPicker !== void 0) autonomy.midRunSendPicker = s.midRunSendPicker;
38139
+ if (s.shellBangWarningDontShowAgain !== void 0)
38140
+ autonomy.shellBangWarningDontShowAgain = s.shellBangWarningDontShowAgain;
37953
38141
  if (s.statuslineMode !== void 0) autonomy.statuslineMode = s.statuslineMode;
37954
38142
  if (s.thinkingWord !== void 0)
37955
38143
  autonomy.thinkingWord = normalizeTuiThinkingWord(s.thinkingWord);
@@ -38787,11 +38975,37 @@ ${color.dim(taskList2)}
38787
38975
  }
38788
38976
  continue;
38789
38977
  }
38790
- const ph = await builder.appendPaste(raw);
38791
- if (ph) {
38792
- const lineCount = raw.split("\n").length;
38793
- opts.renderer.write(color.dim(` \u21B3 ${ph} (${lineCount} lines)
38978
+ if (detectContinueIntent(trimmed)) {
38979
+ const resolved = resolveContinuation({
38980
+ todos: opts.agent.ctx.todos,
38981
+ suggestions: getSuggestions()
38982
+ });
38983
+ if (resolved.source === "open") {
38984
+ opts.renderer.write(
38985
+ ` ${color.amber("\u26A0")} ${color.bold("'continue' has no anchor")} ${color.dim("\u2014 no pending todo or suggestion.")}
38986
+ ` + color.dim(" If you proceed, I'll choose the next step from context; that can drift.\n")
38987
+ );
38988
+ const ans = (await opts.reader.readLine(color.dim(" Proceed anyway? [Y/n \xB7 e = type your own] "))).trim().toLowerCase();
38989
+ if (ans === "n" || ans === "no") {
38990
+ opts.renderer.write(color.dim(" Cancelled \u2014 nothing sent.\n"));
38991
+ continue;
38992
+ }
38993
+ if (ans === "e" || ans === "edit") {
38994
+ opts.renderer.write(color.dim(" Okay \u2014 type what to continue with.\n"));
38995
+ continue;
38996
+ }
38997
+ } else {
38998
+ opts.renderer.write(color.dim(` ${resolved.label}
38999
+ `));
39000
+ }
39001
+ builder.appendText(resolved.text);
39002
+ } else {
39003
+ const ph = await builder.appendPaste(raw);
39004
+ if (ph) {
39005
+ const lineCount = raw.split("\n").length;
39006
+ opts.renderer.write(color.dim(` \u21B3 ${ph} (${lineCount} lines)
38794
39007
  `));
39008
+ }
38795
39009
  }
38796
39010
  const blocks = await builder.submit();
38797
39011
  const sddContext = getActiveSDDContext();
@@ -39347,6 +39561,16 @@ async function execute(deps) {
39347
39561
  saveStatuslineHiddenItems,
39348
39562
  getPluginItems,
39349
39563
  onPluginToggle,
39564
+ getMcpServers,
39565
+ onMcpToggle,
39566
+ onMcpRestart,
39567
+ getToolsItems,
39568
+ onToolToggle,
39569
+ getBrainData,
39570
+ onBrainRiskLevel,
39571
+ getShadowData,
39572
+ onShadowStart,
39573
+ onShadowStop,
39350
39574
  authHost,
39351
39575
  agentsMonitorController,
39352
39576
  onPanelOpen,
@@ -39833,6 +40057,16 @@ async function execute(deps) {
39833
40057
  saveStatuslineHiddenItems,
39834
40058
  getPluginItems,
39835
40059
  onPluginToggle,
40060
+ getMcpServers,
40061
+ onMcpToggle,
40062
+ onMcpRestart,
40063
+ getToolsItems,
40064
+ onToolToggle,
40065
+ getBrainData,
40066
+ onBrainRiskLevel,
40067
+ getShadowData,
40068
+ onShadowStart,
40069
+ onShadowStop,
39836
40070
  authHost,
39837
40071
  agentsMonitorController,
39838
40072
  getLiveSessions: () => getLiveSessions({ state }),
@@ -42841,9 +43075,11 @@ function wireEventWiring(deps) {
42841
43075
  evOn("provider.fallback", (p) => {
42842
43076
  if (!isCurrentSession(p.sessionId)) return;
42843
43077
  stopSpinnerAndStreaming();
43078
+ const contextWarning = p.contextWindowWarning ? ` \u26A0 smaller context window: ${p.contextWindowWarning.fromMaxContext.toLocaleString("en-US")} \u2192 ${p.contextWindowWarning.toMaxContext.toLocaleString("en-US")} tokens${p.contextWindowWarning.currentTokens ? `; current request \u2248 ${p.contextWindowWarning.currentTokens.toLocaleString("en-US")} tokens (${Math.round(p.contextWindowWarning.currentTokens / p.contextWindowWarning.toMaxContext * 100)}% of new window)` : ""}
43079
+ ` : "";
42844
43080
  writeErr(
42845
43081
  color.yellow(` \u21BB rate-limited (${p.status}) \u2014 switched to ${p.to.providerId}/${p.to.model}
42846
- `)
43082
+ ${contextWarning}`)
42847
43083
  );
42848
43084
  spinner.start(color.dim(`${p.to.providerId}/${p.to.model} thinking\u2026`));
42849
43085
  });
@@ -44982,6 +45218,22 @@ Restart WrongStack to load or unload plugin code in this session.`;
44982
45218
  error: result.code === 0 ? void 0 : result.message
44983
45219
  };
44984
45220
  };
45221
+ const getToolPickerItems = () => {
45222
+ const rows = [...toolRegistry.listWithOwner(), ...toolRegistry.listDisabled()];
45223
+ return rows.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
+ };
44985
45237
  const savedProviderCfg = config.providers?.[config.provider];
44986
45238
  return execute({
44987
45239
  agent,
@@ -45045,6 +45297,89 @@ Restart WrongStack to load or unload plugin code in this session.`;
45045
45297
  saveStatuslineHiddenItems,
45046
45298
  getPluginItems: getPluginPickerItems,
45047
45299
  onPluginToggle: togglePluginFromPicker,
45300
+ getMcpServers: () => {
45301
+ const servers = config.mcpServers ?? {};
45302
+ const liveStatus = mcpRegistry.list();
45303
+ const liveMap = new Map(liveStatus.map((s) => [s.name, s]));
45304
+ return Object.entries(servers).map(([name, cfg]) => {
45305
+ const live = liveMap.get(name);
45306
+ return {
45307
+ name,
45308
+ enabled: cfg.enabled !== false,
45309
+ status: live ? live.state : "stopped",
45310
+ transport: cfg.transport ?? "stdio",
45311
+ description: cfg.description,
45312
+ toolCount: live?.toolCount ?? 0,
45313
+ lazy: cfg.lazy
45314
+ };
45315
+ });
45316
+ },
45317
+ onMcpToggle: async (name) => {
45318
+ const { enableMcp, disableMcp, listMcp } = await import('@wrongstack/mcp');
45319
+ const deps = { configPath: wpaths.globalConfig, registry: mcpRegistry, presets: allServers$1() };
45320
+ const live = mcpRegistry.list().find((s) => s.name === name);
45321
+ const isCurrentlyEnabled = live !== void 0 && live.state !== "idle";
45322
+ const result = isCurrentlyEnabled ? await disableMcp(name, deps) : await enableMcp(name, deps);
45323
+ const items = await listMcp(deps);
45324
+ return {
45325
+ 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 })),
45326
+ message: result.ok ? result.server ? `${result.server.status === "connected" ? "\u25CF" : "\u25CB"} ${name}` : result.message : void 0,
45327
+ error: result.ok ? void 0 : result.message
45328
+ };
45329
+ },
45330
+ onMcpRestart: async (name) => {
45331
+ const { listMcp } = await import('@wrongstack/mcp');
45332
+ const deps = { configPath: wpaths.globalConfig, registry: mcpRegistry, presets: allServers$1() };
45333
+ try {
45334
+ await mcpRegistry.restart(name);
45335
+ } catch (err) {
45336
+ const message = err instanceof Error ? err.message : String(err);
45337
+ const items2 = await listMcp(deps);
45338
+ 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 };
45339
+ }
45340
+ const items = await listMcp(deps);
45341
+ 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 };
45342
+ },
45343
+ getToolsItems: getToolPickerItems,
45344
+ onToolToggle: async (name) => {
45345
+ const disabled = new Set(config.tools?.disabledTools ?? []);
45346
+ const isCurrentlyDisabled = toolRegistry.isDisabled(name);
45347
+ if (isCurrentlyDisabled) {
45348
+ toolRegistry.enable(name);
45349
+ disabled.delete(name);
45350
+ } else {
45351
+ toolRegistry.disable(name);
45352
+ disabled.add(name);
45353
+ }
45354
+ const nextTools = { ...config.tools ?? {}, disabledTools: Array.from(disabled) };
45355
+ config = patchConfig(config, { tools: nextTools });
45356
+ configStore.update({ tools: nextTools });
45357
+ return {
45358
+ items: getToolPickerItems(),
45359
+ message: isCurrentlyDisabled ? `Enabled "${name}".` : `Disabled "${name}".`,
45360
+ error: void 0
45361
+ };
45362
+ },
45363
+ getBrainData: () => {
45364
+ const ceiling = brainSettings?.maxAutoRisk ?? "medium";
45365
+ const log = brainLog.slice(-20).map((entry) => ({
45366
+ kind: entry.kind,
45367
+ question: entry.question,
45368
+ outcome: entry.outcome,
45369
+ age: typeof entry.at === "number" ? (() => {
45370
+ const s = Math.max(0, Math.round((Date.now() - entry.at) / 1e3));
45371
+ if (s < 60) return `${s}s`;
45372
+ if (s < 3600) return `${Math.round(s / 60)}m`;
45373
+ return `${Math.round(s / 3600)}h`;
45374
+ })() : ""
45375
+ }));
45376
+ return { riskLevel: ceiling, log };
45377
+ },
45378
+ onBrainRiskLevel: (level) => {
45379
+ if (!brainSettings) return "Brain settings not available.";
45380
+ brainSettings.maxAutoRisk = level;
45381
+ return void 0;
45382
+ },
45048
45383
  // Interactive /auth panel host — provider/key CRUD, catalog/local adds
45049
45384
  // and OAuth sign-in, all executed CLI-side against the encrypted config
45050
45385
  // (secrets never enter the TUI; key values arrive pre-masked).