@sema-agent/core 7.34.0 → 7.35.0

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 (83) hide show
  1. package/CHANGELOG.md +123 -3
  2. package/dist/brain/errors.d.ts +23 -1
  3. package/dist/brain/errors.js +19 -2
  4. package/dist/brain/status-sink.d.ts +7 -1
  5. package/dist/brain/stream-shared.d.ts +3 -1
  6. package/dist/brain/stream-shared.js +16 -4
  7. package/dist/core/ask-origin.d.ts +34 -6
  8. package/dist/core/ask-origin.js +24 -23
  9. package/dist/core/ask-question.js +2 -1
  10. package/dist/core/checkpoint-store.d.ts +4 -0
  11. package/dist/core/gate-fold.js +2 -2
  12. package/dist/core/gate-lanes.js +5 -4
  13. package/dist/core/governance-codes.d.ts +17 -1
  14. package/dist/core/governance-codes.js +11 -1
  15. package/dist/core/hooks.d.ts +3 -0
  16. package/dist/core/message-utils.d.ts +2 -1
  17. package/dist/core/message-utils.js +2 -1
  18. package/dist/core/mode-policy.d.ts +3 -0
  19. package/dist/core/mode-policy.js +5 -0
  20. package/dist/core/permission-rule-model.d.ts +4 -0
  21. package/dist/core/permission-rule-model.js +4 -0
  22. package/dist/core/permission-rules.js +21 -1
  23. package/dist/core/persisted-rule-arms.d.ts +4 -1
  24. package/dist/core/persisted-rule-arms.js +4 -0
  25. package/dist/core/retired-keys.js +1 -1
  26. package/dist/core/runner/active-skill-scope.js +5 -4
  27. package/dist/core/runner/assemble-result.js +2 -2
  28. package/dist/core/runner/contracts.d.ts +25 -3
  29. package/dist/core/runner/denial-limit-arms.d.ts +6 -1
  30. package/dist/core/runner/denial-limit-arms.js +4 -4
  31. package/dist/core/runner/file-history-request.d.ts +26 -0
  32. package/dist/core/runner/file-history-request.js +90 -0
  33. package/dist/core/runner/permission-rule-lanes.d.ts +2 -1
  34. package/dist/core/runner/permission-rule-lanes.js +14 -11
  35. package/dist/core/runner/prepare-ask-lane.d.ts +1 -1
  36. package/dist/core/runner/prepare-ask-lane.js +2 -2
  37. package/dist/core/runner/prepare-file-history.d.ts +9 -3
  38. package/dist/core/runner/prepare-file-history.js +4 -90
  39. package/dist/core/runner/prepare-gate-stations.d.ts +4 -3
  40. package/dist/core/runner/prepare-gate-stations.js +15 -11
  41. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
  42. package/dist/core/runner/prepare-inherited-gate.js +10 -4
  43. package/dist/core/runner/prepare-park-ask.d.ts +4 -2
  44. package/dist/core/runner/prepare-park-ask.js +5 -4
  45. package/dist/core/runner/prepare-policy-chain.d.ts +3 -2
  46. package/dist/core/runner/prepare-policy-chain.js +171 -175
  47. package/dist/core/runner/prepare-task.js +7 -4
  48. package/dist/core/runner/run-brain-sinks.js +3 -1
  49. package/dist/core/runner/run-leg.js +5 -3
  50. package/dist/core/runner/run-notification-lane.d.ts +3 -0
  51. package/dist/core/runner/run-notification-lane.js +2 -1
  52. package/dist/core/runner/runtask.d.ts +1 -0
  53. package/dist/core/runner/runtask.js +5 -11
  54. package/dist/core/runner/session-mode-seats.d.ts +48 -0
  55. package/dist/core/runner/session-mode-seats.js +73 -0
  56. package/dist/core/runner/session-rule-policy.js +3 -2
  57. package/dist/core/secret-env.d.ts +30 -58
  58. package/dist/core/secret-env.js +149 -586
  59. package/dist/core/sensitive-path-policy.js +2 -1
  60. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
  61. package/dist/core/tool-policy.d.ts +31 -6
  62. package/dist/core/tool-policy.js +35 -16
  63. package/dist/core/tool-registry.d.ts +36 -0
  64. package/dist/core/tool-registry.js +22 -1
  65. package/dist/core/tool-roster.d.ts +17 -2
  66. package/dist/core/tool-roster.js +11 -1
  67. package/dist/core/trace.d.ts +11 -0
  68. package/dist/engine/execution-env/node-execution-env.d.ts +3 -1
  69. package/dist/engine/execution-env/node-execution-env.js +5 -2
  70. package/dist/engine/harness/agent-harness.js +2 -1
  71. package/dist/engine/lsp/node-lsp-manager.js +1 -1
  72. package/dist/index.d.ts +4 -4
  73. package/dist/index.js +4 -4
  74. package/dist/stores/file/index.d.ts +5 -3
  75. package/dist/stores/file/session-store.d.ts +8 -2
  76. package/dist/stores/file/session-store.js +5 -5
  77. package/dist/tools/fs/file-read-check.d.ts +2 -1
  78. package/dist/tools/fs/file-read-check.js +15 -7
  79. package/dist/tools/fs/shell-read-check.d.ts +10 -2
  80. package/dist/tools/fs/shell-read-check.js +12 -8
  81. package/package.json +1 -1
  82. package/test/export-surface.snapshot.json +15 -1
  83. package/wire-changes/core@7.35.0.json +584 -0
