@sema-agent/core 7.45.0 → 7.47.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.
- package/CHANGELOG.md +298 -1
- package/dist/agents/extra-tool-names.d.ts +65 -0
- package/dist/agents/extra-tool-names.js +124 -0
- package/dist/agents/subagent.d.ts +17 -5
- package/dist/agents/subagent.js +33 -25
- package/dist/agents/tool-filter.d.ts +17 -1
- package/dist/agents/tool-filter.js +7 -0
- package/dist/core/agent-config-dir.d.ts +20 -0
- package/dist/core/agent-config-dir.js +49 -0
- package/dist/core/allow-entry.d.ts +6 -4
- package/dist/core/allow-entry.js +6 -5
- package/dist/core/ask-origin.d.ts +35 -12
- package/dist/core/ask-origin.js +24 -7
- package/dist/core/checkpoint-store.d.ts +39 -2
- package/dist/core/effective-path-target.d.ts +136 -4
- package/dist/core/effective-path-target.js +110 -2
- package/dist/core/engine-notice.d.ts +12 -4
- package/dist/core/gate-fold.js +5 -2
- package/dist/core/gate-lanes.js +11 -4
- package/dist/core/gate-outcome.d.ts +4 -2
- package/dist/core/gate-outcome.js +2 -2
- package/dist/core/governance-codes.d.ts +3 -1
- package/dist/core/governance-codes.js +3 -0
- package/dist/core/hooks.d.ts +3 -0
- package/dist/core/path-rule-binding.d.ts +65 -0
- package/dist/core/path-rule-binding.js +99 -0
- package/dist/core/permission-rule-model.d.ts +59 -24
- package/dist/core/permission-rule-model.js +48 -44
- package/dist/core/permission-rule-provider.d.ts +7 -0
- package/dist/core/permission-rule-provider.js +10 -3
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +6 -2
- package/dist/core/permission-rule-sync.js +2 -2
- package/dist/core/permission-rules.d.ts +26 -45
- package/dist/core/permission-rules.js +77 -57
- package/dist/core/runner/child-tree.d.ts +97 -0
- package/dist/core/runner/child-tree.js +104 -0
- package/dist/core/runner/construction-doors.d.ts +5 -0
- package/dist/core/runner/construction-doors.js +6 -0
- package/dist/core/runner/contracts.d.ts +46 -0
- package/dist/core/runner/gate-exit.d.ts +4 -1
- package/dist/core/runner/gate-exit.js +5 -1
- package/dist/core/runner/permission-rule-lanes.d.ts +34 -25
- package/dist/core/runner/permission-rule-lanes.js +18 -12
- package/dist/core/runner/persisted-path-rows.d.ts +31 -7
- package/dist/core/runner/persisted-path-rows.js +31 -12
- package/dist/core/runner/prepare-ask-lane.d.ts +4 -0
- package/dist/core/runner/prepare-ask-lane.js +4 -2
- package/dist/core/runner/prepare-execution-env.d.ts +5 -2
- package/dist/core/runner/prepare-execution-env.js +10 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
- package/dist/core/runner/prepare-gate-stations.js +2 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +8 -4
- package/dist/core/runner/prepare-hands-readface.js +11 -11
- package/dist/core/runner/prepare-inherited-gate.d.ts +8 -1
- package/dist/core/runner/prepare-inherited-gate.js +8 -2
- package/dist/core/runner/prepare-park-ask.d.ts +3 -0
- package/dist/core/runner/prepare-park-ask.js +5 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +14 -2
- package/dist/core/runner/prepare-policy-chain.js +13 -5
- package/dist/core/runner/prepare-suspend-saga.d.ts +10 -0
- package/dist/core/runner/prepare-suspend-saga.js +7 -1
- package/dist/core/runner/prepare-task.js +37 -18
- package/dist/core/runner/prepare-turn-wiring.d.ts +2 -0
- package/dist/core/runner/prepare-turn-wiring.js +2 -1
- package/dist/core/runner/prepare-workspace-restore.d.ts +3 -0
- package/dist/core/runner/prepare-workspace-restore.js +1 -0
- package/dist/core/runner/resume-apply.js +17 -3
- package/dist/core/runner/resume-checkpoint-screen.js +13 -0
- package/dist/core/runner/run-leg.js +5 -1
- package/dist/core/runner/runtask.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +3 -2
- package/dist/core/runner/write-protection-station.js +1 -0
- package/dist/core/runner-deps.d.ts +14 -0
- package/dist/core/sensitive-path-policy.d.ts +8 -0
- package/dist/core/sensitive-path-policy.js +18 -2
- package/dist/core/shell-wrapper-projection.d.ts +11 -0
- package/dist/core/shell-wrapper-projection.js +56 -0
- package/dist/core/shell-wrapper-table.d.ts +144 -34
- package/dist/core/shell-wrapper-table.js +40 -20
- package/dist/core/synthetic-read-verdict.d.ts +3 -0
- package/dist/core/synthetic-read-verdict.js +3 -1
- package/dist/core/tool-catalog-entries.d.ts +21 -0
- package/dist/core/tool-catalog-entries.js +12 -2
- package/dist/core/tool-face.d.ts +10 -1
- package/dist/core/tool-name-readings.d.ts +8 -0
- package/dist/core/tool-name-readings.js +2 -0
- package/dist/core/tool-policy.d.ts +40 -17
- package/dist/core/tool-policy.js +11 -9
- package/dist/core/tool-registry.d.ts +9 -0
- package/dist/core/tool-registry.js +10 -0
- package/dist/core/tool-spec.d.ts +3 -2
- package/dist/core/write-protect.d.ts +14 -3
- package/dist/core/write-protect.js +41 -10
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/orchestration/run-spec.js +8 -7
- package/dist/orchestration/workflow.js +1 -1
- package/dist/shell/lex.d.ts +22 -0
- package/dist/shell/lex.js +75 -13
- package/dist/tools/fs/bash-program-position.d.ts +14 -90
- package/dist/tools/fs/bash-program-position.js +41 -74
- package/dist/tools/fs/bash-readonly-classifier.d.ts +17 -444
- package/dist/tools/fs/bash-readonly-classifier.js +169 -1225
- package/dist/tools/fs/index.d.ts +3 -2
- package/dist/tools/fs/program-read-model.d.ts +711 -0
- package/dist/tools/fs/program-read-model.js +1259 -0
- package/dist/tools/fs/program-read-model.rows.d.ts +18 -0
- package/dist/tools/fs/program-read-model.rows.js +624 -0
- package/dist/tools/fs/read-deny-home.d.ts +19 -1
- package/dist/tools/fs/read-deny-home.js +62 -24
- package/dist/tools/fs/read-deny.d.ts +54 -14
- package/dist/tools/fs/read-deny.js +104 -50
- package/dist/tools/fs/removal-targets.d.ts +7 -6
- package/dist/tools/fs/removal-targets.js +34 -24
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +10 -3
- package/dist/tools/fs/shell-read-argv.d.ts +86 -0
- package/dist/tools/fs/shell-read-argv.js +388 -0
- package/dist/tools/fs/shell-read-bindings.d.ts +300 -0
- package/dist/tools/fs/shell-read-bindings.js +755 -0
- package/dist/tools/fs/shell-read-check.js +23 -15
- package/dist/tools/fs/shell-read-establish.js +82 -8
- package/dist/tools/fs/shell-read-judge.d.ts +11 -1
- package/dist/tools/fs/shell-read-judge.js +9 -1
- package/dist/tools/fs/shell-read-plan.d.ts +33 -8
- package/dist/tools/fs/shell-read-plan.js +309 -407
- package/dist/tools/fs/shell-read-word.d.ts +60 -26
- package/dist/tools/fs/shell-read-word.js +47 -37
- package/dist/tools/fs/shell-read-write-targets.d.ts +15 -64
- package/dist/tools/fs/shell-read-write-targets.js +85 -137
- package/dist/tools/fs/shell-reentry-text.d.ts +136 -6
- package/dist/tools/fs/shell-reentry-text.js +203 -53
- package/dist/tools/monitor.d.ts +3 -3
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +25 -5
- package/wire-changes/core@7.46.0.json +1522 -0
- package/wire-changes/core@7.47.0.json +412 -0
package/dist/core/gate-lanes.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withArgsReading } from "./effective-path-target.js";
|
|
1
2
|
import { attestClassifierDenyCause, classifierDenyCauseOf, decisionText, refuseOutOfContractDecision } from "./tool-policy.js";
|
|
2
3
|
import { arbitrateByMode, classifyAsk, fileCommandOptionsSentence, persistedRuleMandateOf, ruleClearanceOf, safetyAxisOf, stampAskOrigin } from "./ask-origin.js";
|
|
3
4
|
import { classifierParseFailureDenyMessage, denialLimitFallbackMessage, rungDidNotRule, unarmedWindow } from "./auto-mode.js";
|
|
@@ -16,7 +17,7 @@ import { callFaceSeat } from "./tool-roster.js";
|
|
|
16
17
|
import { heldBy, wireOf } from "./tool-name-readings.js";
|
|
17
18
|
import { asksUnstated, modeAcceptsFileCommand, permissionSeatAt, unstatedAskMessage } from "./mode-policy.js";
|
|
18
19
|
import { ORG_RULE_DECISION_REASON, ORG_UNAVAILABLE_DECISION_REASON } from "./permission-rule-org.js";
|
|
19
|
-
import { exitGate } from "./runner/gate-exit.js";
|
|
20
|
+
import { exitGate, passAskFace } from "./runner/gate-exit.js";
|
|
20
21
|
import { readOrgRuleLane, readPersistedRuleLane } from "./rule-lane-reads.js";
|
|
21
22
|
import { traceHookCrash } from "./gate-crash-trace.js";
|
|
22
23
|
import { createGateDeadline, awaitWriteProtectionJudgment, withGateTimeout } from "./gate-bounded-await.js";
|
|
@@ -51,6 +52,7 @@ export async function runGateLanes(pass) {
|
|
|
51
52
|
...(input.toolMarkSources !== undefined ? { toolMarkSources: input.toolMarkSources } : {}),
|
|
52
53
|
...(input.a2aIsolatePeers === true ? { a2aIsolatePeers: true } : {}),
|
|
53
54
|
...(readFaceNow !== undefined ? { readFace: readFaceNow } : {}),
|
|
55
|
+
askFace: passAskFace(pass),
|
|
54
56
|
});
|
|
55
57
|
const classifyStanding = (unstamped, facts) => (pass.askClassification = classifyAsk(unstamped, facts));
|
|
56
58
|
let orgTightenCount = 0;
|
|
@@ -118,7 +120,8 @@ export async function runGateLanes(pass) {
|
|
|
118
120
|
pass.decision = orgAnswer.decision;
|
|
119
121
|
const ruleCallUnreadableOf = (lane) => lane?.unreadable === true && lane.reason !== undefined;
|
|
120
122
|
const readPersistedRules = (req) => readPersistedRuleLane(input.persistedRules, req, input.abortSignal);
|
|
121
|
-
const
|
|
123
|
+
const reread = pass.policyRewrite !== undefined ? withArgsReading(pass.req, pass.policyRewrite, pass.callSignal ?? input.abortSignal) : undefined;
|
|
124
|
+
const laneReq = reread !== undefined ? await reread : { ...pass.req, ...(pass.policyRewrite !== undefined ? { args: pass.policyRewrite } : {}) };
|
|
122
125
|
const laneAnswer = input.persistedRules !== undefined && wireOf("lanes.persistedLaneSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME ? await readPersistedRules(laneReq) : undefined;
|
|
123
126
|
{
|
|
124
127
|
const tightened = applyPersistedTightening(pass.decision, laneAnswer);
|
|
@@ -139,6 +142,8 @@ export async function runGateLanes(pass) {
|
|
|
139
142
|
if (pass.policyRewrite !== undefined) {
|
|
140
143
|
pass.currentInput = pass.policyRewrite;
|
|
141
144
|
pass.req.args = pass.policyRewrite;
|
|
145
|
+
if (laneReq.targetReading !== undefined)
|
|
146
|
+
pass.req.targetReading = laneReq.targetReading;
|
|
142
147
|
}
|
|
143
148
|
const ruleMayClear = () => ruleClearanceOf(pass.decision.action === "ask" ? pass.decision : undefined, mandateMarksNow()).ruleMayClear;
|
|
144
149
|
const classMayClear = () => pass.decision.action === "ask" && classifyAsk(pass.decision, askOriginFacts(orgAnswer.org, ruleCallUnreadableOf(laneAnswer))).row.ruleMayClear;
|
|
@@ -576,8 +581,10 @@ export async function runGateLanes(pass) {
|
|
|
576
581
|
break;
|
|
577
582
|
}
|
|
578
583
|
let editRuleCallUnreadable = false;
|
|
584
|
+
const editReread = withArgsReading(pass.req, editArgs, callSignal ?? input.abortSignal);
|
|
585
|
+
const editLaneReq = editReread !== undefined ? await editReread : { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
|
|
579
586
|
if (input.persistedRules !== undefined && wireOf("lanes.persistedEditSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME) {
|
|
580
|
-
const editLane = await readPersistedRules(
|
|
587
|
+
const editLane = await readPersistedRules(editLaneReq);
|
|
581
588
|
editRuleCallUnreadable = ruleCallUnreadableOf(editLane);
|
|
582
589
|
const editTightened = applyPersistedTightening(recheck, editLane);
|
|
583
590
|
recheck = editTightened.decision;
|
|
@@ -588,7 +595,7 @@ export async function runGateLanes(pass) {
|
|
|
588
595
|
break;
|
|
589
596
|
}
|
|
590
597
|
}
|
|
591
|
-
const editSkillRefusal = skillRowRefusal(input.skillGrants,
|
|
598
|
+
const editSkillRefusal = skillRowRefusal(input.skillGrants, editLaneReq);
|
|
592
599
|
if (editSkillRefusal !== undefined) {
|
|
593
600
|
editDenied = editSkillRefusal;
|
|
594
601
|
pass.deniedBy = "policy";
|
|
@@ -343,9 +343,11 @@ export type GateDisposition = {
|
|
|
343
343
|
/**
|
|
344
344
|
* A permission MODE released a surviving ask — the allowed disposition's account of the question it did not put
|
|
345
345
|
* to anyone: the mode, the disclosed class word (`askClass`, the first member of the folded set in `ASK_CLASSES`
|
|
346
|
-
* order — one of {@link
|
|
346
|
+
* order — one of {@link releasableAskClassesFor} on the call's face), the whole set, and the origin / mandate words the card would
|
|
347
347
|
* have shown. `reason` is a member of {@link import("./ask-origin.js").MODE_RELEASE_REASONS} (`isModeReleaseReason`):
|
|
348
|
-
* `"rule_unreadable"` marks a release over a rule the call could not be read against
|
|
348
|
+
* `"rule_unreadable"` marks a release over a rule the call could not be read against, `"write_protection_unresolved"` a release (the
|
|
349
|
+
* shell face) over a write target the judge could not resolve; absent, the release names none. The record carries no face, so the
|
|
350
|
+
* screen asks that SOME face releases the class.
|
|
349
351
|
*/
|
|
350
352
|
export interface ModeRelease {
|
|
351
353
|
mode: PermissionMode;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isAskClass, isAskOrigin, isModeReleaseReason, isPermissionMode,
|
|
1
|
+
import { isAskClass, isAskOrigin, isModeReleaseReason, isPermissionMode, ASK_FACES, releasableAskClassesFor } from "./ask-origin.js";
|
|
2
2
|
import { isAutoModeFallbackCause } from "./auto-mode.js";
|
|
3
3
|
export const SETTLEMENT_KINDS = Object.freeze([
|
|
4
4
|
"human_allowed",
|
|
@@ -139,7 +139,7 @@ export function screenGateOutcome(g) {
|
|
|
139
139
|
defects.push("I7: a mode release carries no settlement — nobody answered the ask it released");
|
|
140
140
|
if (r.mode !== "bypassPermissions")
|
|
141
141
|
defects.push(`I7: a mode release names mode "${String(r.mode)}" — only bypassPermissions releases`);
|
|
142
|
-
if (!isAskClass(r.askClass) || !
|
|
142
|
+
if (!isAskClass(r.askClass) || !ASK_FACES.some((face) => releasableAskClassesFor(face).includes(r.askClass)))
|
|
143
143
|
defects.push(`I7: released.askClass "${String(r.askClass)}" is not a releasable class`);
|
|
144
144
|
if (!Array.isArray(r.classes) || r.classes.length === 0 || !r.classes.every((c) => isAskClass(c)))
|
|
145
145
|
defects.push("I7: released.classes must be a non-empty list of ask classes");
|
|
@@ -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",
|
package/dist/core/hooks.d.ts
CHANGED
|
@@ -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. */
|
|
@@ -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
|
|
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
|
|
@@ -131,7 +131,9 @@ export declare function readRowBehavior(v: unknown): RuleBehavior | undefined;
|
|
|
131
131
|
* clears it. The org/hook/matchedAskRule immunities stay: those conjuncts live in the gate's
|
|
132
132
|
* persisted-rule lane and do not loosen with this set. */
|
|
133
133
|
export type PersistedRuleTool = string;
|
|
134
|
-
/** The
|
|
134
|
+
/** The command grammar's ONE rule word — the spelling a shell command rule is written in (`Bash(<command>)`, upstream's).
|
|
135
|
+
* A rule word, not a tool list: the calls a command rule reaches are the SHELL FACE's — every catalog definition whose
|
|
136
|
+
* `command` the command grammar judges ({@link laneToolNamesOf}). */
|
|
135
137
|
export declare const COMMAND_RULE_TOOL = "Bash";
|
|
136
138
|
/** The one tool whose path family has an ALLOW form (the `Read(//abs-dir/**)` directory grant). */
|
|
137
139
|
export declare const READ_RULE_TOOL = "Read";
|
|
@@ -144,7 +146,7 @@ export declare const READ_RULE_TOOL = "Read";
|
|
|
144
146
|
* its tool's name as its reach (`Write(<path>)` is judged on the Write tool, a stricter reading the reference does not make).
|
|
145
147
|
*
|
|
146
148
|
* The two columns are enforced where each behavior can be: a deny row is exported to the engine's deny tables
|
|
147
|
-
* (`ToolPolicy.
|
|
149
|
+
* (`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
150
|
* 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
151
|
* judged there, on the call's own path target only — it does not descend (a search rooted above the asked path is not
|
|
150
152
|
* asked, and its results are not filtered).
|
|
@@ -167,8 +169,9 @@ export declare const NAME_RULE_FACES: Readonly<Record<string, {
|
|
|
167
169
|
readonly params: readonly string[];
|
|
168
170
|
}>>;
|
|
169
171
|
/**
|
|
170
|
-
* Which tools a rule may name — the model's tool set is DERIVED, never a hand-kept list: the
|
|
171
|
-
* takes the COMMAND grammar
|
|
172
|
+
* Which tools a rule may name — the model's tool set is DERIVED, never a hand-kept list: the command rule word
|
|
173
|
+
* ({@link COMMAND_RULE_TOOL}) takes the COMMAND grammar — the other shell-face tools take none of their own, their command is
|
|
174
|
+
* judged by the `Bash(…)` rules ({@link laneToolNamesOf}); every tool the catalog declares a path target for (Read / Edit / Write /
|
|
172
175
|
* Glob / NotebookEdit / …, `pathTargetOf`) takes the PATH grammar; the tools of {@link NAME_RULE_FACES} take the NAME grammar.
|
|
173
176
|
* A rule on any other tool has no content this model can judge and is refused (`unsupported.tool`). The tool set therefore
|
|
174
177
|
* moves with the catalog's declarations, exactly as the protective fences' covered set does.
|
|
@@ -177,9 +180,12 @@ export declare function ruleToolGrammarOf(toolName: string): "command" | "path"
|
|
|
177
180
|
/** The value a name-grammar tool's call carries in its name argument — the string every NAME rule is read against, the one a
|
|
178
181
|
* `Skill` call is resolved by — or undefined (not a name-grammar tool; no such argument; not a string). */
|
|
179
182
|
export declare function nameRuleSubjectOf(toolName: string, args: unknown): string | undefined;
|
|
180
|
-
/** The
|
|
181
|
-
* name, the other aliases that resolve to it) the
|
|
182
|
-
*
|
|
183
|
+
/** The rule WORDS a call is judged under, once each: for every name the call answers to (the model's spelling, the wire
|
|
184
|
+
* name, the other aliases that resolve to it), the word its rules are written in — a shell-face name's is the command
|
|
185
|
+
* grammar's {@link COMMAND_RULE_TOOL} (a `Bash(<command>)` rule reaches `Monitor` as it reaches `Bash`), a path or name
|
|
186
|
+
* tool's its own name — so a stored `Bash(…)` or `Edit(…)` row reaches a tool that answers to that name under another wire
|
|
187
|
+
* name, as a policy's rule does. Every lane that judges a call by a rule's word reads it here: the policy compiler, the
|
|
188
|
+
* person's stored rows, the org partition, the allow lists. Empty ⇒ no grammar speaks for the call. */
|
|
183
189
|
export declare function laneToolNamesOf(req: Pick<import("./tool-policy.js").ToolCallRequest, "toolName" | "face">): readonly string[];
|
|
184
190
|
/**
|
|
185
191
|
* Match forms. Four members, two of them one predicate:
|
|
@@ -600,7 +606,7 @@ export declare function isUsablePathBase(base: string | undefined, family: PathF
|
|
|
600
606
|
* defect (a `~/` deny falling back to the engine host's home guarded the wrong directory; a `/…` deny with
|
|
601
607
|
* no root reached nothing at all).
|
|
602
608
|
*/
|
|
603
|
-
export declare function pathRuleReachOf(rule: Pick<PersistedRule, "match" | "command" | "behavior">, target: PathIdentity, bases: PathRuleBases): ProgramRunReachOutcome;
|
|
609
|
+
export declare function pathRuleReachOf(rule: Pick<PersistedRule, "match" | "command" | "behavior">, target: PathIdentity, bases: PathRuleBases, treeFamily?: PathFamily | undefined): ProgramRunReachOutcome;
|
|
604
610
|
/**
|
|
605
611
|
* Where a path rule's reach STARTS under the call's bases — its HEAD: the location the resolved pattern names before
|
|
606
612
|
* its first segment carrying `*` (the whole path when none does), or a directory rule's directory. Everything the rule
|
|
@@ -772,7 +778,7 @@ export declare function lexicalNormalAbsolutePathOf(path: string, family: PathFa
|
|
|
772
778
|
* there is nothing here for it to clear). As a DENY/ASK the same containment refuses or questions every
|
|
773
779
|
* path under the directory, on whichever path tool the rule names.
|
|
774
780
|
*/
|
|
775
|
-
export declare function directoryRuleAdmits(rule: Pick<PersistedRule, "match" | "command">, path: PathIdentity, bases: PathRuleBases): boolean;
|
|
781
|
+
export declare function directoryRuleAdmits(rule: Pick<PersistedRule, "match" | "command">, path: PathIdentity, bases: PathRuleBases, treeFamily?: PathFamily | undefined): boolean;
|
|
776
782
|
/** The identity of a directory SPELLING (the cd resolver's `/`-rooted output) under the call's tree, for the
|
|
777
783
|
* consumers that hand {@link directoryRuleAdmits} a spelling; a rule minted from it stores this form. */
|
|
778
784
|
export declare function directoryIdentityOf(spelling: string, bases: PathRuleBases): PathIdentity | undefined;
|
|
@@ -785,7 +791,18 @@ export declare function directoryIdentityOf(spelling: string, bases: PathRuleBas
|
|
|
785
791
|
* r3-② cwd posture), never inferred from the process. ONE function on purpose: this is the scope
|
|
786
792
|
* conjunct of the single eligibility predicate ({@link eligibleContext}), and a sister predicate
|
|
787
793
|
* 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;
|
|
794
|
+
export declare function scopeCoversCwd(scope: RuleScope, cwd: string | undefined, sessionId?: string, identity?: ScopeRootIdentity): boolean;
|
|
795
|
+
/**
|
|
796
|
+
* A leg's root as an IDENTITY for project coverage: its canonical spelling, and the leg's resolution of a project row's
|
|
797
|
+
* scope root to the location it leads to. A DENY or ASK project row written under one spelling of a directory (a link the
|
|
798
|
+
* host spelled, a firmlink) covers a leg rooted at another spelling of the same directory: the row applies by where the two
|
|
799
|
+
* roots ARE, not only by how they are spelled. An allow row never reads it ({@link spelledScope}). A caller that holds no
|
|
800
|
+
* resolution (no leg, no environment) compares the spellings alone.
|
|
801
|
+
*/
|
|
802
|
+
export interface ScopeRootIdentity {
|
|
803
|
+
readonly canonicalRoot: string;
|
|
804
|
+
readonly canonicalOf: (root: string) => string | undefined;
|
|
805
|
+
}
|
|
789
806
|
/** Is this rule live — i.e. does it still carry at least one add? Deleted adds are removed by the store
|
|
790
807
|
* when tombstones are applied, so a rule with an empty `adds` is a rule that no longer exists. */
|
|
791
808
|
export declare function isRuleLive(rule: PersistedRule): boolean;
|
|
@@ -815,6 +832,7 @@ export declare function eligibleContext(rule: {
|
|
|
815
832
|
tool: string;
|
|
816
833
|
cwd: string | undefined;
|
|
817
834
|
sessionId?: string;
|
|
835
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
818
836
|
}): boolean;
|
|
819
837
|
/**
|
|
820
838
|
* design/375 §5.1 — MAY this PERSISTED rule participate in admitting this call at all? The liveness
|
|
@@ -834,7 +852,16 @@ export declare function eligiblePersisted(rule: PersistedRule, call: {
|
|
|
834
852
|
tool: string;
|
|
835
853
|
cwd: string | undefined;
|
|
836
854
|
sessionId?: string;
|
|
855
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
837
856
|
}, behavior: RuleBehavior): boolean;
|
|
857
|
+
/**
|
|
858
|
+
* The call context an ALLOW row's scope is judged in: the spellings alone. A deny or ask row applies wherever its project's
|
|
859
|
+
* directory is (its scope root resolved where it leads — more rows, only ever more protection); an allow row applies only
|
|
860
|
+
* where its scope root is SPELLED, so a link someone can re-point never carries a standing approval to another directory.
|
|
861
|
+
*/
|
|
862
|
+
export declare function spelledScope<C extends {
|
|
863
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
864
|
+
}>(call: C): Omit<C, "scopeIdentity">;
|
|
838
865
|
/**
|
|
839
866
|
* Find the rules that admit this command for a task in `cwd`, or `undefined`.
|
|
840
867
|
*
|
|
@@ -914,19 +941,23 @@ export declare function adjudicatePersistedRules(rules: readonly PersistedRule[]
|
|
|
914
941
|
cwd: string | undefined;
|
|
915
942
|
sessionId?: string;
|
|
916
943
|
execCwd?: string;
|
|
944
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
917
945
|
}): PersistedRuleVerdict | undefined;
|
|
918
946
|
/**
|
|
919
947
|
* 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
|
|
948
|
+
* of one path-targeting tool, judged on the call's target views by the one judgment every path rule meets
|
|
949
|
+
* ({@link pathRowsReach}: rows outer, views inner).
|
|
950
|
+
*
|
|
951
|
+
* TWO readings, because the two directions read the call's path slot differently (design/388 B6/B17): the
|
|
952
|
+
* tightening arms judge the PROTECTIVE reading's views (`views.tighten` — the object face's declaration, the catalog's
|
|
953
|
+
* for the name as the floor: reading the catalog for an undeclared same-name tool can only tighten a deny), every row
|
|
954
|
+
* also where its head leads (`leads`, the judging leg's resolution); the allow arm judges the DECLARED reading's views
|
|
955
|
+
* (`views.allow` — the face's OWN declaration only: a same-name tool that declares no path target is unconfirmable, and
|
|
956
|
+
* no grant admits it) with the directory rows, for the Read tool ONLY — a directory allow is a standing yes to reads,
|
|
957
|
+
* never to a write — and admits only when every view lies under the directory. Either reading may be absent (no
|
|
958
|
+
* resolvable path in that reading); the arm that needs it then speaks for nothing.
|
|
921
959
|
*
|
|
922
|
-
*
|
|
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.
|
|
960
|
+
* 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
961
|
*
|
|
931
962
|
* `call.face` is the face the call's protective target is on (`read` / `write`): an ASK row speaks for the call when it
|
|
932
963
|
* 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 +969,11 @@ export declare function adjudicatePersistedPathRules(rules: readonly PersistedRu
|
|
|
938
969
|
cwd: string | undefined;
|
|
939
970
|
sessionId?: string;
|
|
940
971
|
face?: DenyFace | undefined;
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
readonly
|
|
944
|
-
|
|
972
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
973
|
+
}, views: {
|
|
974
|
+
readonly tighten?: TargetViews;
|
|
975
|
+
readonly allow?: TargetViews;
|
|
976
|
+
}, anchorsOf: (rule: PersistedRule) => PathRuleBases, leads: ReadonlyMap<string, string | undefined>): PersistedRuleVerdict | undefined;
|
|
945
977
|
/**
|
|
946
978
|
* The name-family sibling of {@link adjudicatePersistedRules}: the same precedence walk over the rules of one name tool
|
|
947
979
|
* ({@link NAME_RULE_FACES}), judged on the one string the call names (`nameRuleSubjectOf`). A rule of the tool speaks for the call
|
|
@@ -955,6 +987,7 @@ export declare function adjudicatePersistedNameRules(rules: readonly PersistedRu
|
|
|
955
987
|
name: string | undefined;
|
|
956
988
|
cwd: string | undefined;
|
|
957
989
|
sessionId?: string;
|
|
990
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
958
991
|
}): PersistedRuleVerdict | undefined;
|
|
959
992
|
/**
|
|
960
993
|
* 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 +1042,8 @@ export declare function segmentCoverageOf(command: string, rules: {
|
|
|
1009
1042
|
/** The relative-cd resolution base (see {@link findAdmittingRule}'s member of the same name) —
|
|
1010
1043
|
* defaults to `cwd`; scope/eligibility stays `cwd`. */
|
|
1011
1044
|
execCwd?: string;
|
|
1045
|
+
/** The leg's root as an identity for project coverage ({@link ScopeRootIdentity}). */
|
|
1046
|
+
scopeIdentity?: ScopeRootIdentity;
|
|
1012
1047
|
}): readonly SegmentCoverage[] | undefined;
|
|
1013
1048
|
/** One row of a per-segment coverage table (see {@link segmentCoverageOf}): the FOLDED, trimmed
|
|
1014
1049
|
* segment text (a display/correlation seat, never adjudication input) and whether an eligible rule
|