@wrongstack/cli 1.0.10 → 1.0.12

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 (31) hide show
  1. package/dist/{acp-CXLANMEZ.js → acp-IJ55NBMJ.js} +5 -3
  2. package/dist/acp-mcp-servers.d.ts +2 -0
  3. package/dist/arg-parser.d.ts +6 -0
  4. package/dist/{auth-3K6EN5JP.js → auth-YXK3EDUL.js} +9 -3
  5. package/dist/{chunk-EK2P53GL.js → chunk-C3Z4N6A6.js} +23 -3
  6. package/dist/{chunk-7K3IJGWC.js → chunk-OJR7K3OI.js} +8 -8
  7. package/dist/{chunk-SXJTVNWF.js → chunk-OWNC7LMD.js} +2 -2
  8. package/dist/{chunk-FSZ5QU3M.js → chunk-RDHFXOJM.js} +153 -69
  9. package/dist/{chunk-5VPDKQDH.js → chunk-TNZBQG45.js} +3 -3
  10. package/dist/{chunk-7FPN3QTH.js → chunk-YRC3I3LE.js} +172 -15
  11. package/dist/{cli-context-6GMXUOXD.js → cli-context-5IF7ZYEY.js} +7 -7
  12. package/dist/{cli-main-BU5DEHDO.js → cli-main-6LMQSS66.js} +84 -42
  13. package/dist/{diag-doctor-PCER6KHH.js → diag-doctor-ANPRUYFM.js} +13 -3
  14. package/dist/{execution-4RXQLDAF.js → execution-EXDRBS4F.js} +2 -2
  15. package/dist/{hq-DQTUE7RC.js → hq-NO2NWGU4.js} +153 -5
  16. package/dist/hq-server/auth-state.d.ts +11 -0
  17. package/dist/hq-server/mailbox-gateway-health.d.ts +67 -0
  18. package/dist/hq-server/mailbox-gateway-manager.d.ts +38 -0
  19. package/dist/hq-server/routes/system-handlers.d.ts +27 -0
  20. package/dist/hq-server/routes.d.ts +11 -0
  21. package/dist/hq-server/snapshot.d.ts +14 -1
  22. package/dist/hq-server/upgrade-handler.d.ts +7 -0
  23. package/dist/{hq-server-JJFGFWI5.js → hq-server-KE5YDNGG.js} +2 -2
  24. package/dist/index.js +4 -4
  25. package/dist/{mcp-FX7TKPTV.js → mcp-DC5WSBOO.js} +28 -10
  26. package/dist/mcp-serve.d.ts +9 -0
  27. package/dist/services/mcp-management.d.ts +0 -6
  28. package/dist/{short-circuit-flags-LHUNLCZY.js → short-circuit-flags-72E77TJI.js} +3 -3
  29. package/dist/{subcommands-UXWY3OPC.js → subcommands-EJI7DBQS.js} +2 -2
  30. package/dist/wiring/codebase-index.d.ts +8 -0
  31. package/package.json +28 -28
@@ -7,9 +7,36 @@
7
7
  import type * as http from 'node:http';
8
8
  import type { HqAlertEngine, HqCommandAuditLog, HqEventEnvelope, HqPersistence } from '@wrongstack/core/hq';
9
9
  import type { WebSocket } from 'ws';
10
+ import type { HqMailboxGatewayHealth } from '../mailbox-gateway-health.js';
10
11
  import type { ConnectedClient } from '../types.js';
11
12
  export declare function handleApiSystemUpdate(res: http.ServerResponse): Promise<void>;
12
13
  export declare function handleApiSystemHealth(res: http.ServerResponse, clients: Map<WebSocket, ConnectedClient>, persistence: HqPersistence, eventLog: HqEventEnvelope[]): Promise<void>;
13
14
  export declare function handleApiCommandsAudit(req: http.IncomingMessage, res: http.ServerResponse, auditLog: HqCommandAuditLog): Promise<void>;
14
15
  export declare function handleApiAlerts(req: http.IncomingMessage, res: http.ServerResponse, alertEngine: HqAlertEngine): Promise<void>;
