@sema-agent/core 7.44.0 → 7.46.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 (159) hide show
  1. package/CHANGELOG.md +418 -1
  2. package/dist/agents/extra-tool-names.d.ts +65 -0
  3. package/dist/agents/extra-tool-names.js +124 -0
  4. package/dist/agents/subagent.d.ts +17 -5
  5. package/dist/agents/subagent.js +65 -38
  6. package/dist/agents/tool-filter.d.ts +82 -5
  7. package/dist/agents/tool-filter.js +134 -4
  8. package/dist/core/agent-config-dir.d.ts +20 -0
  9. package/dist/core/agent-config-dir.js +49 -0
  10. package/dist/core/agent-definition.d.ts +2 -2
  11. package/dist/core/allow-entry.d.ts +30 -4
  12. package/dist/core/allow-entry.js +32 -5
  13. package/dist/core/ask-origin.d.ts +23 -4
  14. package/dist/core/ask-origin.js +11 -5
  15. package/dist/core/checkpoint-store.d.ts +41 -4
  16. package/dist/core/decision-receipt.js +1 -1
  17. package/dist/core/effective-path-target.d.ts +143 -10
  18. package/dist/core/effective-path-target.js +113 -9
  19. package/dist/core/engine-notice.d.ts +25 -3
  20. package/dist/core/engine-notice.js +12 -6
  21. package/dist/core/gate-fold.js +3 -0
  22. package/dist/core/gate-lanes.js +11 -3
  23. package/dist/core/gate-outcome.d.ts +5 -0
  24. package/dist/core/gate-outcome.js +2 -0
  25. package/dist/core/governance-codes.d.ts +3 -1
  26. package/dist/core/governance-codes.js +3 -0
  27. package/dist/core/hooks.d.ts +5 -0
  28. package/dist/core/memory-engine/content-origin.d.ts +0 -34
  29. package/dist/core/memory-engine/content-origin.js +9 -4
  30. package/dist/core/memory-engine/layout.d.ts +5 -1
  31. package/dist/core/memory-engine/layout.js +1 -0
  32. package/dist/core/path-rule-binding.d.ts +65 -0
  33. package/dist/core/path-rule-binding.js +99 -0
  34. package/dist/core/permission-rule-model.d.ts +47 -18
  35. package/dist/core/permission-rule-model.js +38 -42
  36. package/dist/core/permission-rule-provider.d.ts +7 -0
  37. package/dist/core/permission-rule-provider.js +10 -3
  38. package/dist/core/permission-rule-store.d.ts +8 -0
  39. package/dist/core/permission-rule-store.js +6 -2
  40. package/dist/core/permission-rule-sync.js +2 -2
  41. package/dist/core/permission-rules.d.ts +22 -36
  42. package/dist/core/permission-rules.js +50 -40
  43. package/dist/core/real-approval.d.ts +9 -6
  44. package/dist/core/real-approval.js +5 -5
  45. package/dist/core/runner/child-tree.d.ts +110 -0
  46. package/dist/core/runner/child-tree.js +107 -0
  47. package/dist/core/runner/construction-doors.d.ts +5 -0
  48. package/dist/core/runner/construction-doors.js +6 -0
  49. package/dist/core/runner/contracts.d.ts +54 -2
  50. package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
  51. package/dist/core/runner/permission-rule-lanes.js +18 -12
  52. package/dist/core/runner/persisted-path-rows.d.ts +31 -7
  53. package/dist/core/runner/persisted-path-rows.js +31 -12
  54. package/dist/core/runner/prepare-ask-lane.d.ts +6 -0
  55. package/dist/core/runner/prepare-ask-lane.js +4 -2
  56. package/dist/core/runner/prepare-config-doors.js +3 -1
  57. package/dist/core/runner/prepare-execution-env.d.ts +5 -2
  58. package/dist/core/runner/prepare-execution-env.js +11 -3
  59. package/dist/core/runner/prepare-gate-stations.d.ts +6 -0
  60. package/dist/core/runner/prepare-gate-stations.js +3 -1
  61. package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
  62. package/dist/core/runner/prepare-hands-readface.js +6 -6
  63. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
  64. package/dist/core/runner/prepare-inherited-gate.js +8 -2
  65. package/dist/core/runner/prepare-listings.d.ts +4 -4
  66. package/dist/core/runner/prepare-listings.js +2 -22
  67. package/dist/core/runner/prepare-park-ask.d.ts +5 -0
  68. package/dist/core/runner/prepare-park-ask.js +6 -4
  69. package/dist/core/runner/prepare-policy-chain.d.ts +16 -2
  70. package/dist/core/runner/prepare-policy-chain.js +14 -5
  71. package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
  72. package/dist/core/runner/prepare-suspend-saga.js +7 -1
  73. package/dist/core/runner/prepare-task.js +41 -18
  74. package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
  75. package/dist/core/runner/prepare-turn-wiring.js +2 -1
  76. package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
  77. package/dist/core/runner/prepare-workspace-restore.js +1 -0
  78. package/dist/core/runner/resume-apply.js +17 -3
  79. package/dist/core/runner/resume-checkpoint-screen.js +13 -0
  80. package/dist/core/runner/resume-policy-outcome.js +2 -1
  81. package/dist/core/runner/run-leg.js +5 -1
  82. package/dist/core/runner/run-notification-lane.js +2 -2
  83. package/dist/core/runner/runtask.d.ts +2 -0
  84. package/dist/core/runner/runtask.js +4 -2
  85. package/dist/core/runner/stream-steer-verb.js +2 -2
  86. package/dist/core/runner/sub-agent-deny-lists.d.ts +32 -0
  87. package/dist/core/runner/sub-agent-deny-lists.js +121 -0
  88. package/dist/core/runner/synthetic-tools.d.ts +1 -1
  89. package/dist/core/runner/synthetic-tools.js +3 -2
  90. package/dist/core/runner/write-protection-station.d.ts +3 -2
  91. package/dist/core/runner/write-protection-station.js +1 -0
  92. package/dist/core/runner-deps.d.ts +14 -0
  93. package/dist/core/sensitive-path-policy.d.ts +8 -0
  94. package/dist/core/sensitive-path-policy.js +18 -2
  95. package/dist/core/session-policy-store.d.ts +6 -2
  96. package/dist/core/session-policy-store.js +2 -1
  97. package/dist/core/shell-wrapper-projection.d.ts +11 -0
  98. package/dist/core/shell-wrapper-projection.js +56 -0
  99. package/dist/core/shell-wrapper-table.d.ts +144 -34
  100. package/dist/core/shell-wrapper-table.js +40 -20
  101. package/dist/core/skill-grant.d.ts +10 -2
  102. package/dist/core/skill-grant.js +20 -4
  103. package/dist/core/synthetic-read-verdict.d.ts +3 -0
  104. package/dist/core/synthetic-read-verdict.js +3 -1
  105. package/dist/core/task-notification.d.ts +12 -1
  106. package/dist/core/task-notification.js +13 -1
  107. package/dist/core/task-spec.d.ts +5 -3
  108. package/dist/core/tool-catalog-entries.d.ts +21 -0
  109. package/dist/core/tool-catalog-entries.js +9 -0
  110. package/dist/core/tool-policy.d.ts +45 -12
  111. package/dist/core/tool-policy.js +18 -20
  112. package/dist/core/tool-spec.d.ts +23 -4
  113. package/dist/core/types.d.ts +1 -1
  114. package/dist/core/types.js +1 -1
  115. package/dist/core/write-protect.d.ts +4 -0
  116. package/dist/core/write-protect.js +30 -9
  117. package/dist/index.d.ts +10 -6
  118. package/dist/index.js +9 -5
  119. package/dist/orchestration/run-spec.js +8 -7
  120. package/dist/orchestration/workflow.js +3 -2
  121. package/dist/shell/lex.d.ts +7 -0
  122. package/dist/shell/lex.js +17 -0
  123. package/dist/tools/fs/bash-program-position.d.ts +8 -87
  124. package/dist/tools/fs/bash-program-position.js +33 -69
  125. package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
  126. package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
  127. package/dist/tools/fs/index.d.ts +3 -2
  128. package/dist/tools/fs/program-read-model.d.ts +694 -0
  129. package/dist/tools/fs/program-read-model.js +1252 -0
  130. package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
  131. package/dist/tools/fs/program-read-model.rows.js +613 -0
  132. package/dist/tools/fs/read-deny-home.d.ts +19 -1
  133. package/dist/tools/fs/read-deny-home.js +62 -24
  134. package/dist/tools/fs/read-deny.d.ts +54 -14
  135. package/dist/tools/fs/read-deny.js +104 -50
  136. package/dist/tools/fs/removal-targets.d.ts +83 -0
  137. package/dist/tools/fs/removal-targets.js +236 -0
  138. package/dist/tools/fs/safety.d.ts +3 -0
  139. package/dist/tools/fs/safety.js +10 -3
  140. package/dist/tools/fs/shell-read-argv.d.ts +85 -0
  141. package/dist/tools/fs/shell-read-argv.js +386 -0
  142. package/dist/tools/fs/shell-read-bindings.d.ts +273 -0
  143. package/dist/tools/fs/shell-read-bindings.js +746 -0
  144. package/dist/tools/fs/shell-read-check.js +23 -15
  145. package/dist/tools/fs/shell-read-establish.js +79 -5
  146. package/dist/tools/fs/shell-read-judge.d.ts +11 -1
  147. package/dist/tools/fs/shell-read-judge.js +9 -1
  148. package/dist/tools/fs/shell-read-plan.d.ts +31 -7
  149. package/dist/tools/fs/shell-read-plan.js +299 -393
  150. package/dist/tools/fs/shell-read-word.d.ts +29 -26
  151. package/dist/tools/fs/shell-read-word.js +30 -38
  152. package/dist/tools/fs/shell-read-write-targets.d.ts +15 -37
  153. package/dist/tools/fs/shell-read-write-targets.js +83 -136
  154. package/dist/tools/fs/shell-reentry-text.d.ts +38 -6
  155. package/dist/tools/fs/shell-reentry-text.js +90 -53
  156. package/package.json +1 -1
  157. package/test/export-surface.snapshot.json +49 -3
  158. package/wire-changes/core@7.45.0.json +1084 -0
  159. package/wire-changes/core@7.46.0.json +1522 -0
