@wrongstack/cli 1.0.4 → 1.0.6

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 (26) hide show
  1. package/dist/{acp-AB54FWM2.js → acp-GOQURNC2.js} +9 -6
  2. package/dist/{auth-WDMSNZ3S.js → auth-WBXXIQUO.js} +2 -2
  3. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  4. package/dist/{chunk-ONOT5OJ2.js → chunk-5A5GCSJC.js} +1 -1
  5. package/dist/{chunk-I7V2OYVH.js → chunk-5EA6OTLJ.js} +3 -6
  6. package/dist/{chunk-O4A3HHKD.js → chunk-672UXYL3.js} +2 -2
  7. package/dist/{chunk-U6PGWDMZ.js → chunk-NR7BD73C.js} +2 -2
  8. package/dist/{chunk-3I5ZJXM5.js → chunk-PQZPHGGD.js} +128 -61
  9. package/dist/{chunk-BIWE22O5.js → chunk-QDQPF4PB.js} +5 -5
  10. package/dist/{chunk-VFCJOWJB.js → chunk-VPS2SJW4.js} +4 -5
  11. package/dist/{cli-context-WFC3BNGM.js → cli-context-BYKJDAFF.js} +19 -10
  12. package/dist/{cli-main-GU3YZLMO.js → cli-main-5WZBH3WA.js} +127 -109
  13. package/dist/{execution-RAZDDQFC.js → execution-Z6A26EG6.js} +26 -26
  14. package/dist/{hq-5XHEIIH6.js → hq-V4PHEETW.js} +3 -3
  15. package/dist/hq-server/auth-state.d.ts +6 -0
  16. package/dist/hq-server/auth.d.ts +10 -1
  17. package/dist/hq-server/routes/auth/common.d.ts +34 -0
  18. package/dist/hq-server/routes/auth/password-routes.d.ts +4 -2
  19. package/dist/hq-server/types.d.ts +18 -0
  20. package/dist/{hq-server-CNUTBWTK.js → hq-server-MZ7DV6X7.js} +3 -3
  21. package/dist/index.js +8 -5
  22. package/dist/{mcp-HOMLC4WE.js → mcp-FX7TKPTV.js} +10 -8
  23. package/dist/mcp-serve.d.ts +31 -0
  24. package/dist/{short-circuit-flags-YDMLAQ5R.js → short-circuit-flags-KBTYSJTW.js} +2 -2
  25. package/dist/{subcommands-7N4RIK6H.js → subcommands-DEYSYHIM.js} +2 -2
  26. package/package.json +28 -28
@@ -1258,7 +1258,7 @@ import * as path7 from "node:path";
1258
1258
  import { restoreSessionSubagentPolicy } from "@wrongstack/core/coordination";
1259
1259
  import { attachTodosCheckpoint, loadTodosCheckpoint } from "@wrongstack/core/storage";
1260
1260
  import { projectLastRequestTokens } from "@wrongstack/core/types/session-timeline";
1261
- import { sessionScopedPath as sessionScopedPath2 } from "@wrongstack/core/utils";
1261
+ import { sessionScopedPath as sessionScopedPath2, toErrorMessage } from "@wrongstack/core/utils";
1262
1262
  var RESERVATION_WINDOW_MS = 6e4;
1263
1263
  var RESERVATION_RENEW_MS = 2e4;
1264
1264
  function messageText(content) {
@@ -1288,7 +1288,7 @@ async function resumeSession(ctx, sessionId) {
1288
1288
  };
1289
1289
  const warnings = [];
1290
1290
  const warn = (label, err) => {
1291
- warnings.push(`${label}: ${err instanceof Error ? err.message : String(err)}`);
1291
+ warnings.push(`${label}: ${toErrorMessage(err)}`);
1292
1292
  };
1293
1293
  let stage = "start";
1294
1294
  const setStage = (next) => {
@@ -1309,7 +1309,7 @@ async function resumeSession(ctx, sessionId) {
1309
1309
  throw new TypeError("@wrongstack/tui does not export replaySessionMessages");
1310
1310
  }
1311
1311
  } catch (err) {
1312
- return fail(stage, err instanceof Error ? err.message : String(err));
1312
+ return fail(stage, toErrorMessage(err));
1313
1313
  }
1314
1314
  setStage("resolve_id");
1315
1315
  let canonicalSessionId = sessionId;
@@ -1323,11 +1323,11 @@ async function resumeSession(ctx, sessionId) {
1323
1323
  level: "error",
1324
1324
  event: "execution.resume_id_resolve_failed",
1325
1325
  sessionId,
1326
- message: err instanceof Error ? err.message : String(err),
1326
+ message: toErrorMessage(err),
1327
1327
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1328
1328
  })