16
+ /**
17
+ * Structural view of the gateway manager this handler needs. Typing the
18
+ * parameter structurally — rather than importing `MailboxGatewayManager` —
19
+ * keeps this module out of the type-inclusive cycle
20
+ * `mailbox-gateway-manager → routes → system-handlers`, which
21
+ * `check:architecture` reports as unexcepted. The real manager satisfies this
22
+ * shape, so callers and the wire contract are unaffected.
23
+ */
24
+ interface MailboxHealthSource {
25
+ getHealth(): HqMailboxGatewayHealth;
26
+ }
27
+ /**
28
+ * W2 #14 (RFC hq-improvements-2026-09.md): GET /api/health/mailbox —
29
+ * mailbox gateway health snapshot for the cockpit's "Mailbox gateway" card.
30
+ *
31
+ * Surfaces {@link MailboxHealthSource.getHealth} verbatim. The contract
32
+ * (basename as `projectId`, full path as `projectRoot`, `actorAttached: false`
33
+ * on the HQ mount, sorted gateways) is locked by the focused test in
34
+ * `packages/cli/tests/hq-mailbox-gateway-health.test.ts`.
35
+ *
36
+ * No query parameters. No mutation. Same auth contract as
37
+ * `/api/system/health` — gated by `requireBrowserAuth` upstream in the
38
+ * router, not duplicated here.
39
+ */
40
+ export declare function handleApiMailboxHealth(res: http.ServerResponse, mailboxManager: MailboxHealthSource): void;
41
+ export {};
15
42
  //# sourceMappingURL=system-handlers.d.ts.map