@@ -136,7 +136,7 @@ export type NoticeAudience = "user" | "operator";
136
136
  * the union's catalog ({@link EngineNotice.code}). The groups below say only which family a row joins,
137
137
  * so the catalog is not written a second time here and the two cannot drift.
138
138
  */
139
- export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.write_protection_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.allowed_tool_not_granted", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.base_url_changed_key_unchanged", "route.response_model_mismatch", "route.tool_call_id_folded", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable"];
139
+ export declare const ENGINE_NOTICE_CODES: readonly ["config.autocompact_window_clamped", "config.env_timeout_discarded", "config.materialize_env_discarded", "config.models_swapped", "config.context_settings_swapped", "config.read_face_swapped", "config.read_face_deployment_clamped", "config.write_face_swapped", "config.write_face_deployment_clamped", "config.tool_model_gate_removed", "config.tool_model_gate_unknown_class", "config.tool_model_gate_env_invalid", "config.artifact_host_invalid", "config.task_root_not_canonical", "config.write_protection_target_view_absent", "config.write_protection_unresolved", "config.execution_env_capability_invalid", "config.tool_card_undeclared", "config.tool_face_undeclared", "config.tool_face_invalid", "config.forward_sink_failed", "config.durable_gate_unavailable", "config.peer_admission_out_of_range", "config.peer_lane_unmounted", "config.secret_env_scrubbed", "config.permission_mode_unavailable", "permission.ask_released_by_mode", "permission.read_deny_unapplied", "permission.rule_store_unavailable", "permission.rule_row_dropped", "permission.allowed_tool_not_granted", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "classifier.fallback", "classifier.role_defaulted", "classifier.contract_broken", "classifier.unavailable", "checkpoint.execution_outcome_unrecorded", "delegation.transcript_integrity", "delegation.ask_unresolvable", "mcp.injection_dropped", "mcp.revocation_probe_failed", "mcp.server_redialed", "workflow.governance_key_stripped", "workflow.agent_option_ignored", "memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.content_class_declared", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "memory.consolidation_recommended", "memory.consolidation_committed", "memory.consolidation_conflict", "memory.consolidation_incomplete", "memory.consolidation_refused", "memory.consolidation_withheld", "memory.restore_withheld", "memory.project_scope_absent", "route.fallback_to_primary", "route.classifier_unroutable", "route.base_url_changed_key_unchanged", "route.response_model_mismatch", "route.tool_call_id_folded", "context.tool_turn_repaired", "task.user_steer_undrained", "task.user_followup_undrained", "steering.parked_input_blocked", "task.turn_interrupted", "task.halt_unconsumed", "task.late_approval", "task.interrupt_unconsumed", "task.tool_turn_incomplete", "approval.read_root_granted", "approval.read_root_grant_rejected", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "skills.listing_truncated", "agents.listing_truncated", "tool_result.offload_put_failed", "instructions.source_changed", "session.records_skipped", "memory.layer_locked_legacy", "server.model_unreachable"];
140
140
  /** A catalogued code (see {@link ENGINE_NOTICE_CODES}); {@link NOTICE_MINTER} says who mints it. NOT the type of
141
141
  * `EngineNotice.code`, which stays `string` — a host forwarding its own notices through the same
142
142
  * sink is a supported shape, and narrowing that field would break it. */
