@wrongstack/cli 1.1.2 → 1.1.4

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.
Files changed (42) hide show
  1. package/dist/{acp-HCGUTFNE.js → acp-MZ5MQBFN.js} +13 -5
  2. package/dist/acp-leader/acp-leader-confirm.d.ts +18 -0
  3. package/dist/acp-leader/acp-leader-context.d.ts +29 -0
  4. package/dist/acp-leader/acp-leader-fleet.d.ts +26 -0
  5. package/dist/acp-leader/acp-leader-host-binding.d.ts +16 -0
  6. package/dist/acp-leader/acp-leader-host.d.ts +80 -0
  7. package/dist/acp-leader/acp-leader-picker.d.ts +21 -0
  8. package/dist/acp-leader/acp-leader-provider.d.ts +85 -0
  9. package/dist/acp-leader/acp-leader-resume.d.ts +10 -0
  10. package/dist/acp-leader/acp-leader-stream.d.ts +82 -0
  11. package/dist/{auth-ANOVZVHE.js → auth-IHQS6AFW.js} +60 -64
  12. package/dist/auth-menu/index.d.ts +1 -2
  13. package/dist/boot/dispatch-webui.d.ts +16 -0
  14. package/dist/{chunk-GRAGMA4B.js → chunk-2LTHDKZX.js} +4 -4
  15. package/dist/chunk-3LEIFO5D.js +65 -0
  16. package/dist/chunk-COGI7EQU.js +1458 -0
  17. package/dist/chunk-GKGWPFW2.js +50 -0
  18. package/dist/{chunk-RAWHRRUJ.js → chunk-I5LJLKA3.js} +198 -197
  19. package/dist/{chunk-5TRZZHMN.js → chunk-JCZ2D3VV.js} +4 -65
  20. package/dist/{chunk-XT3NAHRX.js → chunk-JKTJSLUT.js} +192 -1
  21. package/dist/{chunk-NMXQFQ26.js → chunk-TAE3EGBM.js} +3 -3
  22. package/dist/{chunk-3R3OADC5.js → chunk-ZF4HRR5F.js} +7 -3
  23. package/dist/{cli-context-YIT4FEDM.js → cli-context-E44HQ4ZO.js} +13 -7
  24. package/dist/{cli-main-JIADJ5OL.js → cli-main-OT63I2FX.js} +452 -217
  25. package/dist/{execution-BAP566QC.js → execution-OK34CJKJ.js} +7 -2
  26. package/dist/fleet/acp-live-steer.d.ts +28 -0
  27. package/dist/fleet/acp-permission-bridge.d.ts +49 -0
  28. package/dist/fleet/acp-quota-hold.d.ts +3 -0
  29. package/dist/fleet/acp-quota-reading.d.ts +3 -0
  30. package/dist/fleet/acp-turn-reminders.d.ts +15 -0
  31. package/dist/fleet/acp-wrongstack-bridge.d.ts +42 -0
  32. package/dist/fleet/host-acp.d.ts +20 -2
  33. package/dist/index.js +7 -4
  34. package/dist/{mcp-2XWBJEQN.js → mcp-W7A5HUXV.js} +97 -1
  35. package/dist/mcp-serve-project.d.ts +18 -0
  36. package/dist/{per-subcommand-help-D6J4ZXW2.js → per-subcommand-help-4GYSCMLU.js} +2 -2
  37. package/dist/{short-circuit-flags-CPCT5MWB.js → short-circuit-flags-QEXUS3BY.js} +2 -2
  38. package/dist/{subcommands-VTMIZQBP.js → subcommands-YADUV7IJ.js} +2 -2
  39. package/dist/{webui-server-HIUY3RHD.js → webui-server-CB64CFDG.js} +41 -3
  40. package/package.json +34 -30
  41. package/dist/auth-menu/anthropic-oauth.d.ts +0 -43
  42. package/dist/chunk-ZNNFEKDZ.js +0 -319
@@ -61,6 +61,9 @@ import {
61
61
  startCliHqConnection
62
62
  } from "./chunk-76JE54WD.js";
63
63
  import "./chunk-OZCYZYN2.js";
64
+ import {
65
+ confirmAcpLeaderThroughEvents
66
+ } from "./chunk-GKGWPFW2.js";
64
67
  import {
65
68
  CLI_VERSION
66
69
  } from "./chunk-HKMOIIPQ.js";
