@sema-agent/core 7.23.0 → 7.23.2

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 (132) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/cascade.js +2 -1
  4. package/dist/agents/list-agents-tool.js +2 -1
  5. package/dist/agents/observer.js +3 -2
  6. package/dist/agents/peer-session-drain.js +2 -1
  7. package/dist/agents/retain-ledger.js +2 -1
  8. package/dist/agents/send-message-tool.js +11 -10
  9. package/dist/agents/subagent.js +18 -17
  10. package/dist/agents/teacher.js +5 -4
  11. package/dist/brain/circuit-breaker.js +2 -1
  12. package/dist/brain/degrading.js +2 -1
  13. package/dist/brain/errors.js +24 -15
  14. package/dist/brain/failover.js +2 -1
  15. package/dist/brain/stream-engine.js +2 -1
  16. package/dist/core/a2a.js +4 -3
  17. package/dist/core/artifact-host.js +2 -1
  18. package/dist/core/ask-question.js +3 -2
  19. package/dist/core/auto-promote.js +3 -2
  20. package/dist/core/gate-bounded-await.d.ts +1 -1
  21. package/dist/core/gate-bounded-await.js +3 -2
  22. package/dist/core/gate-crash-trace.d.ts +7 -0
  23. package/dist/core/gate-crash-trace.js +3 -0
  24. package/dist/core/gate-fold.js +6 -2
  25. package/dist/core/gate-lanes.js +6 -3
  26. package/dist/core/git-worktree-env.js +6 -5
  27. package/dist/core/hooks.js +6 -5
  28. package/dist/core/lsp-session.js +3 -2
  29. package/dist/core/mcp.js +4 -3
  30. package/dist/core/memory-admission.js +2 -1
  31. package/dist/core/memory-engine/consolidation-driver.js +5 -4
  32. package/dist/core/memory-engine/consolidation.js +2 -1
  33. package/dist/core/memory-engine/delegation-settlement.js +4 -3
  34. package/dist/core/memory-engine/distiller.js +8 -4
  35. package/dist/core/memory-engine/engine.js +63 -55
  36. package/dist/core/memory-engine/file-backend.js +11 -10
  37. package/dist/core/memory-engine/layout.js +5 -4
  38. package/dist/core/memory-engine/session-incarnation.js +2 -1
  39. package/dist/core/memory.js +2 -1
  40. package/dist/core/oracle-isolation.js +3 -2
  41. package/dist/core/permission-rule-store.js +2 -1
  42. package/dist/core/runner/announce-once-ledger.js +2 -1
  43. package/dist/core/runner/compaction-seams.js +3 -2
  44. package/dist/core/runner/gate-exit.d.ts +5 -5
  45. package/dist/core/runner/gate-exit.js +0 -3
  46. package/dist/core/runner/git-leg-delivery.js +4 -3
  47. package/dist/core/runner/git-status-frame.js +2 -1
  48. package/dist/core/runner/mcp-redial.js +2 -1
  49. package/dist/core/runner/memory-consolidation-driver.js +2 -1
  50. package/dist/core/runner/permission-rule-lanes.js +3 -2
  51. package/dist/core/runner/prepare-artifact.js +2 -1
  52. package/dist/core/runner/prepare-ask-lane.js +2 -1
  53. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  54. package/dist/core/runner/prepare-inherited-gate.js +2 -1
  55. package/dist/core/runner/prepare-memory-engine-session.js +2 -1
  56. package/dist/core/runner/prepare-memory.js +5 -4
  57. package/dist/core/runner/prepare-policy-chain.js +3 -2
  58. package/dist/core/runner/prepare-project-context.js +3 -2
  59. package/dist/core/runner/prepare-protocol-tools.js +3 -2
  60. package/dist/core/runner/prepare-suspend-saga.js +2 -1
  61. package/dist/core/runner/prepare-task.js +6 -5
  62. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  63. package/dist/core/runner/resume-apply.js +5 -4
  64. package/dist/core/runner/resume-preflight.js +3 -2
  65. package/dist/core/runner/run-git-lane.js +4 -3
  66. package/dist/core/runner/run-leg.js +4 -3
  67. package/dist/core/runner/run-recovery-lanes.js +3 -2
  68. package/dist/core/runner/run-settle-and-teardown.js +2 -1
  69. package/dist/core/runner/run-stop-and-final-verify.js +2 -1
  70. package/dist/core/runner/run-telemetry-and-budget-seats.js +2 -1
  71. package/dist/core/runner/run-terminal-adoption.js +6 -5
  72. package/dist/core/runner/run-turn-boundary.js +5 -4
  73. package/dist/core/runner/runtask.js +2 -1
  74. package/dist/core/runner/stream-settle-backstop.js +5 -4
  75. package/dist/core/runner/stream-steer-verb.js +2 -1
  76. package/dist/core/runner/strict-output-schema.js +2 -1
  77. package/dist/core/runner/teardown-bounded.js +2 -1
  78. package/dist/core/safe-notify.js +2 -1
  79. package/dist/core/skills-directory.js +2 -1
  80. package/dist/core/strategy-store.js +2 -1
  81. package/dist/core/task-registry-agent.js +2 -1
  82. package/dist/core/task-registry-monitor.js +2 -1
  83. package/dist/core/task-registry-workflow.js +2 -1
  84. package/dist/core/task-registry.js +3 -2
  85. package/dist/core/thrown-value.d.ts +79 -0
  86. package/dist/core/thrown-value.js +56 -0
  87. package/dist/core/tool-errors.d.ts +0 -6
  88. package/dist/core/tool-errors.js +36 -14
  89. package/dist/core/tool-model-gate.js +2 -1
  90. package/dist/core/tool-policy.js +6 -13
  91. package/dist/core/tool-result-store.js +2 -1
  92. package/dist/core/tool-spec.d.ts +12 -0
  93. package/dist/core/write-protect.js +4 -4
  94. package/dist/engine/compaction/compaction.js +3 -4
  95. package/dist/engine/harness/agent-harness.js +2 -1
  96. package/dist/engine/harness/types.js +8 -7
  97. package/dist/engine/loop/agent-loop.js +7 -6
  98. package/dist/engine/lsp/node-lsp-manager.js +5 -4
  99. package/dist/engine/lsp/stdio-lsp-transport.js +12 -5
  100. package/dist/orchestration/dev-vm-script-runner.js +2 -1
  101. package/dist/orchestration/run-workflow-tool.js +7 -6
  102. package/dist/orchestration/workflow-governance.js +2 -1
  103. package/dist/orchestration/workflow-sandbox-conformance.js +3 -2
  104. package/dist/orchestration/workflow-script-store.js +2 -1
  105. package/dist/orchestration/workflow.js +15 -14
  106. package/dist/server/http.js +3 -2
  107. package/dist/stores/file/adoption/adopt.js +3 -2
  108. package/dist/stores/file/fs-atomic.js +2 -1
  109. package/dist/stores/file/permission-rule-adopt.js +2 -1
  110. package/dist/stores/file/permission-rule-store.js +2 -1
  111. package/dist/stores/file/session-store.js +4 -3
  112. package/dist/stores/file/strategy-store.js +7 -6
  113. package/dist/tools/artifact/artifact-tool.js +3 -2
  114. package/dist/tools/artifact/conformance.js +4 -3
  115. package/dist/tools/fs/bash-lexer.d.ts +12 -5
  116. package/dist/tools/fs/bash-lexer.js +5 -2
  117. package/dist/tools/fs/bash-program-position.d.ts +18 -0
  118. package/dist/tools/fs/bash-program-position.js +13 -1
  119. package/dist/tools/fs/bash-readonly-classifier.d.ts +23 -7
  120. package/dist/tools/fs/bash-readonly-classifier.js +74 -41
  121. package/dist/tools/fs/fs-bash.d.ts +28 -0
  122. package/dist/tools/fs/fs-bash.js +31 -13
  123. package/dist/tools/fs/fs-write.js +3 -2
  124. package/dist/tools/fs/safety.js +2 -1
  125. package/dist/tools/fs/search.js +3 -2
  126. package/dist/tools/monitor.js +3 -2
  127. package/dist/tools/sql.js +2 -1
  128. package/dist/tools/web.js +5 -15
  129. package/dist/tools/worktree.js +12 -9
  130. package/package.json +2 -1
  131. package/wire-changes/core@7.23.1.json +205 -0
  132. package/wire-changes/core@7.23.2.json +42 -0