@@ -5,6 +5,7 @@ import { compileSegmentPattern, matchSegmentPatterns, READ_FACE_BUILTIN_DENY_TAB
5
5
  import { isProtectedWrite, protectivePathTargetOf } from "./tool-registry.js";
6
6
  import { pathTargetBaseOf } from "./effective-path-target.js";
7
7
  import { symlinkChainHops } from "./path-identity.js";
8
+ import { toolNameSetHas } from "./tool-roster.js";
8
9
  export function agentConfigDenyPatterns() {
9
10
  return READ_FACE_BUILTIN_DENY_TABLE.filter((row) => row.tier === "agent-config").map((row) => readDenyPatternRun(row.pattern).run);
10
11
  }
@@ -146,7 +147,7 @@ export function createSensitivePathPolicy(opts) {
146
147
  async check(req, signal) {
147
148
  if (compiled.length === 0)
148
149
  return { action: "allow" };
149
- if (guardedByName !== undefined ? !guardedByName.has(req.toolName) : !isProtectedWrite(req))
150
+ if (guardedByName !== undefined ? !toolNameSetHas(guardedByName, req) : !isProtectedWrite(req))
150
151
  return { action: "allow" };
151
152
  const protective = protectivePathTargetOf(req);
152
153
  const path = writeTargetPath(req, protective);
@@ -301,7 +301,7 @@ export async function checkpointStoreContract(make, runAssertion) {
301
301
  const stored = (await store.get(bitless.token)).pendingAction;
302
302
  assert.equal("hasBidiControls" in stored, false, "projection backfill must not write back to the row");
303
303
  });
304
- run("design/388 B18 × B6 identity + face group: a row's seven optional members (capabilityId/contractId/shapeDigest/implementationRevision/rosterDigest + family/pathTarget) survive the round-trip verbatim; an absent group stays absent", async () => {
304
+ run("design/388 B18 × B6 identity + face group: a row's eight optional members (capabilityId/contractId/shapeDigest/implementationRevision/rosterDigest + family/pathTarget/names) survive the round-trip verbatim; an absent group stays absent", async () => {
305
305
  const store = make();
306
306
  const carried = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "id-carried" });
307
307
  const group = {
@@ -312,6 +312,7 @@ export async function checkpointStoreContract(make, runAssertion) {
312
312
  rosterDigest: "sha256:fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210",
313
313
  family: "file-write",
314
314
  pathTarget: { param: "destination", aliases: ["path"], access: "create", skillScopeEligible: true },
315
+ names: ["AcmeWrite", "acme_write"],
315
316
  };
316
317
  Object.assign(carried.pendingAction, group);
317
318
  const bare = createCheckpointFixture({ token: mintCheckpointToken(), sessionId: "id-bare" });
@@ -1,9 +1,14 @@
1
- import { type AskOrigin } from "./ask-origin.js";
1
+ import { type AskOrigin, type AssertAllKeysHandled } from "./ask-origin.js";
2
2
  import { type ReadRootGrantScreen } from "./read-root-grant-screen.js";
3
3
  import { type Settlement } from "./gate-outcome.js";
4
4
  /** A tool call presented to a policy before it executes. */
5
5
  /** design/388 B6 — the per-call face (see {@link ToolCallRequest.face}). */
6
6
  export interface ToolCallFace {
7
+ /** Every name a tool-name rule may spell this tool by: the tool's wire name first, then each alias that resolves to
8
+ * it on the leg's roster (`rosterToolName`). A rule reaches the call iff its tool name is on this list — read it
9
+ * through {@link ruleNamesOf}, never off `toolName` alone. Absent on a face rebuilt from a park row that predates it
10
+ * (the call's own name is then the list). */
11
+ names?: readonly string[];
7
12
  family: import("./tool-face.js").ToolFamily;
8
13
  pathTarget?: import("./tool-face.js").ToolRosterPathTarget;
9
14
  capabilityId: string;
@@ -12,6 +17,8 @@ export interface ToolCallFace {
12
17
  implementationRevision: string;
13
18
  }
14
19
  export interface ToolCallRequest {
20
+ /** The tool's wire name — the Runner's gate resolves a call made under an alias to the wire name of the tool it
21
+ * dispatches to before any policy runs (`rosterToolName`); the names a rule may use for it are {@link ruleNamesOf}. */
15
22
  toolName: string;
16
23
  args: unknown;
17
24
  toolCallId: string;
@@ -520,7 +527,28 @@ export interface ToolPolicy {
520
527
  * reaches a person — it is not refused. A PURE judgment: no side effect, no audit record, no hook, no approver; `true`
521
528
  * on a target it cannot judge. Carried through {@link combinePolicies} (any member's `true` is the answer). */
522
529
  readonly writeTargetGuard?: (target: string, signal?: AbortSignal) => Promise<boolean>;
530
+ /** The raw tool-name lists a name-keyed policy was built from — the prepare-time policy-name audit's feed (a retired
531
+ * name refuses the run, an unmounted one is advised). Carried through {@link combinePolicies} (the union of the
532
+ * members' groups); read with {@link toolPolicyNameSets}. */
533
+ readonly nameSets?: readonly ToolPolicyNameSets[];
523
534
  }
535
+ /**
536
+ * The members a policy carries beside `check` — one table for every seat that carries them: {@link wrapToolPolicy} reads
537
+ * each by name off the wrapped policy, {@link combinePolicies} folds each. The fence makes a new {@link ToolPolicy} member
538
+ * a compile error until the table names it.
539
+ */
540
+ declare const TOOL_POLICY_CARRIED_MEMBERS: readonly ["projection", "pathDenyRules", "writeTargetGuard", "nameSets"];
541
+ type ToolPolicyCarriedMember = (typeof TOOL_POLICY_CARRIED_MEMBERS)[number];
542
+ export type ToolPolicyCarriesEveryMember = AssertAllKeysHandled<Exclude<Exclude<keyof ToolPolicy, "check">, ToolPolicyCarriedMember>>;
543
+ /**
544
+ * The ONE way to wrap a policy: the wrapper decides through `check`; every member {@link ToolPolicy} declares beside it
545
+ * (projection, name sets, path deny rows, write-target guard — the carried-member table) rides as `inner` holds it, read
546
+ * by name, so a class instance's accessor or a non-enumerable member rides too — a `{ check }` literal drops them, and
547
+ * engine stations the wrapper never sees read each one. The carried members describe what `inner` refuses, so the wrapper
548
+ * must refuse at least that (an observer, a tightener); one that releases what `inner` refuses is a policy of its own.
549
+ * The ask-class brand is not carried: it attests the replaced `check`.
550
+ */
551
+ export declare function wrapToolPolicy<P extends ToolPolicy>(inner: P, check: ToolPolicy["check"]): Pick<P, ToolPolicyCarriedMember> & ToolPolicy;
524
552
  /** Every path deny row the given policies carry (combined policies included), in order — the deny tables' rule rows. */
525
553
  export declare function toolPolicyPathDenyRules(policies: readonly (ToolPolicy | undefined)[]): readonly import("../tools/fs/read-deny.js").PathRuleDenyRow[];
526
554
  /** The one write-target guard the given policies carry together (combined policies included): `true` when any member
@@ -604,10 +632,7 @@ export declare function namespacedCoveringHit(covering: readonly string[], toolN
604
632
  * trusting a re-supplied policy's execution half for the frozen deny data: the projection persisted
605
633
  * at suspend is the authority for what the chain refused, whatever a re-supplied closure claims.
606
634
  */
607
- export declare function checkToolPolicyProjection(projection: Pick<ToolPolicyProjection, "components">, req: {
608
- toolName: string;
609
- args: unknown;
610
- }): Extract<PermissionResult, {
635
+ export declare function checkToolPolicyProjection(projection: Pick<ToolPolicyProjection, "components">, req: Pick<ToolCallRequest, "toolName" | "args" | "face">): Extract<PermissionResult, {
611
636
  action: "deny";
612
637
  }> | undefined;
613
638
  /**
@@ -781,7 +806,7 @@ export interface ToolPolicyNameSets {
781
806
  * here silently WIDENS (the tool runs without ever asking), so it is audited too. */
782
807
  readonly ask?: readonly string[];
783
808
  }
784
- /** A policy that exposes its name lists for the host-side pool audit. Composition-transparent:
809
+ /** A policy that states its name lists ({@link ToolPolicy.nameSets} set). Composition-transparent:
785
810
  * {@link combinePolicies} (and therefore {@link tightenTaskSpec}) unions children's groups onto the
786
811
  * combined policy, so metadata survives the deployment's tighten/compose path. */
787
812
  export type NamedToolPolicy = ToolPolicy & {
@@ -8,6 +8,7 @@ import { sanitizeAutoModeArmingRecipe } from "./auto-mode-arming.js";
8
8
  import { join, normalize as normalizePath, sep } from "node:path";
9
9
  import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
10
10
  import { protectivePathTargetOf } from "./tool-registry.js";
11
+ import { ruleNamesOf, toolNameSetHas } from "./tool-roster.js";
11
12
  import { boundInputHashOf } from "./canonical-json.js";
12
13
  import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY } from "./untrusted-text.js";
13
14
  import { describeRejectedValue } from "./tool-search-setting.js";
@@ -122,6 +123,21 @@ export const ASK_EVIDENCE_ABSENCE_VALUES = ["not_wired", "not_adjudicated", "una
122
123
  export function decisionText(d) {
123
124
  return d.message;
124
125
  }
126
+ const TOOL_POLICY_CARRIED_MEMBERS = ["projection", "pathDenyRules", "writeTargetGuard", "nameSets"];
127
+ function carriedMembersOf(p) {
128
+ const out = {};
129
+ const carry = (k) => {
130
+ const v = p[k];
131
+ if (v !== undefined)
132
+ out[k] = v;
133
+ };
134
+ for (const k of TOOL_POLICY_CARRIED_MEMBERS)
135
+ carry(k);
136
+ return out;
137
+ }
138
+ export function wrapToolPolicy(inner, check) {
139
+ return { ...carriedMembersOf(inner), check };
140
+ }
125
141
  export function toolPolicyPathDenyRules(policies) {
126
142
  return policies.flatMap((p) => (Array.isArray(p?.pathDenyRules) ? p.pathDenyRules : []));
127
143
  }
@@ -149,20 +165,21 @@ export function namespacedCoveringHit(covering, toolName) {
149
165
  return covering.length > 0 && covering.some((e) => namespacedRuleNameCovers(e, toolName));
150
166
  }
151
167
  export function checkToolPolicyProjection(projection, req) {
168
+ const names = ruleNamesOf(req);
152
169
  for (const c of projection.components) {
153
170
  if (c.kind === "tool_deny") {
154
- if (c.names.includes(req.toolName) || namespacedCoveringHit(namespacedCoveringEntries(c.names), req.toolName)) {
171
+ if (names.some((n) => c.names.includes(n)) || namespacedCoveringHit(namespacedCoveringEntries(c.names), req.toolName)) {
155
172
  return { action: "deny", message: `tool "${req.toolName}" is denied by a frozen inherited policy projection` };
156
173
  }
157
174
  continue;
158
175
  }
159
176
  if (c.kind === "tool_allowlist") {
160
- if (!c.names.includes(req.toolName) && !namespacedCoveringHit(namespacedCoveringEntries(c.names), req.toolName)) {
177
+ if (!names.some((n) => c.names.includes(n)) && !namespacedCoveringHit(namespacedCoveringEntries(c.names), req.toolName)) {
161
178
  return { action: "deny", message: `tool "${req.toolName}" is not in a frozen inherited policy projection's allowlist` };
162
179
  }
163
180
  continue;
164
181
  }
165
- if (!c.tools.includes(req.toolName))
182
+ if (!names.some((n) => c.tools.includes(n)))
166
183
  continue;
167
184
  const command = req.args?.command;
168
185
  if (typeof command !== "string") {
@@ -371,10 +388,10 @@ export function createAllowDenyPolicy(opts) {
371
388
  nameSets: [{ ...(opts.allow ? { allow: [...opts.allow] } : {}), ...(opts.deny ? { deny: [...opts.deny] } : {}) }],
372
389
  check(req) {
373
390
  const toolName = req.toolName;
374
- if (deny.has(toolName) || namespacedCoveringHit(denyCovering, toolName)) {
391
+ if (toolNameSetHas(deny, req) || namespacedCoveringHit(denyCovering, toolName)) {
375
392
  return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
376
393
  }
377
- if (allow && !allow.has(toolName) && !namespacedCoveringHit(allowCovering, toolName)) {
394
+ if (allow && !toolNameSetHas(allow, req) && !namespacedCoveringHit(allowCovering, toolName)) {
378
395
  return { action: "deny", message: `tool "${req.toolName}" is not in the allowlist` };
379
396
  }
380
397
  return ALLOW;
@@ -411,10 +428,10 @@ export function createApprovalPolicy(opts) {
411
428
  ],
412
429
  async check(req, signal) {
413
430
  const toolName = req.toolName;
414
- if (deny.has(toolName) || namespacedCoveringHit(denyCovering, toolName)) {
431
+ if (toolNameSetHas(deny, req) || namespacedCoveringHit(denyCovering, toolName)) {
415
432
  return { action: "deny", message: `tool "${req.toolName}" is denied by policy` };
416
433
  }
417
- if (need.has(toolName) || namespacedCoveringHit(needCovering, toolName)) {
434
+ if (toolNameSetHas(need, req) || namespacedCoveringHit(needCovering, toolName)) {
418
435
  const attest = (d, settlement) => attestEngineSettlement(d, { settlement, origin: "policy" }, req);
419
436
  if (signal?.aborted) {
420
437
  return attest({ action: "deny", message: `approval aborted for "${req.toolName}" (run or turn interrupted)` }, settledByNobody("task_aborted"));
@@ -464,7 +481,7 @@ export function createApprovalPolicy(opts) {
464
481
  }
465
482
  return attest({ action: "deny", message: `approval denied for "${req.toolName}"` }, settledByPerson("human_refused", undefined));
466
483
  }
467
- if (opts.denyByDefault && !auto.has(toolName) && !namespacedCoveringHit(autoCovering, toolName)) {
484
+ if (opts.denyByDefault && !toolNameSetHas(auto, req) && !namespacedCoveringHit(autoCovering, toolName)) {
468
485
  return { action: "deny", message: `tool "${req.toolName}" requires explicit allow` };
469
486
  }
470
487
  return ALLOW;
@@ -492,11 +509,14 @@ export function combinePolicies(...policies) {
492
509
  const combinedProjection = childProjections.some((p) => p !== undefined)
493
510
  ? { components: projectedComponents, requiresLiveRemainder: combinedRemainder }
494
511
  : undefined;
512
+ const folded = {
513
+ projection: combinedProjection,
514
+ nameSets: nameSets.length > 0 ? nameSets : undefined,
515
+ pathDenyRules: pathDenyRules.length > 0 ? pathDenyRules : undefined,
516
+ writeTargetGuard,
517
+ };
495
518
  return {
496
- ...(combinedProjection !== undefined ? { projection: combinedProjection } : {}),
497
- ...(nameSets.length > 0 ? { nameSets } : {}),
498
- ...(pathDenyRules.length > 0 ? { pathDenyRules } : {}),
499
- ...(writeTargetGuard !== undefined ? { writeTargetGuard } : {}),
519
+ ...carriedMembersOf(folded),
500
520
  async check(req, signal) {
501
521
  let asked;
502
522
  let current = req;
@@ -601,7 +621,7 @@ export function createCoarseCommandNamePolicy(opts) {
601
621
  return brandPolicyAskClass({
602
622
  projection,
603
623
  check(req) {
604
- if (!shellTools.has(req.toolName))
624
+ if (!toolNameSetHas(shellTools, req))
605
625
  return ALLOW;
606
626
  const command = req.args?.command;
607
627
  if (typeof command !== "string") {
@@ -855,7 +875,7 @@ export function createUnverifiableDeletePolicy(opts) {
855
875
  const shellTools = canonicalToolNameSet(opts?.tools);
856
876
  return brandPolicyAskClass({
857
877
  check(req) {
858
- if (!shellTools.has(req.toolName))
878
+ if (!toolNameSetHas(shellTools, req))
859
879
  return ALLOW;
860
880
  const command = req.args?.command;
861
881
  if (typeof command !== "string")
@@ -952,8 +972,7 @@ export function createTranscriptIntegrityPolicy(opts) {
952
972
  });
953
973
  return brandPolicyAskClass({
954
974
  check(req) {
955
- const toolName = req.toolName;
956
- if (shellTools.has(toolName)) {
975
+ if (toolNameSetHas(shellTools, req)) {
957
976
  const command = req.args?.command;
958
977
  if (typeof command !== "string")
959
978
  return ALLOW;
@@ -48,9 +48,40 @@ export interface ToolCallLike {
48
48
  args: unknown;
49
49
  face?: {
50
50
  pathTarget?: ToolCallPathTarget;
51
+ names?: readonly string[];
51
52
  } | undefined;
52
53
  }
53
54
  type CallPathTarget = ToolCallPathTarget;
55
+ /**
56
+ * The names a tool-name rule may spell this call's tool by — the face's `names` when they include the call's name,
57
+ * else the call's name alone (a bare request, or a face minted for another name). Every name-keyed matcher and the
58
+ * protective path floor read a rule's tool name against THIS list, which is the roster's one canonicalization seen
59
+ * from the call's side: a rule written against an alias and one written against the wire name reach the same calls.
60
+ */
61
+ export declare function ruleNamesOf(req: Pick<ToolCallLike, "toolName" | "face">): readonly string[];
62
+ /** Does the call answer to `name` — is it one of the call's names ({@link ruleNamesOf})? The engine's TIGHTENS keyed on
63
+ * one of its own tool names read this, so a tool that wears the name under any of its names is tightened (the
64
+ * fail-safe direction); a grant or a routing keyed on an engine tool name reads the wire name. */
65
+ export declare function callAnswersTo(req: Pick<ToolCallLike, "toolName" | "face">, name: string): boolean;
66
+ /** Does a set of rule tool names name this call's tool ({@link ruleNamesOf})? */
67
+ export declare function toolNameSetHas(set: {
68
+ has(name: string): boolean;
69
+ }, req: Pick<ToolCallLike, "toolName" | "face">): boolean;
70
+ /** Does `set` hold any of the call's names ({@link ruleNamesOf})? The read of a MEMBERSHIP tighten keyed on the engine's
71
+ * own tool names (the egress set, a read station's tools, the compliance veto): a tool is held under every name it
72
+ * answers to. A grant or a routing keyed on an engine tool name reads the wire name instead. */
73
+ export declare function anyNamed(set: {
74
+ has(name: string): boolean;
75
+ }, names: readonly string[]): boolean;
76
+ /** The first of the call's names ({@link ruleNamesOf}, the spelling first) that `map` holds an entry for, with the entry.
77
+ * The read of a SEAT keyed on the engine's own tool names (a tier, a mark's sources): every key of one seat is read under
78
+ * the ONE name this returns — a seat is never assembled from two names' entries. */
79
+ export declare function firstNamed<V>(map: {
80
+ get(name: string): V | undefined;
81
+ }, names: readonly string[]): {
82
+ readonly name: string;
83
+ readonly value: V;
84
+ } | undefined;
54
85
  /**
55
86
  * design/388 B6/B17 — the path target a PROTECTIVE fence reads (a deny-list judging a write's target: sensitive paths,
56
87
  * frozen paths, write protection, the transcript gate; edit tracking): the object face's own declaration first, the
@@ -58,6 +89,11 @@ type CallPathTarget = ToolCallPathTarget;
58
89
  * face that declares none. Reading the catalog for an undeclared same-name tool can only TIGHTEN a deny-list (it adds
59
90
  * a slot to judge — the pre-388 posture, never wider), which is exactly why this floor is wrong for a grant.
60
91
  *
92
+ * The floor reads EVERY name the call answers to (`ruleNamesOf`: the face's `names`, else the call's name alone) in
93
+ * the face's order — the name the call was made under first, then the wire name, then the other aliases — and the
94
+ * first name the catalog declares a target for wins: a call made under a catalog name and resolved to a tool that
95
+ * declares none keeps THAT name's slot, also when the tool answers to a second catalog name with another slot.
96
+ *
61
97
  * #635: "can only tighten" is true of the SLOT and false of the RESOLUTION, so the floor hands over the first and
62
98
  * defaults the second (`pathTargetSlotOnly`). Telling a fence that a FOREIGN tool of the same name resolves its slot
63
99
  * against the project root is a claim about someone else's implementation: get it wrong and the judged path moves to
@@ -51,10 +51,31 @@ export function pathTargetValue(args, pt) {
51
51
  }
52
52
  return undefined;
53
53
  }
54
+ export function ruleNamesOf(req) {
55
+ const names = req.face?.names;
56
+ return names !== undefined && names.includes(req.toolName) ? names : [req.toolName];
57
+ }
58
+ export function callAnswersTo(req, name) {
59
+ return ruleNamesOf(req).includes(name);
60
+ }
61
+ export function toolNameSetHas(set, req) {
62
+ return anyNamed(set, ruleNamesOf(req));
63
+ }
64
+ export function anyNamed(set, names) {
65
+ return names.some((n) => set.has(n));
66
+ }
67
+ export function firstNamed(map, names) {
68
+ for (const name of names) {
69
+ const value = map.get(name);
70
+ if (value !== undefined)
71
+ return { name, value };
72
+ }
73
+ return undefined;
74
+ }
54
75
  export function protectivePathTargetOf(call) {
55
76
  if (call.face?.pathTarget !== undefined)
56
77
  return call.face.pathTarget;
57
- const floor = pathTargetOf(call.toolName);
78
+ const floor = ruleNamesOf(call).map((n) => pathTargetOf(n)).find((pt) => pt !== undefined);
58
79
  return floor === undefined || call.face === undefined ? floor : pathTargetSlotOnly(floor);
59
80
  }
60
81
  export const BARE_REQUEST_CODE = "policy.bare_request";
@@ -249,7 +249,19 @@ export type ToolRosterDelta = Static<typeof ToolRosterDelta>;
249
249
  /** The ONE name→row resolution every per-call reader shares (the call face, the park identity): the wire name first,
250
250
  * then an alias — the same order the dispatcher resolves a model's call. */
251
251
  export declare function rosterEntryNamed(roster: ToolRoster, toolName: string): ToolRosterEntry | undefined;
252
- /** design/388 B6 — the per-call face a gated request carries, read off a roster snapshot by name (aliases resolve). */
252
+ /**
253
+ * The ONE tool-name canonicalization: the wire name of the row `name` resolves to on the roster ({@link rosterEntryNamed}
254
+ * — the wire name first, then an alias, the dispatcher's order), or `name` itself when no row answers to it. The gate
255
+ * reads a call's name through it before any policy runs, and a rule's tool name reaches a call exactly when it
256
+ * canonicalizes to the same wire name (`ToolCallFace.names` is that set, minted here) — so a rule written against
257
+ * an alias and one written against the wire name are one rule.
258
+ */
259
+ export declare function rosterToolName(roster: ToolRoster | undefined, name: string): string;
260
+ export { anyNamed, callAnswersTo, firstNamed, ruleNamesOf, toolNameSetHas } from "./tool-registry.js";
261
+ /** design/388 B6 — the per-call face a gated request carries, read off a roster snapshot by name (aliases resolve).
262
+ * `names` leads with the name the face was minted under (the model's spelling at the gate), then the wire name and the
263
+ * other aliases: a reader that must pick ONE of the call's names (the protective path floor) picks the spelling first,
264
+ * as the same call was judged before name resolution. */
253
265
  export declare function toolCallFaceOf(roster: ToolRoster | undefined, toolName: string): import("./tool-policy.js").ToolCallFace | undefined;
254
266
  /** design/388 B18 — the identity members a park row carries, read off a roster snapshot by name; an empty object when
255
267
  * the name is not on the snapshot (the row then reads pre-identity and the resume takes the name-only path). */
@@ -268,6 +280,7 @@ export declare function parkedToolIdentity(roster: ToolRoster | undefined, toolN
268
280
  export declare function parkedToolFace(roster: ToolRoster | undefined, toolName: string): {
269
281
  family?: ToolFamily;
270
282
  pathTarget?: ToolRosterEntry["pathTarget"];
283
+ names?: readonly string[];
271
284
  };
272
285
  /** The call face a park row carries — present iff the row was minted with BOTH its face members and its four
273
286
  * identity members (one mint writes all of them; a row missing any is pre-388 and yields undefined, never a
@@ -275,6 +288,7 @@ export declare function parkedToolFace(roster: ToolRoster | undefined, toolName:
275
288
  export declare function parkedCallFaceOf(pending: {
276
289
  family?: ToolFamily;
277
290
  pathTarget?: ToolRosterPathTarget;
291
+ names?: readonly string[];
278
292
  capabilityId?: string;
279
293
  contractId?: string;
280
294
  shapeDigest?: string;
@@ -321,7 +335,8 @@ export interface RosterBoundMembers {
321
335
  cardId?: string;
322
336
  }
323
337
  /** The typed refusal a member over its bound mints — the door's two codes, and the mint's own for the members no
324
- * declaration door names (`modelGate`, the derived `cardId`). */
338
+ * declaration door names (`modelGate`, the derived `cardId`). Spelled out as literals (a consumer's tooling reads
339
+ * the words); each is a member of {@link ToolDeclarationCode}, which every mint below satisfies. */
325
340
  export type RosterBoundCode = "config.tool_name_too_long" | "config.tool_contract_too_long" | "config.tool_roster_bound";
326
341
  /**
327
342
  * design/388 B20 / #626 ① — the ONE bound judge over a row's identity members: a problem `{ code, message }`, or
@@ -74,13 +74,22 @@ export const ToolRosterDelta = Type.Object({
74
74
  export function rosterEntryNamed(roster, toolName) {
75
75
  return roster.entries.find((r) => r.name === toolName) ?? roster.entries.find((r) => r.aliases.includes(toolName));
76
76
  }
77
+ export function rosterToolName(roster, name) {
78
+ return (roster === undefined ? undefined : rosterEntryNamed(roster, name)?.name) ?? name;
79
+ }
80
+ function namesResolvingTo(roster, e) {
81
+ return [e.name, ...e.aliases.filter((a) => a !== e.name && rosterToolName(roster, a) === e.name)];
82
+ }
83
+ export { anyNamed, callAnswersTo, firstNamed, ruleNamesOf, toolNameSetHas } from "./tool-registry.js";
77
84
  export function toolCallFaceOf(roster, toolName) {
78
85
  if (roster === undefined)
79
86
  return undefined;
80
87
  const e = rosterEntryNamed(roster, toolName);
81
88
  if (e === undefined)
82
89
  return undefined;
90
+ const resolving = namesResolvingTo(roster, e);
83
91
  return {
92
+ names: resolving.includes(toolName) ? [toolName, ...resolving.filter((n) => n !== toolName)] : resolving,
84
93
  family: e.family,
85
94
  ...(e.pathTarget !== undefined ? { pathTarget: e.pathTarget } : {}),
86
95
  capabilityId: e.capabilityId,
@@ -103,12 +112,13 @@ export function parkedToolFace(roster, toolName) {
103
112
  const e = rosterEntryNamed(roster, toolName);
104
113
  if (e === undefined)
105
114
  return {};
106
- return { family: e.family, ...(e.pathTarget !== undefined ? { pathTarget: e.pathTarget } : {}) };
115
+ return { family: e.family, ...(e.pathTarget !== undefined ? { pathTarget: e.pathTarget } : {}), names: namesResolvingTo(roster, e) };
107
116
  }
108
117
  export function parkedCallFaceOf(pending) {
109
118
  if (pending.family === undefined || pending.capabilityId === undefined || pending.contractId === undefined || pending.shapeDigest === undefined || pending.implementationRevision === undefined)
110
119
  return undefined;
111
120
  return {
121
+ ...(pending.names !== undefined ? { names: pending.names } : {}),
112
122
  family: pending.family,
113
123
  ...(pending.pathTarget !== undefined ? { pathTarget: pending.pathTarget } : {}),
114
124
  capabilityId: pending.capabilityId,
@@ -857,6 +857,17 @@ export type TraceEvent = {
857
857
  /** Image blocks replaced in THIS request. */
858
858
  count: number;
859
859
  ts: number;
860
+ } | {
861
+ /** A provider echo field was refused by {@link import("../brain/errors.js").PROVIDER_ECHO_SHAPE} (visible ASCII,
862
+ * 1–128 characters) and dropped: the response's `request-id` / `x-request-id` header values (`field:
863
+ * "requestId"`, read at connect — the id a failure would carry as `apiFailure.requestId`), or the model name
864
+ * its frames report (`field: "responseModel"`). One frame per provider response per field; the value itself
865
+ * is never carried (metadata-only). A count of these frames is this engine's drop count. */
866
+ kind: "brain.echo_dropped";
867
+ version: 1;
868
+ taskId: string;
869
+ field: "requestId" | "responseModel";
870
+ ts: number;
860
871
  } | {
861
872
  /** C10 — a `preemptSignal` fired on a task that is NOT resource-suspend-eligible: the preempt is a
862
873
  * documented silent no-op, but the SCHEDULER that raised it needs to know it was ignored. */
@@ -117,7 +117,9 @@ export declare class NodeExecutionEnv implements ExecutionEnv, BackgroundShellCa
117
117
  shellEnv?: NodeJS.ProcessEnv;
118
118
  /** VENDORED EDIT (D1, security): how much of `process.env` the shell child inherits. Default `"scrub"` =
119
119
  * fail-closed (drop secret-pattern keys, keep PATH/build/locale). `"all"` = full inherit (trusted env);
120
- * `string[]` = strict allowlist. `shellEnv`/per-exec `env` always pass through. */
120
+ * `string[]` = strict allowlist. `shellEnv`/per-exec `env` always pass through. Any other value — an unknown
121
+ * word, a non-string, a list entry that is not a variable name — throws here (`inheritEnvPolicyProblem`'s
122
+ * reason), the same judgment the oracle gate's `inheritEnv` meets. */
121
123
  inheritEnv?: "all" | "scrub" | string[];
122
124
  /** design/105: inject a resident scheduler daemon backend (the shell daemon). Absent ⇒ scheduling INERT. */
123
125
  scheduler?: SchedulerCapability;
@@ -7,7 +7,7 @@ import { dirname, isAbsolute, join, resolve, sep } from "node:path";
7
7
  import { createInterface } from "node:readline";
8
8
  import { ExecutionError, err, FileError, ok, toError, } from "../harness/types.js";
9
9
  import { killProcessTree, shutdownDebug } from "./kill-tree.js";
10
- import { __resetSecretEnvScrubNoticeAnnouncement, announceSecretEnvScrub, inheritedHostEnv, scrubSecretEnv } from "../../core/secret-env.js";
10
+ import { __resetSecretEnvScrubNoticeAnnouncement, announceSecretEnvScrub, inheritEnvPolicyProblem, inheritedHostEnv, scrubSecretEnv } from "../../core/secret-env.js";
11
11
  import { physicalPathOfAsync } from "../../core/physical-path.js";
12
12
  import { isUncSpelling } from "../../tools/fs/safety.js";
13
13
  import { RollingTailBuffer, markTruncated, newStreamCursorState, sliceStreamIncrement, } from "../../core/exec-output-tail.js";
@@ -294,7 +294,10 @@ export class NodeExecutionEnv {
294
294
  this.cwd = options.cwd;
295
295
  this.shellPath = options.shellPath;
296
296
  this.shellEnv = options.shellEnv;
297
- this.inheritEnv = options.inheritEnv ?? "scrub";
297
+ const inheritEnvProblem = inheritEnvPolicyProblem(options.inheritEnv);
298
+ if (inheritEnvProblem !== undefined)
299
+ throw new Error(`NodeExecutionEnv: ${inheritEnvProblem}`);
300
+ this.inheritEnv = Array.isArray(options.inheritEnv) ? [...options.inheritEnv] : (options.inheritEnv ?? "scrub");
298
301
  this.scheduler = options.scheduler;
299
302
  this.retainBackgroundProcesses = options.retainBackgroundProcesses ?? false;
300
303
  this.onSecretEnvScrub = options.onSecretEnvScrub;
@@ -3,6 +3,7 @@ import { runAgentLoop } from "../loop/agent-loop.js";
3
3
  import { resolveAgentCoreStreamFn } from "../loop/runtime-deps.js";
4
4
  import { normalizeEngineSegments } from "../../core/untrusted-text.js";
5
5
  import { AUTH_CARRIER_NAMES } from "../../brain/request-params.js";
6
+ import { isProviderEchoShape } from "../../brain/errors.js";
6
7
  import { convertToLlm } from "./messages.js";
7
8
  import { thrownText } from "../../core/thrown-value.js";
8
9
  import { AgentHarnessError, CompactionError, SessionError, SYNTHETIC_MESSAGE_MODEL, toError, } from "./types.js";
@@ -783,7 +784,7 @@ export class AgentHarness {
783
784
  model: SYNTHETIC_MESSAGE_MODEL,
784
785
  isApiErrorMessage: true,
785
786
  ...(failure.apiErrorStatus !== undefined ? { apiErrorStatus: failure.apiErrorStatus } : {}),
786
- ...(failure.requestId !== undefined ? { requestId: failure.requestId } : {}),
787
+ ...(typeof failure.requestId === "string" && isProviderEchoShape(failure.requestId) ? { requestId: failure.requestId } : {}),
787
788
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
788
789
  usageMissing: true,
789
790
  stopReason: "error",
@@ -336,7 +336,7 @@ const lspSpawnWithEnv = (env, onNotice) => (command, args, cwd, signal) => new P
336
336
  let scrubbedEnv = env;
337
337
  if (scrubbedEnv == null) {
338
338
  const findings = [];
339
- scrubbedEnv = scrubSecretEnv(process.env, findings, process.platform);
339
+ scrubbedEnv = scrubSecretEnv(process.env, findings);
340
340
  announceSecretEnvScrub(onNotice, findings);
341
341
  }
342
342
  child = spawn(command, args, { ...lspSpawnOptions(cwd), env: scrubbedEnv });
package/dist/index.d.ts CHANGED
@@ -42,7 +42,7 @@ export { StdioLspTransport, type LspChildProcess } from "./engine/lsp/stdio-lsp-
42
42
  export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
43
43
  export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, type ModelRole, type RoleSpec, type ModelRoles, type ResolvedRole, type ModelMention, } from "./core/roles.js";
44
44
  export { selectModel, selectModelOrThrow, type ModelCriteria, type ModelTier } from "./core/select-model.js";
45
- export { BrainError, classifyHttp, type BrainErrorCode } from "./brain/errors.js";
45
+ export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, type BrainErrorCode } from "./brain/errors.js";
46
46
  export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
47
47
  export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.js";
48
48
  export { computeCostMicroUsd, isModelPriced, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
@@ -78,7 +78,7 @@ export { LOCKED_KEY_REGISTRY, resolveLockedKeys, type LockedKey, type LockedConf
78
78
  export { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, WEB_FETCH_TOOL_NAME, complianceCallDenial, resolveComplianceDenies, type ComplianceCapability, type CompliancePosture, type ComplianceProfile, } from "./core/compliance.js";
79
79
  export { admitMemoryScopes, foldAdmissionFreeze, type OwnOrgAdmissionVerdict, type MemoryAdmissionInput, type MemoryAdmissionOutcome, type MemoryAdmissionVerdict, type MemoryScopeAdmission, type MemoryScopeOrigin, type MemoryScopeRequest, } from "./core/memory-admission.js";
80
80
  export { assertRetentionCapability, RETENTION_CASCADE_DOMAINS, RETENTION_CASCADE_EXEMPT, type ManagedRetentionCapability, type RetentionDeclaration, type RetentionDeclaring, type RetentionPolicy, type RetentionReceipt, } from "./core/retention.js";
81
- export { GOVERNANCE_CODES, governanceRetryClass, type GovernanceCode, type GovernanceRetryClass } from "./core/governance-codes.js";
81
+ export { GOVERNANCE_CODES, governanceRetryClass, TOOL_DECLARATION_CODES, type GovernanceCode, type GovernanceRetryClass, type ToolDeclarationCode } from "./core/governance-codes.js";
82
82
  export { NOTICE_AUDIENCE, noticeAudienceOf, ENGINE_NOTICE_CODES, type EngineNoticeCode, type NoticeAudience } from "./core/governance-codes.js";
83
83
  export { TtlSessionStore, type TtlSessionStoreOptions, type EvictPolicy } from "./core/session-store.js";
84
84
  export { reconcileInterruptedSession, findOrphanToolCalls, type OrphanToolCall, type ReconcileReport, } from "./core/session-reconcile.js";
@@ -145,7 +145,7 @@ NOTIFICATION_INJECTION_OUTCOMES, // …and their value half + guard, so a host w
145
145
  isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
146
146
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
147
147
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
148
- export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
148
+ export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
149
149
  export { type ToolCallFace } from "./core/tool-policy.js";
150
150
  export { effectivePathTargetOf, pathTargetBaseOf, type ToolPathBases, type PathTargetReading } from "./core/effective-path-target.js";
151
151
  export { pathFamilyOf, isAbsoluteForFamily, pathIdentityOf, win32NamespaceScreen, WIN32_NAMESPACE_REFUSALS, type PathFamily, type PathIdentity, type PathIdentityReading, type Win32NamespaceRefusal } from "./tools/fs/safety.js";
@@ -189,7 +189,7 @@ export { createAllowDenyPolicy, createApprovalPolicy,
189
189
  * members that seat has no lane for (`"unavailable"`, a routing answer; `updatedInput`, an operator edit a
190
190
  * policy verdict cannot get re-adjudicated). Exported so a host can NAME it instead of deriving it through
191
191
  * `Parameters<typeof createApprovalPolicy>[0]["approve"]`. */
192
- type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
192
+ type ApprovalSeatOutcome, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, type AskRuleEvidence, type AskEvidenceAbsence, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
193
193
  export { type ReadRootGrantScreen } from "./core/read-root-grant-screen.js";
194
194
  export { type AskOrigin, ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, type PersistedRuleMandate, isPersistedRuleMandate } from "./core/ask-origin.js";
195
195
  export { PERMISSION_MODES, type PermissionMode, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, type AskClass, isAskClass, MODE_ARBITRATION, type ModeArbitrationRow, RELEASABLE_ASK_CLASSES, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, type AskClassification, type AskClassFacts, type ToolMarkSource, arbitrateByMode, type Arbitration, fileCommandOptionsSentence } from "./core/ask-origin.js";
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ export { StdioLspTransport } from "./engine/lsp/stdio-lsp-transport.js";
29
29
  export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
30
30
  export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, } from "./core/roles.js";
31
31
  export { selectModel, selectModelOrThrow } from "./core/select-model.js";
32
- export { BrainError, classifyHttp } from "./brain/errors.js";
32
+ export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE } from "./brain/errors.js";
33
33
  export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
34
34
  export { computeCostMicroUsd, isModelPriced, modelCostToPricing, } from "./core/pricing.js";
35
35
  export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf } from "./core/runner/usage-accounting.js";
@@ -64,7 +64,7 @@ export { LOCKED_KEY_REGISTRY, resolveLockedKeys } from "./core/locked-config.js"
64
64
  export { BUILTIN_COMPLIANCE_DENIES, COMPLIANCE_CAPABILITIES, WEB_FETCH_TOOL_NAME, complianceCallDenial, resolveComplianceDenies, } from "./core/compliance.js";
65
65
  export { admitMemoryScopes, foldAdmissionFreeze, } from "./core/memory-admission.js";
66
66
  export { assertRetentionCapability, RETENTION_CASCADE_DOMAINS, RETENTION_CASCADE_EXEMPT, } from "./core/retention.js";
67
- export { GOVERNANCE_CODES, governanceRetryClass } from "./core/governance-codes.js";
67
+ export { GOVERNANCE_CODES, governanceRetryClass, TOOL_DECLARATION_CODES } from "./core/governance-codes.js";
68
68
  export { NOTICE_AUDIENCE, noticeAudienceOf, ENGINE_NOTICE_CODES } from "./core/governance-codes.js";
69
69
  export { TtlSessionStore } from "./core/session-store.js";
70
70
  export { reconcileInterruptedSession, findOrphanToolCalls, } from "./core/session-reconcile.js";
@@ -117,7 +117,7 @@ export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
117
117
  export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
118
118
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
119
119
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, skillScopeWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
120
- export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
120
+ export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
121
121
  export {} from "./core/tool-policy.js";
122
122
  export { effectivePathTargetOf, pathTargetBaseOf } from "./core/effective-path-target.js";
123
123
  export { pathFamilyOf, isAbsoluteForFamily, pathIdentityOf, win32NamespaceScreen, WIN32_NAMESPACE_REFUSALS } from "./tools/fs/safety.js";
@@ -154,7 +154,7 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
154
154
  export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
155
155
  export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
156
156
  export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
157
- export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
157
+ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, wrapToolPolicy, decisionText, resolveAsk, toolPolicyNameSets, toolPolicyPathDenyRules, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, screenApproverAttribution, APPROVER_ATTRIBUTION_MAX_CHARS, ASK_EVIDENCE_ABSENCE_VALUES, } from "./core/tool-policy.js";
158
158
  export {} from "./core/read-root-grant-screen.js";
159
159
  export { ASK_ORIGINS, isAskOrigin, ORIGIN_IMPLIES_REAL_APPROVAL, PERSISTED_RULE_MANDATES, isPersistedRuleMandate } from "./core/ask-origin.js";
160
160
  export { PERMISSION_MODES, isPermissionMode, PERMISSION_MODE_RANK, clampPermissionMode, ASK_CLASSES, isAskClass, MODE_ARBITRATION, RELEASABLE_ASK_CLASSES, RRA_EXPLAINERS, classifyAsk, foldArbitrationRow, arbitrateByMode, fileCommandOptionsSentence } from "./core/ask-origin.js";
@@ -96,8 +96,8 @@ export interface FileStorageBackendOptions {
96
96
  * grows the seat later is wired here in the same constructor.
97
97
  *
98
98
  * The payload is the UNION shape ({@link FileStorageCorruptReadInfo}): `path` + `reason` always,
99
- * with the session-policy face's `sessionId`/`principal` present only when the reading store keys by
100
- * them. One sink for one failure grammar — a host does not register three.
99
+ * `sessionId` when the disclosure is about one session (the session store and the session-policy face),
100
+ * `principal` when the read was keyed by one. One sink for one failure grammar — a host does not register three.
101
101
  */
102
102
  onCorruptRead?: (info: FileStorageCorruptReadInfo) => void;
103
103
  }
@@ -110,7 +110,9 @@ export interface FileStorageBackendOptions {
110
110
  * that replay's count (`"replay"`) from a disclosure about a file or directory as a whole (`"file"`).
111
111
  */
112
112
  export type FileStorageCorruptReadInfo = CorruptReadInfo & {
113
- /** Present only when the reading store keys by session (the session-policy face). */
113
+ /** Present when the disclosure is about ONE session: the session-policy face's rows, and the session store's
114
+ * log of that session (its skipped records and tally, or the log skipped from a listing). Absent on a
115
+ * disclosure about a directory as a whole or about a store not keyed by session. */
114
116
  sessionId?: string;
115
117
  /** Present only when the read was keyed by a principal. */
116
118
  principal?: string;