1329
1329
  );
1330
- return fail(stage, err instanceof Error ? err.message : String(err));
1330
+ return fail(stage, toErrorMessage(err));
1331
1331
  }
1332
1332
  const previousSessionId = agent.ctx.session?.id;
1333
1333
  let hydrated;
@@ -1369,7 +1369,7 @@ async function resumeSession(ctx, sessionId) {
1369
1369
  level: "warn",
1370
1370
  event: "execution.resume_reservation_renew_failed",
1371
1371
  sessionId: canonicalSessionId,
1372
- message: err instanceof Error ? err.message : String(err),
1372
+ message: toErrorMessage(err),
1373
1373
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1374
1374
  })
1375
1375
  );
@@ -1441,7 +1441,7 @@ async function resumeSession(ctx, sessionId) {
1441
1441
  JSON.stringify({
1442
1442
  level: "error",
1443
1443
  event: "execution.resume_journal_flush_failed",
1444
- message: err instanceof Error ? err.message : String(err),
1444
+ message: toErrorMessage(err),
1445
1445
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1446
1446
  })
1447
1447
  );
@@ -1498,7 +1498,7 @@ async function resumeSession(ctx, sessionId) {
1498
1498
  event: "execution.resume_model_restore_failed",
1499
1499
  provider: targetProviderId,
1500
1500
  model: targetModel,
1501
- message: err instanceof Error ? err.message : String(err),
1501
+ message: toErrorMessage(err),
1502
1502
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1503
1503
  })
1504
1504
  );
@@ -1526,7 +1526,7 @@ async function resumeSession(ctx, sessionId) {
1526
1526
  JSON.stringify({
1527
1527
  level: "error",
1528
1528
  event: "execution.session_end_append_failed",
1529
- message: err instanceof Error ? err.message : String(err),
1529
+ message: toErrorMessage(err),
1530
1530
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1531
1531
  })
1532
1532
  );
@@ -1539,7 +1539,7 @@ async function resumeSession(ctx, sessionId) {
1539
1539
  JSON.stringify({
1540
1540
  level: "error",
1541
1541
  event: "execution.session_close_failed",
1542
- message: err instanceof Error ? err.message : String(err),
1542
+ message: toErrorMessage(err),
1543
1543
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1544
1544
  })
1545
1545
  );
@@ -1580,7 +1580,7 @@ async function resumeSession(ctx, sessionId) {
1580
1580
  level: "error",
1581
1581
  event: "execution.resume_identity_rollback_failed",
1582
1582
  sessionId: previousSessionId,
1583
- message: rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr),
1583
+ message: toErrorMessage(rollbackErr),
1584
1584
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1585
1585
  })
1586
1586
  );
@@ -1602,7 +1602,7 @@ async function resumeSession(ctx, sessionId) {
1602
1602
  JSON.stringify({
1603
1603
  level: "error",
1604
1604
  event: "execution.resume_post_swap_rollback_failed",
1605
- message: rollbackErr instanceof Error ? rollbackErr.message : String(rollbackErr),
1605
+ message: toErrorMessage(rollbackErr),
1606
1606
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1607
1607
  })
1608
1608
  );
@@ -1613,7 +1613,7 @@ async function resumeSession(ctx, sessionId) {
1613
1613
  JSON.stringify({
1614
1614
  level: "error",
1615
1615
  event: "execution.resume_opened_writer_close_failed",
1616
- message: closeErr instanceof Error ? closeErr.message : String(closeErr),
1616
+ message: toErrorMessage(closeErr),
1617
1617
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1618
1618
  })
1619
1619
  );
@@ -1631,7 +1631,7 @@ async function resumeSession(ctx, sessionId) {
1631
1631
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1632
1632
  })
1633
1633
  );
1634
- const message = err instanceof Error ? err.message : String(err);
1634
+ const message = toErrorMessage(err);
1635
1635
  if (err instanceof Error && err.name === "SessionOwnershipConflictError") {
1636
1636
  return fail(stage, message);
1637
1637
  }
@@ -1670,7 +1670,7 @@ async function resumeSession(ctx, sessionId) {
1670
1670
  level: "error",
1671
1671
  event: "execution.resume_readonly_render_failed",
1672
1672
  sessionId: canonicalSessionId,
1673
- message: renderErr instanceof Error ? renderErr.message : String(renderErr),
1673
+ message: toErrorMessage(renderErr),
1674
1674
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1675
1675
  })
1676
1676
  );