@@ -5266,8 +5269,9 @@ async function runWebUIDispatch(ctx) {
5266
5269
  const isSessionChild = Boolean(webuiSessionChild);
5267
5270
  const isSimpleUi = !isSessionChild && flags["simpleui"] === true;
5268
5271
  agent.disableInteractiveConfirmation();
5272
+ confirmAcpLeaderThroughEvents();
5269
5273
  renderer.setSilent(true);
5270
- const { runWebUI } = await import("./webui-server-HIUY3RHD.js");
5274
+ const { runWebUI } = await import("./webui-server-CB64CFDG.js");
5271
5275
  const flagValue = (names) => {
5272
5276
  for (const name of names) {
5273
5277
  if (!Object.hasOwn(flags, name)) continue;
@@ -7192,6 +7196,7 @@ async function execute(deps) {
7192
7196
  });
7193
7197
  } else if (executionMode === "tui") {
7194
7198
  agent.disableInteractiveConfirmation();
7199
+ confirmAcpLeaderThroughEvents();
7195
7200
  const state = {
7196
7201
  projectRoot,
7197
7202
  wpaths,
@@ -7579,4 +7584,4 @@ export {
7579
7584
  execute,
7580
7585
  resolveReviewerFallbackModels
7581
7586
  };
7582
- //# sourceMappingURL=execution-BAP566QC.js.map
7587
+ //# sourceMappingURL=execution-OK34CJKJ.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Live notes to a running external ACP worker.
3
+ *
4
+ * A WrongStack agent registers in the session note hub and folds notes in at
5
+ * its next iteration. An external agent (Claude Code over ACP) has no such
6
+ * loop, so while its turn runs this registers an inbox for it that injects
7
+ * each note into the turn through the agent's steering extension. The leader
8
+ * then reaches the worker with `session_note`, as it reaches its own workers.
9
+ */
10
+ import type { AcpSteerOutcome } from '@wrongstack/acp';
11
+ import { type SessionNoteHub } from '@wrongstack/core/coordination';
12
+ import type { SubagentRunContext, TaskSpec } from '@wrongstack/core/types';
13
+ interface Note {
14
+ from: string;
15
+ kind: string;
16
+ body: string;
17
+ subject?: string | undefined;
18
+ }
19
+ /** The note as the worker reads it: who sent it, as what, then the text. */
20
+ export declare function steerMessage(note: Note): string;
21
+ /**
22
+ * Register `ctx.subagentId` (and its display name) as a live agent of the
23
+ * delegating session for the length of the turn. Returns the unregister, or
24
+ * undefined when no WrongStack session delegated the task.
25
+ */
26
+ export declare function registerAcpSteerInbox(ctx: SubagentRunContext, _task: TaskSpec, steer: (text: string) => Promise<AcpSteerOutcome>, hub?: Pick<SessionNoteHub, 'register'>, onUndelivered?: (outcome: string) => void): (() => void) | undefined;
27
+ export {};
28
+ //# sourceMappingURL=acp-live-steer.d.ts.map
@@ -0,0 +1,49 @@
1
+ /**
2
+ * WrongStack's permission rules for an external ACP worker.
3
+ *
4
+ * A delegated agent must not be a one-hop bypass of the user's approval
5
+ * system. WrongStack's own subagents run every tool call through
6
+ * `AutoApprovePermissionPolicy`: the user's deny rules bind them, destructive
7
+ * commands and credential reads are refused (a worker cannot ask), and the
8
+ * user's YOLO+ lifts those refusals. An ACP worker gets the same treatment:
9
+ * the host starts it in a mode where it asks before edits, commands and
10
+ * fetches, and each `session/request_permission` is translated into the
11
+ * matching WrongStack tool call and decided by that policy. A request it
12
+ * cannot evaluate — an unknown kind, a call naming no target, a tool the run
13
+ * does not have — is refused, never waved through.
14
+ */
15
+ import type { PermissionPolicy as AcpPermissionPolicy } from '@wrongstack/acp';
16
+ import type { PermissionDecision, Tool } from '@wrongstack/core/types';
17
+ /** The WrongStack tool call an ACP permission request stands for. */
18
+ export interface WrongStackCall {
19
+ tool: string;
20
+ input: Record<string, unknown>;
21
+ }
22
+ export interface AcpPermissionBridgeOptions {
23
+ /** WrongStack's subagent policy (an `AutoApprovePermissionPolicy`). */
24
+ evaluate: (tool: Tool, input: unknown, ctx: {
25
+ projectRoot: string;
26
+ cwd: string;
27
+ }) => Promise<PermissionDecision>;
28
+ /** Resolve a WrongStack tool by name (the host's tool registry). */
29
+ getTool: (name: string) => Tool | undefined;
30
+ projectRoot: string;
31
+ /**
32
+ * Whether MCP tools may run at all. False under `--restricted`, which keeps
33
+ * MCP tools out of the registry and so out of a worker's reach too.
34
+ */
35
+ allowMcp?: boolean | undefined;
36
+ /**
37
+ * Ask the user when the policy wants a question (`confirm`). A worker has
38
+ * no one to ask, so without this a `confirm` is refused; a leader runs in
39
+ * front of the user and passes the session's own confirmation prompt.
40
+ */
41
+ confirm?: ((tool: Tool, call: WrongStackCall, request: {
42
+ toolCallId: string | undefined;
43
+ signal: AbortSignal;
44
+ }) => Promise<boolean>) | undefined;
45
+ /** Told about every refusal, for the host's log. */
46
+ onRefused?: ((call: WrongStackCall, reason: string) => void) | undefined;
47
+ }
48
+ export declare function wrongstackAcpPermissionPolicy(opts: AcpPermissionBridgeOptions): AcpPermissionPolicy;
49
+ //# sourceMappingURL=acp-permission-bridge.d.ts.map
@@ -0,0 +1,3 @@
1
+ /** Run `start` unless `agentId` is held; record a hold when it fails on quota. */
2
+ export declare function runWithQuotaHold<T>(agentId: string, start: () => Promise<T>, now?: () => number): Promise<T>;
3
+ //# sourceMappingURL=acp-quota-hold.d.ts.map
@@ -0,0 +1,3 @@
1
+ /** Record one rate-limit reading from `agentId`; ignores readings it cannot read. */
2
+ export declare function recordAcpRateLimit(agentId: string, info: Record<string, unknown>, now?: number): void;
3
+ //# sourceMappingURL=acp-quota-reading.d.ts.map
@@ -0,0 +1,15 @@
1
+ /** Remind an active ACP turn about local /btw notes and newly waiting mail. */
2
+ import { type Context } from '@wrongstack/core/agent';
3
+ type Steer = (text: string) => Promise<'injected' | 'promptRequired' | 'startedNewTurn' | 'unsupported'>;
4
+ export interface AcpTurnRemindersOptions {
5
+ steer: Steer;
6
+ context?: Context | undefined;
7
+ unreadCount?: (() => Promise<number>) | undefined;
8
+ btwPollMs?: number | undefined;
9
+ mailPollMs?: number | undefined;
10
+ }
11
+ /** Mailbox awareness embeds message bodies; ask ACP to read inbox instead. */
12
+ export declare function acpBtwBlock(notes: readonly string[]): string;
13
+ export declare function startAcpTurnReminders(options: AcpTurnRemindersOptions): () => void;
14
+ export {};
15
+ //# sourceMappingURL=acp-turn-reminders.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { type AcpSessionSetup } from '@wrongstack/acp';
2
+ import type { Config, SubagentRunContext, TaskSpec } from '@wrongstack/core/types';
3
+ export type BridgeServer = 'sage' | 'mailbox' | 'kanban' | 'codebase-index' | 'requirement-intake';
4
+ export declare const DEFAULT_BRIDGE_AGENTS: readonly string[];
5
+ export declare const DEFAULT_BRIDGE_SERVERS: readonly BridgeServer[];
6
+ type BridgeConfig = NonNullable<NonNullable<Config['acp']>['bridge']>;
7
+ /** How to start this same `wstack`: the binary itself, or node/bun + the CLI entry. */
8
+ export declare function wstackLaunch(args: string[], entry?: string | undefined): {
9
+ command: string;
10
+ args: string[];
11
+ };
12
+ /** A short task-local cue: the Claude adapter gives user-turn text more immediate weight. */
13
+ export declare function bridgeTaskKickoff(servers: readonly BridgeServer[]): string;
14
+ /**
15
+ * The note appended to the worker's system prompt. It must not vary per task
16
+ * or per worker: the system prompt is the head of the agent's prompt cache, so
17
+ * a task id or worker id in it made every worker rewrite ~25k cached tokens
18
+ * (measured: $0.21 per one-line task, against $0.008 with a stable prompt).
19
+ * Per-worker identity lives in the MCP servers' arguments instead.
20
+ */
21
+ export declare function bridgeNote(servers: readonly BridgeServer[], delegated?: boolean): string;
22
+ /**
23
+ * The note for an agent running as the session's LEADER: the user talks to it
24
+ * through WrongStack, so it answers them directly and ends a turn the way
25
+ * WrongStack's own leader does, with next steps the user can send back.
26
+ */
27
+ export declare function leaderBridgeNote(servers: readonly BridgeServer[]): string;
28
+ /** True when `command` resolves to a file on PATH (PATHEXT-aware on Windows). */
29
+ export declare function onPath(command: string, env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
30
+ /**
31
+ * Bridged agents the leader can hand a task to on this machine: listed in
32
+ * `acp.bridge.agents` (by catalog or registry id) and either configured by
33
+ * the user in `acp.agents` or with their CLI on PATH. Catalog ids, in order.
34
+ */
35
+ export declare function installedBridgeAgents(acp: Config['acp'] | undefined, isOnPath?: (command: string) => boolean): string[];
36
+ /**
37
+ * The per-session setup for `agentId`, or undefined when the bridge does not
38
+ * apply to it (not listed, turned off, or no servers).
39
+ */
40
+ export declare function wrongstackBridgeSetup(agentId: string, projectRoot: string, config: BridgeConfig | undefined, role?: 'worker' | 'leader'): ((task: TaskSpec, ctx: SubagentRunContext) => AcpSessionSetup) | undefined;
41
+ export {};
42
+ //# sourceMappingURL=acp-wrongstack-bridge.d.ts.map
@@ -1,10 +1,28 @@
1
- import { type ACPProgressEvent, type AcpAgentCommandOverrides, type AcpLiveCatalog } from '@wrongstack/acp';
2
- import type { SubagentRunContext, SubagentRunner, TaskSpec } from '@wrongstack/core/types';
1
+ import { type ACPProgressEvent, type AcpAgentCommandOverrides, type AcpLiveCatalog, type PermissionPolicy as AcpPermissionPolicy } from '@wrongstack/acp';
2
+ import type { Config, SubagentRunContext, SubagentRunner, TaskSpec } from '@wrongstack/core/types';
3
3
  export type AcpLivePublisher = (ctx: SubagentRunContext, task: TaskSpec, event: ACPProgressEvent) => void;
4
4
  export interface BuildAcpSubagentRunnerOptions {
5
+ /**
6
+ * The project the worker works in: its cwd and file-access root. Without it
7
+ * the worker ran in the host process's cwd — a subdirectory, or another
8
+ * repository than the session's.
9
+ */
10
+ projectRoot?: string | undefined;
5
11
  overrides?: AcpAgentCommandOverrides | undefined;
6
12
  live?: AcpLiveCatalog | undefined;
7
13
  publishLive?: AcpLivePublisher | undefined;
14
+ /** Project the worker runs in, plus `acp.bridge` config: see acp-wrongstack-bridge.ts. */
15
+ bridge?: {
16
+ projectRoot: string;
17
+ config?: NonNullable<Config['acp']>['bridge'] | undefined;
18
+ } | undefined;
19
+ /**
20
+ * WrongStack's permission rules for the worker's session (see
21
+ * acp-permission-bridge.ts). When set, the worker is also started in its
22
+ * `default` mode so it asks before edits and commands, whatever mode the
23
+ * user runs the agent in on their own.
24
+ */
25
+ permissions?: ((ctx: SubagentRunContext) => AcpPermissionPolicy) | undefined;
8
26
  }
9
27
  /**
10
28
  * Same command resolution as `wstack acp spawn` / `/acp` — user override,
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ import {
6
6
  import {
7
7
  parseArgs
8
8
  } from "./chunk-75OLD563.js";
9
+ import {
10
+ closeAcpLeaderSessions
11
+ } from "./chunk-GKGWPFW2.js";
9
12
  import {
10
13
  CLI_VERSION
11
14
  } from "./chunk-HKMOIIPQ.js";
@@ -122,7 +125,7 @@ async function main(argv) {
122
125
  applyAsciiMode(earlyFlags);
123
126
  }
124
127
  if (earlyFlags["help"] === true || earlyFlags["version"] === true) {
125
- const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-CPCT5MWB.js");
128
+ const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-QEXUS3BY.js");
126
129
  const earlyExit = await handleHelpVersionShortCircuit(argv);
127
130
  if (earlyExit !== null) return earlyExit;
128
131
  }
@@ -131,7 +134,7 @@ async function main(argv) {
131
134
  shouldCaptureTuiStartup(parsed.flags, parsed.positional)
132
135
  );
133
136
  try {
134
- const { initializeCli } = await import("./cli-context-YIT4FEDM.js");
137
+ const { initializeCli } = await import("./cli-context-E44HQ4ZO.js");
135
138
  const cliCtx = await initializeCli(argv, {
136
139
  onNonTuiLaunch: () => startupOutput.stop()
137
140
  });
@@ -141,7 +144,7 @@ async function main(argv) {
141
144
  } else {
142
145
  startupOutput.stop();
143
146
  }
144
- const { runInteractive } = await import("./cli-main-JIADJ5OL.js");
147
+ const { runInteractive } = await import("./cli-main-OT63I2FX.js");
145
148
  return await runInteractive(cliCtx);
146
149
  } finally {
147
150
  startupOutput.stop();
@@ -252,7 +255,7 @@ function runCliProcess(mainFn) {
252
255
  mainFn(process.argv.slice(2)).then(
253
256
  (c) => {
254
257
  process.exitCode = c;
255
- scheduleForcedExit(c);
258
+ void closeAcpLeaderSessions().finally(() => scheduleForcedExit(c));
256
259
  },
257
260
  (err) => {
258
261
  runFatalSalvageSync();
@@ -345,12 +345,108 @@ async function serveMcpStdio(deps, positional) {
345
345
  return 0;
346
346
  }
347
347
 
348
+ // src/mcp-serve-project.ts
349
+ var PROJECT_MCP_SERVERS = [
350
+ "mailbox",
351
+ "kanban",
352
+ "codebase-index",
353
+ "requirement-intake",
354
+ "sage"
355
+ ];
356
+ function isProjectMcpServer(value) {
357
+ return PROJECT_MCP_SERVERS.includes(value);
358
+ }
359
+ var SERVER_FLAGS = [
360
+ "project-root",
361
+ "actor",
362
+ "session-id",
363
+ "name",
364
+ "role",
365
+ "writable",
366
+ "admin",
367
+ "destructive",
368
+ "http",
369
+ "stdio",
370
+ "port",
371
+ "host",
372
+ "token",
373
+ "index-dir",
374
+ "origin",
375
+ "watch"
376
+ ];
377
+ var SWITCHES = /* @__PURE__ */ new Set([
378
+ "--writable",
379
+ "--admin",
380
+ "--destructive",
381
+ "--http",
382
+ "--stdio",
383
+ "--watch"
384
+ ]);
385
+ function normalizeSwitches(args) {
386
+ const out = [];
387
+ for (let i = 0; i < args.length; i++) {
388
+ const arg = args[i];
389
+ const eq = arg.indexOf("=");
390
+ const flag = eq === -1 ? arg : arg.slice(0, eq);
391
+ if (!SWITCHES.has(flag)) {
392
+ out.push(arg);
393
+ continue;
394
+ }
395
+ const value = eq === -1 ? void 0 : arg.slice(eq + 1);
396
+ if (value === "false") continue;
397
+ out.push(flag);
398
+ if (eq === -1 && args[i + 1] === "true") i++;
399
+ }
400
+ return out;
401
+ }
402
+ function optionValue(args, name) {
403
+ const flag = `--${name}`;
404
+ for (let i = 0; i < args.length; i++) {
405
+ const arg = args[i];
406
+ if (arg === flag) {
407
+ const next = args[i + 1];
408
+ return next !== void 0 && !next.startsWith("--") ? next : void 0;
409
+ }
410
+ if (arg.startsWith(`${flag}=`)) return arg.slice(flag.length + 1);
411
+ }
412
+ return void 0;
413
+ }
414
+ async function serveProjectMcp(server, rawArgs, deps) {
415
+ const args = normalizeSwitches(restoreFlags(rawArgs, deps, SERVER_FLAGS));
416
+ if (server === "sage") {
417
+ const { serveAttachedSageMcpStdio } = await import("@wrongstack/sage-mcp");
418
+ await serveAttachedSageMcpStdio({
419
+ // A client may start this server from any directory; an explicit root wins.
420
+ projectRoot: optionValue(args, "project-root") ?? deps.projectRoot,
421
+ directory: deps.config.Sage?.storage?.directory,
422
+ origin: optionValue(args, "origin")?.trim() || "mcp-client"
423
+ });
424
+ return 0;
425
+ }
426
+ const argv = optionValue(args, "project-root") === void 0 ? [...args, "--project-root", deps.projectRoot] : args;
427
+ if (server === "mailbox") {
428
+ const { runMailboxMcpServer } = await import("@wrongstack/mailbox-mcp");
429
+ return runMailboxMcpServer(argv);
430
+ }
431
+ if (server === "kanban") {
432
+ const { runKanbanMcpServer } = await import("@wrongstack/kanban-mcp");
433
+ return runKanbanMcpServer(argv);
434
+ }
435
+ if (server === "requirement-intake") {
436
+ const { runRequirementIntakeMcpServer } = await import("@wrongstack/requirement-intake-mcp");
437
+ return runRequirementIntakeMcpServer(argv);
438
+ }
439
+ const { runCodebaseIndexMcpServer } = await import("@wrongstack/codebase-index-mcp");
440
+ return runCodebaseIndexMcpServer(argv);
441
+ }
442
+
348
443
  // src/subcommands/handlers/mcp.ts
349
444
  var BUILT_IN_MCP = allServers();
350
445
  var mcpCmd = async (args, deps) => {
351
446
  args = restoreFlags(args, deps, ["enable", "e", "transport", "url", "command"]);
352
447
  const sub = args[0];
353
448
  if (sub === "serve") {
449
+ if (isProjectMcpServer(args[1])) return serveProjectMcp(args[1], args.slice(2), deps);
354
450
  return serveMcpStdio(deps, args.slice(1));
355
451
  }
356
452
  if (!sub || sub === "list") {
@@ -461,4 +557,4 @@ function isRecord(value) {
461
557
  export {
462
558
  mcpCmd
463
559
  };
464
- //# sourceMappingURL=mcp-2XWBJEQN.js.map
560
+ //# sourceMappingURL=mcp-W7A5HUXV.js.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * `wstack mcp serve <mailbox|kanban|codebase-index|requirement-intake|sage>` — run one of
3
+ * WrongStack's project MCP servers from inside `wstack` itself.
4
+ *
5
+ * Mailbox, Kanban, Codebase Index and Requirements Intake also ship as their own npm bins
6
+ * (`wstack-mailbox-mcp`, …), but the standalone binary carries none of them,
7
+ * so this is the launch path that works in every install. Each server is bound
8
+ * to one project: `--project-root` defaults to the project this command runs
9
+ * in, and every server only attaches to that project's running owner.
10
+ *
11
+ * stdout is the JSON-RPC channel; everything else goes to stderr.
12
+ */
13
+ import type { SubcommandDeps } from './subcommands/contracts.js';
14
+ export declare const PROJECT_MCP_SERVERS: readonly ['mailbox', 'kanban', 'codebase-index', 'requirement-intake', 'sage'];
15
+ export type ProjectMcpServer = (typeof PROJECT_MCP_SERVERS)[number];
16
+ export declare function isProjectMcpServer(value: string | undefined): value is ProjectMcpServer;
17
+ export declare function serveProjectMcp(server: ProjectMcpServer, rawArgs: string[], deps: SubcommandDeps): Promise<number>;
18
+ //# sourceMappingURL=mcp-serve-project.d.ts.map
@@ -7,7 +7,7 @@ import {
7
7
  renderFocusedHelpToString,
8
8
  renderGenericHelp,
9
9
  subcommandsWithFocusedHelp
10
- } from "./chunk-3R3OADC5.js";
10
+ } from "./chunk-ZF4HRR5F.js";
11
11
  import "./chunk-ZXX3MJRL.js";
12
12
  import "./chunk-W23PY4IJ.js";
13
13
  export {
@@ -20,4 +20,4 @@ export {
20
20
  renderGenericHelp,
21
21
  subcommandsWithFocusedHelp
22
22
  };
23
- //# sourceMappingURL=per-subcommand-help-D6J4ZXW2.js.map
23
+ //# sourceMappingURL=per-subcommand-help-4GYSCMLU.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  handleHelpVersionShortCircuit
3
- } from "./chunk-NMXQFQ26.js";
3
+ } from "./chunk-TAE3EGBM.js";
4
4
  import "./chunk-75OLD563.js";
5
5
  import "./chunk-6VPWQ4TG.js";
6
6
  import "./chunk-HKMOIIPQ.js";
@@ -8,4 +8,4 @@ import "./chunk-W23PY4IJ.js";
8
8
  export {
9
9
  handleHelpVersionShortCircuit
10
10
  };
11
- //# sourceMappingURL=short-circuit-flags-CPCT5MWB.js.map
11
+ //# sourceMappingURL=short-circuit-flags-QEXUS3BY.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  subcommandNames,
3
3
  subcommands
4
- } from "./chunk-GRAGMA4B.js";
4
+ } from "./chunk-2LTHDKZX.js";
5
5
  import "./chunk-W23PY4IJ.js";
6
6
  export {
7
7
  subcommandNames,
8
8
  subcommands
9
9
  };
10
- //# sourceMappingURL=subcommands-VTMIZQBP.js.map
10
+ //# sourceMappingURL=subcommands-YADUV7IJ.js.map
@@ -14,14 +14,19 @@ import {
14
14
  import {
15
15
  createHqCommandDispatcher,
16
16
  createProjectKanbanAssignHandler,
17
- createProjectKanbanTransitionHandler
18
- } from "./chunk-XT3NAHRX.js";
17
+ createProjectKanbanTransitionHandler,
18
+ installedBridgeAgents
19
+ } from "./chunk-JKTJSLUT.js";
19
20
  import {
20
21
  startCliHqConnection
21
22
  } from "./chunk-76JE54WD.js";
22
23
  import {
23
24
  WebSocketServer
24
25
  } from "./chunk-OZCYZYN2.js";
26
+ import {
27
+ ACP_LEADER_PROVIDER_ID,
28
+ setAcpLeaderSessionAgents
29
+ } from "./chunk-GKGWPFW2.js";
25
30
  import {
26
31
  CLI_VERSION
27
32
  } from "./chunk-HKMOIIPQ.js";
@@ -1092,6 +1097,33 @@ import {
1092
1097
  createEmbeddedProviderOperations
1093
1098
  } from "@wrongstack/webui-server";
1094
1099
 
1100
+ // src/acp-leader/acp-leader-picker.ts
1101
+ import { findAgentDescriptor } from "@wrongstack/acp";
1102
+ function acpLeaderPickable(config) {
1103
+ const agents = installedBridgeAgents(config?.acp);
1104
+ if (agents.length === 0) return [];
1105
+ return [
1106
+ {
1107
+ id: ACP_LEADER_PROVIDER_ID,
1108
+ type: ACP_LEADER_PROVIDER_ID,
1109
+ models: agents.map((id) => {
1110
+ const descriptor = findAgentDescriptor(id);
1111
+ return {
1112
+ id,
1113
+ name: descriptor?.displayName ?? id,
1114
+ description: "ACP agent leading the session",
1115
+ ...descriptor?.contextWindow ? { contextWindow: descriptor.contextWindow } : {}
1116
+ };
1117
+ })
1118
+ }
1119
+ ];
1120
+ }
1121
+ function buildAcpLeaderProvider(registry, providerId, config) {
1122
+ const type = config.type ?? providerId;
1123
+ if (type !== ACP_LEADER_PROVIDER_ID || !registry?.has(type)) return void 0;
1124
+ return registry.create({ ...config, type: providerId }, type);
1125
+ }
1126
+
1095
1127
  // src/webui-server/credential-watcher.ts
1096
1128
  import { TOKENS } from "@wrongstack/core/kernel";
1097
1129
  import { watchProviderConfig } from "@wrongstack/core/storage";
@@ -1175,6 +1207,9 @@ function createEmbeddedProviderPlane(input) {
1175
1207
  providerAuthRegistry: opts.providerAuthRegistry,
1176
1208
  getDisabledModels: () => opts.appConfig?.disabledModels ?? [],
1177
1209
  getDisabledProviders: () => opts.appConfig?.disabledProviders ?? [],
1210
+ // `acp` with the installed ACP agents: an agent such as Claude Code can
1211
+ // lead a tab like a model (see docs/slash/acp.md).
1212
+ hostProviders: () => acpLeaderPickable(opts.appConfig),
1178
1213
  send,
1179
1214
  broadcast,
1180
1215
  log: (m) => console.log(m)
@@ -1308,6 +1343,8 @@ function createWebuiRouteContexts({
1308
1343
  getConfig: () => opts.appConfig,
1309
1344
  onMaxContextResolved: opts.onModelContextResolved,
1310
1345
  persistPrefs,
1346
+ // The ACP leader's factory lives in the CLI's provider registry.
1347
+ buildProvider: (providerId, config) => buildAcpLeaderProvider(opts.agent.providers, providerId, config),
1311
1348
  send,
1312
1349
  broadcast,
1313
1350
  log: (m) => console.log(m)
@@ -2302,6 +2339,7 @@ async function runWebUI(opts) {
2302
2339
  abortControllers
2303
2340
  );
2304
2341
  sessionAgentsRef = sessionAgents;
2342
+ setAcpLeaderSessionAgents((sessionId) => sessionAgents.peek(sessionId));
2305
2343
  const autoWakeHost = opts.leaderAutoWake ? createWebuiLeaderAutoWakeHost({
2306
2344
  controller: opts.leaderAutoWake,
2307
2345
  events: opts.events,
@@ -2458,4 +2496,4 @@ async function runWebUI(opts) {
2458
2496
  export {
2459
2497
  runWebUI
2460
2498
  };
2461
- //# sourceMappingURL=webui-server-HIUY3RHD.js.map
2499
+ //# sourceMappingURL=webui-server-CB64CFDG.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/cli",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack CLI — terminal AI coding agent with provider catalog from models.dev. Provides `wrongstack` and `wstack` binaries.",
6
6
  "keywords": [
@@ -48,42 +48,46 @@
48
48
  "clean": "bun -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\""
49
49
  },
50
50
  "dependencies": {
51
- "@wrongstack/acp": "1.1.0",
52
- "@wrongstack/bench": "1.1.0",
53
- "@wrongstack/core": "1.1.0",
54
- "@wrongstack/kanban": "1.1.0",
55
- "@wrongstack/mcp": "1.1.0",
56
- "@wrongstack/persistence": "1.1.0",
57
- "@wrongstack/plug-lsp": "1.1.0",
58
- "@wrongstack/plugins": "1.1.0",
59
- "@wrongstack/primitives": "1.1.0",
60
- "@wrongstack/providers": "1.1.0",
61
- "@wrongstack/requirement-intake": "1.1.0",
62
- "@wrongstack/runtime": "1.1.0",
63
- "@wrongstack/sage": "1.1.0",
64
- "@wrongstack/sage-mcp": "1.1.0",
65
- "@wrongstack/sdd": "1.1.0",
66
- "@wrongstack/security-scanner": "1.1.0",
67
- "@wrongstack/simpleui": "1.1.0",
68
- "@wrongstack/techstack": "1.1.0",
69
- "@wrongstack/telegram": "1.1.0",
70
- "@wrongstack/tools": "1.1.0",
71
- "@wrongstack/tui": "1.1.0",
72
- "@wrongstack/vector-memory": "1.1.0",
73
- "@wrongstack/webui": "1.1.0",
74
- "@wrongstack/webui-hq": "1.1.0",
75
- "@wrongstack/webui-protocol": "1.1.0",
76
- "@wrongstack/webui-server": "1.1.0",
77
- "@wrongstack/wrongtrace": "1.1.0",
51
+ "@wrongstack/acp": "1.1.2",
52
+ "@wrongstack/bench": "1.1.2",
53
+ "@wrongstack/codebase-index-mcp": "1.1.2",
54
+ "@wrongstack/core": "1.1.2",
55
+ "@wrongstack/kanban": "1.1.2",
56
+ "@wrongstack/kanban-mcp": "1.1.2",
57
+ "@wrongstack/mailbox-mcp": "1.1.2",
58
+ "@wrongstack/mcp": "1.1.2",
59
+ "@wrongstack/persistence": "1.1.2",
60
+ "@wrongstack/plug-lsp": "1.1.2",
61
+ "@wrongstack/plugins": "1.1.2",
62
+ "@wrongstack/primitives": "1.1.2",
63
+ "@wrongstack/providers": "1.1.2",
64
+ "@wrongstack/requirement-intake": "1.1.2",
65
+ "@wrongstack/requirement-intake-mcp": "1.1.2",
66
+ "@wrongstack/runtime": "1.1.2",
67
+ "@wrongstack/sage": "1.1.2",
68
+ "@wrongstack/sage-mcp": "1.1.2",
69
+ "@wrongstack/sdd": "1.1.2",
70
+ "@wrongstack/security-scanner": "1.1.2",
71
+ "@wrongstack/simpleui": "1.1.2",
72
+ "@wrongstack/techstack": "1.1.2",
73
+ "@wrongstack/telegram": "1.1.2",
74
+ "@wrongstack/tools": "1.1.2",
75
+ "@wrongstack/tui": "1.1.2",
76
+ "@wrongstack/vector-memory": "1.1.2",
77
+ "@wrongstack/webui": "1.1.2",
78
+ "@wrongstack/webui-hq": "1.1.2",
79
+ "@wrongstack/webui-protocol": "1.1.2",
80
+ "@wrongstack/webui-server": "1.1.2",
81
+ "@wrongstack/wrongtrace": "1.1.2",
78
82
  "ws": "^8.22.0"
79
83
  },
80
84
  "optionalDependencies": {
81
- "@wrongstack/desktop": "1.1.0"
85
+ "@wrongstack/desktop": "1.1.2"
82
86
  },
83
87
  "devDependencies": {
84
88
  "@types/node": "^26.5.1",
85
89
  "@types/ws": "^8.18.1",
86
- "@wrongstack/governance": "1.1.0",
90
+ "@wrongstack/governance": "1.1.2",
87
91
  "jsdom": "^30.0.1",
88
92
  "typescript": "^7.0.2"
89
93
  },
@@ -1,43 +0,0 @@
1
- /**
2
- * Anthropic "Sign in with Claude" OAuth (Authorization Code + PKCE) — Claude
3
- * Pro/Max subscription login. Parallel to the Codex flow but with Anthropic's
4
- * endpoints and quirks:
5
- * - authorize at claude.ai/oauth/authorize (params include `code=true`),
6
- * - the OAuth `state` is the PKCE verifier (Anthropic's convention),
7
- * - JSON (not form) token exchange at platform.claude.com/v1/oauth/token,
8
- * - loopback callback on http://localhost:53692/callback.
9
- *
10
- * Stored under the canonical `anthropic-oauth` provider (family `anthropic-oauth`)
11
- * so it never clobbers an API-key `anthropic` provider. The provider adapter
12
- * adds the Bearer + beta headers and the required Claude Code system block.
13
- */
14
- import type { AuthMenuDeps } from './types.js';
15
- export declare const CLAUDE_PROVIDER_ID = "anthropic-oauth";
16
- export interface ClaudeTokens {
17
- access: string;
18
- refresh: string;
19
- expires: number;
20
- }
21
- export declare function generatePkce(): {
22
- verifier: string;
23
- challenge: string;
24
- };
25
- /** Build the Claude authorize URL. Anthropic uses the PKCE verifier as `state`. */
26
- export declare function buildAuthorizeUrl(challenge: string, verifier: string): string;
27
- export declare function parseAuthorizationInput(input: string): {
28
- code?: string | undefined;
29
- state?: string | undefined;
30
- };
31
- /** Exchange an authorization code (+ verifier, reused as state) for tokens. */
32
- export declare function exchangeAuthorizationCode(code: string, state: string, verifier: string, signal?: AbortSignal): Promise<ClaudeTokens>;
33
- export interface ClaudeLoginOptions {
34
- providerId?: string;
35
- /**
36
- * External cancellation signal (e.g. the TUI auth panel's Esc). When
37
- * provided, the flow does NOT install its own SIGINT handler — the
38
- * caller owns cancellation.
39
- */
40
- signal?: AbortSignal | undefined;
41
- }
42
- export declare function runClaudeOAuthLogin(deps: AuthMenuDeps, opts?: ClaudeLoginOptions): Promise<number>;
43
- //# sourceMappingURL=anthropic-oauth.d.ts.map