@wrongstack/cli 1.0.4 → 1.0.7

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 (44) hide show
  1. package/dist/{acp-AB54FWM2.js → acp-A5EQEXQO.js} +69 -11
  2. package/dist/{auth-WDMSNZ3S.js → auth-3K6EN5JP.js} +3 -3
  3. package/dist/boot/container-wiring.d.ts +2 -0
  4. package/dist/boot/short-circuit-desktop.d.ts +1 -0
  5. package/dist/{chunk-VUVOMXWP.js → chunk-3VXYY5JC.js} +8 -1
  6. package/dist/{chunk-U6PGWDMZ.js → chunk-4OLAZIIN.js} +2 -2
  7. package/dist/{chunk-I7V2OYVH.js → chunk-5EA6OTLJ.js} +3 -6
  8. package/dist/{chunk-O4A3HHKD.js → chunk-672UXYL3.js} +2 -2
  9. package/dist/{chunk-ONOT5OJ2.js → chunk-FSZ5QU3M.js} +2 -2
  10. package/dist/{chunk-KNMIBKLV.js → chunk-JY52HWL6.js} +47 -1
  11. package/dist/{chunk-BIWE22O5.js → chunk-RLCKKLJA.js} +8 -8
  12. package/dist/{chunk-VFCJOWJB.js → chunk-RMQNCHGO.js} +8 -7
  13. package/dist/{chunk-3I5ZJXM5.js → chunk-XIZZ2EXG.js} +161 -62
  14. package/dist/{cli-context-WFC3BNGM.js → cli-context-TIAP6YQK.js} +95 -15
  15. package/dist/cli-context.d.ts +2 -0
  16. package/dist/{cli-main-GU3YZLMO.js → cli-main-AKJHDSHX.js} +1111 -721
  17. package/dist/config-doctor.d.ts +1 -1
  18. package/dist/execute-deps.d.ts +3 -1
  19. package/dist/{execution-RAZDDQFC.js → execution-FJE27VQ6.js} +105 -28
  20. package/dist/{hq-5XHEIIH6.js → hq-G5PCP325.js} +8 -6
  21. package/dist/hq-command-controller.d.ts +15 -0
  22. package/dist/hq-server/auth-state.d.ts +6 -0
  23. package/dist/hq-server/auth.d.ts +10 -1
  24. package/dist/hq-server/routes/auth/common.d.ts +34 -0
  25. package/dist/hq-server/routes/auth/password-routes.d.ts +4 -2
  26. package/dist/hq-server/types.d.ts +18 -0
  27. package/dist/{hq-server-CNUTBWTK.js → hq-server-G3VVVMIG.js} +3 -3
  28. package/dist/index.js +8 -5
  29. package/dist/input-reader.d.ts +2 -2
  30. package/dist/{mcp-HOMLC4WE.js → mcp-FX7TKPTV.js} +10 -8
  31. package/dist/mcp-serve.d.ts +31 -0
  32. package/dist/{modeldiag-46CMWUNM.js → modeldiag-CJSFHZ3J.js} +55 -31
  33. package/dist/permission-prompt-mirror.d.ts +70 -0
  34. package/dist/permission-prompt.d.ts +10 -1
  35. package/dist/{providers-models-6MOGAOVK.js → providers-models-LFNZ5WI7.js} +2 -2
  36. package/dist/{short-circuit-flags-YDMLAQ5R.js → short-circuit-flags-RAT6UZVI.js} +2 -2
  37. package/dist/slash-commands/subagent-models.d.ts +4 -0
  38. package/dist/subagent-models/panel-service.d.ts +28 -0
  39. package/dist/subcommands/handlers/modeldiag-test.d.ts +7 -0
  40. package/dist/{subcommands-7N4RIK6H.js → subcommands-VFVUTYAV.js} +2 -2
  41. package/dist/webui-server/prefs-seeding.d.ts +8 -0
  42. package/dist/{webui-server-OBV5JYJV.js → webui-server-3NYXBZHX.js} +36 -12
  43. package/dist/wiring/hq-telemetry.d.ts +7 -0
  44. package/package.json +28 -28