@@ -4592,7 +4592,7 @@ import {
4592
4592
  color as color11,
4593
4593
  estimateRequestTokensCalibrated as estimateRequestTokensCalibrated2,
4594
4594
  hasOpenTodos as hasOpenTodos2,
4595
- toErrorMessage as toErrorMessage3
4595
+ toErrorMessage as toErrorMessage4
4596
4596
  } from "@wrongstack/core/utils";
4597
4597
  import { readClipboardImage, routeImagesForModel } from "@wrongstack/runtime";
4598
4598
  import { createAutoProceedLoopGuard } from "@wrongstack/tools/auto-proceed-loop-guard";
@@ -4820,11 +4820,11 @@ function registerReplClient(opts) {
4820
4820
 
4821
4821
  // src/repl-eternal-loop.ts
4822
4822
  import { goalFilePath as goalFilePath2, summarizeUsage } from "@wrongstack/core/goal";
4823
- import { color as color8, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
4823
+ import { color as color8, toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
4824
4824
 
4825
4825
  // src/repl-goal-banner.ts
4826
4826
  import { goalFilePath, loadGoal } from "@wrongstack/core/goal";
4827
- import { color as color7, expectDefined, toErrorMessage } from "@wrongstack/core/utils";
4827
+ import { color as color7, expectDefined, toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
4828
4828
  async function loadGoalSafe(opts) {
4829
4829
  if (!opts.projectRoot) return null;
4830
4830
  try {
@@ -4858,7 +4858,7 @@ async function renderGoalBanner(opts) {
4858
4858
  try {
4859
4859
  await opts.slashRegistry.dispatch("/autonomy eternal", opts.agent.ctx);
4860
4860
  } catch (err) {
4861
- opts.renderer.writeError(`Auto-resume failed: ${toErrorMessage(err)}`);
4861
+ opts.renderer.writeError(`Auto-resume failed: ${toErrorMessage2(err)}`);
4862
4862
  }
4863
4863
  } else {
4864
4864
  opts.renderer.write(
@@ -4934,7 +4934,7 @@ async function runReplEternalLoop(opts, onInterruptsReset) {
4934
4934
  return true;
4935
4935
  }
4936
4936
  } catch (err) {
4937
- opts.renderer.writeError(`[eternal] ${toErrorMessage2(err)}`);
4937
+ opts.renderer.writeError(`[eternal] ${toErrorMessage3(err)}`);
4938
4938
  }
4939
4939
  await new Promise((resolve4) => setTimeout(resolve4, 250));
4940
4940
  return true;
@@ -5005,7 +5005,7 @@ async function runReplEternalLoop(opts, onInterruptsReset) {
5005
5005
  return true;
5006
5006
  }
5007
5007
  } catch (err) {
5008
- opts.renderer.writeError(`[parallel] ${toErrorMessage2(err)}`);
5008
+ opts.renderer.writeError(`[parallel] ${toErrorMessage3(err)}`);
5009
5009
  }
5010
5010
  await new Promise((resolve4) => setTimeout(resolve4, 250));
5011
5011
  return true;
@@ -5245,7 +5245,7 @@ ${lines.join("\n")}
5245
5245
  if (res?.message) opts.renderer.write(`${res.message}
5246
5246
  `);
5247
5247
  } catch (err) {
5248
- opts.renderer.writeError(toErrorMessage3(err));
5248
+ opts.renderer.writeError(toErrorMessage4(err));
5249
5249
  }
5250
5250
  continue;
5251
5251
  }
@@ -5337,7 +5337,7 @@ ${color11.dim(taskList2)}
5337
5337
  }
5338
5338
  }
5339
5339
  } catch (err) {
5340
- opts.renderer.writeError(toErrorMessage3(err));
5340
+ opts.renderer.writeError(toErrorMessage4(err));
5341
5341
  }
5342
5342
  continue;
5343
5343
  }
@@ -5616,7 +5616,7 @@ ${color11.dim(lines)}
5616
5616
  }
5617
5617
  }
5618
5618
  } catch (err) {
5619
- opts.renderer.writeError(toErrorMessage3(err));
5619
+ opts.renderer.writeError(toErrorMessage4(err));
5620
5620
  } finally {
5621
5621
  activeCtrl = void 0;
5622
5622
  }
@@ -5642,7 +5642,7 @@ async function pasteClipboardImage(builder, opts) {
5642
5642
  opts.renderer.write(color11.dim(` \u21B3 ${placeholder} (PNG ${kb}KB)
5643
5643
  `));
5644
5644
  } catch (err) {
5645
- opts.renderer.writeError(`Clipboard image error: ${toErrorMessage3(err)}`);
5645
+ opts.renderer.writeError(`Clipboard image error: ${toErrorMessage4(err)}`);
5646
5646
  }