@@ -13,6 +13,7 @@ import type { createHqPersistence, HqAlertEngine, HqCommandAuditLog, HqEventEnve
13
13
  import type { TrustBoundary } from '@wrongstack/core/security';
14
14
  import type { WebSocket } from 'ws';
15
15
  import * as HqServerAuth from './auth.js';
16
+ import type { HqMailboxGatewayHealth } from './mailbox-gateway-health.js';
16
17
  import { type ApplyHqAuthFile } from './routes/auth-handlers.js';
17
18
  import * as HqServerUtils from './utils.js';
18
19
  export declare const setHqSecurityHeaders: typeof HqServerAuth.setHqSecurityHeaders;
@@ -73,6 +74,16 @@ export interface HqRouterDeps {
73
74
  agentMessages: Map<string, HqTranscriptEntry[]>;
74
75
  mailboxGateways: Map<string, HqRouterMailboxGateway>;
75
76
  mailboxGatewayRateLimiter: MailboxHttpRateLimiter;
77
+ /**
78
+ * W2 #14 (RFC hq-improvements-2026-09.md): mailbox gateway manager used
79
+ * by `/api/health/mailbox` to surface the cockpit "Mailbox gateway"
80
+ * card. Same manager that owns `mailboxGateways` and
81
+ * `mailboxGatewayRateLimiter` — passed explicitly so the handler can
82
+ * call `getHealth()` without reaching into a closure.
83
+ */
84
+ mailboxManager: {
85
+ getHealth(): HqMailboxGatewayHealth;
86
+ };
76
87
  alertEngine: HqAlertEngine;
77
88
  auditLog: HqCommandAuditLog;
78
89
  persistence: ReturnType<typeof createHqPersistence>;
@@ -53,8 +53,21 @@ export declare const HQ_STALE_SNAPSHOT_MS: number;
53
53
  export declare function reapStaleClientState(clients: Map<WebSocket, ConnectedClient>, nowMs?: number): void;
54
54
  export declare function buildSnapshot(clients: Map<WebSocket, ConnectedClient>, options?: {
55
55
  tokenStats?: HqSnapshot['totals']['tokenStats'];
56
+ /**
57
+ * Recent command-audit entries (W4 #7). The caller owns the audit ring, so
58
+ * it hands over the window rather than the builder reaching for a global.
59
+ */
60
+ commandAudit?: readonly HqCommandAuditEntry[];
56
61
  }): HqSnapshot;
57
- export declare function createSnapshotBroadcaster(clients: Map<WebSocket, ConnectedClient>, browsers: Set<WebSocket>, persistence?: HqPersistence): HqSnapshotBroadcaster;
62
+ export declare function createSnapshotBroadcaster(clients: Map<WebSocket, ConnectedClient>, browsers: Set<WebSocket>, persistence?: HqPersistence, options?: {
63
+ /**
64
+ * W4 #7: command-audit window for the latency roll-up. Passed as a
65
+ * provider rather than an array because the broadcaster caches its
66
+ * serialized frame and only rebuilds when marked dirty — reading the ring
67
+ * at serialize time is what keeps the cached frame current.
68
+ */
69
+ commandAudit?: () => readonly HqCommandAuditEntry[];
70
+ }): HqSnapshotBroadcaster;
58
71
  export declare function buildProjectDetail(clients: Map<WebSocket, ConnectedClient>, projectId: string): ProjectDetail | null;
59
72
  export declare function broadcastEvent(event: HqEventEnvelope, browsers: Set<WebSocket>): void;
60
73
  /** Push one control command's lifecycle to every authenticated HQ browser. */
@@ -21,6 +21,13 @@ interface HqUpgradeHandlerDeps {
21
21
  sessions: Map<string, HqSessionEntry>;
22
22
  clients: Map<WebSocket, ConnectedClient>;
23
23
  clientSocketTokens: Map<WebSocket, HqToken | undefined>;
24
+ /**
25
+ * Session id that authorized each open browser socket, so token revocation
26
+ * can close only the affected browsers. Absent for a socket that
27
+ * authenticated with a bare loopback `?token=` rather than a cookie session;
28
+ * the revocation path treats that absence as "affected" (fail closed).
29
+ */
30
+ browserSocketSessions: Map<WebSocket, string>;
24
31
  browsers: Set<WebSocket>;
25
32
  eventLog: import('@wrongstack/core/hq').HqEventEnvelope[];
26
33
  transcripts: Map<string, TranscriptRing>;
@@ -10,7 +10,7 @@ import {
10
10
  readLocalSubagentTranscript,
11
11
  sanitizeApiError,
12
12
  startHqServer
13
- } from "./chunk-7FPN3QTH.js";
13
+ } from "./chunk-YRC3I3LE.js";
14
14
  import "./chunk-HXJYHAR4.js";
15
15
  import "./chunk-5EA6OTLJ.js";
16
16
  import "./chunk-Q7E3BPDU.js";
@@ -27,4 +27,4 @@ export {
27
27
  sanitizeApiError,
28
28
  startHqServer
29
29
  };
30
- //# sourceMappingURL=hq-server-JJFGFWI5.js.map
30
+ //# sourceMappingURL=hq-server-KE5YDNGG.js.map
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-XJXDOF63.js";
9
9
  import {
10
10
  parseArgs
11
- } from "./chunk-EK2P53GL.js";
11
+ } from "./chunk-C3Z4N6A6.js";
12
12
 
13
13
  // src/cli-entry-main.ts
14
14
  async function main(argv) {
@@ -16,14 +16,14 @@ async function main(argv) {
16
16
  applySessionShellDefault();
17
17
  const earlyFlags = parseArgs(argv).flags;
18
18
  if (earlyFlags["help"] === true || earlyFlags["version"] === true) {
19
- const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-LHUNLCZY.js");
19
+ const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-72E77TJI.js");
20
20
  const earlyExit = await handleHelpVersionShortCircuit(argv);
21
21
  if (earlyExit !== null) return earlyExit;
22
22
  }
23
- const { initializeCli } = await import("./cli-context-6GMXUOXD.js");
23
+ const { initializeCli } = await import("./cli-context-5IF7ZYEY.js");
24
24
  const cliCtx = await initializeCli(argv);
25
25
  if (typeof cliCtx === "number") return cliCtx;
26
- const { runInteractive } = await import("./cli-main-BU5DEHDO.js");
26
+ const { runInteractive } = await import("./cli-main-6LMQSS66.js");
27
27
  return runInteractive(cliCtx);
28
28
  }
29
29
 
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-YMXXOOFN.js";
7
7
 
8
8
  // src/subcommands/handlers/mcp.ts
9
- import { allServers } from "@wrongstack/core/infrastructure";
9
+ import { allServers, resolveMcpServerConfig } from "@wrongstack/core/infrastructure";
10
10
  import {
11
11
  expectDefined,
12
12
  jsonObjectFileExists,
@@ -49,6 +49,15 @@ function parseToolsFlag(flags, positional) {
49
49
  );
50
50
  return set.size > 0 ? set : null;
51
51
  }
52
+ function resolveServeHttpPort(flags) {
53
+ const raw = typeof flags["port"] === "string" ? flags["port"] : typeof flags["http"] === "string" ? flags["http"] : void 0;
54
+ if (raw === void 0 || raw.trim() === "") return 0;
55
+ const port = Number(raw);
56
+ if (!Number.isInteger(port) || port < 0 || port > 65535) {
57
+ throw new Error(`invalid --port "${raw}" \u2014 expected an integer between 0 and 65535`);
58
+ }
59
+ return port;
60
+ }
52
61
  async function loadSelectedMcpServeContent(flags, cwd) {
53
62
  const resources = [];
54
63
  const prompts = [];
@@ -287,7 +296,13 @@ async function serveMcpStdio(deps, positional) {
287
296
  });
288
297
  const mode = yolo ? "yolo: all tools" : "safe: read-only tools";
289
298
  if (flags["http"] === true || typeof flags["http"] === "string" || flags["port"] || flags["host"]) {
290
- const port = Number(flags["port"] ?? flags["http"] ?? 0) || 0;
299
+ let port;
300
+ try {
301
+ port = resolveServeHttpPort(flags);
302
+ } catch (err) {
303
+ log(`wrongstack MCP server: ${err instanceof Error ? err.message : String(err)}`);
304
+ return 1;
305
+ }
291
306
  const httpHost = typeof flags["host"] === "string" ? flags["host"] : "127.0.0.1";
292
307
  const tokenFromArg = typeof flags["token"] === "string" ? flags["token"] : void 0;
293
308
  const token = tokenFromArg ?? process.env.WRONGSTACK_MCP_TOKEN?.trim() ?? void 0;
@@ -344,10 +359,13 @@ var mcpCmd = async (args, deps) => {
344
359
  deps.renderer.write("Use `wstack mcp add <name>` or set mcpServers in your config.\n");
345
360
  return 0;
346
361
  }
347
- for (const [name, cfg] of Object.entries(servers)) {
348
- const status = cfg.enabled === false ? "disabled" : "enabled";
349
- const desc = cfg.description ? ` # ${cfg.description}` : "";
350
- deps.renderer.write(` ${name.padEnd(20)} ${cfg.transport.padEnd(16)} ${status}${desc}
362
+ for (const [name, entry] of Object.entries(servers)) {
363
+ const cfg = resolveMcpServerConfig(name, entry);
364
+ const status = entry?.enabled === false ? "disabled" : "enabled";
365
+ const description = cfg?.description ?? entry?.description;
366
+ const desc = description ? ` # ${description}` : "";
367
+ const transport = cfg?.transport ?? "invalid (no transport)";
368
+ deps.renderer.write(` ${name.padEnd(20)} ${transport.padEnd(16)} ${status}${desc}
351
369
  `);
352
370
  }
353
371
  return 0;
@@ -391,7 +409,7 @@ async function addMcpServer(args, deps) {
391
409
  deps.renderer.write("\nRun `wstack mcp add <name> --enable` to enable immediately.\n");
392
410
  return 1;
393
411
  }
394
- const factory = BUILT_IN_MCP[name];
412
+ const factory = Object.hasOwn(BUILT_IN_MCP, name) ? BUILT_IN_MCP[name] : void 0;
395
413
  if (!factory) {
396
414
  deps.renderer.writeError(
397
415
  `Unknown server "${name}". Run \`wstack mcp add\` without args to see available servers.
@@ -403,7 +421,7 @@ async function addMcpServer(args, deps) {
403
421
  serverCfg.enabled = enable;
404
422
  const existing = await readJsonObjectFile(configPath);
405
423
  const mcpServers = isRecord(existing.mcpServers) ? existing.mcpServers : {};
406
- if (mcpServers[name])
424
+ if (Object.hasOwn(mcpServers, name))
407
425
  deps.renderer.writeWarning(`Server "${name}" already in config. Updating.
408
426
  `);
409
427
  await updateJsonObjectFile(configPath, (config) => {
@@ -424,7 +442,7 @@ async function removeMcpServer(name, deps) {
424
442
  }
425
443
  const existing = await readJsonObjectFile(configPath);
426
444
  const mcpServers = isRecord(existing.mcpServers) ? existing.mcpServers : {};
427
- if (!mcpServers[name]) {
445
+ if (!Object.hasOwn(mcpServers, name)) {
428
446
  deps.renderer.writeError(`Server "${name}" not in config.
429
447
  `);
430
448
  return 1;
@@ -442,4 +460,4 @@ function isRecord(value) {
442
460
  export {
443
461
  mcpCmd
444
462
  };
445
- //# sourceMappingURL=mcp-FX7TKPTV.js.map
463
+ //# sourceMappingURL=mcp-DC5WSBOO.js.map
@@ -45,6 +45,15 @@ export declare function yoloServePolicy(): AutoApprovePermissionPolicy;
45
45
  * "flag present but no list" as an error, never as "no whitelist".
46
46
  */
47
47
  export declare function parseToolsFlag(flags: Record<string, string | boolean>, positional?: readonly string[]): Set<string> | null;
48
+ /**
49
+ * Resolve the TCP port for `mcp serve --http`.
50
+ *
51
+ * `--http` is also a boolean flag, and the old `Number(flags.port ?? flags.http)`
52
+ * turned a bare `--http` into `Number(true) === 1` — the server tried to bind
53
+ * privileged port 1 instead of an ephemeral one. A bare flag now means "pick a
54
+ * free port" (0); an explicit value must be an integer in 0–65535.
55
+ */
56
+ export declare function resolveServeHttpPort(flags: Record<string, string | boolean>): number;
48
57
  interface SelectedMcpServeContent {
49
58
  resources: MCPServerResource[];
50
59
  prompts: MCPServerPrompt[];
@@ -1,9 +1,3 @@
1
- /**
2
- * Shared MCP management service.
3
- * Contains the argument parser and the actual management logic shared between
4
- * the CLI subcommand handler (packages/cli/src/subcommands/handlers/mcp.ts)
5
- * and the slash-command wiring in index.ts.
6
- */
7
1
  import type { Config, MCPServerConfig } from '@wrongstack/core/types';
8
2
  import type { MCPRegistry } from '@wrongstack/mcp';
9
3
  export interface McpParsedArgs {
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  handleHelpVersionShortCircuit
3
- } from "./chunk-5VPDKQDH.js";
3
+ } from "./chunk-TNZBQG45.js";
4
4
  import "./chunk-6WRKAACA.js";
5
5
  import "./chunk-XJXDOF63.js";
6
- import "./chunk-EK2P53GL.js";
6
+ import "./chunk-C3Z4N6A6.js";
7
7
  export {
8
8
  handleHelpVersionShortCircuit
9
9
  };
10
- //# sourceMappingURL=short-circuit-flags-LHUNLCZY.js.map
10
+ //# sourceMappingURL=short-circuit-flags-72E77TJI.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  subcommandNames,
3
3
  subcommands
4
- } from "./chunk-7K3IJGWC.js";
4
+ } from "./chunk-OJR7K3OI.js";
5
5
  export {
6
6
  subcommandNames,
7
7
  subcommands
8
8
  };
9
- //# sourceMappingURL=subcommands-UXWY3OPC.js.map
9
+ //# sourceMappingURL=subcommands-EJI7DBQS.js.map
@@ -17,6 +17,14 @@
17
17
  */
18
18
  import type { AgentPipelines, Context } from '@wrongstack/core/agent';
19
19
  import type { IndexingConfig, Logger } from '@wrongstack/core/types';
20
+ /**
21
+ * Project files a successful file-changing tool call wrote, resolved against
22
+ * `cwd`. Only `write`/`edit` were handled, so `codebase-ast-replace`, `patch`
23
+ * and `format` left the index describing the pre-edit code until a restart
24
+ * (external watching is off by default) — incoming calls and impact analysis
25
+ * then answered for a function body that no longer existed.
26
+ */
27
+ export declare function editedFilePaths(toolName: string, input: unknown, cwd: string): string[];
20
28
  interface CodebaseIndexingDeps {
21
29
  config: {
22
30
  indexing?: IndexingConfig | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
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": [
@@ -41,36 +41,36 @@
41
41
  "data"
42
42
  ],
43
43
  "dependencies": {
44
- "@wrongstack/acp": "1.0.10",
45
- "@wrongstack/bench": "1.0.10",
46
- "@wrongstack/core": "1.0.10",
47
- "@wrongstack/kanban": "1.0.10",
48
- "@wrongstack/mcp": "1.0.10",
49
- "@wrongstack/persistence": "1.0.10",
50
- "@wrongstack/plug-lsp": "1.0.10",
51
- "@wrongstack/plugins": "1.0.10",
52
- "@wrongstack/primitives": "1.0.10",
53
- "@wrongstack/providers": "1.0.10",
54
- "@wrongstack/requirement-intake": "1.0.10",
55
- "@wrongstack/runtime": "1.0.10",
56
- "@wrongstack/sage": "1.0.10",
57
- "@wrongstack/sdd": "1.0.10",
58
- "@wrongstack/security-scanner": "1.0.10",
59
- "@wrongstack/simpleui": "1.0.10",
60
- "@wrongstack/techstack": "1.0.10",
61
- "@wrongstack/telegram": "1.0.10",
62
- "@wrongstack/tools": "1.0.10",
63
- "@wrongstack/tui": "1.0.10",
64
- "@wrongstack/vector-memory": "1.0.10",
65
- "@wrongstack/webui": "1.0.10",
66
- "@wrongstack/webui-hq": "1.0.10",
67
- "@wrongstack/webui-protocol": "1.0.10",
68
- "@wrongstack/webui-server": "1.0.10",
69
- "@wrongstack/wrongtrace": "1.0.10",
44
+ "@wrongstack/acp": "1.0.12",
45
+ "@wrongstack/bench": "1.0.12",
46
+ "@wrongstack/core": "1.0.12",
47
+ "@wrongstack/kanban": "1.0.12",
48
+ "@wrongstack/mcp": "1.0.12",
49
+ "@wrongstack/persistence": "1.0.12",
50
+ "@wrongstack/plug-lsp": "1.0.12",
51
+ "@wrongstack/plugins": "1.0.12",
52
+ "@wrongstack/primitives": "1.0.12",
53
+ "@wrongstack/providers": "1.0.12",
54
+ "@wrongstack/requirement-intake": "1.0.12",
55
+ "@wrongstack/runtime": "1.0.12",
56
+ "@wrongstack/sage": "1.0.12",
57
+ "@wrongstack/sdd": "1.0.12",
58
+ "@wrongstack/security-scanner": "1.0.12",
59
+ "@wrongstack/simpleui": "1.0.12",
60
+ "@wrongstack/techstack": "1.0.12",
61
+ "@wrongstack/telegram": "1.0.12",
62
+ "@wrongstack/tools": "1.0.12",
63
+ "@wrongstack/tui": "1.0.12",
64
+ "@wrongstack/vector-memory": "1.0.12",
65
+ "@wrongstack/webui": "1.0.12",
66
+ "@wrongstack/webui-hq": "1.0.12",
67
+ "@wrongstack/webui-protocol": "1.0.12",
68
+ "@wrongstack/webui-server": "1.0.12",
69
+ "@wrongstack/wrongtrace": "1.0.12",
70
70
  "ws": "^8.21.3"
71
71
  },
72
72
  "optionalDependencies": {
73
- "@wrongstack/desktop": "1.0.10"
73
+ "@wrongstack/desktop": "1.0.12"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/node": "^26.5.1",