@@ -5,6 +5,9 @@ import {
5
5
  refreshAcpRegistry,
6
6
  setupProvider
7
7
  } from "./chunk-KEPABQYT.js";
8
+ import {
9
+ createHqCommandDispatcher
10
+ } from "./chunk-JY52HWL6.js";
8
11
  import {
9
12
  startCliHqConnection
10
13
  } from "./chunk-TE3Q32JP.js";
@@ -36,18 +39,50 @@ import { WebSocketServer } from "ws";
36
39
 
37
40
  // src/acp-hq-telemetry.ts
38
41
  import { AgentStatusTracker } from "@wrongstack/core/coordination";
39
- import { startSessionTelemetryBridge } from "@wrongstack/core/hq";
42
+ import {
43
+ createApprovalRegistry,
44
+ startApprovalTelemetryBridge,
45
+ startSessionTelemetryBridge
46
+ } from "@wrongstack/core/hq";
40
47
  var NO_REGISTRY = { updateAgents: async () => void 0 };
41
48
  function startAcpHqTelemetry(options) {
49
+ const entries = /* @__PURE__ */ new Map();
50
+ let stopped = false;
51
+ const resolveApproval = (toolUseId, decision, sessionId) => {
52
+ if (sessionId !== void 0) {
53
+ return entries.get(sessionId)?.approvals?.resolve(toolUseId, decision, sessionId) ?? false;
54
+ }
55
+ for (const entry of entries.values()) {
56
+ if (entry.approvals?.resolve(toolUseId, decision) === true) return true;
57
+ }
58
+ return false;
59
+ };
42
60
  const connection = startCliHqConnection({
43
61
  clientKind: "acp",
44
62
  projectRoot: options.projectRoot,
45
63
  ...options.projectName !== void 0 ? { projectName: options.projectName } : {},
46
64
  ...options.appConfig !== void 0 ? { appConfig: options.appConfig } : {},
47
- capabilities: ["telemetry.publish", "mailbox.summary", "fleet.summary", "session.summary"]
65
+ capabilities: [
66
+ "telemetry.publish",
67
+ "mailbox.summary",
68
+ "fleet.summary",
69
+ "session.summary",
70
+ // Approvals are the ONLY control this host accepts. `control.receive` is
71
+ // the server's gate for any command at all, so it has to be declared;
72
+ // everything except `approve` falls through the dispatcher and is
73
+ // refused, because an ACP session has no mailbox to steer and no leader
74
+ // to abort.
75
+ "control.receive",
76
+ "control.approve"
77
+ ],
78
+ onCommand: createHqCommandDispatcher({
79
+ interruptLeader: () => false,
80
+ sessionTag: () => "acp",
81
+ ownsSession: (sessionId) => entries.has(sessionId),
82
+ allowRunCommand: () => false,
83
+ resolveApproval
84
+ })
48
85
  });
49
- const entries = /* @__PURE__ */ new Map();
50
- let stopped = false;
51
86
  const attach = (sessionId, agent, cwd) => {
52
87
  if (stopped || entries.has(sessionId)) return;
53
88
  const publisher = connection.getPublisher();
@@ -73,7 +108,19 @@ function startAcpHqTelemetry(options) {
73
108
  tracker.stop();
74
109
  return;
75
110
  }
76
- entries.set(sessionId, { tracker, stopBridge });
111
+ const entry = { tracker, stopBridge };
112
+ try {
113
+ const approvals = createApprovalRegistry(events);
114
+ entry.approvals = approvals;
115
+ entry.stopApprovalBridge = startApprovalTelemetryBridge({
116
+ registry: approvals,
117
+ publisher,
118
+ projectRoot: cwd,
119
+ sessionId
120
+ });
121
+ } catch {
122
+ }
123
+ entries.set(sessionId, entry);
77
124
  };
78
125
  const detach = (sessionId) => {
79
126
  const entry = entries.get(sessionId);
@@ -83,6 +130,14 @@ function startAcpHqTelemetry(options) {
83
130
  entry.stopBridge();
84
131
  } catch {
85
132
  }
133
+ try {
134
+ entry.stopApprovalBridge?.();
135
+ } catch {
136
+ }
137
+ try {
138
+ entry.approvals?.dispose();
139
+ } catch {
140
+ }
86
141
  try {
87
142
  entry.tracker.stop();
88
143
  } catch {
@@ -649,13 +704,16 @@ async function runACPWebSocketServer(deps, port) {
649
704
  const acpToken = process.env["WRONGSTACK_ACP_TOKEN"]?.trim() || randomBytes(32).toString("hex");
650
705
  const gate = createAcpConnectionGate({ host, port, token: acpToken });
651
706
  let liveConnections = 0;
652
- const wss = new WebSocketServer({ host, port, maxPayload: 20 * 1024 * 1024 });
653
- wss.on("connection", (socket, req) => {
654
- const verdict = gate.check(req, liveConnections);
655
- if (!verdict.ok) {
656
- socket.close(verdict.code ?? 1008, verdict.reason ?? "forbidden");
707
+ const verifyClient = (info, cb) => {
708
+ const verdict = gate.check(info.req, liveConnections);
709
+ if (verdict.ok) {
710
+ cb(true);
657
711
  return;
658
712
  }
713
+ cb(false, 403, verdict.reason ?? "forbidden");
714
+ };
715
+ const wss = new WebSocketServer({ host, port, maxPayload: 20 * 1024 * 1024, verifyClient });
716
+ wss.on("connection", (socket) => {
659
717
  liveConnections++;
660
718
  socket.once("close", () => {
661
719
  liveConnections--;
@@ -1099,4 +1157,4 @@ ${renderAcpBenchText(result)}
1099
1157
  export {
1100
1158
  acpCmd
1101
1159
  };
1102
- //# sourceMappingURL=acp-AB54FWM2.js.map
1160
+ //# sourceMappingURL=acp-A5EQEXQO.js.map
@@ -14,7 +14,7 @@ import {
14
14
  runOAuthLoginKind,
15
15
  runOAuthLoginMenu,
16
16
  validateFamily
17
- } from "./chunk-ONOT5OJ2.js";
17
+ } from "./chunk-FSZ5QU3M.js";
18
18
  import {
19
19
  renderAuthLocalHelpToString,
20
20
  wantsLocalHelp
@@ -23,7 +23,7 @@ import "./chunk-B4JLSXZB.js";
23
23
  import {
24
24
  restoreFlags
25
25
  } from "./chunk-CSAPOCBP.js";
26
- import "./chunk-VUVOMXWP.js";
26
+ import "./chunk-3VXYY5JC.js";
27
27
  import {
28
28
  activeProfileConfigPath
29
29
  } from "./chunk-YMXXOOFN.js";
@@ -619,4 +619,4 @@ async function runAuthRemove(deps, providerId) {
619
619
  export {
620
620
  authCmd
621
621
  };
622
- //# sourceMappingURL=auth-WDMSNZ3S.js.map
622
+ //# sourceMappingURL=auth-3K6EN5JP.js.map
@@ -4,6 +4,7 @@ import type { Config, Logger, ModelsRegistry, Renderer } from '@wrongstack/core/
4
4
  import type { WstackPaths } from '@wrongstack/core/utils';
5
5
  import { createDefaultContainer } from '@wrongstack/runtime';
6
6
  import { makePromptDelegate } from '../permission-prompt.js';
7
+ import { type ApprovalMirrorRef } from '../permission-prompt-mirror.js';
7
8
  interface WireContainerDeps {
8
9
  config: Config;
9
10
  wpaths: WstackPaths;
@@ -30,6 +31,7 @@ export declare function wireContainer(deps: WireContainerDeps): {
30
31
  pathResolver: InstanceType<typeof DefaultPathResolver>;
31
32
  events: EventBus;
32
33
  container: ReturnType<typeof createDefaultContainer>;
34
+ approvalMirror: ApprovalMirrorRef;
33
35
  };
34
36
  export {};
35
37
  //# sourceMappingURL=container-wiring.d.ts.map
@@ -1,3 +1,4 @@
1
1
  export declare function stripDesktopLauncherArgs(argv: string[]): string[];
2
+ export declare function selectDesktopLauncherExecutable(execPath: string, runningUnderBun: boolean, nodeOverride?: string): string;
2
3
  export declare function handleDesktopShortCircuit(flags: Record<string, string | boolean>, argv: string[]): Promise<number | null>;
3
4
  //# sourceMappingURL=short-circuit-desktop.d.ts.map
@@ -102,6 +102,13 @@ function modelDetails(models) {
102
102
  tools: model.tool_call,
103
103
  vision: model.modalities?.input?.includes("image"),
104
104
  reasoning: model.reasoning ?? model.reasoningConfig !== void 0,
105
+ // Documented effort vocabulary, mirroring the gate
106
+ // `getActiveModelReasoningEffortLevels` applies for the settings
107
+ // panel: `effortSupported === false` is a documented "no effort
108
+ // control", and the picker must not offer a strip for it. An absent
109
+ // field stays absent, which the strip reads as "undocumented →
110
+ // canonical set".
111
+ ...model.reasoningConfig?.effortSupported && model.reasoningConfig.effortLevels?.length ? { effortLevels: [...model.reasoningConfig.effortLevels] } : {},
105
112
  maxContext: model.limit?.context,
106
113
  maxOutput: model.limit?.output,
107
114
  inputCost: model.cost?.input,
@@ -120,4 +127,4 @@ export {
120
127
  hasApiKey,
121
128
  buildPickableProviders
122
129
  };
123
- //# sourceMappingURL=chunk-VUVOMXWP.js.map
130
+ //# sourceMappingURL=chunk-3VXYY5JC.js.map
@@ -22,7 +22,7 @@ async function handleHelpVersionShortCircuit(argv) {
22
22
  }
23
23
  if (earlyFlags["help"] === true) {
24
24
  if (positional.length > 0) {
25
- const { subcommandNames } = await import("./subcommands-7N4RIK6H.js");
25
+ const { subcommandNames } = await import("./subcommands-VFVUTYAV.js");
26
26
  if (subcommandNames.includes(positional[0])) {
27
27
  const first = positional[0];
28
28
  const deep = positional[1];
@@ -43,4 +43,4 @@ async function handleHelpVersionShortCircuit(argv) {
43
43
  export {
44
44
  handleHelpVersionShortCircuit
45
45
  };
46
- //# sourceMappingURL=chunk-U6PGWDMZ.js.map
46
+ //# sourceMappingURL=chunk-4OLAZIIN.js.map
@@ -16,6 +16,7 @@ import * as fs from "node:fs/promises";
16
16
  import * as os2 from "node:os";
17
17
  import * as path from "node:path";
18
18
  import { resolveHqDataDir } from "@wrongstack/core/hq";
19
+ import { isSafeSessionId as coreIsSafeSessionId } from "@wrongstack/core/utils";
19
20
  import { sanitizeApiError, scrubErrorDetail } from "@wrongstack/core/security";
20
21
  var TRANSCRIPT_RING_MAX = 4e3;
21
22
  var MAX_TRANSCRIPT_SESSIONS = 400;
@@ -99,11 +100,7 @@ function isSafePathSegment(value) {
99
100
  return true;
100
101
  }
101
102
  function isSafeSessionId(value) {
102
- if (value.length === 0 || value.length > MAX_PATH_SEGMENT_LENGTH) return false;
103
- if (value.includes("\\") || value.includes("\0") || value.includes(":")) return false;
104
- const parts = value.split("/");
105
- if (parts.length > 2) return false;
106
- return parts.every((p) => p.length > 0 && p !== "." && p !== "..");
103
+ return coreIsSafeSessionId(value);
107
104
  }
108
105
  function displayHost(host) {
109
106
  return host === "0.0.0.0" ? "127.0.0.1" : host;
@@ -239,4 +236,4 @@ export {
239
236
  recordTimeseriesSignal,
240
237
  sanitizeApiError
241
238
  };
242
- //# sourceMappingURL=chunk-I7V2OYVH.js.map
239
+ //# sourceMappingURL=chunk-5EA6OTLJ.js.map
@@ -1,6 +1,6 @@
1
1
 
2
2
  // src/preflight.ts
3
- import { ensureSessionShell } from "@wrongstack/tools";
3
+ import { ensureSessionShell } from "@wrongstack/tools/session-shell";
4
4
 
5
5
  // src/cli-update-notice.ts
6
6
  import { writeErr } from "@wrongstack/core/utils";
@@ -62,4 +62,4 @@ export {
62
62
  applySessionShellDefault,
63
63
  runPreflight
64
64
  };
65
- //# sourceMappingURL=chunk-O4A3HHKD.js.map
65
+ //# sourceMappingURL=chunk-672UXYL3.js.map
@@ -6,7 +6,7 @@ import {
6
6
  hasApiKey,
7
7
  isKeylessLocalProvider,
8
8
  visibleModelIds
9
- } from "./chunk-VUVOMXWP.js";
9
+ } from "./chunk-3VXYY5JC.js";
10
10
  import {
11
11
  openBrowser
12
12
  } from "./chunk-DAKVBMD4.js";
@@ -1813,4 +1813,4 @@ export {
1813
1813
  addCustomProvider,
1814
1814
  addKeyForProvider
1815
1815
  };
1816
- //# sourceMappingURL=chunk-ONOT5OJ2.js.map
1816
+ //# sourceMappingURL=chunk-FSZ5QU3M.js.map
@@ -235,6 +235,52 @@ async function dispatch(controller, commandId, type, payload) {
235
235
  });
236
236
  return { commandId, status: "completed", message };
237
237
  }
238
+ case "approve": {
239
+ const resolveApproval = controller.resolveApproval;
240
+ if (resolveApproval === void 0) {
241
+ return {
242
+ commandId,
243
+ status: "rejected",
244
+ message: "this client does not mirror approvals"
245
+ };
246
+ }
247
+ const toolUseId = typeof payload["toolUseId"] === "string" ? payload["toolUseId"] : "";
248
+ const decision = payload["decision"];
249
+ if (toolUseId.length === 0 || decision !== "yes" && decision !== "no" && decision !== "always" && decision !== "deny") {
250
+ return { commandId, status: "rejected", message: "malformed approve command" };
251
+ }
252
+ const applied = resolveApproval(toolUseId, decision, sessionId);
253
+ if (!applied) {
254
+ return {
255
+ commandId,
256
+ status: "rejected",
257
+ // Says WHY, because "rejected" alone reads as a failure the operator
258
+ // should retry — and retrying a settled prompt does nothing.
259
+ message: `approval ${toolUseId} is no longer pending (already answered, aborted or timed out)`
260
+ };
261
+ }
262
+ return { commandId, status: "completed", message: `approval ${decision}` };
263
+ }
264
+ case "answer-input": {
265
+ const resolver = controller.resolveUserInput;
266
+ if (!resolver)
267
+ return {
268
+ commandId,
269
+ status: "rejected",
270
+ message: "this client does not mirror user input forms"
271
+ };
272
+ const requestId = typeof payload["requestId"] === "string" ? payload["requestId"] : "";
273
+ const response = payload["response"];
274
+ if (!requestId || !response || !Array.isArray(response.answers))
275
+ return { commandId, status: "rejected", message: "malformed answer-input command" };
276
+ if (!resolver(requestId, response, sessionId))
277
+ return {
278
+ commandId,
279
+ status: "rejected",
280
+ message: `user input ${requestId} is no longer pending`
281
+ };
282
+ return { commandId, status: "completed", message: "user input submitted" };
283
+ }
238
284
  case "run-command": {
239
285
  if (!controller.allowRunCommand()) {
240
286
  return {
@@ -274,4 +320,4 @@ export {
274
320
  createProjectKanbanAssignHandler,
275
321
  createHqCommandDispatcher
276
322
  };
277
- //# sourceMappingURL=chunk-KNMIBKLV.js.map
323
+ //# sourceMappingURL=chunk-JY52HWL6.js.map
@@ -1,9 +1,9 @@
1
1
 
2
2
  // src/subcommands/index.ts
3
3
  var loaders = {
4
- acp: async () => (await import("./acp-AB54FWM2.js")).acpCmd,
4
+ acp: async () => (await import("./acp-A5EQEXQO.js")).acpCmd,
5
5
  init: async () => (await import("./init-DRMMFG2G.js")).initCmd,
6
- auth: async () => (await import("./auth-WDMSNZ3S.js")).authCmd,
6
+ auth: async () => (await import("./auth-3K6EN5JP.js")).authCmd,
7
7
  update: async () => (await import("./update-5DPB4YD4.js")).updateCmd,
8
8
  sessions: async () => (await import("./sessions-config-UL45XKX7.js")).sessionsCmd,
9
9
  config: async () => (await import("./sessions-config-UL45XKX7.js")).configCmd,
@@ -14,9 +14,9 @@ var loaders = {
14
14
  audit: async () => (await import("./audit-46YK5DSC.js")).auditCmd,
15
15
  tools: async () => (await import("./tools-skills-GH24UCBY.js")).toolsCmd,
16
16
  skills: async () => (await import("./tools-skills-GH24UCBY.js")).skillsCmd,
17
- providers: async () => (await import("./providers-models-6MOGAOVK.js")).providersCmd,
18
- models: async () => (await import("./providers-models-6MOGAOVK.js")).modelsCmd,
19
- mcp: async () => (await import("./mcp-HOMLC4WE.js")).mcpCmd,
17
+ providers: async () => (await import("./providers-models-LFNZ5WI7.js")).providersCmd,
18
+ models: async () => (await import("./providers-models-LFNZ5WI7.js")).modelsCmd,
19
+ mcp: async () => (await import("./mcp-FX7TKPTV.js")).mcpCmd,
20
20
  plugin: async () => (await import("./plugin-usage-M6KET4OZ.js")).pluginCmd,
21
21
  plugins: async () => (await import("./plugin-usage-M6KET4OZ.js")).pluginCmd,
22
22
  diag: async () => (await import("./diag-doctor-PCER6KHH.js")).diagCmd,
@@ -27,11 +27,11 @@ var loaders = {
27
27
  version: async () => (await import("./version-help-WXI42PZ3.js")).versionCmd,
28
28
  help: async () => (await import("./version-help-WXI42PZ3.js")).helpCmd,
29
29
  projects: async () => (await import("./projects-LMNAGGEU.js")).projectsCmd,
30
- modeldiag: async () => (await import("./modeldiag-46CMWUNM.js")).modeldiagCmd,
30
+ modeldiag: async () => (await import("./modeldiag-CJSFHZ3J.js")).modeldiagCmd,
31
31
  quick: async () => (await import("./quick-CNB4Z3HS.js")).quickCmd,
32
32
  bench: async () => (await import("./bench-YBU6BVQP.js")).benchCmd,
33
33
  chronicle: async () => (await import("./chronicle-UTFETHP6.js")).chronicleCmd,
34
- hq: async () => (await import("./hq-5XHEIIH6.js")).hqCmd,
34
+ hq: async () => (await import("./hq-G5PCP325.js")).hqCmd,
35
35
  mailbox: async () => (await import("./mailbox-serve-X3CR6VFW.js")).mailboxServeCmd,
36
36
  permissions: async () => (await import("./permissions-CFDLXETM.js")).permissionsCmd,
37
37
  project: async () => (await import("./project-AOQI5XTK.js")).projectCmd,
@@ -51,4 +51,4 @@ export {
51
51
  subcommands,
52
52
  subcommandNames
53
53
  };
54
- //# sourceMappingURL=chunk-BIWE22O5.js.map
54
+ //# sourceMappingURL=chunk-RLCKKLJA.js.map
@@ -27,7 +27,8 @@ import {
27
27
  writeOut
28
28
  } from "@wrongstack/core/utils";
29
29
  function makePromptDelegate(reader) {
30
- return async (tool, input, suggestedPattern) => {
30
+ return async (tool, input, suggestedPattern, signal) => {
31
+ if (signal?.aborted) return "no";
31
32
  writeOut("\x07");
32
33
  writeOut(
33
34
  `
@@ -54,7 +55,8 @@ ${theme.warn("\u26A0 APPROVAL REQUIRED")} ${theme.primary("\u2502")} ${theme.bol
54
55
  const alwaysHint = noAlwaysReason ? "" : ` ${theme.bold("[a]")}lways allow (${sanitizeTerminalText2(suggestedPattern)})`;
55
56
  const answer = await reader.readKey(
56
57
  `${theme.bold("[y]")}es ${theme.bold("[n]")}o${alwaysHint} ${theme.bold("[d]")}eny: `,
57
- options
58
+ options,
59
+ ...signal ? [{ signal }] : []
58
60
  );
59
61
  return answer;
60
62
  };
@@ -74,15 +76,14 @@ function stringifyInput(input) {
74
76
  var PREVIEW_MAX_LINES = 40;
75
77
  var PREVIEW_MAX_CHARS = 8e3;
76
78
  function clipPreview(body, decorate = (l) => l) {
77
- const safe = sanitizeTerminalText2(body);
78
- const { text, truncated } = sanitizeTerminalPreview(body, {
79
+ const { text, truncated, sanitizedLength, sanitizedLines } = sanitizeTerminalPreview(body, {
79
80
  maxLines: PREVIEW_MAX_LINES,
80
81
  maxChars: PREVIEW_MAX_CHARS
81
82
  });
82
83
  const rendered = text.split("\n").map(decorate).join("\n");
83
84
  if (!truncated) return rendered;
84
- const hiddenLines = safe.split("\n").length - text.split("\n").length;
85
- const detail = hiddenLines > 0 ? `${hiddenLines} more line${hiddenLines === 1 ? "" : "s"} not shown` : `${safe.length - text.length} more characters not shown`;
85
+ const hiddenLines = sanitizedLines - text.split("\n").length;
86
+ const detail = hiddenLines > 0 ? `${hiddenLines} more line${hiddenLines === 1 ? "" : "s"} not shown` : `${sanitizedLength - text.length} more characters not shown`;
86
87
  return `${rendered}
87
88
  ${color2.dim(`\u2026 ${detail} \u2014 review the file before approving`)}`;
88
89
  }
@@ -481,4 +482,4 @@ export {
481
482
  detectProjectFacts,
482
483
  renderAgentsTemplate
483
484
  };
484
- //# sourceMappingURL=chunk-VFCJOWJB.js.map
485
+ //# sourceMappingURL=chunk-RMQNCHGO.js.map