@@ -1,4 +1,5 @@
1
1
  import { sessionRecordBindsIncarnation, usableSessionIncarnation } from "./layout.js";
2
+ import { thrownText } from "../thrown-value.js";
2
3
  export function createSessionIncarnationSeat(input) {
3
4
  const { resolve, onIncident } = input;
4
5
  let faultAnnounced = false;
@@ -24,7 +25,7 @@ export function createSessionIncarnationSeat(input) {
24
25
  catch (err) {
25
26
  if (!faultAnnounced) {
26
27
  faultAnnounced = true;
27
- disclose("memory.session_incarnation_unreadable", `the session incarnation resolver threw (${err instanceof Error ? err.message : String(err)}) — this run cannot tell one occupant of a session id from the next, so every durable session record binds by id alone (the conservative reading, and the behavior of a deployment that wires no resolver)`);
28
+ disclose("memory.session_incarnation_unreadable", `the session incarnation resolver threw (${thrownText(err)}) — this run cannot tell one occupant of a session id from the next, so every durable session record binds by id alone (the conservative reading, and the behavior of a deployment that wires no resolver)`);
28
29
  }
29
30
  return undefined;
30
31
  }
@@ -3,6 +3,7 @@ import { parseScopeKey } from "./memory-engine/scope-contract.js";
3
3
  import { termSet } from "./memory-vector.js";
4
4
  import { attrEscape } from "./task-notification.js";
5
5
  import { sanitizeUntrustedText, ENGINE_AUTHORITY_ENVELOPE_TAGS } from "./untrusted-text.js";
6
+ import { thrownText } from "./thrown-value.js";
6
7
  export function supportsConsolidation(store) {
7
8
  return (typeof store.searchScored === "function" &&
8
9
  typeof store.update === "function" &&
@@ -27,7 +28,7 @@ export class MemoryProjectionError extends Error {
27
28
  committed = true;
28
29
  path;
29
30
  constructor(path, cause) {
30
- const detail = cause instanceof Error ? cause.message : String(cause);
31
+ const detail = thrownText(cause);
31
32
  super(`memory.projection_failed: the note IS durably committed — only the derived projection ${path} could not be rewritten: ${detail}. ` +
32
33
  `Do not retry the write (it would store the note twice); the projection is rebuilt by the next mutation of this scope.`, cause !== undefined ? { cause } : undefined);
33
34
  this.name = "MemoryProjectionError";
@@ -1,5 +1,6 @@
1
1
  import { isRemoteExecutionEnv, isIsolated } from "./remote-env.js";
2
2
  import { canonicalizeTarget, pathFamilyOf } from "../tools/fs/safety.js";
3
+ import { thrownText } from "./thrown-value.js";
3
4
  function probeCommand(canonOraclePath) {
4
5
  const q = `'${canonOraclePath.replace(/'/g, `'\\''`)}'`;
5
6
  return `touch -- ${q}/.oracle-isolation-probe 2>/dev/null`;
@@ -19,7 +20,7 @@ export async function assertOracleIsolation(workerEnv, grader, opts) {
19
20
  workerId = workerEnv.workspaceHandle().sandboxId;
20
21
  }
21
22
  catch (e) {
22
- return { protected: false, isolationClass, reason: `workspaceHandle() threw during identity check: ${String(e?.message ?? e)}` };
23
+ return { protected: false, isolationClass, reason: `workspaceHandle() threw during identity check: ${thrownText(e)}` };
23
24
  }
24
25
  if (graderId === workerId) {
25
26
  return { protected: false, isolationClass, reason: `grader and worker share sandboxId "${graderId}" (no isolation)` };
@@ -39,7 +40,7 @@ export async function assertOracleIsolation(workerEnv, grader, opts) {
39
40
  writable = res.ok && res.value.exitCode === 0;
40
41
  }
41
42
  catch (e) {
42
- return { protected: false, isolationClass, reason: `isolation probe threw for "${oraclePath}": ${String(e?.message ?? e)}` };
43
+ return { protected: false, isolationClass, reason: `isolation probe threw for "${oraclePath}": ${thrownText(e)}` };
43
44
  }
44
45
  if (writable) {
45
46
  return { protected: false, isolationClass, reason: `oracle path "${oraclePath}" is WRITABLE from the worker env (probe wrote it)` };
@@ -1,6 +1,7 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import { canonicalize } from "./canonical-json.js";
3
3
  import { escapeForDisclosure, isRuleBehavior, isRuleLive, parseRuleText } from "./permission-rule-model.js";
4
+ import { thrownText } from "./thrown-value.js";
4
5
  export function sameRuleOwner(a, b) {
5
6
  return a.kind === "principal" ? b.kind === "principal" && a.principal === b.principal : b.kind === "local-owner";
6
7
  }
@@ -473,7 +474,7 @@ export async function removePersistedRule(opts) {
473
474
  }
474
475
  }
475
476
  export function errText(err) {
476
- return err instanceof Error ? err.message : String(err);
477
+ return thrownText(err);
477
478
  }
478
479
  export const EMPTY_DURABLE_RULE_PARTITION = {
479
480
  list: async () => ({ rules: [], tombstones: [], rev: 0 }),
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { redactSecrets } from "../untrusted-egress.js";
3
3
  import { inlineUntrusted } from "../untrusted-text.js";
4
+ import { thrownText } from "../thrown-value.js";
4
5
  export const ANNOUNCE_ONCE_MAX_DIGESTS = 200;
5
6
  const DROPPED_TOOL_MODEL_LANE = "mcp_dropped_tools";
6
7
  export function announceDigest(lane, text) {
@@ -9,7 +10,7 @@ export function announceDigest(lane, text) {
9
10
  export function warningDigest(err) {
10
11
  const e = err;
11
12
  const code = typeof e?.code === "string" ? e.code : "";
12
- const message = err instanceof Error ? err.message : String(err);
13
+ const message = thrownText(err);
13
14
  return announceDigest(code, redactSecrets(message));
14
15
  }
15
16
  export function droppedToolDigest(d) {
@@ -1,4 +1,5 @@
1
1
  import { hookSeatExpiredError, resolveHookTimeoutMs, runHookSeat } from "../hooks.js";
2
+ import { asThrownError } from "../thrown-value.js";
2
3
  export function seamCCompactionOptions(runner, prepared) {
3
4
  if (!runner.deps.summaryProvider)
4
5
  return undefined;
@@ -42,7 +43,7 @@ export function compactionHookOptions(runner, spec, sessionId, trigger, identity
42
43
  return r;
43
44
  }
44
45
  catch (err) {
45
- report(err instanceof Error ? err : new Error(String(err)));
46
+ report(asThrownError(err));
46
47
  return undefined;
47
48
  }
48
49
  },
@@ -63,7 +64,7 @@ export function compactionHookOptions(runner, spec, sessionId, trigger, identity
63
64
  }
64
65
  catch (err) {
65
66
  try {
66
- runner.deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId });
67
+ runner.deps.onError?.(asThrownError(err), { phase: "hook", sessionId });
67
68
  }
68
69
  catch {
69
70
  }
@@ -112,11 +112,6 @@ export declare function createSettlementLedger(call: {
112
112
  * a non-object primitive passes through as-is (immutable anyway).
113
113
  */
114
114
  export declare function cloneObserverInput(input: unknown): unknown;
115
- /** Hand the crash itself to the deployment's trace lane (`onError(phase:"hook")`), never letting a
116
- * throwing sink alter the fail-closed outcome — the same swallow posture as every other observer here.
117
- * Shared by the gate's dispatch (the phase-1 crash arm, the seat-bound refusal), the reversibility probe's
118
- * two failure arms and the approved-edit re-screen. */
119
- export declare function traceHookCrash(input: ToolGateInput, err: unknown, notifier: SafeNotifier): void;
120
115
  /**
121
116
  * The PreToolUse screening face as the gate's stations see it — the hook machinery of `runToolGate` (the seat
122
117
  * runner, the per-call seat bound, the fresh per-screening context, the result screen, the two fail-closed
@@ -251,6 +246,11 @@ export interface GatePass {
251
246
  * leaves the call's boundary UNKNOWN: the allow layer (a stored allow rule, the read-only reader) must
252
247
  * not clear the surviving ask — a person confirms it. Writer: the fold. Reader: the lanes' mandate. */
253
248
  probeUnanswered?: true;
249
+ /** borrowed-mutable — the probe ANSWERED and reported that the read boundary DECLINED to judge where this
250
+ * command reads ({@link import("../tool-spec.js").ReversibilityVerdict.boundaryDeclined}). The member above's
251
+ * twin on the answered side, and narrower: the ask stays ordinary for every ANSWERER, and only the allow
252
+ * layer's read-only-command arm stands down. Writer: the fold. Reader: that arm, and nothing else. */
253
+ probeBoundaryDeclined?: true;
254
254
  /** borrowed-mutable — the write-protection judge covered this call and its table MATCHED: the allow
255
255
  * layer must not clear the surviving ask, a live decider still may. Writer: the fold's fourth tighten,
256
256
  * on BOTH its arms. Reader: the lanes' mandate. */
@@ -76,9 +76,6 @@ export function cloneObserverInput(input) {
76
76
  return input;
77
77
  }
78
78
  }
79
- export function traceHookCrash(input, err, notifier) {
80
- notifier.notify(() => input.onHookError?.(err), "toolGate.onHookError");
81
- }
82
79
  const PARK_FAILURE_CAUSE_MAX = 600;
83
80
  function withParkFailureCause(reason, parkFailed) {
84
81
  if (parkFailed === undefined)
@@ -2,6 +2,7 @@ import { gitFrameContextVisible, normalizeGitAnnouncement } from "../../internal
2
2
  import { mintSystemReminder } from "../reminder-mint.js";
3
3
  import { sanitizeUntrustedText, SHELLED_BODY_ENVELOPE_TAGS } from "../untrusted-text.js";
4
4
  import { branchCarriesVisiblePositiveGitFrame, newestEngineGitFrame } from "./git-status-frame.js";
5
+ import { asThrownError } from "../thrown-value.js";
5
6
  export function wrapGitFrame(body, mark) {
6
7
  return mintSystemReminder(sanitizeUntrustedText(body, SHELLED_BODY_ENVELOPE_TAGS), mark);
7
8
  }
@@ -42,7 +43,7 @@ export async function resolveGitLegDelivery(prepared, cpMirror, report) {
42
43
  }
43
44
  catch (err) {
44
45
  pending = true;
45
- report(err instanceof Error ? err : new Error(String(err)));
46
+ report(asThrownError(err));
46
47
  }
47
48
  if (prior !== undefined && !pending && prior.entryId !== undefined) {
48
49
  try {
@@ -52,7 +53,7 @@ export async function resolveGitLegDelivery(prepared, cpMirror, report) {
52
53
  }
53
54
  catch (err) {
54
55
  pending = true;
55
- report(err instanceof Error ? err : new Error(String(err)));
56
+ report(asThrownError(err));
56
57
  }
57
58
  }
58
59
  if (prior !== undefined)
@@ -66,7 +67,7 @@ export async function resolveGitLegDelivery(prepared, cpMirror, report) {
66
67
  }
67
68
  catch (err) {
68
69
  mustDisown = true;
69
- report(err instanceof Error ? err : new Error(String(err)));
70
+ report(asThrownError(err));
70
71
  }
71
72
  return mustDisown ? frame.body : undefined;
72
73
  }
@@ -4,6 +4,7 @@ import { inlineUntrusted } from "../untrusted-text.js";
4
4
  import { openSystemReminder } from "../reminder-mint.js";
5
5
  import { engineRegionCovers, protectGitFrame } from "../context-guard.js";
6
6
  import { gitFrameContextVisible } from "../../internal/harness.js";
7
+ import { thrownText } from "../thrown-value.js";
7
8
  export const GIT_STATUS_FRAME_FORMAT_VERSION = 1;
8
9
  export const GIT_STATUS_FRAME_PREAMBLE = "This is the git status observed while preparing this request. When the visible snapshot changes it will be re-sent in a later message — the most recent git status frame supersedes earlier ones.";
9
10
  export const GIT_STATUS_UNAVAILABLE_BODY = "Git status is currently unavailable; the most recent git status frame above may be stale.";
@@ -104,7 +105,7 @@ export async function probeGitStatusLane(args) {
104
105
  }
105
106
  }
106
107
  catch (err) {
107
- onDegrade(err instanceof Error ? err.message : String(err));
108
+ onDegrade(thrownText(err));
108
109
  }
109
110
  }
110
111
  else if (envFacts.isGitRepo === false) {
@@ -1,4 +1,5 @@
1
1
  import { deliverEngineNotice } from "../types.js";
2
+ import { thrownText } from "../thrown-value.js";
2
3
  export function applyMcpRosterDelta(input, delta) {
3
4
  const { toolFaceSnapshot, withFaces, remoteToolOffload, foldProtocolAxes, toolEffects, axisExplicitNegatives, roster } = input;
4
5
  const excludedSet = new Set(toolFaceSnapshot.exclude ?? []);
@@ -24,7 +25,7 @@ export function applyMcpRosterDelta(input, delta) {
24
25
  catch (foldErr) {
25
26
  restoreDomain(toolEffects, priorDomainEffects);
26
27
  restoreDomain(axisExplicitNegatives, priorDomainNegatives);
27
- return { applied: false, foldError: foldErr instanceof Error ? foldErr.message : String(foldErr) };
28
+ return { applied: false, foldError: thrownText(foldErr) };
28
29
  }
29
30
  roster.replaceDomain(delta.prefix, withFaces(pushable, delta.server).map((t) => remoteToolOffload(t)), { source: "mcp", mountedBy: "optional", origin: { peer: delta.server } });
30
31
  return { applied: true, pushed: pushable.length, excluded };
@@ -3,6 +3,7 @@ import { expandTiers, roleModelIfSet } from "../roles.js";
3
3
  import { isAliasModelId, openAiCompatChatSeat } from "../memory-engine/distiller.js";
4
4
  import { runMemoryConsolidationDriver } from "../memory-engine/consolidation-driver.js";
5
5
  import { recommendationUnconsumed } from "../memory-engine/consolidation.js";
6
+ import { asThrownError } from "../thrown-value.js";
6
7
  function seatRefusal(message) {
7
8
  const e = new Error(message);
8
9
  e.code = "config.memory_consolidation_driver";
@@ -74,7 +75,7 @@ export function autoRunConsolidationFromRecommendation(args) {
74
75
  }
75
76
  catch (err) {
76
77
  try {
77
- onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "memory", sessionId });
78
+ onError?.(asThrownError(err), { phase: "memory", sessionId });
78
79
  }
79
80
  catch {
80
81
  }
@@ -5,6 +5,7 @@ import { isAbsolutePathForm } from "../../tools/fs/safety.js";
5
5
  import { effectivePathTargetOf } from "../effective-path-target.js";
6
6
  import { declaredPathTargetOf, protectivePathTargetOf } from "../tool-registry.js";
7
7
  import { orgRuleVerdictFor } from "../permission-rule-org.js";
8
+ import { thrownText } from "../thrown-value.js";
8
9
  export const PERSISTED_RULE_TOOL = "Bash";
9
10
  const HANDOFF_BOUND = 256;
10
11
  export function inheritedAskRuleEvidence(provider) {
@@ -97,7 +98,7 @@ export function createPermissionRuleLanes(cfg) {
97
98
  resolution = (await hand(req.toolCallId)).org;
98
99
  }
99
100
  catch (err) {
100
- return { status: "unavailable", disclosures: [`the permission-rule store threw while resolving the org partition: ${err instanceof Error ? err.message : String(err)}`] };
101
+ return { status: "unavailable", disclosures: [`the permission-rule store threw while resolving the org partition: ${thrownText(err)}`] };
101
102
  }
102
103
  if (resolution.status === "unavailable" || resolution.status === "ungoverned") {
103
104
  return { status: "unavailable", disclosures: resolution.status === "ungoverned" ? ["the store reports no org partition while the provider declares one — unreadable governance, never an empty one"] : resolution.disclosures };
@@ -124,7 +125,7 @@ export function createPermissionRuleLanes(cfg) {
124
125
  view = await claim(req.toolCallId);
125
126
  }
126
127
  catch (err) {
127
- cfg.onDisclosure(err instanceof Error ? err.message : String(err));
128
+ cfg.onDisclosure(thrownText(err));
128
129
  return { unreadable: true };
129
130
  }
130
131
  if (view.unreadable !== undefined) {
@@ -7,6 +7,7 @@ import { inlineUntrusted } from "../untrusted-text.js";
7
7
  import { physicalPathOfExisting } from "../physical-path.js";
8
8
  import { pathFamilyOf, resolveKey, violationDetails, violationText, withinAnyRoot } from "../../tools/fs/safety.js";
9
9
  import { createArtifactTool } from "../../tools/artifact/artifact-tool.js";
10
+ import { thrownText } from "../thrown-value.js";
10
11
  export function prepareArtifact(input) {
11
12
  const { deps, runId, taskId, sessionId, agentName, onAsk, executionEnv, rootCanonical, additionalRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames } = input;
12
13
  const host = deps.artifactHost;
@@ -35,7 +36,7 @@ export function prepareArtifact(input) {
35
36
  host.onMount?.(runId);
36
37
  }
37
38
  catch (err) {
38
- return refuse(`artifactHost.onMount threw: ${err instanceof Error ? err.message : String(err)}`);
39
+ return refuse(`artifactHost.onMount threw: ${thrownText(err)}`);
39
40
  }
40
41
  const readLocalFile = async (path, maxBytes, signal) => {
41
42
  if (rootCanonical === undefined)
@@ -4,6 +4,7 @@ import { advertisedWritableRootsSeat, isLiveApproverSeat, resolveAsk } from "../
4
4
  import { composeCallSignal, raceAbort } from "./abort-race.js";
5
5
  import { gateAskCarry, lateAskSettlementObserver } from "./denial-limit-arms.js";
6
6
  import { consumeInheritedAskGrant } from "./inherited-ask-grants.js";
7
+ import { asThrownError } from "../thrown-value.js";
7
8
  function createDenyObserverNotifier(hooks, hookTimeoutMs, signal, report) {
8
9
  if (hooks?.permissionDenied === undefined)
9
10
  return undefined;
@@ -124,7 +125,7 @@ export function prepareAskLane(input) {
124
125
  const notifyPermissionDenied = createDenyObserverNotifier(hooks, hookTimeoutMs, abortController.signal, notifyOwnHookCrash);
125
126
  const notifyHookError = (err) => {
126
127
  try {
127
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId });
128
+ deps.onError?.(asThrownError(err), { phase: "hook", sessionId });
128
129
  }
129
130
  catch {
130
131
  }
@@ -20,6 +20,7 @@ import { derivedRouteFallsBack } from "./derived-route-fallback.js";
20
20
  import { CLASSIFIER_ATTEMPT_SUFFIX, CLASSIFIER_THINK_SEAT, announceClassifierRoleDefaulted, classifierLadderRungs, classifierReplyAsksAgain, classifierReplyFailure, classifierReplyVerdictText, classifierRoundObserver, classifierRungSeat, classifierSeatModel } from "./classifier-ladder.js";
21
21
  import { REPORT_FINDINGS_TOOL_NAME, createReportBlockedTool, createReportFindingsTool } from "./synthetic-tools.js";
22
22
  import { RosterBuilder, callerMountSource } from "../tool-roster.js";
23
+ import { asThrownError, thrownText } from "../thrown-value.js";
23
24
  function assembleParentCaptureState(o, i, ctl, ancestors) {
24
25
  const build = (optedOut, indeterminate) => ({
25
26
  optedOut: optedOut === true,
@@ -59,7 +60,7 @@ function screenAutoModeCap(caps, onError, sessionId) {
59
60
  record = snapshotRuntimeCaps(caps);
60
61
  }
61
62
  catch (err) {
62
- onError?.(new Error(`runtimeCapsResolver's record threw while being read (${err instanceof Error ? err.message : String(err)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain).`), { phase: "config", sessionId });
63
+ onError?.(new Error(`runtimeCapsResolver's record threw while being read (${thrownText(err)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain).`), { phase: "config", sessionId });
63
64
  return { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, faulted: true };
64
65
  }
65
66
  const { autoMode, autoModeDenySource } = record;
@@ -148,7 +149,7 @@ export async function prepareCapsAndWorkflow(input) {
148
149
  runtimeCaps = (await deps.runtimeCapsResolver(spec.principal)) ?? undefined;
149
150
  }
150
151
  catch (err) {
151
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
152
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
152
153
  runtimeCaps = { allowWorkflows: false, allowFork: false, autoMode: false };
153
154
  runtimeCapsFaulted = true;
154
155
  }
@@ -165,7 +166,7 @@ export async function prepareCapsAndWorkflow(input) {
165
166
  complianceDenies = resolveComplianceDenies(posture);
166
167
  }
167
168
  catch (err) {
168
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
169
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
169
170
  complianceDenies = new Set(COMPLIANCE_CAPABILITIES);
170
171
  complianceDegraded = true;
171
172
  }
@@ -5,6 +5,7 @@ import { createPreToolUseConstraintPolicy } from "../hooks.js";
5
5
  import { StubExecutionEnv } from "../stub-env.js";
6
6
  import { askApproverIdentity, durableMandateSourceOf } from "../tool-policy.js";
7
7
  import { attachRebuiltDenialTrackers, createDenialLimitStop } from "./denial-limit-arms.js";
8
+ import { asThrownError } from "../thrown-value.js";
8
9
  export function prepareInheritedGate(input) {
9
10
  const { spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun } = input;
10
11
  const liveInheritedGate = internals?.inheritedGate;
@@ -94,7 +95,7 @@ export function prepareInheritedGate(input) {
94
95
  const hookEnvSource = (ownedEnv ?? deps.executionEnv) != null ? executionEnv : undefined;
95
96
  const notifyOwnHookCrash = (err) => {
96
97
  try {
97
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "hook", sessionId });
98
+ deps.onError?.(asThrownError(err), { phase: "hook", sessionId });
98
99
  }
99
100
  catch {
100
101
  }
@@ -6,6 +6,7 @@ import { deliverEngineNotice } from "../types.js";
6
6
  import { inlineUntrusted } from "../untrusted-text.js";
7
7
  import { fileArgPath } from "../../tools/fs/safety.js";
8
8
  import { RosterBuilder } from "../tool-roster.js";
9
+ import { thrownText } from "../thrown-value.js";
9
10
  export function prepareMemoryEngineSession(input) {
10
11
  const { memoryEngineSession, internals, memoryDelegationEvidence, externalContentTargetActive, lockedPreflight, mcp, sessionId, runId, deps, provenanceForChildrenRef, delegationSettlementRef, spec, envHandToolNames, roster, contentOriginWrapRef } = input;
11
12
  const tools = roster.tools;
@@ -167,7 +168,7 @@ export function prepareMemoryEngineSession(input) {
167
168
  recordSyncUnattestable(settlementSeat.controlDir, { sessionId: settlementSeat.sessionId, toolCallId, now: Date.now });
168
169
  }
169
170
  catch (err) {
170
- const e = new Error(`delegated output withheld (fail-closed): the delegation delivered without a provable attestation and the settlement account could not record the fact (${err instanceof Error ? err.message : String(err)}) — repair the memory control plane or retry`);
171
+ const e = new Error(`delegated output withheld (fail-closed): the delegation delivered without a provable attestation and the settlement account could not record the fact (${thrownText(err)}) — repair the memory control plane or retry`);
171
172
  e.code = "memory.settlement_record_failed";
172
173
  throw e;
173
174
  }
@@ -11,6 +11,7 @@ import { createMemoryEngineTools } from "../memory-engine/tools.js";
11
11
  import { assertScopeContractPlacement, parseScopeKey, resolveProjectId } from "../memory-engine/scope-contract.js";
12
12
  import { FileMemoryEngineBackend } from "../memory-engine/file-backend.js";
13
13
  import { writableRootOf } from "../memory-engine/types.js";
14
+ import { asThrownError, thrownText } from "../thrown-value.js";
14
15
  let undeclaredCapturePostureAnnounced = false;
15
16
  export async function prepareMemory(input) {
16
17
  const { spec, deps, sessionId, taskRootPath, admissionCtx } = input;
@@ -108,7 +109,7 @@ export async function prepareMemory(input) {
108
109
  catch (err) {
109
110
  if (consumesProjectIdentity)
110
111
  throw err;
111
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
112
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
112
113
  }
113
114
  if (marker) {
114
115
  identityKey = marker.projectId;
@@ -403,7 +404,7 @@ export async function prepareMemory(input) {
403
404
  readReport = await readOther[0].harvest(readOther[1]);
404
405
  }
405
406
  catch (err) {
406
- readFailure = err instanceof Error ? err.message : String(err);
407
+ readFailure = thrownText(err);
407
408
  }
408
409
  const merged = readReport !== undefined ? mergeHarvestReports(writeReport, readReport) : writeReport;
409
410
  if (readFailure !== undefined)
@@ -548,7 +549,7 @@ export async function prepareMemory(input) {
548
549
  }
549
550
  catch (err) {
550
551
  try {
551
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "memory", sessionId });
552
+ deps.onError?.(asThrownError(err), { phase: "memory", sessionId });
552
553
  }
553
554
  catch {
554
555
  }
@@ -700,7 +701,7 @@ export async function prepareMemory(input) {
700
701
  err.code.startsWith("config.memory_capture"))) {
701
702
  throw err;
702
703
  }
703
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "memory", sessionId });
704
+ deps.onError?.(asThrownError(err), { phase: "memory", sessionId });
704
705
  if (effectiveMemoryScopes === undefined) {
705
706
  effectiveMemoryScopes = {
706
707
  state: "memoryless",
@@ -15,6 +15,7 @@ import { headlessDenyAtFold, headlessDenyAtRecheck, inheritedAskCarry, judgeInhe
15
15
  import { askGrantShapeOf } from "./inherited-ask-grants.js";
16
16
  import { createPermissionRuleLanes, inheritedAskRuleEvidence, createRuleOffersOf } from "./permission-rule-lanes.js";
17
17
  import { createSessionRulePolicy } from "./session-rule-policy.js";
18
+ import { thrownText } from "../thrown-value.js";
18
19
  export async function preparePolicyChain(input) {
19
20
  const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
20
21
  const policy = lockedPreflight.toolPolicy;
@@ -300,7 +301,7 @@ export async function preparePolicyChain(input) {
300
301
  catch (err) {
301
302
  return vetoed({
302
303
  action: "deny",
303
- message: `inherited parent policy re-check of the approved edit errored for "${creq.toolName}": ${err instanceof Error ? err.message : String(err)}`,
304
+ message: `inherited parent policy re-check of the approved edit errored for "${creq.toolName}": ${thrownText(err)}`,
304
305
  });
305
306
  }
306
307
  if (re.action === "deny")
@@ -437,7 +438,7 @@ export async function preparePolicyChain(input) {
437
438
  catch (err) {
438
439
  return {
439
440
  action: "deny",
440
- message: `inherited parent policy errored for "${creq.toolName}": ${err instanceof Error ? err.message : String(err)}`,
441
+ message: `inherited parent policy errored for "${creq.toolName}": ${thrownText(err)}`,
441
442
  };
442
443
  }
443
444
  if (decision.action !== "ask")
@@ -8,6 +8,7 @@ import { defineTool } from "../tools.js";
8
8
  import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
9
9
  import { substitutedSkillLength } from "./skill-base-dir.js";
10
10
  import { RosterBuilder } from "../tool-roster.js";
11
+ import { asThrownError } from "../thrown-value.js";
11
12
  export async function prepareProjectContext(input) {
12
13
  const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume, skillListingBudget } = input;
13
14
  const tools = roster.tools;
@@ -49,7 +50,7 @@ export async function prepareProjectContext(input) {
49
50
  }));
50
51
  }
51
52
  catch (err) {
52
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
53
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
53
54
  }
54
55
  const projectMem = loaded !== null && typeof loaded === "object" ? loaded.content : loaded;
55
56
  const seededFiles = loaded !== null && typeof loaded === "object" ? loaded.seededFiles : undefined;
@@ -61,7 +62,7 @@ export async function prepareProjectContext(input) {
61
62
  await seedContextFiles(seededFiles);
62
63
  }
63
64
  catch (err) {
64
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
65
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
65
66
  }
66
67
  }
67
68
  if (projectMem != null && projectMem.trim()) {
@@ -9,6 +9,7 @@ import { REFRESH_MCP_TOOLS_TOOL_NAME, toolFace } from "../tool-catalog-entries.j
9
9
  import { MCP_NAMESPACE, A2A_NAMESPACE } from "../protocol-table.js";
10
10
  import { mintNamespacePrefix } from "../protocol-naming.js";
11
11
  import { applyMcpToolFaces } from "./tool-face-overlay.js";
12
+ import { thrownText } from "../thrown-value.js";
12
13
  export async function prepareProtocolTools(input) {
13
14
  const { lockedPreflight, spec, deps, reminderMark, reminderDisclosureCounts, runId, sessionId, onceLedger, roster, rosterSeat, remoteToolOffload, toolFaceSnapshot, toolEffects, axisExplicitNegatives, irreversibilityTier, irreversibleTools, egressTools, abortController, rollback } = input;
14
15
  const overPeer = (lockedPreflight.mcp ?? []).find((s) => s.name.length > TOOL_WIRE_NAME_MAX_CHARS);
@@ -176,8 +177,8 @@ function mcpRevocationWiring(deps, runId) {
176
177
  isRevoked: (name) => ledger.isRevoked(name),
177
178
  onProbeFailure: (e) => deliverEngineNotice(deps.onNotice, {
178
179
  code: "mcp.revocation_probe_failed",
179
- message: `the mcpRevocations.isRevoked probe threw — MCP dispatch fails OPEN (no server treated as revoked) until the probe recovers: ${e instanceof Error ? e.message : String(e)}`,
180
- detail: { message: e instanceof Error ? e.message : String(e), runId },
180
+ message: `the mcpRevocations.isRevoked probe threw — MCP dispatch fails OPEN (no server treated as revoked) until the probe recovers: ${thrownText(e)}`,
181
+ detail: { message: thrownText(e), runId },
181
182
  }),
182
183
  };
183
184
  }
@@ -5,6 +5,7 @@ import { raceSettlementAgainstSignal } from "./abort-race.js";
5
5
  import { placementValueOrAbsent } from "./checkpoint-scope.js";
6
6
  import { serializeAnnouncedListings } from "./announce-once-ledger.js";
7
7
  import { remoteEnvFailureNote, restoreWorkspaceWithRetry } from "./remote-env-retry.js";
8
+ import { thrownText } from "../thrown-value.js";
8
9
  const PARK_COMPENSATION_TIMEOUT_MS = 30_000;
9
10
  export async function compensateUnparkedPause(remoteEnv, snapshotId, io) {
10
11
  const boundCtl = new AbortController();
@@ -40,7 +41,7 @@ export async function compensateUnparkedPause(remoteEnv, snapshotId, io) {
40
41
  if (raced.tag === "threw") {
41
42
  io.noteFailure(remoteEnvFailureNote(phase, raced.error instanceof RemoteExecutionError
42
43
  ? raced.error
43
- : new RemoteExecutionError("unknown", `the pause compensation's ${phase} call threw: ${raced.error instanceof Error ? raced.error.message : String(raced.error)}`), phase === "resumeVM" ? restoreAttempts : 1));
44
+ : new RemoteExecutionError("unknown", `the pause compensation's ${phase} call threw: ${thrownText(raced.error)}`), phase === "resumeVM" ? restoreAttempts : 1));
44
45
  io.disclose(raced.error);
45
46
  return {
46
47
  ok: false,
@@ -80,6 +80,7 @@ import { catalogEntriesNamed, pathTargetOf } from "../tool-registry.js";
80
80
  import { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
81
81
  import { resolveTaskRootCanonical } from "./task-root-canonical.js";
82
82
  import { createStructuredProjector } from "./tool-output-projection.js";
83
+ import { asThrownError, thrownText } from "../thrown-value.js";
83
84
  function warnCompactionWindowHazard(tracer, spec, model, compModel, hostTaskId) {
84
85
  if (compModel === undefined)
85
86
  return;
@@ -209,7 +210,7 @@ async function adoptReminderMark(session, sessionId, seedMark, spawnMark, onErro
209
210
  return await session.getReminderMark();
210
211
  }
211
212
  catch (err) {
212
- onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
213
+ onError?.(asThrownError(err), { phase: "config", sessionId });
213
214
  return undefined;
214
215
  }
215
216
  })();
@@ -225,7 +226,7 @@ async function adoptReminderMark(session, sessionId, seedMark, spawnMark, onErro
225
226
  await session.appendReminderMark(reminderMark);
226
227
  }
227
228
  catch (err) {
228
- onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
229
+ onError?.(asThrownError(err), { phase: "config", sessionId });
229
230
  }
230
231
  }
231
232
  return { reminderMark, reminderDisclosureCounts: {} };
@@ -246,7 +247,7 @@ function refuseRequireExistingWithoutSession(spec) {
246
247
  }
247
248
  }
248
249
  function validateInputFaultNotice(onError, sessionId) {
249
- return ({ toolName, toolCallId, error }) => onError?.(new Error(`tool input pre-validation (validateInput) threw for ${toolName} (call ${toolCallId}) — read as no verdict; the call proceeded to the gate: ${error instanceof Error ? error.message : String(error)}`), { phase: "hook", sessionId });
250
+ return ({ toolName, toolCallId, error }) => onError?.(new Error(`tool input pre-validation (validateInput) threw for ${toolName} (call ${toolCallId}) — read as no verdict; the call proceeded to the gate: ${thrownText(error)}`), { phase: "hook", sessionId });
250
251
  }
251
252
  function refuseInvalidAutoModeSeat(spec) {
252
253
  if (spec.autoModeRequested !== undefined && spec.autoModeRequested !== true) {
@@ -350,7 +351,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
350
351
  return physicalPathOf(resolveFsPath(p));
351
352
  }
352
353
  catch (err) {
353
- return failIsolation(`cannot canonicalize ${what} (${err instanceof Error ? err.message : String(err)}) — an unverifiable path is treated as not isolated`);
354
+ return failIsolation(`cannot canonicalize ${what} (${thrownText(err)}) — an unverifiable path is treated as not isolated`);
354
355
  }
355
356
  };
356
357
  if (deps.rootPath !== undefined || internals.parentCwd !== undefined) {
@@ -573,7 +574,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
573
574
  await seedContextFiles(memorySeedFiles);
574
575
  }
575
576
  catch (err) {
576
- deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
577
+ deps.onError?.(asThrownError(err), { phase: "config", sessionId });
577
578
  }
578
579
  }
579
580
  const projectContext = await prepareProjectContext({ deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, roster, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume, skillListingBudget: doors.skillListingBudget });
@@ -10,6 +10,7 @@ import { applyContextShrinkToReadFileState, isReadDedupStubResult } from "../../
10
10
  import { resolveKey } from "../../tools/fs/safety.js";
11
11
  import { PROMPT_HASH_SALT } from "./prompt-hash-salt.js";
12
12
  import { CHANGED_FILES_MTIME_EPS_MS } from "./turn-attachments.js";
13
+ import { thrownText } from "../thrown-value.js";
13
14
  export function prepareTurnWiring(input) {
14
15
  const { deps, systemPromptSeat, harnessTools, fpRef, model, epochArtifactDigestForSnapshot, promptProfile, fableMitigations, systemBlocks, thinking, spec, sessionId, turnSnapshotRef, promptManifest, charsPerToken, handsEnabled, executionEnv, attachmentRootCanonical, additionalRootsCanonical, additionalReadRootsCanonical, readDenyMatcher, resolvedReadFace, handsCwdRef, readFileStateForCheckpoint, denyNarrowingPolicy, abortController, hostTaskId, taskScope, buildAssembleInputs, centerAdoptionRef, harnessRef, epochDeclaredSections, carrierReadFace, carrierWriteFace, readDenyAdditionsNormalized, preparedHolder } = input;
15
16
  const cacheBreakDetector = deps.cacheBreakDetection === false ? undefined : new CacheBreakDetector();
@@ -72,7 +73,7 @@ export function prepareTurnWiring(input) {
72
73
  return d.text;
73
74
  }
74
75
  catch (err) {
75
- announceAttachmentSkip(path, err instanceof Error ? err.message : String(err));
76
+ announceAttachmentSkip(path, thrownText(err));
76
77
  return null;
77
78
  }
78
79
  }
@@ -9,6 +9,7 @@ import { callFaceSeat, parkedCallFaceOf } from "../tool-roster.js";
9
9
  import { inlineUntrusted } from "../untrusted-text.js";
10
10
  import { deepJsonEqual, describeSuppliedValue } from "./decide-continuation.js";
11
11
  import { mintGateOutcome } from "./gate-exit.js";
12
+ import { asThrownError, thrownText } from "../thrown-value.js";
12
13
  export async function resumeApply(input) {
13
14
  const { cp, config, internals, outcomeGate, wakeMessage, resumeSignal, recheckGovernanceWindow, plainReviewOutcome, plainParkOutcome, runner, effectiveDelegationFacts } = input;
14
15
  let plainPolicyOutcome = input.plainPolicyOutcome;
@@ -29,7 +30,7 @@ export async function resumeApply(input) {
29
30
  });
30
31
  const screenTimeoutMs = resolveHookTimeoutMs(resumeScreenHooks?.timeoutMs, (badErr) => {
31
32
  try {
32
- runner.deps.onError?.(badErr instanceof Error ? badErr : new Error(String(badErr)), { phase: "hook", sessionId: cp.sessionId });
33
+ runner.deps.onError?.(asThrownError(badErr), { phase: "hook", sessionId: cp.sessionId });
33
34
  }
34
35
  catch {
35
36
  }
@@ -53,7 +54,7 @@ export async function resumeApply(input) {
53
54
  catch (hookErr) {
54
55
  if (hookErr instanceof CheckpointError)
55
56
  throw hookErr;
56
- const err = hookErr instanceof Error ? hookErr : new Error(String(hookErr));
57
+ const err = asThrownError(hookErr);
57
58
  try {
58
59
  runner.deps.onError?.(err, { phase: "hook", sessionId: cp.sessionId });
59
60
  }
@@ -138,7 +139,7 @@ export async function resumeApply(input) {
138
139
  catch (err) {
139
140
  if (err instanceof CheckpointError)
140
141
  throw err;
141
- rechecked = { action: "deny", message: `the resume-edit policy re-check errored: ${err instanceof Error ? err.message : String(err)}` };
142
+ rechecked = { action: "deny", message: `the resume-edit policy re-check errored: ${thrownText(err)}` };
142
143
  }
143
144
  if (rechecked.action === "deny") {
144
145
  throw new CheckpointError("resume.constraint_rejected", `the approver EDITED this call's input and the deployment's resume-edit policy denies the edited args${rechecked.message ? `: ${rechecked.message}` : ""}. ` +
@@ -160,7 +161,7 @@ export async function resumeApply(input) {
160
161
  catch (err) {
161
162
  if (err instanceof CheckpointError)
162
163
  throw err;
163
- throw new CheckpointError("resume.constraint_rejected", `the declared-observational PreToolUse face threw while observing the approver's edited args (${err instanceof Error ? err.message : String(err)}) — ` +
164
+ throw new CheckpointError("resume.constraint_rejected", `the declared-observational PreToolUse face threw while observing the approver's edited args (${thrownText(err)}) — ` +
164
165
  "refused fail-closed pre-CAS (the checkpoint stays pending and remains decidable)");
165
166
  }
166
167
  }