5647
5647
  }
5648
5648
 
@@ -6840,4 +6840,4 @@ export {
6840
6840
  execute,
6841
6841
  resolveReviewerFallbackModels
6842
6842
  };
6843
- //# sourceMappingURL=execution-RAZDDQFC.js.map
6843
+ //# sourceMappingURL=execution-Z6A26EG6.js.map
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  normalizeHqPublicOrigin,
9
9
  resolveAuditActor
10
- } from "./chunk-I7V2OYVH.js";
10
+ } from "./chunk-5EA6OTLJ.js";
11
11
  import {
12
12
  parseHqIpAllowlist
13
13
  } from "./chunk-Q7E3BPDU.js";
@@ -62,7 +62,7 @@ var hqCmd = async (args, deps) => {
62
62
  return 1;
63
63
  };
64
64
  async function startServer(deps) {
65
- const { startHqServer } = await import("./hq-server-CNUTBWTK.js");
65
+ const { startHqServer } = await import("./hq-server-MZ7DV6X7.js");
66
66
  const dataDir = resolveDataDir(deps);
67
67
  const flags = deps.flags ?? {};
68
68
  const rawPublicUrl = typeof flags["hq-public-url"] === "string" ? flags["hq-public-url"] : process.env.WRONGSTACK_HQ_PUBLIC_URL;
@@ -827,4 +827,4 @@ export {
827
827
  hqCmd,
828
828
  resolveAuditActor
829
829
  };
830
- //# sourceMappingURL=hq-5XHEIIH6.js.map
830
+ //# sourceMappingURL=hq-V4PHEETW.js.map
@@ -6,6 +6,12 @@ export interface HqAuthState {
6
6
  tokenStats(): NonNullable<HqSnapshot['totals']['tokenStats']>;
7
7
  }
8
8
  interface HqAuthStateOptions {
9
+ /**
10
+ * The server's `requireBrowserAuth` option, stamped onto the state so every
11
+ * `hqAuthRequired(mutableAuth)` gate observes it without having to be handed
12
+ * it separately. See the field's doc on `HqRouterMutableAuth`.
13
+ */
14
+ requireBrowserAuth?: boolean | undefined;
9
15
  /**
10
16
  * Invoked after every {@link HqAuthState.apply}, with the freshly projected
11
17
  * `mutableAuth`. The server wires this to the WS-010 exposure re-assessment
@@ -38,7 +38,16 @@ export type HqBrowserAuthResult = HqBrowserAuthContext | HqCookieAuthContext | u
38
38
  * inline style is not script execution.
39
39
  */
40
40
  export declare function setHqSecurityHeaders(res: http.ServerResponse): void;
41
- export declare function hasTrustedBrowserOrigin(req: http.IncomingMessage, boundHost?: string, boundPort?: number, trustedPublicOrigins?: ReadonlySet<string>, allowFileOrigin?: boolean): boolean;
41
+ export declare function hasTrustedBrowserOrigin(req: http.IncomingMessage, boundHost?: string, boundPort?: number, trustedPublicOrigins?: ReadonlySet<string>, allowFileOrigin?: boolean,
42
+ /**
43
+ * Whether this surface has any credential configured — pass
44
+ * `hqAuthRequired(mutableAuth, requireBrowserAuth)`.
45
+ *
46
+ * Defaults to `false`, the STRICT side, deliberately: a caller that forgets
47
+ * to wire it gets the tighter rule rather than the looser one. That is the
48
+ * opposite of how the WS-077 gates drifted.
49
+ */
50
+ credentialedSurface?: boolean): boolean;
42
51
  export declare function serializeHqSessionCookie(sessionId: string, secret: string): string;
43
52
  export declare function parseHqSessionCookie(value: string, secret: string): string | undefined;
44
53
  export declare function parseCookieHeader(cookieHeader: string | undefined): Record<string, string>;
@@ -1,7 +1,41 @@
1
1
  import type * as http from 'node:http';
2
2
  import { type HqAuthFile } from '@wrongstack/core/hq';
3
3
  import { type HqBrowserAuthResult } from '../../auth.js';
4
+ import type { LoginAttemptStore } from '../../login-attempt-store.js';
4
5
  import type { HqRouterMutableAuth, HqSessionEntry } from '../../types.js';
6
+ /**
7
+ * Record a failed second-factor confirmation and return the new failure count.
8
+ *
9
+ * Shared by every route that verifies a factor outside `/api/login`
10
+ * (totp/disable, password change). Kept here rather than copied per route: the
11
+ * whole point is that each of those routes feeds the SAME per-IP counter, so a
12
+ * attacker cannot get a fresh budget by switching endpoints.
13
+ */
14
+ export declare function recordVerifyFailure(loginAttempts: LoginAttemptStore, clientIp: string): number;
15
+ /** Outcome of {@link consumeTotpCode}. */
16
+ export type TotpConsumeResult = 'ok' | 'invalid' | 'replayed';
17
+ /**
18
+ * Verify a TOTP code AND burn it, so it cannot be presented a second time.
19
+ *
20
+ * A TOTP code stays valid for its whole time step plus the verification
21
+ * window — roughly 90 seconds. Without a single-use record, one observed code
22
+ * can be replayed at a *different* endpoint for as long as that window lasts.
23
+ * That is not theoretical here: `/api/login/verify` advanced
24
+ * `totpLastUsedCounter` and the other two verification sites
25
+ * (`totp/disable`, `auth/password`) called the counter-less `verifyTotp`, so a
26
+ * code already spent on a login replayed into removing 2FA outright or
27
+ * rotating the password and cookie secret.
28
+ *
29
+ * Kept in this module for the same reason as {@link recordVerifyFailure}: the
30
+ * property only holds if EVERY site that verifies a code shares one counter.
31
+ * A route that verifies a TOTP code by any other means is a bug —
32
+ * `hq-totp-single-use.test.ts` enumerates the call sites to keep it that way.
33
+ *
34
+ * The counter is advanced in memory first and persisted best-effort, matching
35
+ * the pre-existing behaviour at `/api/login/verify`: a failed write must not
36
+ * turn a consumed code back into an unconsumed one for this process.
37
+ */
38
+ export declare function consumeTotpCode(code: string, mutableAuth: HqRouterMutableAuth, dataDir: string, applyAuthFile: ApplyHqAuthFile): Promise<TotpConsumeResult>;
5
39
  export declare function isLoopbackRequest(req: http.IncomingMessage): boolean;
6
40
  export declare const HQ_AUTH_ADMIN_CAPABILITY = "auth.admin";
7
41
  export declare function callerCanAdministerAuth(auth: HqBrowserAuthResult): boolean;
@@ -3,7 +3,9 @@ import type { LoginAttemptStore } from '../../login-attempt-store.js';
3
3
  import type { HqRouterMutableAuth, HqSessionEntry } from '../../types.js';
4
4
  import { type ApplyHqAuthFile } from './common.js';
5
5
  export declare function handleApiAuthStatus(req: http.IncomingMessage, res: http.ServerResponse, url: URL, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, requireBrowserAuth: boolean | undefined, trustedPublicOrigins: Set<string>, secureCookies: boolean | undefined): Promise<void>;
6
- export declare function handleApiLogin(req: http.IncomingMessage, res: http.ServerResponse, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, loginAttempts: LoginAttemptStore, secureCookies: boolean | undefined, trustedProxyHops: number, sessionCapabilities?: string[]): Promise<void>;
6
+ export declare function handleApiLogin(req: http.IncomingMessage, res: http.ServerResponse, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, loginAttempts: LoginAttemptStore, secureCookies: boolean | undefined, trustedProxyHops: number,
7
+ /** Where `auth.json` lives — needed to persist a transparent KDF upgrade. */
8
+ dataDir: string, sessionCapabilities?: string[]): Promise<void>;
7
9
  export declare function handleApiLogout(req: http.IncomingMessage, res: http.ServerResponse, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, secureCookies: boolean | undefined): Promise<void>;
8
- export declare function handleApiPassword(req: http.IncomingMessage, res: http.ServerResponse, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, dataDir: string, secureCookies: boolean | undefined, requireBrowserAuth: boolean | undefined, applyAuthFile: ApplyHqAuthFile): Promise<void>;
10
+ export declare function handleApiPassword(req: http.IncomingMessage, res: http.ServerResponse, mutableAuth: HqRouterMutableAuth, sessions: Map<string, HqSessionEntry>, dataDir: string, secureCookies: boolean | undefined, requireBrowserAuth: boolean | undefined, applyAuthFile: ApplyHqAuthFile, loginAttempts: LoginAttemptStore, trustedProxyHops: number): Promise<void>;
9
11
  //# sourceMappingURL=password-routes.d.ts.map
@@ -103,6 +103,24 @@ export interface HqRouterMutableAuth {
103
103
  * the surface fails closed instead of opening up.
104
104
  */
105
105
  requireAuthFloor?: boolean | undefined;
106
+ /**
107
+ * The server's `requireBrowserAuth` option, carried on the state rather than
108
+ * passed to every gate.
109
+ *
110
+ * `hqAuthRequired` takes it as an optional second argument, and five gates
111
+ * called it with one — `command-handlers`, three in `mailbox-handlers`, and
112
+ * `mailbox-gateway-manager` — so a public relay did not raise the auth
113
+ * requirement on those routes. That is the WS-077 drift class the helper's
114
+ * own docstring warns about, recurring on the same routes. Holding the value
115
+ * on the state makes the one-argument call correct instead of incomplete.
116
+ *
117
+ * Required, not optional, and deliberately so. Optional would mean a second
118
+ * construction site could omit it and every one-argument gate would silently
119
+ * read `undefined` — the same drift this field exists to end, one level down.
120
+ * With `exactOptionalPropertyTypes` the compiler now makes every builder say
121
+ * what it means, including `undefined`.
122
+ */
123
+ requireBrowserAuth: boolean | undefined;
106
124
  }
107
125
  /**
108
126
  * Session record stored in the server-side `sessions` Map.
@@ -10,9 +10,9 @@ import {
10
10
  readLocalSubagentTranscript,
11
11
  sanitizeApiError,
12
12
  startHqServer
13
- } from "./chunk-3I5ZJXM5.js";
13
+ } from "./chunk-PQZPHGGD.js";
14
14
  import "./chunk-HXJYHAR4.js";
15
- import "./chunk-I7V2OYVH.js";
15
+ import "./chunk-5EA6OTLJ.js";
16
16
  import "./chunk-Q7E3BPDU.js";
17
17
  export {
18
18
  DEFAULT_HOST,
@@ -27,4 +27,4 @@ export {
27
27
  sanitizeApiError,
28
28
  startHqServer
29
29
  };
30
- //# sourceMappingURL=hq-server-CNUTBWTK.js.map
30
+ //# sourceMappingURL=hq-server-MZ7DV6X7.js.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  applyNodeEnvDefault,
4
4
  applySessionShellDefault
5
- } from "./chunk-O4A3HHKD.js";
5
+ } from "./chunk-672UXYL3.js";
6
6
  import {
7
7
  CLI_VERSION
8
8
  } from "./chunk-XJXDOF63.js";
@@ -16,20 +16,21 @@ 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-YDMLAQ5R.js");
19
+ const { handleHelpVersionShortCircuit } = await import("./short-circuit-flags-KBTYSJTW.js");
20
20
  const earlyExit = await handleHelpVersionShortCircuit(argv);
21
21
  if (earlyExit !== null) return earlyExit;
22
22
  }
23
- const { initializeCli } = await import("./cli-context-WFC3BNGM.js");
23
+ const { initializeCli } = await import("./cli-context-BYKJDAFF.js");
24
24
  const cliCtx = await initializeCli(argv);
25
25
  if (typeof cliCtx === "number") return cliCtx;
26
- const { runInteractive } = await import("./cli-main-GU3YZLMO.js");
26
+ const { runInteractive } = await import("./cli-main-5WZBH3WA.js");
27
27
  return runInteractive(cliCtx);
28
28
  }
29
29
 
30
30
  // src/cli-entry-point.ts
31
31
  import { resolve } from "node:path";
32
32
  import { pathToFileURL } from "node:url";
33
+ import { scrubErrorText } from "@wrongstack/core/security";
33
34
  import { installCrashShield, runFatalSalvageSync, writeErr } from "@wrongstack/core/utils";
34
35
  var SQLITE_WARNING_RE = /sqlite is an experimental feature/i;
35
36
  function installSqliteWarningFilter() {
@@ -128,7 +129,9 @@ function runAsMain(mainFn) {
128
129
  },
129
130
  (err) => {
130
131
  runFatalSalvageSync();
131
- writeErr((err instanceof Error ? err.stack : String(err)) + "\n");
132
+ writeErr(
133
+ scrubErrorText(err instanceof Error ? err.stack ?? err.message : String(err)) + "\n"
134
+ );
132
135
  process.exitCode = 1;
133
136
  scheduleForcedExit(1);
134
137
  }
@@ -23,7 +23,11 @@ import { pathToFileURL } from "node:url";
23
23
  import { Context } from "@wrongstack/core/agent";
24
24
  import { ToolExecutor } from "@wrongstack/core/execution";
25
25
  import { ToolRegistry } from "@wrongstack/core/registry";
26
- import { AutoApprovePermissionPolicy, DefaultSecretScrubber } from "@wrongstack/core/security";
26
+ import {
27
+ AutoApprovePermissionPolicy,
28
+ DefaultSecretScrubber,
29
+ ToolCapabilities
30
+ } from "@wrongstack/core/security";
27
31
  import { normalizeTokenSavingTier } from "@wrongstack/core/types";
28
32
  import {
29
33
  DEFAULT_MCP_INSERTION_MAX_BYTES,
@@ -33,11 +37,9 @@ import {
33
37
  } from "@wrongstack/mcp";
34
38
  import { registerBuiltinToolTier } from "@wrongstack/tools/tool-tier";
35
39
  import { wireKanbanPorts } from "@wrongstack/runtime";
36
- var AllowAllPermissionPolicy = class extends AutoApprovePermissionPolicy {
37
- async evaluate() {
38
- return { permission: "auto", source: "default" };
39
- }
40
- };
40
+ function yoloServePolicy() {
41
+ return new AutoApprovePermissionPolicy(Object.values(ToolCapabilities));
42
+ }
41
43
  function parseToolsFlag(flags, positional) {
42
44
  const raw = flags["tools"];
43
45
  const csv = typeof raw === "string" ? raw : raw === true ? positional?.[0] ?? "" : "";
@@ -226,7 +228,7 @@ async function serveMcpStdio(deps, positional) {
226
228
  controller.signal,
227
229
  resolveServeFsRestriction(deps.config)
228
230
  );
229
- const permissionPolicy = yolo ? new AllowAllPermissionPolicy() : new AutoApprovePermissionPolicy();
231
+ const permissionPolicy = yolo ? yoloServePolicy() : new AutoApprovePermissionPolicy();
230
232
  const executor = new ToolExecutor(registry, {
231
233
  permissionPolicy,
232
234
  secretScrubber: new DefaultSecretScrubber(),
@@ -440,4 +442,4 @@ function isRecord(value) {
440
442
  export {
441
443
  mcpCmd
442
444
  };
443
- //# sourceMappingURL=mcp-HOMLC4WE.js.map
445
+ //# sourceMappingURL=mcp-FX7TKPTV.js.map
@@ -1,8 +1,39 @@
1
1
  import { Context } from '@wrongstack/core/agent';
2
2
  import { ToolRegistry } from '@wrongstack/core/registry';
3
+ import { AutoApprovePermissionPolicy } from '@wrongstack/core/security';
3
4
  import type { PermissionPolicy, Tool } from '@wrongstack/core/types';
4
5
  import { type MCPServerPrompt, type MCPServerResource } from '@wrongstack/mcp';
5
6
  import type { SubcommandDeps } from './subcommands/contracts.js';
7
+ /**
8
+ * `--yolo` for `mcp serve`: widen the CAPABILITY allowlist, keep every guard.
9
+ *
10
+ * This replaced an `AllowAllPermissionPolicy extends AutoApprovePermissionPolicy`
11
+ * whose `evaluate()` returned `{ permission: 'auto' }` unconditionally. That
12
+ * override skipped the whole base implementation — the sensitive-read denial,
13
+ * the leader deny rules, the destructive-command classifier, the agent-state
14
+ * write guard, and `LOCKED_DESTRUCTIVE_KINDS`. It was the only place in the
15
+ * codebase where `agent-state` and `credential-bind` could be un-gated, so a
16
+ * third-party MCP client could have written `hooks` into config.json (boot-time
17
+ * RCE) or `auto: true` into trust.json.
18
+ *
19
+ * It did not actually get there — but only by accident, and the accident is the
20
+ * reason this is a rewrite rather than a patch. The override returned
21
+ * `source: 'default'` where the base class returns `source: 'yolo'`, so
22
+ * `ToolExecutor.capabilityDowngraded` re-armed and forced `confirm`; `mcp serve`
23
+ * has no confirmAwaiter, so the call hard-errored. Changing that one string
24
+ * literal to `'yolo'` — which reads as a trivial consistency cleanup — would
25
+ * have made the bypass live. Safety must not rest on a string nobody knows is
26
+ * load-bearing.
27
+ *
28
+ * Granting every capability is what `--yolo` actually means, and it is what
29
+ * lets `ToolExecutor` trust an `auto` instead of downgrading it (see the
30
+ * `dangerousNotAllowed` reasoning in `auto-approve-policy.ts`). The destructive
31
+ * classifier is deliberately NOT relaxed: `yoloConfirmKinds` is left at its
32
+ * default, which gates every destructive kind. Destructive calls therefore
33
+ * still require a confirmation this surface cannot answer, exactly as before —
34
+ * this change removes a latent bypass without widening anything.
35
+ */
36
+ export declare function yoloServePolicy(): AutoApprovePermissionPolicy;
6
37
  /**
7
38
  * Resolve the `--tools` whitelist for `mcp serve`.
8
39
  *
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  handleHelpVersionShortCircuit
3
- } from "./chunk-U6PGWDMZ.js";
3
+ } from "./chunk-NR7BD73C.js";
4
4
  import "./chunk-6WRKAACA.js";
5
5
  import "./chunk-XJXDOF63.js";
6
6
  import "./chunk-EK2P53GL.js";
7
7
  export {
8
8
  handleHelpVersionShortCircuit
9
9
  };
10
- //# sourceMappingURL=short-circuit-flags-YDMLAQ5R.js.map
10
+ //# sourceMappingURL=short-circuit-flags-KBTYSJTW.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  subcommandNames,
3
3
  subcommands
4
- } from "./chunk-BIWE22O5.js";
4
+ } from "./chunk-QDQPF4PB.js";
5
5
  export {
6
6
  subcommandNames,
7
7
  subcommands
8
8
  };
9
- //# sourceMappingURL=subcommands-7N4RIK6H.js.map
9
+ //# sourceMappingURL=subcommands-DEYSYHIM.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
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.4",
45
- "@wrongstack/bench": "1.0.4",
46
- "@wrongstack/core": "1.0.4",
47
- "@wrongstack/primitives": "1.0.4",
48
- "@wrongstack/kanban": "1.0.4",
49
- "@wrongstack/mcp": "1.0.4",
50
- "@wrongstack/persistence": "1.0.4",
51
- "@wrongstack/plug-lsp": "1.0.4",
52
- "@wrongstack/plugins": "1.0.4",
53
- "@wrongstack/providers": "1.0.4",
54
- "@wrongstack/requirement-intake": "1.0.4",
55
- "@wrongstack/runtime": "1.0.4",
56
- "@wrongstack/sage": "1.0.4",
57
- "@wrongstack/sdd": "1.0.4",
58
- "@wrongstack/security-scanner": "1.0.4",
59
- "@wrongstack/simpleui": "1.0.4",
60
- "@wrongstack/techstack": "1.0.4",
61
- "@wrongstack/telegram": "1.0.4",
62
- "@wrongstack/tools": "1.0.4",
63
- "@wrongstack/tui": "1.0.4",
64
- "@wrongstack/vector-memory": "1.0.4",
65
- "@wrongstack/webui": "1.0.4",
66
- "@wrongstack/webui-hq": "1.0.4",
67
- "@wrongstack/webui-protocol": "1.0.4",
68
- "@wrongstack/wrongtrace": "1.0.4",
69
- "@wrongstack/webui-server": "1.0.4",
44
+ "@wrongstack/acp": "1.0.6",
45
+ "@wrongstack/bench": "1.0.6",
46
+ "@wrongstack/core": "1.0.6",
47
+ "@wrongstack/primitives": "1.0.6",
48
+ "@wrongstack/kanban": "1.0.6",
49
+ "@wrongstack/mcp": "1.0.6",
50
+ "@wrongstack/persistence": "1.0.6",
51
+ "@wrongstack/plug-lsp": "1.0.6",
52
+ "@wrongstack/plugins": "1.0.6",
53
+ "@wrongstack/providers": "1.0.6",
54
+ "@wrongstack/requirement-intake": "1.0.6",
55
+ "@wrongstack/runtime": "1.0.6",
56
+ "@wrongstack/sage": "1.0.6",
57
+ "@wrongstack/sdd": "1.0.6",
58
+ "@wrongstack/security-scanner": "1.0.6",
59
+ "@wrongstack/simpleui": "1.0.6",
60
+ "@wrongstack/techstack": "1.0.6",
61
+ "@wrongstack/telegram": "1.0.6",
62
+ "@wrongstack/tools": "1.0.6",
63
+ "@wrongstack/tui": "1.0.6",
64
+ "@wrongstack/vector-memory": "1.0.6",
65
+ "@wrongstack/webui": "1.0.6",
66
+ "@wrongstack/webui-hq": "1.0.6",
67
+ "@wrongstack/webui-protocol": "1.0.6",
68
+ "@wrongstack/wrongtrace": "1.0.6",
69
+ "@wrongstack/webui-server": "1.0.6",
70
70
  "ws": "^8.21.3"
71
71
  },
72
72
  "optionalDependencies": {
73
- "@wrongstack/desktop": "1.0.4"
73
+ "@wrongstack/desktop": "1.0.6"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/node": "^26.2.0",