@@ -181,6 +181,7 @@ declare const NOTICE_AUDIENCE_TABLE: {
181
181
  readonly "permission.ask_released_by_mode": "user";
182
182
  readonly "permission.read_deny_unapplied": "user";
183
183
  readonly "permission.rule_store_unavailable": "user";
184
+ readonly "permission.rule_row_dropped": "user";
184
185
  readonly "permission.allowed_tool_not_granted": "user";
185
186
  readonly "memory.capture_opted_out": "user";
186
187
  readonly "memory.capture_optout_unpersisted": "user";
@@ -295,6 +296,7 @@ declare const NOTICE_MINTER_TABLE: {
295
296
  readonly "permission.ask_released_by_mode": "engine";
296
297
  readonly "permission.read_deny_unapplied": "engine";
297
298
  readonly "permission.rule_store_unavailable": "engine";
299
+ readonly "permission.rule_row_dropped": "engine";
298
300
  readonly "permission.allowed_tool_not_granted": "engine";
299
301
  readonly "peer.inbound_disposition": "engine";
300
302
  readonly "peer.held_settled": "engine";
@@ -144,6 +144,7 @@ export const ENGINE_NOTICE_CODES = Object.freeze([
144
144
  "permission.ask_released_by_mode",
145
145
  "permission.read_deny_unapplied",
146
146
  "permission.rule_store_unavailable",
147
+ "permission.rule_row_dropped",
147
148
  "permission.allowed_tool_not_granted",
148
149
  "peer.inbound_disposition",
149
150
  "peer.held_settled",
@@ -229,6 +230,7 @@ const NOTICE_AUDIENCE_TABLE = {
229
230
  "permission.ask_released_by_mode": "user",
230
231
  "permission.read_deny_unapplied": "user",
231
232
  "permission.rule_store_unavailable": "user",
233
+ "permission.rule_row_dropped": "user",
232
234
  "permission.allowed_tool_not_granted": "user",
233
235
  "memory.capture_opted_out": "user",
234
236
  "memory.capture_optout_unpersisted": "user",
@@ -324,6 +326,7 @@ const NOTICE_MINTER_TABLE = {
324
326
  "permission.ask_released_by_mode": "engine",
325
327
  "permission.read_deny_unapplied": "engine",
326
328
  "permission.rule_store_unavailable": "engine",
329
+ "permission.rule_row_dropped": "engine",
327
330
  "permission.allowed_tool_not_granted": "engine",
328
331
  "peer.inbound_disposition": "engine",
329
332
  "peer.held_settled": "engine",
@@ -1,6 +1,7 @@
1
1
  import type { ActorAssertion, DocumentContent, ImageContent, TextContent } from "../internal/llm.js";
2
2
  import type { ExecutionEnv, FileError, Result, SessionTreeEntry } from "../internal/harness-types.js";
3
3
  import type { DecisionReason, PermissionResult, ResolvedAsk, ToolCallFace, ToolCallRequest, ToolPolicy } from "./tool-policy.js";
4
+ import type { CallTargetStamp } from "./effective-path-target.js";
4
5
  import type { GateOutcome } from "./gate-outcome.js";
5
6
  import { type PreToolUseScreening } from "./runner/gate-exit.js";
6
7
  export { normalizeOrgGateVerdict, normalizePersistedRuleHit } from "./rule-lane-reads.js";
@@ -1176,6 +1177,8 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
1176
1177
  * starting directory and answer for a run that has since `cd`ed. Absent ⇒ the contexts carry no
1177
1178
  * `cwd`, which is the honest answer for a run with no tracked one. */
1178
1179
  trackedCwd?: () => string | undefined;
1180
+ /** The leg's target-reading stamp, applied where the gate's request is minted over the final args (a rewrite re-reads it: `withArgsReading`). */
1181
+ stampCallTarget?: CallTargetStamp;
1179
1182
  /** The read-only env capability face put on every {@link HookToolContext} this gate call
1180
1183
  * builds ({@link HookEnvCapabilities}). Built ONCE per task by the runner (after the env is minted) and
1181
1184
  * passed through unchanged; omitted when the deployment wired no execution environment. */
@@ -1466,6 +1469,8 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
1466
1469
  permissionMode?: () => import("./ask-origin.js").PermissionMode;
1467
1470
  /** The leg's approval-seat form (`WiringManifest.ask.form`): the deny exit's way-out clause names a declaration, never a missing approver. */
1468
1471
  askSeatForm?: import("./wiring-manifest.js").AskSeamForm;
1472
+ /** The read face the leg resolved, read per call into the class derivation (`roots` withholds the classifier from a `probe` question); absent ⇒ none resolved. */
1473
+ readFace?: () => import("../tools/fs/containment-face.js").ContainmentFace | undefined;
1469
1474
  /** WHO put the tool's egress / irreversibility marks on the seat ({@link import("./ask-origin.js").ToolMarkSource});
1470
1475
  * absent or empty with a mark present reads as the deployment's own (fail-closed: an operator's mandate). */
1471
1476
  toolMarkSources?: ReadonlySet<import("./ask-origin.js").ToolMarkSource>;
@@ -1,37 +1,3 @@
1
- /**
2
- * design/178 §3 — the tool content-origin classification (three tiers by CAPABILITY, fail-closed).
3
- *
4
- * The question this face answers per mounted tool: can invoking it bring content from OUTSIDE the
5
- * deployment's trust boundary into the session — and therefore, via the automatic harvest path,
6
- * into long-term memory? Three tiers:
7
- *
8
- * - "external" — network-retrieval families and external protocol channels. Invocation marks the
9
- * session's memory EXTERNALLY EXPOSED (one-way, durable; what the mark does at
10
- * harvest is the provenance mode's question — design/336: tag-admit with an origin
11
- * marker under "carry", full quarantine under "off").
12
- * - "execution" — general execution (shell/exec). A NAMED residual channel: it can reach external
13
- * content indirectly, but the two industry anchors this tier is calibrated against
14
- * gate on network/protocol families only, and excluding every shell session would
15
- * disable memory for the main coding scenario. Not polluting by default; the
16
- * `execIsExternalContent` strict knob upgrades it to external.
17
- * - "local" — purely local reads/computation.
18
- *
19
- * WHO CLASSIFIES (single-source rule): core built-ins declare `contentOrigin` on their own ToolSpec
20
- * (the classification lives with the tool definition); protocol tools (MCP/A2A) are structurally
21
- * external (the channel itself crosses the boundary); a HOST tool declares its own — and when it
22
- * does not, the default is EXTERNAL (fail-closed: unknown = external), overridable only through the
23
- * explicit `TaskSpec.memory.trustedTools` allowlist. A core-mounted built-in without a declaration
24
- * defaults local: core owns those definitions, and the fail-closed default exists for tools core
25
- * CANNOT vouch for, not for its own. A declaration is honored only when it SPELLS a member of the
26
- * closed vocabulary — an unreadable one is not a declaration.
27
- *
28
- * The three tier names are BOUNDARY-RELATIVE, not statements about topology: `"local"` means "does
29
- * not bring content from outside the deployment's trust boundary", which a unix socket to another
30
- * process the deployment itself runs satisfies and a loopback HTTP call to somebody else's service
31
- * does not. Distance is not the axis; whose content it is, is.
32
- *
33
- * There is deliberately no "gate inactive" state: every mounted tool gets a class.
34
- */
35
1
  import type { ToolContentOrigin } from "../types.js";
36
2
  export interface ClassifyToolContentOriginInput {
37
3
  /** The tool's own `contentOrigin` declaration (ToolSpec/AgentTool carry) — wins when present AND
@@ -1,3 +1,4 @@
1
+ import { allowedToolNames, readDeniedEntry, readToolNameList } from "../../agents/tool-filter.js";
1
2
  const TOOL_CONTENT_ORIGIN_SET = { external: true, execution: true, local: true };
2
3
  export const TOOL_CONTENT_ORIGINS = Object.keys(TOOL_CONTENT_ORIGIN_SET);
3
4
  export function isToolContentOrigin(value) {
@@ -27,10 +28,14 @@ export function delegationCallIsExternal(input) {
27
28
  if (face === undefined)
28
29
  return true;
29
30
  const selectedFor = (f) => {
30
- const d = f.denyTools ?? [];
31
- const a = f.allowTools;
32
- const isNarrowed = a !== undefined && !a.includes("*");
33
- return input.pool.filter((t) => (!isNarrowed || a.some((x) => selectedBy(x, t))) && !d.some((x) => selectedBy(x, t)));
31
+ const deniedList = readToolNameList(f.denyTools);
32
+ const d = deniedList.kind === "entries" ? deniedList.entries : [];
33
+ const a = allowedToolNames(f.allowTools);
34
+ const denies = (t) => d.some((x) => {
35
+ const read = readDeniedEntry(x);
36
+ return read.kind === "name" && selectedBy(read.name, t);
37
+ });
38
+ return input.pool.filter((t) => (a === undefined || [...a].some((x) => selectedBy(x, t))) && !denies(t));
34
39
  };
35
40
  if (selectedFor(face).some((t) => input.isPolluting(t)))
36
41
  return true;
@@ -259,6 +259,10 @@ export declare function adoptRootScopeLayout(rootPath: string, controlDir: strin
259
259
  export declare const canonicalize: typeof physicalPathOfExisting;
260
260
  /** True iff `child` (canonicalized) is `root` or inside it. */
261
261
  export declare function isContainedIn(root: string, child: string): boolean;
262
+ /** The codes the store's physical form refuses an act with — the whole family, one closed set: {@link TARGET_OUTSIDE_STORE} and
263
+ * {@link SCOPE_HOME_NOT_DIRECTORY}. Each is a plain `Error` carrying `code` and a `detail` ({@link StoreFormRefusalDetail}). */
264
+ export declare const STORE_FORM_REFUSAL_CODES: readonly ["memory.target_outside_store", "memory.scope_home_not_directory"];
265
+ export type StoreFormRefusalCode = (typeof STORE_FORM_REFUSAL_CODES)[number];
262
266
  /** The code an act on a store path is refused with when it would land outside the store ({@link landsOutsideStore}). */
263
267
  export declare const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
264
268
  /** The code a scope home that is not a real directory is refused with ({@link assertHomePhysicalForm}). */
@@ -283,7 +287,7 @@ export type StoreFormRefusalDetail = {
283
287
  * the engine's own account is intact, the layout it was handed is not the layout it needs) carrying a
284
288
  * `code` and a `detail`. */
285
289
  export type StoreFormRefusal = Error & {
286
- code: typeof TARGET_OUTSIDE_STORE | typeof SCOPE_HOME_NOT_DIRECTORY;
290
+ code: StoreFormRefusalCode;
287
291
  detail: StoreFormRefusalDetail;
288
292
  };
289
293
  /** Seat 1 — an act the store's physical form refuses: `act` names what was refused (no path), `path` is the
@@ -731,6 +731,7 @@ export function isContainedIn(root, child) {
731
731
  const c = canonicalize(child);
732
732
  return c === r || c.startsWith(`${r}${sep}`);
733
733
  }
734
+ export const STORE_FORM_REFUSAL_CODES = Object.freeze(["memory.target_outside_store", "memory.scope_home_not_directory"]);
734
735
  export const TARGET_OUTSIDE_STORE = "memory.target_outside_store";
735
736
  export const SCOPE_HOME_NOT_DIRECTORY = "memory.scope_home_not_directory";
736
737
  export const SCOPE_HOME_FORMS = Object.freeze(["symlink", "file", "other"]);
@@ -0,0 +1,65 @@
1
+ import { type PathRuleBase, type PathRuleBases, type PersistedRule, type RuleBehavior, type RuleScope, type ScopeRootIdentity } from "./permission-rule-model.js";
2
+ import { type DenyFace, type JudgedPathRow, type PathRowReach } from "../tools/fs/read-deny.js";
3
+ import { type ToolPolicy } from "./tool-policy.js";
4
+ export { pathRowsReach, rowsWhereTheyLead, type PathRowsHit, type TargetViews } from "../tools/fs/read-deny.js";
5
+ /** One path rule as a binding reads it: the parsed rule, its text, and — for a deny rule that guards a face of the
6
+ * engine's deny tables — those faces (absent: the rule is judged on its own tool's calls only). */
7
+ export interface PathRuleSpec {
8
+ readonly parsed: Pick<PersistedRule, "match" | "command" | "behavior" | "tool">;
9
+ readonly ruleText: string;
10
+ readonly faces?: readonly DenyFace[];
11
+ }
12
+ /** A rule bound to its anchors: a deny-table row (`faces` empty for a rule that guards no table face), its three-valued
13
+ * reach over an absolute spelling, and the spec it was bound from. `unanchored` names the base words its pattern needs
14
+ * that the anchors do not supply (the rule reads `unreadable` everywhere: a gate lane fails closed on it; a deny table
15
+ * cannot judge it and leaves it to the gate). */
16
+ export interface BoundPathRule<S extends PathRuleSpec = PathRuleSpec> extends JudgedPathRow {
17
+ readonly spec: S;
18
+ /** The rule's behavior (a deny table takes the `deny` rows that guard a face). */
19
+ readonly behavior: RuleBehavior;
20
+ readonly reach: (absolutePath: string) => PathRowReach;
21
+ readonly unanchored?: readonly PathRuleBase[];
22
+ }
23
+ /**
24
+ * The ONE binding of path rules to their anchors (`anchors`: one set for every spec, or a set per spec). Each row resolves
25
+ * its pattern once against its anchors and reads an absolute spelling under the anchors' family — a row installed on a win
26
+ * root reads `C:\proj\x`, `C:/proj/x` and `c:\proj\x` as one path; a row whose anchors name no tree reads the spelling's
27
+ * own family. The head (where the row's reach starts) is spelled for the environment, so a leg can judge the row where
28
+ * the head leads.
29
+ */
30
+ export declare function bindPathRules<S extends PathRuleSpec>(specs: readonly S[], anchors: PathRuleBases | ((spec: S) => PathRuleBases)): BoundPathRule<S>[];
31
+ /** A caller policy's anchors on the leg it is installed on: the declared `pathBases` word by word, else the leg's — `/x`
32
+ * at the declared root (else the leg's root), a relative pattern at the declared cwd (else the `/x` anchor), `~/` at the
33
+ * declared home (else the leg environment's). `install` absent (a policy called outside a Runner leg): the declaration
34
+ * alone. */
35
+ export declare function policyAnchors(declared: PathRuleBases, install: PathRuleBases | undefined): PathRuleBases;
36
+ /** A stored row's anchors: a PROJECT row's `/x` and relative words at the row's own scope root (the project it was written
37
+ * for), a global or session row's at the chain's top leg; `~/` at the top leg's home for every row. */
38
+ export declare function persistedRowAnchors(scope: RuleScope, chainTop: PathRuleBases): PathRuleBases;
39
+ /** A leg's root as an identity for project coverage ({@link ScopeRootIdentity}): its canonical root, and each project
40
+ * row's scope root resolved through the leg's resolution (`leads`, each location once per leg) — so a row written under
41
+ * one spelling of the project's directory applies to a leg rooted at another spelling of it. `undefined` when the leg
42
+ * has no canonical root (the spellings alone are compared). */
43
+ export declare function projectScopeIdentity(rules: readonly Pick<PersistedRule, "scope">[], canonicalRoot: string | undefined, leads: HeadLeads): Promise<ScopeRootIdentity | undefined>;
44
+ /** A leg's resolution of the locations rule heads pass through: each location resolved once (twins are not refreshed
45
+ * within a leg — a link re-pointed mid-leg is met through the row as spelled, and at its new location from the next
46
+ * prepare; a location that does not resolve has no twin). `resolve` settles the parts of the given rows and answers
47
+ * every location settled so far. */
48
+ export interface HeadLeads {
49
+ resolve(rows: readonly Pick<JudgedPathRow, "head">[]): Promise<ReadonlyMap<string, string | undefined>>;
50
+ }
51
+ export declare function createHeadLeads(leadsTo: (part: string) => Promise<string | undefined>): HeadLeads;
52
+ /**
53
+ * INSTALL a policy on a leg: its path rules are anchored at `anchors` (the leg's root and home; the policy's declared
54
+ * `pathBases` still win word by word) — once, for every judgment of the policy from then on: its `check` (the copy of each
55
+ * request it hands its inner check carries `ToolCallRequest.pathRuleAnchors`), the deny-table rows
56
+ * (`ToolPolicy.pathRules` answers with this installation's rows whatever it is given), and every child the leg hands
57
+ * the policy to as a parent constraint. A policy with no path rules is returned as it is. Installing an installed policy
58
+ * installs what it was installed FROM; one policy installed at the same anchors is one object (identity is the
59
+ * installation). Every member the policy carries rides as it holds it; the decision its `check` answers is untouched.
60
+ */
61
+ export declare function installPolicyAnchors(policy: ToolPolicy | undefined, anchors: PathRuleBases): ToolPolicy | undefined;
62
+ /** The policy an installation was installed from (`undefined`: not an installation). */
63
+ export declare function installedFrom(policy: ToolPolicy | undefined): ToolPolicy | undefined;
64
+ /** The anchors an installation was installed at (`undefined`: not an installation). */
65
+ export declare function installationAnchorsOf(policy: ToolPolicy | undefined): PathRuleBases | undefined;
@@ -0,0 +1,99 @@
1
+ import { parsePermissionRule } from "./permission-rule-syntax.js";
2
+ import { isUsablePathBase, pathRuleHeadOf, pathRuleReachOf, ruleBasesNeeded } from "./permission-rule-model.js";
3
+ import { pathFamilyOf, spellingOfIdentity } from "../tools/fs/safety.js";
4
+ import { absoluteTargetIdentityOf } from "./effective-path-target.js";
5
+ import { locationLeadsTo, ruleHeadParts } from "../tools/fs/read-deny.js";
6
+ import { carriedMembersOf } from "./tool-policy.js";
7
+ export { pathRowsReach, rowsWhereTheyLead } from "../tools/fs/read-deny.js";
8
+ const NOT_REACHED = { reach: "not_reached" };
9
+ export function bindPathRules(specs, anchors) {
10
+ return specs.map((spec) => {
11
+ const a = typeof anchors === "function" ? anchors(spec) : anchors;
12
+ const family = pathFamilyOf(a);
13
+ const head = pathRuleHeadOf(spec.parsed, a);
14
+ const unanchored = ruleBasesNeeded(spec.parsed).filter((b) => !isUsablePathBase(b === "cwd" ? (a.cwd ?? a.root) : a[b], family));
15
+ const reach = (absolutePath) => {
16
+ const tree = a.root !== undefined || a.cwd !== undefined ? a : { root: absolutePath };
17
+ const id = absoluteTargetIdentityOf(absolutePath, tree);
18
+ return id === undefined ? NOT_REACHED : pathRuleReachOf(spec.parsed, id, a, pathFamilyOf(tree));
19
+ };
20
+ return {
21
+ spec,
22
+ behavior: spec.parsed.behavior,
23
+ rule: spec.ruleText,
24
+ tool: spec.parsed.tool,
25
+ pattern: parsePermissionRule(spec.ruleText).ruleContent ?? "",
26
+ faces: spec.faces ?? [],
27
+ reach,
28
+ reaches: (absolutePath) => reach(absolutePath).reach !== "not_reached",
29
+ ...(head !== undefined ? { head: spellingOfIdentity(head, family) } : {}),
30
+ ...(unanchored.length > 0 ? { unanchored } : {}),
31
+ };
32
+ });
33
+ }
34
+ export function policyAnchors(declared, install) {
35
+ const root = declared.root ?? install?.root;
36
+ const cwd = declared.cwd ?? root;
37
+ const home = declared.home ?? install?.home;
38
+ return { ...(root !== undefined ? { root } : {}), ...(cwd !== undefined ? { cwd } : {}), ...(home !== undefined ? { home } : {}) };
39
+ }
40
+ export function persistedRowAnchors(scope, chainTop) {
41
+ const root = scope.kind === "project" ? scope.root : chainTop.root;
42
+ return { ...(root !== undefined ? { root, cwd: root } : {}), ...(chainTop.home !== undefined ? { home: chainTop.home } : {}) };
43
+ }
44
+ export async function projectScopeIdentity(rules, canonicalRoot, leads) {
45
+ if (canonicalRoot === undefined)
46
+ return undefined;
47
+ const roots = rules.flatMap((r) => (r.scope.kind === "project" ? [{ head: r.scope.root }] : []));
48
+ const led = roots.length > 0 ? await leads.resolve(roots) : new Map();
49
+ return { canonicalRoot, canonicalOf: (root) => locationLeadsTo(root, led) };
50
+ }
51
+ export function createHeadLeads(leadsTo) {
52
+ const pending = new Map();
53
+ const settled = new Map();
54
+ return {
55
+ async resolve(rows) {
56
+ const parts = ruleHeadParts(rows).filter((p) => !settled.has(p));
57
+ await Promise.all(parts.map((part) => {
58
+ let p = pending.get(part);
59
+ if (p === undefined) {
60
+ p = leadsTo(part).catch(() => undefined);
61
+ pending.set(part, p);
62
+ }
63
+ return p.then((led) => settled.set(part, led));
64
+ }));
65
+ return settled;
66
+ },
67
+ };
68
+ }
69
+ const INSTALLED = new WeakMap();
70
+ const INSTALLATIONS = new WeakMap();
71
+ export function installPolicyAnchors(policy, anchors) {
72
+ if (policy === undefined)
73
+ return undefined;
74
+ const from = INSTALLED.get(policy)?.from ?? policy;
75
+ const rules = from.pathRules;
76
+ if (rules === undefined)
77
+ return from;
78
+ const key = JSON.stringify([anchors.root ?? null, anchors.cwd ?? null, anchors.home ?? null]);
79
+ const byAnchors = INSTALLATIONS.get(from) ?? new Map();
80
+ INSTALLATIONS.set(from, byAnchors);
81
+ const prior = byAnchors.get(key);
82
+ if (prior !== undefined)
83
+ return prior;
84
+ const seated = Object.freeze({ ...anchors });
85
+ const installed = {
86
+ ...carriedMembersOf(from),
87
+ pathRules: () => rules(seated),
88
+ check: (req, signal) => from.check({ ...req, pathRuleAnchors: seated }, signal),
89
+ };
90
+ INSTALLED.set(installed, { from, anchors: seated });
91
+ byAnchors.set(key, installed);
92
+ return installed;
93
+ }
94
+ export function installedFrom(policy) {
95
+ return policy === undefined ? undefined : INSTALLED.get(policy)?.from;
96
+ }
97
+ export function installationAnchorsOf(policy) {
98
+ return policy === undefined ? undefined : INSTALLED.get(policy)?.anchors;
99
+ }
@@ -76,7 +76,7 @@ import { type DenyFace } from "../tools/fs/read-deny.js";
76
76
  import type { AssertAllKeysHandled } from "./ask-origin.js";
77
77
  import { type ToolCallLike } from "./tool-registry.js";
78
78
  import { type PathFamily, type PathIdentity } from "../tools/fs/safety.js";
79
- import type { PathTargetReading } from "./effective-path-target.js";
79
+ import { type TargetViews } from "./path-rule-binding.js";
80
80
  /**
81
81
  * The closed set of rule BEHAVIORS — what a matching rule says about the call. The upstream vocabulary
82
82
  * verbatim (`allow` / `deny` / `ask`, the three settings lists), in PRECEDENCE order: when rules of more
@@ -144,7 +144,7 @@ export declare const READ_RULE_TOOL = "Read";
144
144
  * its tool's name as its reach (`Write(<path>)` is judged on the Write tool, a stricter reading the reference does not make).
145
145
  *
146
146
  * The two columns are enforced where each behavior can be: a deny row is exported to the engine's deny tables
147
- * (`ToolPolicy.pathDenyRules`, the person's rows at prepare), which refuse inside the tool, descend into a search's
147
+ * (`ToolPolicy.pathRules` bound where the policy is installed, the person's rows at prepare), which refuse inside the tool, descend into a search's
148
148
  * results and reach the shell's file commands; an ask is a question asked at the gate before the call runs, so it is
149
149
  * judged there, on the call's own path target only — it does not descend (a search rooted above the asked path is not
150
150
  * asked, and its results are not filtered).
@@ -600,7 +600,7 @@ export declare function isUsablePathBase(base: string | undefined, family: PathF
600
600
  * defect (a `~/` deny falling back to the engine host's home guarded the wrong directory; a `/…` deny with
601
601
  * no root reached nothing at all).
602
602
  */
603
- export declare function pathRuleReachOf(rule: Pick<PersistedRule, "match" | "command" | "behavior">, target: PathIdentity, bases: PathRuleBases): ProgramRunReachOutcome;
603
+ export declare function pathRuleReachOf(rule: Pick<PersistedRule, "match" | "command" | "behavior">, target: PathIdentity, bases: PathRuleBases, treeFamily?: PathFamily | undefined): ProgramRunReachOutcome;
604
604
  /**
605
605
  * Where a path rule's reach STARTS under the call's bases — its HEAD: the location the resolved pattern names before
606
606
  * its first segment carrying `*` (the whole path when none does), or a directory rule's directory. Everything the rule
@@ -772,7 +772,7 @@ export declare function lexicalNormalAbsolutePathOf(path: string, family: PathFa
772
772
  * there is nothing here for it to clear). As a DENY/ASK the same containment refuses or questions every
773
773
  * path under the directory, on whichever path tool the rule names.
774
774
  */
775
- export declare function directoryRuleAdmits(rule: Pick<PersistedRule, "match" | "command">, path: PathIdentity, bases: PathRuleBases): boolean;
775
+ export declare function directoryRuleAdmits(rule: Pick<PersistedRule, "match" | "command">, path: PathIdentity, bases: PathRuleBases, treeFamily?: PathFamily | undefined): boolean;
776
776
  /** The identity of a directory SPELLING (the cd resolver's `/`-rooted output) under the call's tree, for the
777
777
  * consumers that hand {@link directoryRuleAdmits} a spelling; a rule minted from it stores this form. */
778
778
  export declare function directoryIdentityOf(spelling: string, bases: PathRuleBases): PathIdentity | undefined;
@@ -785,7 +785,18 @@ export declare function directoryIdentityOf(spelling: string, bases: PathRuleBas
785
785
  * r3-② cwd posture), never inferred from the process. ONE function on purpose: this is the scope
786
786
  * conjunct of the single eligibility predicate ({@link eligibleContext}), and a sister predicate
787
787
  * would be the second fact source the 375 §5.1 discipline exists to forbid. */
788
- export declare function scopeCoversCwd(scope: RuleScope, cwd: string | undefined, sessionId?: string): boolean;
788
+ export declare function scopeCoversCwd(scope: RuleScope, cwd: string | undefined, sessionId?: string, identity?: ScopeRootIdentity): boolean;
789
+ /**
790
+ * A leg's root as an IDENTITY for project coverage: its canonical spelling, and the leg's resolution of a project row's
791
+ * scope root to the location it leads to. A DENY or ASK project row written under one spelling of a directory (a link the
792
+ * host spelled, a firmlink) covers a leg rooted at another spelling of the same directory: the row applies by where the two
793
+ * roots ARE, not only by how they are spelled. An allow row never reads it ({@link spelledScope}). A caller that holds no
794
+ * resolution (no leg, no environment) compares the spellings alone.
795
+ */
796
+ export interface ScopeRootIdentity {
797
+ readonly canonicalRoot: string;
798
+ readonly canonicalOf: (root: string) => string | undefined;
799
+ }
789
800
  /** Is this rule live — i.e. does it still carry at least one add? Deleted adds are removed by the store
790
801
  * when tombstones are applied, so a rule with an empty `adds` is a rule that no longer exists. */
791
802
  export declare function isRuleLive(rule: PersistedRule): boolean;
@@ -815,6 +826,7 @@ export declare function eligibleContext(rule: {
815
826
  tool: string;
816
827
  cwd: string | undefined;
817
828
  sessionId?: string;
829
+ scopeIdentity?: ScopeRootIdentity;
818
830
  }): boolean;
819
831
  /**
820
832
  * design/375 §5.1 — MAY this PERSISTED rule participate in admitting this call at all? The liveness
@@ -834,7 +846,16 @@ export declare function eligiblePersisted(rule: PersistedRule, call: {
834
846
  tool: string;
835
847
  cwd: string | undefined;
836
848
  sessionId?: string;
849
+ scopeIdentity?: ScopeRootIdentity;
837
850
  }, behavior: RuleBehavior): boolean;
851
+ /**
852
+ * The call context an ALLOW row's scope is judged in: the spellings alone. A deny or ask row applies wherever its project's
853
+ * directory is (its scope root resolved where it leads — more rows, only ever more protection); an allow row applies only
854
+ * where its scope root is SPELLED, so a link someone can re-point never carries a standing approval to another directory.
855
+ */
856
+ export declare function spelledScope<C extends {
857
+ scopeIdentity?: ScopeRootIdentity;
858
+ }>(call: C): Omit<C, "scopeIdentity">;
838
859
  /**
839
860
  * Find the rules that admit this command for a task in `cwd`, or `undefined`.
840
861
  *
@@ -914,19 +935,23 @@ export declare function adjudicatePersistedRules(rules: readonly PersistedRule[]
914
935
  cwd: string | undefined;
915
936
  sessionId?: string;
916
937
  execCwd?: string;
938
+ scopeIdentity?: ScopeRootIdentity;
917
939
  }): PersistedRuleVerdict | undefined;
918
940
  /**
919
941
  * The path-family sibling of {@link adjudicatePersistedRules}: the same precedence walk over the rules
920
- * of one path-targeting tool, judged on the call's resolved target path.
942
+ * of one path-targeting tool, judged on the call's target views by the one judgment every path rule meets
943
+ * ({@link pathRowsReach}: rows outer, views inner).
944
+ *
945
+ * TWO readings, because the two directions read the call's path slot differently (design/388 B6/B17): the
946
+ * tightening arms judge the PROTECTIVE reading's views (`views.tighten` — the object face's declaration, the catalog's
947
+ * for the name as the floor: reading the catalog for an undeclared same-name tool can only tighten a deny), every row
948
+ * also where its head leads (`leads`, the judging leg's resolution); the allow arm judges the DECLARED reading's views
949
+ * (`views.allow` — the face's OWN declaration only: a same-name tool that declares no path target is unconfirmable, and
950
+ * no grant admits it) with the directory rows, for the Read tool ONLY — a directory allow is a standing yes to reads,
951
+ * never to a write — and admits only when every view lies under the directory. Either reading may be absent (no
952
+ * resolvable path in that reading); the arm that needs it then speaks for nothing.
921
953
  *
922
- * TWO targets, because the two directions read the call's path slot differently (design/388 B6/B17): the
923
- * tightening arms judge the PROTECTIVE target (`protectivePathTargetOf` — the object face's declaration,
924
- * the catalog's for the name as the floor: reading the catalog for an undeclared same-name tool can only
925
- * tighten a deny) with {@link pathRuleReaches}; the allow arm judges the DECLARED target
926
- * (`declaredPathTargetOf` — the face's OWN declaration only: a same-name tool that declares no path
927
- * target is unconfirmable, and no grant admits it) with {@link directoryRuleAdmits}, and for the Read tool
928
- * ONLY — a directory allow is a standing yes to reads, never to a write. Either target may be absent
929
- * (no resolvable path in that reading); the arm that needs it then speaks for nothing.
954
+ * A row is anchored by `anchorsOf` (the person's rows: a project row at its scope root, the rest at the chain's top leg).
930
955
  *
931
956
  * `call.face` is the face the call's protective target is on (`read` / `write`): an ASK row speaks for the call when it
932
957
  * is the call's tool's row, or when {@link PATH_RULE_FACES} puts that face in the row's ask column (a `Read(<path>)` ask
@@ -938,10 +963,11 @@ export declare function adjudicatePersistedPathRules(rules: readonly PersistedRu
938
963
  cwd: string | undefined;
939
964
  sessionId?: string;
940
965
  face?: DenyFace | undefined;
941
- }, targets: {
942
- readonly tighten?: PathTargetReading;
943
- readonly allow?: PathTargetReading;
944
- }, bases: PathRuleBases): PersistedRuleVerdict | undefined;
966
+ scopeIdentity?: ScopeRootIdentity;
967
+ }, views: {
968
+ readonly tighten?: TargetViews;
969
+ readonly allow?: TargetViews;
970
+ }, anchorsOf: (rule: PersistedRule) => PathRuleBases, leads: ReadonlyMap<string, string | undefined>): PersistedRuleVerdict | undefined;
945
971
  /**
946
972
  * The name-family sibling of {@link adjudicatePersistedRules}: the same precedence walk over the rules of one name tool
947
973
  * ({@link NAME_RULE_FACES}), judged on the one string the call names (`nameRuleSubjectOf`). A rule of the tool speaks for the call
@@ -955,6 +981,7 @@ export declare function adjudicatePersistedNameRules(rules: readonly PersistedRu
955
981
  name: string | undefined;
956
982
  cwd: string | undefined;
957
983
  sessionId?: string;
984
+ scopeIdentity?: ScopeRootIdentity;
958
985
  }): PersistedRuleVerdict | undefined;
959
986
  /**
960
987
  * The ONE offer a name tool's approval card carries: the exact rule for the name the call carries (`Skill(<name>)`, the reference's
@@ -1009,6 +1036,8 @@ export declare function segmentCoverageOf(command: string, rules: {
1009
1036
  /** The relative-cd resolution base (see {@link findAdmittingRule}'s member of the same name) —
1010
1037
  * defaults to `cwd`; scope/eligibility stays `cwd`. */
1011
1038
  execCwd?: string;
1039
+ /** The leg's root as an identity for project coverage ({@link ScopeRootIdentity}). */
1040
+ scopeIdentity?: ScopeRootIdentity;
1012
1041
  }): readonly SegmentCoverage[] | undefined;
1013
1042
  /** One row of a per-segment coverage table (see {@link segmentCoverageOf}): the FOLDED, trimmed
1014
1043
  * segment text (a display/correlation seat, never adjudication input) and whether an eligible rule