@sema-agent/core 5.19.0 → 5.21.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 +102 -4
- package/dist/agents/agent-definition.d.ts +7 -0
- package/dist/agents/agent-transcript-tool.d.ts +30 -0
- package/dist/agents/builtin-agents.d.ts +60 -0
- package/dist/agents/cascade.d.ts +107 -0
- package/dist/agents/cumulative-stats.d.ts +56 -0
- package/dist/agents/observer.d.ts +162 -0
- package/dist/agents/peer-admission.d.ts +95 -0
- package/dist/agents/repair-loop.d.ts +226 -0
- package/dist/agents/retain-ledger.d.ts +141 -0
- package/dist/agents/roster-store.d.ts +105 -0
- package/dist/agents/roster-store.js +3 -0
- package/dist/agents/send-message-tool.d.ts +92 -0
- package/dist/agents/session-util.d.ts +5 -0
- package/dist/agents/subagent-steps.d.ts +66 -0
- package/dist/agents/subagent.d.ts +600 -0
- package/dist/agents/suspend-guard.d.ts +29 -0
- package/dist/agents/teacher.d.ts +75 -0
- package/dist/agents/team.d.ts +120 -1
- package/dist/agents/tool-filter.d.ts +34 -0
- package/dist/agents/verify.d.ts +198 -0
- package/dist/bench/metrics.d.ts +455 -0
- package/dist/brain/anthropic.d.ts +30 -0
- package/dist/brain/circuit-breaker.d.ts +33 -0
- package/dist/brain/circuit-breaker.js +14 -3
- package/dist/brain/context-overflow.d.ts +60 -3
- package/dist/brain/degrading.d.ts +67 -0
- package/dist/brain/errors.d.ts +42 -0
- package/dist/brain/failover.d.ts +15 -0
- package/dist/brain/media-degrade.d.ts +39 -0
- package/dist/brain/model-presets.d.ts +31 -0
- package/dist/brain/open-responses.d.ts +19 -0
- package/dist/brain/openai.d.ts +46 -0
- package/dist/brain/reasoning.d.ts +106 -1
- package/dist/brain/repetition.d.ts +83 -0
- package/dist/brain/request-params.d.ts +56 -0
- package/dist/brain/retry.d.ts +46 -0
- package/dist/brain/routing.d.ts +12 -0
- package/dist/brain/status-sink.d.ts +30 -1
- package/dist/brain/stream-engine.d.ts +147 -0
- package/dist/brain/stream-shared.d.ts +34 -0
- package/dist/brain/terminal-cause.d.ts +31 -0
- package/dist/brain/timeout.d.ts +108 -0
- package/dist/brain/timeout.js +11 -0
- package/dist/brain/tool-call-id.d.ts +20 -0
- package/dist/brain/tool-call-repair.d.ts +13 -0
- package/dist/config/catalog.d.ts +47 -0
- package/dist/config/defaults.d.ts +33 -0
- package/dist/core/a2a-task-state.d.ts +53 -0
- package/dist/core/a2a.d.ts +51 -0
- package/dist/core/arg-summary.d.ts +62 -0
- package/dist/core/ask-question.d.ts +272 -2
- package/dist/core/auto-compaction.d.ts +467 -0
- package/dist/core/auto-compaction.js +20 -6
- package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
- package/dist/core/auto-mode-prompt.d.ts +27 -0
- package/dist/core/auto-mode.d.ts +54 -3
- package/dist/core/auto-promote.d.ts +100 -0
- package/dist/core/background-agent-store.d.ts +293 -0
- package/dist/core/background-agent-store.js +5 -0
- package/dist/core/background-shell.d.ts +110 -0
- package/dist/core/cache-break-detector.d.ts +34 -0
- package/dist/core/canonical-json.d.ts +57 -0
- package/dist/core/checkpoint-store.d.ts +1574 -16
- package/dist/core/compliance.d.ts +30 -0
- package/dist/core/consolidate-scope.d.ts +75 -0
- package/dist/core/context-edit.d.ts +99 -0
- package/dist/core/context-guard.d.ts +46 -0
- package/dist/core/exec-gate.d.ts +44 -0
- package/dist/core/exec-output-tail.d.ts +61 -0
- package/dist/core/file-snapshot-store.d.ts +104 -0
- package/dist/core/fs-write-gate-policy.d.ts +36 -0
- package/dist/core/git-worktree-env.d.ts +31 -0
- package/dist/core/governance-codes.d.ts +19 -0
- package/dist/core/hooks.d.ts +609 -1
- package/dist/core/human-input-projection.d.ts +37 -0
- package/dist/core/human-input-projection.js +13 -0
- package/dist/core/image-downsample.d.ts +74 -0
- package/dist/core/locked-config.d.ts +37 -0
- package/dist/core/lsp-diagnostics.d.ts +77 -0
- package/dist/core/lsp-protocol.d.ts +29 -0
- package/dist/core/lsp-session.d.ts +60 -1
- package/dist/core/lsp.d.ts +150 -1
- package/dist/core/mailbox-store.d.ts +57 -0
- package/dist/core/mailbox-store.js +2 -0
- package/dist/core/mcp.d.ts +385 -0
- package/dist/core/mcp.js +58 -11
- package/dist/core/media-byte-cap.d.ts +21 -0
- package/dist/core/memory-admission.d.ts +71 -0
- package/dist/core/memory-engine/content-origin.d.ts +64 -0
- package/dist/core/memory-engine/data-plane.d.ts +43 -0
- package/dist/core/memory-engine/dual-root.d.ts +24 -0
- package/dist/core/memory-engine/engine.d.ts +230 -0
- package/dist/core/memory-engine/engine.js +103 -35
- package/dist/core/memory-engine/file-backend.d.ts +155 -0
- package/dist/core/memory-engine/frontmatter.d.ts +16 -0
- package/dist/core/memory-engine/layout.d.ts +217 -0
- package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
- package/dist/core/memory-engine/migrate.d.ts +9 -0
- package/dist/core/memory-engine/scan.d.ts +12 -0
- package/dist/core/memory-engine/scope-contract.d.ts +61 -1
- package/dist/core/memory-engine/sync-client.d.ts +87 -0
- package/dist/core/memory-engine/sync.d.ts +60 -0
- package/dist/core/memory-engine/tools.d.ts +41 -0
- package/dist/core/memory-engine/types.d.ts +188 -0
- package/dist/core/memory-recall.d.ts +141 -0
- package/dist/core/memory-vector.d.ts +20 -0
- package/dist/core/memory.d.ts +458 -0
- package/dist/core/message-utils.d.ts +6 -0
- package/dist/core/oracle-isolation.d.ts +69 -0
- package/dist/core/permission-rule-consent.d.ts +138 -0
- package/dist/core/permission-rule-model.d.ts +122 -0
- package/dist/core/permission-rule-store.d.ts +119 -3
- package/dist/core/permission-rules.d.ts +87 -1
- package/dist/core/present-plan-tool.d.ts +20 -0
- package/dist/core/pricing.d.ts +26 -0
- package/dist/core/property-harness.d.ts +86 -0
- package/dist/core/protocol-naming.d.ts +38 -0
- package/dist/core/protocol-table.d.ts +61 -0
- package/dist/core/push-queue.d.ts +1 -0
- package/dist/core/remote-env.d.ts +383 -1
- package/dist/core/retention-policy.d.ts +40 -0
- package/dist/core/retention-policy.js +21 -0
- package/dist/core/retention.d.ts +51 -0
- package/dist/core/roles.d.ts +59 -0
- package/dist/core/runner/active-skill-scope.d.ts +34 -0
- package/dist/core/runner/assemble-result.d.ts +134 -0
- package/dist/core/runner/compaction-call-options.d.ts +97 -1
- package/dist/core/runner/grounding-signal.d.ts +10 -0
- package/dist/core/runner/image.d.ts +17 -0
- package/dist/core/runner/image.js +29 -15
- package/dist/core/runner/memory-consolidation.d.ts +60 -0
- package/dist/core/runner/prepare-memory.d.ts +59 -0
- package/dist/core/runner/prepare-task.d.ts +1011 -2
- package/dist/core/runner/prepare-task.js +51 -14
- package/dist/core/runner/prompt-suggestions.d.ts +7 -0
- package/dist/core/runner/runtask.d.ts +304 -3
- package/dist/core/runner/runtask.js +17 -2
- package/dist/core/runner/session-file-state-replay.d.ts +49 -0
- package/dist/core/runner/session-rule-policy.d.ts +58 -0
- package/dist/core/runner/strict-output-schema.d.ts +18 -3
- package/dist/core/runner/synthetic-tools.d.ts +113 -0
- package/dist/core/runner/teardown-bounded.d.ts +34 -0
- package/dist/core/runner/tool-disclosure.d.ts +227 -0
- package/dist/core/runner/tool-output-projection.d.ts +6 -0
- package/dist/core/runner/turn-attachments.d.ts +634 -0
- package/dist/core/runner/usage-accounting.d.ts +32 -0
- package/dist/core/runtime.d.ts +9 -0
- package/dist/core/safe-notify.d.ts +64 -0
- package/dist/core/safety-axis-vocab.d.ts +23 -0
- package/dist/core/safety-merge-corpus.d.ts +37 -0
- package/dist/core/scheduler.d.ts +121 -0
- package/dist/core/secret-env.d.ts +32 -0
- package/dist/core/select-model.d.ts +15 -0
- package/dist/core/sensitive-path-policy.d.ts +42 -0
- package/dist/core/session-policy-store.d.ts +94 -0
- package/dist/core/session-reconcile.d.ts +80 -0
- package/dist/core/session-store.d.ts +85 -0
- package/dist/core/session.d.ts +153 -0
- package/dist/core/shared-memory/contract.d.ts +22 -0
- package/dist/core/shared-memory/normalize.d.ts +123 -2
- package/dist/core/shared-memory/tools.d.ts +14 -0
- package/dist/core/shared-memory/types.d.ts +105 -0
- package/dist/core/shutdown-debug.d.ts +6 -0
- package/dist/core/side-query.d.ts +38 -0
- package/dist/core/side-query.js +6 -1
- package/dist/core/skill-tool-specifier.d.ts +72 -0
- package/dist/core/skills-directory.d.ts +100 -1
- package/dist/core/spec-contract.d.ts +89 -0
- package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
- package/dist/core/store-contracts/contract-harness.d.ts +20 -0
- package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
- package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
- package/dist/core/strategy-store.d.ts +37 -0
- package/dist/core/stub-env.d.ts +7 -0
- package/dist/core/surrogate-safe-slice.d.ts +35 -0
- package/dist/core/task-notification.d.ts +202 -0
- package/dist/core/task-outcome.d.ts +53 -0
- package/dist/core/task-registry-agent.d.ts +337 -1
- package/dist/core/task-registry-agent.js +2 -0
- package/dist/core/task-registry-monitor.d.ts +12 -0
- package/dist/core/task-registry-shared.d.ts +540 -0
- package/dist/core/task-registry.d.ts +343 -0
- package/dist/core/task-registry.js +13 -2
- package/dist/core/task-tool-shape.d.ts +44 -0
- package/dist/core/tighten-task-spec.d.ts +21 -0
- package/dist/core/tool-detach.d.ts +21 -0
- package/dist/core/tool-errors.d.ts +131 -0
- package/dist/core/tool-errors.js +4 -0
- package/dist/core/tool-name-aliases.d.ts +27 -0
- package/dist/core/tool-policy.d.ts +555 -0
- package/dist/core/tool-policy.js +3 -0
- package/dist/core/tool-result-budget.d.ts +32 -0
- package/dist/core/tool-result-store.d.ts +174 -1
- package/dist/core/tools.d.ts +45 -0
- package/dist/core/trace.d.ts +323 -0
- package/dist/core/types.d.ts +3859 -2
- package/dist/core/untrusted-egress.d.ts +8 -0
- package/dist/core/untrusted-text.d.ts +156 -0
- package/dist/core/usage-window-store.d.ts +95 -0
- package/dist/core/version.d.ts +1 -0
- package/dist/core/warm-resume.d.ts +17 -0
- package/dist/core/wiring-manifest.d.ts +169 -0
- package/dist/core/with-retry.d.ts +24 -0
- package/dist/core/workflow-journal-store.d.ts +160 -0
- package/dist/core/workflow-run-store-contract.d.ts +25 -0
- package/dist/core/workflow-run-store.d.ts +119 -0
- package/dist/core/workflow-run-store.js +2 -0
- package/dist/engine/compaction/compaction.d.ts +256 -1
- package/dist/engine/compaction/utils.d.ts +94 -0
- package/dist/engine/execution-env/kill-tree.d.ts +29 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
- package/dist/engine/harness/agent-harness.d.ts +116 -0
- package/dist/engine/harness/agent-harness.js +3 -14
- package/dist/engine/harness/messages.d.ts +15 -0
- package/dist/engine/harness/types.d.ts +464 -2
- package/dist/engine/llm/diagnostics.d.ts +4 -0
- package/dist/engine/llm/event-stream.d.ts +3 -0
- package/dist/engine/llm/index.d.ts +7 -0
- package/dist/engine/llm/types.d.ts +500 -3
- package/dist/engine/llm/validation.d.ts +3 -0
- package/dist/engine/loop/agent-loop.d.ts +87 -2
- package/dist/engine/loop/runtime-deps.d.ts +7 -0
- package/dist/engine/loop/types.d.ts +424 -0
- package/dist/engine/lsp/frame-decoder.d.ts +13 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
- package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
- package/dist/engine/session/import-validate.d.ts +27 -0
- package/dist/engine/session/log-digest.d.ts +93 -0
- package/dist/engine/session/memory-repo.d.ts +6 -0
- package/dist/engine/session/memory-storage.d.ts +2 -0
- package/dist/engine/session/session.d.ts +75 -0
- package/dist/engine/session/storage-base.d.ts +8 -0
- package/dist/fixtures/index.d.ts +36 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1 -2
- package/dist/internal/harness-types.d.ts +6 -0
- package/dist/internal/harness.d.ts +11 -0
- package/dist/internal/llm.d.ts +6 -0
- package/dist/orchestration/builtin-workflows.d.ts +53 -0
- package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
- package/dist/orchestration/goal.d.ts +57 -0
- package/dist/orchestration/goal.js +3 -0
- package/dist/orchestration/run-spec.d.ts +42 -0
- package/dist/orchestration/run-spec.js +4 -0
- package/dist/orchestration/run-workflow-tool.d.ts +169 -0
- package/dist/orchestration/workflow-governance.d.ts +61 -0
- package/dist/orchestration/workflow-meta.d.ts +28 -0
- package/dist/orchestration/workflow-observe.d.ts +60 -0
- package/dist/orchestration/workflow-primitives.d.ts +23 -1
- package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
- package/dist/orchestration/workflow-script-runner.d.ts +88 -0
- package/dist/orchestration/workflow-script-store.d.ts +98 -0
- package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
- package/dist/orchestration/workflow-types.d.ts +169 -2
- package/dist/orchestration/workflow.d.ts +358 -0
- package/dist/orchestration/workflow.js +13 -2
- package/dist/prompt-assembly/artifact-store.d.ts +33 -0
- package/dist/prompt-assembly/artifact.d.ts +25 -0
- package/dist/prompt-assembly/assemble.d.ts +20 -0
- package/dist/prompt-assembly/composer.d.ts +29 -0
- package/dist/prompt-assembly/epoch.d.ts +55 -1
- package/dist/prompt-assembly/event-registry.d.ts +35 -0
- package/dist/prompt-assembly/explain.d.ts +12 -0
- package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
- package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
- package/dist/prompt-assembly/types.d.ts +115 -0
- package/dist/prompts/coordinator.d.ts +27 -0
- package/dist/prompts/default.d.ts +539 -0
- package/dist/prompts/simple-sections.d.ts +45 -0
- package/dist/prompts/supervisor.d.ts +66 -0
- package/dist/scenarios/env.d.ts +28 -0
- package/dist/scenarios/full-body.d.ts +50 -0
- package/dist/scenarios/scenario-registry.d.ts +60 -0
- package/dist/scenarios/teacher-quickstart.d.ts +27 -0
- package/dist/server/http.d.ts +17 -0
- package/dist/stores/cc/lockfile.d.ts +6 -0
- package/dist/stores/cc/mailbox-store.d.ts +8 -0
- package/dist/stores/cc/roster-adapter.d.ts +4 -0
- package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
- package/dist/stores/file/background-agent-store.d.ts +24 -0
- package/dist/stores/file/background-agent-store.js +2 -1
- package/dist/stores/file/checkpoint-store.d.ts +38 -0
- package/dist/stores/file/file-snapshot-store.d.ts +25 -0
- package/dist/stores/file/fs-atomic.d.ts +155 -0
- package/dist/stores/file/index.d.ts +89 -0
- package/dist/stores/file/mailbox-store.d.ts +36 -0
- package/dist/stores/file/mailbox-store.js +2 -0
- package/dist/stores/file/memory-store.d.ts +82 -0
- package/dist/stores/file/permission-rule-store.d.ts +79 -0
- package/dist/stores/file/session-policy-store.d.ts +28 -0
- package/dist/stores/file/session-store.d.ts +40 -0
- package/dist/stores/file/shared-ledger.d.ts +83 -0
- package/dist/stores/file/tool-result-store.d.ts +11 -0
- package/dist/stores/file/usage-window-store.d.ts +18 -0
- package/dist/stores/file/workflow-journal-store.d.ts +100 -0
- package/dist/stores/file/workflow-run-store.d.ts +11 -0
- package/dist/stores/file/workflow-run-store.js +2 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
- package/dist/tools/fs/encoding.d.ts +60 -0
- package/dist/tools/fs/fs-bash.d.ts +133 -0
- package/dist/tools/fs/fs-pdf.d.ts +28 -0
- package/dist/tools/fs/fs-search-tools.d.ts +5 -0
- package/dist/tools/fs/fs-shared.d.ts +360 -0
- package/dist/tools/fs/fs-write.d.ts +16 -0
- package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
- package/dist/tools/fs/index.d.ts +79 -0
- package/dist/tools/fs/notebook.d.ts +56 -0
- package/dist/tools/fs/pdf.d.ts +70 -0
- package/dist/tools/fs/pdf.js +8 -2
- package/dist/tools/fs/repo-map.d.ts +10 -0
- package/dist/tools/fs/safety.d.ts +376 -0
- package/dist/tools/fs/search.d.ts +131 -0
- package/dist/tools/loop-tick.d.ts +24 -0
- package/dist/tools/monitor.d.ts +55 -0
- package/dist/tools/scheduler-tools.d.ts +51 -0
- package/dist/tools/sql-adapters.d.ts +18 -0
- package/dist/tools/sql.d.ts +25 -0
- package/dist/tools/task-list.d.ts +77 -0
- package/dist/tools/todo.d.ts +8 -0
- package/dist/tools/web.d.ts +184 -0
- package/dist/tools/web.js +32 -5
- package/dist/tools/worktree.d.ts +81 -0
- package/package.json +2 -2
- package/dist/tools/gitea-issue.d.ts +0 -13
- package/dist/tools/gitea-issue.js +0 -75
|
@@ -1,18 +1,133 @@
|
|
|
1
|
+
/** A tool call presented to a policy before it executes. */
|
|
1
2
|
export interface ToolCallRequest {
|
|
2
3
|
toolName: string;
|
|
3
4
|
args: unknown;
|
|
4
5
|
toolCallId: string;
|
|
6
|
+
/**
|
|
7
|
+
* RB-108 — the LIVE working directory this call's RELATIVE path arguments will actually resolve
|
|
8
|
+
* against, read at adjudication time from the same tracked `cwdRef` the fs hand tools resolve with
|
|
9
|
+
* (design/64 §16.3: a resident shell's `cd` persists and moves the fs tools' relative base with it).
|
|
10
|
+
*
|
|
11
|
+
* WHY IT EXISTS: every path guard here (sensitive-path, fs-write gate, session rules, skill scope,
|
|
12
|
+
* transcript integrity) re-resolves the model's spelling itself, and each was handed a STATIC root at
|
|
13
|
+
* wiring time. After a `cd` the two sides of a single call disagreed about which file it was: the tool
|
|
14
|
+
* wrote `<liveCwd>/pre-commit` while the guard judged `<wiringRoot>/pre-commit` — measured on a host
|
|
15
|
+
* lane, `cd .git/hooks` + `Write("pre-commit")` landed a git hook past a guard that names `.git/hooks`.
|
|
16
|
+
* Reading THIS field makes the guard's resolution base the same value the tool will use.
|
|
17
|
+
*
|
|
18
|
+
* Applies to the call's TARGET only. A guard's own configured directories (accept/exempt domains,
|
|
19
|
+
* `allowDirs`, manifest `allowPaths`) are DEPLOYMENT text and keep resolving against the static root —
|
|
20
|
+
* a shell `cd` must never relocate an allow-domain.
|
|
21
|
+
*
|
|
22
|
+
* ABSENT when the run has no tracked cwd (read-only hands, no execution env) or when a policy is
|
|
23
|
+
* invoked directly outside a Runner: consumers then fall back to their own configured root, which is
|
|
24
|
+
* exactly the pre-RB-108 behavior. Read-only — a policy cannot move the shell by writing it back.
|
|
25
|
+
*
|
|
26
|
+
* RESIDUAL (recorded honestly — this is a snapshot of a mutable ref, not a frozen binding): the gate
|
|
27
|
+
* reads the ref when it adjudicates and the tool reads it again when it executes. No interleaving that
|
|
28
|
+
* moves the cwd in between is constructible on the current loop, and it is worth naming WHY, because
|
|
29
|
+
* the reason is a property of the tool declarations rather than of this field: the loop adjudicates a
|
|
30
|
+
* whole batch before executing it, but only calls classified concurrency-safe ever share a batch, and
|
|
31
|
+
* every cwd MOVER (a `cd`-bearing Bash — `cd` is not on the readonly allowlist and any shell operator
|
|
32
|
+
* disqualifies — plus the worktree enter/exit tools) and every path-confinable WRITE tool declares
|
|
33
|
+
* `effect: "write"`, which derives `executionMode: "sequential"`, which forces a batch of one. A
|
|
34
|
+
* deployment tool that declared itself read/parallel while moving the shared cwd would reopen the
|
|
35
|
+
* window — at that declaration, not here.
|
|
36
|
+
*/
|
|
5
37
|
cwd?: string;
|
|
38
|
+
/**
|
|
39
|
+
* design/80 D-E-core: read-only per-run budget snapshot so a STATELESS policy can self-limit against
|
|
40
|
+
* state that survives suspend/resume (a fresh in-memory counter would reset every leg — the supervisor
|
|
41
|
+
* escalation-budget gap). Built by core at prepare time from the DURABLE resource ledger
|
|
42
|
+
* ({@link import("./checkpoint-store.js").ResourceLedger}) + the durable suspend chain; the policy CANNOT
|
|
43
|
+
* widen it (no write-back). Present on every gated `check()` once the runner builds the gate; absent only
|
|
44
|
+
* when a policy is invoked directly (outside a Runner). A NORMAL-ask escalation policy reads it; a SAFETY
|
|
45
|
+
* ask (egress / irreversible) ignores it and ALWAYS asks (invariant #2 stays structural — core mints
|
|
46
|
+
* `irreversible_ask` for safety tools regardless of any budget).
|
|
47
|
+
*/
|
|
6
48
|
budget?: {
|
|
49
|
+
/**
|
|
50
|
+
* Durable resource $ this run may STILL spend (micro-USD); `undefined` = no $ ceiling configured. Frozen
|
|
51
|
+
* total, prior-wins → it monotonically SHRINKS across legs and is NEVER re-granted by a resume (a
|
|
52
|
+
* deny-resume continues with the same frozen remaining). **NEVER falsy-test** (`0` = exhausted, NOT
|
|
53
|
+
* "unlimited" — only `undefined` is unlimited).
|
|
54
|
+
*/
|
|
7
55
|
resourceRemainingMicroUsd?: number;
|
|
56
|
+
/** Durable cumulative resource $ already spent across all prior legs (micro-USD); accumulates, never refunded. */
|
|
8
57
|
resourceSpentMicroUsd: number;
|
|
58
|
+
/** How many times this run has already suspended (the durable suspend chain). Lets the policy tighten as
|
|
59
|
+
* the chain grows — the precise complement to the unconditional `suspendLoopCap` backstop. */
|
|
9
60
|
suspendCount: number;
|
|
10
61
|
};
|
|
11
62
|
}
|
|
63
|
+
/** Where a decision came from, for audit (design/37). */
|
|
12
64
|
export type DecisionReason = "rule" | "mode" | "hook" | "safety" | "classifier" | "persisted_rule";
|
|
65
|
+
/**
|
|
66
|
+
* WHO (or what) ENDED an approval — the machine-readable twin of a settlement's human-readable text,
|
|
67
|
+
* so a consumer tells "a person decided this" from "nobody answered" without prose-matching a sentence.
|
|
68
|
+
* The sibling axis of {@link DecisionReason}, which says which LAYER produced a verdict; this one says
|
|
69
|
+
* what ended the WAIT.
|
|
70
|
+
*
|
|
71
|
+
* - `"human"` — a person, or the approver acting for one, returned a final verdict (allow or deny).
|
|
72
|
+
* - `"timeout"` — the configured approval window elapsed with no answer.
|
|
73
|
+
* - `"aborted"` — every other NON-HUMAN end: the task aborted, the approver threw or reported nobody
|
|
74
|
+
* reachable, the decision arrived out of contract, a store or transport gave way, retries ran out.
|
|
75
|
+
*
|
|
76
|
+
* The three words are exhaustive and mutually exclusive over the ways an approval can end, and the
|
|
77
|
+
* minimum discrimination a consumer needs — someone refused vs nobody answered — is `"human"` vs the
|
|
78
|
+
* other two.
|
|
79
|
+
*
|
|
80
|
+
* **Fill it AT the settlement site.** Each site knows its own cause and names it; deriving the value
|
|
81
|
+
* afterwards from whatever outcome happens to be at hand is exactly how a window that elapsed comes to
|
|
82
|
+
* be reported as a person's refusal.
|
|
83
|
+
*
|
|
84
|
+
* ABSENT means this settlement named no source: an older caller that predates the field, or a verdict
|
|
85
|
+
* that settled no wait at all (a policy POSTURE — headless auto-deny, a blanket bypass — where nobody
|
|
86
|
+
* was ever asked). A consumer MUST NOT read a semantic out of the absence; render the text instead.
|
|
87
|
+
*/
|
|
13
88
|
export type ApprovalSettledBy = "human" | "timeout" | "aborted";
|
|
89
|
+
/** The closed set above, for runtime domain checks at the seams that accept a caller-supplied value. */
|
|
14
90
|
export declare const APPROVAL_SETTLED_BY_VALUES: readonly ApprovalSettledBy[];
|
|
91
|
+
/** True iff `v` is one of the three {@link ApprovalSettledBy} words. */
|
|
15
92
|
export declare function isApprovalSettledBy(v: unknown): v is ApprovalSettledBy;
|
|
93
|
+
/**
|
|
94
|
+
* A three-state permission decision for a tool call (design/37). Upgrades the old two-state
|
|
95
|
+
* `{allow|deny}`:
|
|
96
|
+
* - `allow` may carry `updatedInput` — REWRITTEN args (redact a secret, clamp a path/value) that
|
|
97
|
+
* REPLACE the model's args before execution (re-validated against the tool schema first).
|
|
98
|
+
* `deny` may ALSO carry `updatedInput` (1.256 复审 MED-2): it never executes anything, but a
|
|
99
|
+
* combined-policy deny reports the ACCUMULATED pre-deny rewrite (policy A redacted → policy B
|
|
100
|
+
* denied) so a deny OBSERVER (`Hooks.permissionDenied`) sees the final post-rewrite args, not the
|
|
101
|
+
* stale un-redacted ones.
|
|
102
|
+
* - `ask` requests human confirmation; with no approver wired it resolves deterministically to deny
|
|
103
|
+
* (headless auto-deny, see `RunnerDeps.onAsk`). `requiresRealApproval: true` (RB-203 codex review,
|
|
104
|
+
* confirmed P1) additionally refuses to let a BLANKET `onAsk: "allow"` bypass clear it — that
|
|
105
|
+
* configuration is "no approver looked at this at all", indistinguishable from headless, for a rule
|
|
106
|
+
* whose whole point is that a blanket policy setting must not be the thing that clears it (see
|
|
107
|
+
* {@link resolveAsk}). A live auto-mode classifier verdict (tried earlier in the gate, if configured)
|
|
108
|
+
* or a genuine approver CALLBACK (actual judgment, even if it always says yes) still can.
|
|
109
|
+
* - `deny` blocks the call.
|
|
110
|
+
* Human-readable text is `message`; read it via {@link decisionText}.
|
|
111
|
+
*
|
|
112
|
+
* The two TERMINAL arms may also carry {@link ApprovalSettledBy} as `settledBy` — what ended the wait,
|
|
113
|
+
* when this verdict ended one. It is on `allow`/`deny` and deliberately NOT on `ask`: an `ask` has
|
|
114
|
+
* settled nothing yet, so a source there would name a decider who has not decided. A layer that never
|
|
115
|
+
* waited for anyone omits it (see the type's ABSENT clause).
|
|
116
|
+
* RB-479-B① (ruled 2026-08-02): the legacy `reason` field is REMOVED — one name for one thing.
|
|
117
|
+
*
|
|
118
|
+
* How far the TYPE carries that retirement (measured 2026-08-03, correcting this note's earlier claim
|
|
119
|
+
* that a policy returning `{reason}` "compiles red for TS consumers"): TypeScript's excess-property
|
|
120
|
+
* check fires only where the decision is a LITERAL in an ANNOTATED position — `const d: PermissionResult
|
|
121
|
+
* = {…}`, or a `check` written with an explicit `: PermissionResult` return annotation. The ordinary
|
|
122
|
+
* policy shape, `{ check: () => ({…}) }` with an INFERRED return type (also the method-syntax and
|
|
123
|
+
* assign-then-return forms), compiles GREEN with a stray `reason`. That is not a hole to plug in the
|
|
124
|
+
* type system — it is how contextual typing works — so the enforcement is at RUNTIME instead: every
|
|
125
|
+
* point that CONSUMES a decision REFUSES one carrying an own `reason` property, fail-closed (deny, with
|
|
126
|
+
* a migration message) — the {@link combinePolicies} fold, the PreToolUse hook face, and the durable
|
|
127
|
+
* resume-edit rechecks (see {@link refuseOutOfContractDecision}). Same doctrine as the strict `approve`
|
|
128
|
+
* / `onAsk` folds in this file: an out-of-contract value on the permission face is a loud rejection,
|
|
129
|
+
* never a best-effort read.
|
|
130
|
+
*/
|
|
16
131
|
export type PermissionResult = {
|
|
17
132
|
action: "allow";
|
|
18
133
|
updatedInput?: unknown;
|
|
@@ -32,87 +147,482 @@ export type PermissionResult = {
|
|
|
32
147
|
decisionReason?: DecisionReason;
|
|
33
148
|
settledBy?: ApprovalSettledBy;
|
|
34
149
|
};
|
|
150
|
+
/** The human/model-readable text of a decision. */
|
|
35
151
|
export declare function decisionText(d: PermissionResult): string | undefined;
|
|
152
|
+
/**
|
|
153
|
+
* Gates tool calls before they execute (the production safety layer for "processing/changing data").
|
|
154
|
+
*
|
|
155
|
+
* `check` runs before each tool call. Return `{ action: "deny", message }` to block it — the model
|
|
156
|
+
* receives an error tool result with the reason and can continue or report blocked. Return
|
|
157
|
+
* `{ action: "allow" }` to permit it.
|
|
158
|
+
*
|
|
159
|
+
* `check` may be async, which is also how **human-in-the-loop approval** works: a deployment can
|
|
160
|
+
* hold the promise open until an operator approves/denies. `signal` fires when the task aborts
|
|
161
|
+
* (timeout / max turns / cancel) — honor it to release a pending approval instead of hanging (F4).
|
|
162
|
+
* The Runner also races `check` against `signal` itself, so a policy that ignores it still cannot
|
|
163
|
+
* hang the worker past the deadline; passing it through just lets you clean up the wait early.
|
|
164
|
+
*/
|
|
36
165
|
export interface ToolPolicy {
|
|
37
166
|
check(req: ToolCallRequest, signal?: AbortSignal): PermissionResult | Promise<PermissionResult>;
|
|
38
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Refuse a decision that speaks the retired `reason` dialect (RB-479-B①, tripwire ruled 2026-08-03).
|
|
170
|
+
*
|
|
171
|
+
* Applied at every point a decision is CONSUMED, because no single fold sees them all (ruled
|
|
172
|
+
* 2026-08-03): {@link combinePolicies} (the runner's gate path), the PreToolUse hook's result seam
|
|
173
|
+
* (`hooks.ts` — a hook result reaches the gate decision without ever passing through a fold), and the
|
|
174
|
+
* durable resume-edit rechecks (`runtask.ts` — direct `check()` calls on the caller's own policy). The
|
|
175
|
+
* wording is face-neutral for that reason: one construction point, three consumers. The export exists
|
|
176
|
+
* for those two engine modules only and is deliberately NOT re-exported from `src/index.ts`: this is an
|
|
177
|
+
* internal screen on inputs the engine receives, not a facility deployments call.
|
|
178
|
+
*
|
|
179
|
+
* Why this is a DENY and not a best-effort read of the old field: the retirement is settled, so the
|
|
180
|
+
* value is out-of-contract input to the permission face — the same class as an untyped `approve`
|
|
181
|
+
* returning a truthy non-`true`, which this file already refuses fail-closed. Reading the old name
|
|
182
|
+
* anyway would re-open the two-names-for-one-thing surface; ignoring it (the pre-tripwire behavior)
|
|
183
|
+
* silently dropped the policy's own text and returned the per-site generic default, so a deployment
|
|
184
|
+
* whose deny messages had quietly degraded looked healthy. The type system cannot carry this alone —
|
|
185
|
+
* excess-property checking does not reach an inferred `check` return (see {@link PermissionResult}).
|
|
186
|
+
*
|
|
187
|
+
* OWN property only (`hasOwnProperty`, not `in`): a decision whose PROTOTYPE happens to expose
|
|
188
|
+
* `reason` never wrote the retired field. A non-object decision is passed through untouched — reading
|
|
189
|
+
* `.action` off it is the caller's existing failure, and inventing a second failure mode here would
|
|
190
|
+
* change which error a broken policy raises.
|
|
191
|
+
*
|
|
192
|
+
* Any accumulated `updatedInput` is deliberately NOT carried onto this deny: it came from the same
|
|
193
|
+
* out-of-contract decision object, so it is not a rewrite this layer is willing to report as audited.
|
|
194
|
+
* (A rewrite from an EARLIER, contract-shaped policy still rides out — {@link combinePolicies} adds it
|
|
195
|
+
* on the deny path per the observer contract.)
|
|
196
|
+
*/
|
|
39
197
|
export declare function refuseOutOfContractDecision(d: PermissionResult): PermissionResult;
|
|
198
|
+
/** The raw tool-name lists a name-keyed policy was built from (audit feed, see block note above). */
|
|
40
199
|
export interface ToolPolicyNameSets {
|
|
41
200
|
readonly allow?: readonly string[];
|
|
42
201
|
readonly deny?: readonly string[];
|
|
202
|
+
/** Names gated behind an approval decision ({@link createApprovalPolicy.requireApproval}) — a typo
|
|
203
|
+
* here silently WIDENS (the tool runs without ever asking), so it is audited too. */
|
|
43
204
|
readonly ask?: readonly string[];
|
|
44
205
|
}
|
|
206
|
+
/** A policy that exposes its name lists for the host-side pool audit. Composition-transparent:
|
|
207
|
+
* {@link combinePolicies} (and therefore {@link tightenTaskSpec}) unions children's groups onto the
|
|
208
|
+
* combined policy, so metadata survives the deployment's tighten/compose path. */
|
|
45
209
|
export type NamedToolPolicy = ToolPolicy & {
|
|
46
210
|
readonly nameSets: readonly ToolPolicyNameSets[];
|
|
47
211
|
};
|
|
212
|
+
/** All name-set groups reachable on `p` — `[]` when it carries none (e.g. a custom closure policy,
|
|
213
|
+
* which simply opts out of the audit). */
|
|
48
214
|
export declare function toolPolicyNameSets(p: ToolPolicy | undefined): readonly ToolPolicyNameSets[];
|
|
215
|
+
/**
|
|
216
|
+
* Name-based allow/deny. `deny` always wins. If `allow` is provided, only those tools are permitted
|
|
217
|
+
* (everything else denied). Without `allow`, everything not in `deny` is permitted.
|
|
218
|
+
* Carries {@link NamedToolPolicy.nameSets} so the host can audit the raw lists against the mounted
|
|
219
|
+
* pool ([c209-E] advisory); enforcement semantics are unchanged.
|
|
220
|
+
*/
|
|
49
221
|
export declare function createAllowDenyPolicy(opts: {
|
|
50
222
|
allow?: string[];
|
|
51
223
|
deny?: string[];
|
|
224
|
+
/**
|
|
225
|
+
* What to do with an entry that is not a tool NAME but a rule CONTENT form (`Bash(ps:*)`, `Edit(src/**)`).
|
|
226
|
+
* `"throw"` (default, matching {@link createPermissionRulePolicy}'s posture toward a rule it cannot
|
|
227
|
+
* compile) refuses at construction; `"skip"` drops the entry and reports it. Under BOTH, the entry never
|
|
228
|
+
* silently narrows the allowlist.
|
|
229
|
+
*/
|
|
52
230
|
onInvalidName?: "throw" | "skip";
|
|
231
|
+
/** Called once per dropped entry under `"skip"`. */
|
|
53
232
|
onInvalidNameIssue?: (issue: {
|
|
54
233
|
entry: string;
|
|
55
234
|
list: "allow" | "deny";
|
|
56
235
|
message: string;
|
|
57
236
|
}) => void;
|
|
58
237
|
}): NamedToolPolicy;
|
|
238
|
+
/**
|
|
239
|
+
* Human-in-the-loop approval for selected tools. Tools in `requireApproval` call `approve(req)` and
|
|
240
|
+
* are allowed only if it resolves true; tools in `deny` are always blocked; everything else is allowed
|
|
241
|
+
* (override with `denyByDefault: true` to allow only `requireApproval` + an explicit `autoAllow`).
|
|
242
|
+
*/
|
|
59
243
|
export declare function createApprovalPolicy(opts: {
|
|
244
|
+
/** Tools that need an approval decision. */
|
|
60
245
|
requireApproval: string[];
|
|
246
|
+
/**
|
|
247
|
+
* The approval decision (e.g. await an operator). Resolve true to allow, false to deny. `signal`
|
|
248
|
+
* fires when the task aborts — race your wait against it (e.g. an OA approval callback) so a
|
|
249
|
+
* never-answered request is released at the deadline rather than holding the worker.
|
|
250
|
+
*/
|
|
61
251
|
approve: (req: ToolCallRequest, signal?: AbortSignal) => boolean | Promise<boolean>;
|
|
252
|
+
/** Always-denied tools. */
|
|
62
253
|
deny?: string[];
|
|
254
|
+
/** Always-allowed tools (only meaningful with `denyByDefault`). */
|
|
63
255
|
autoAllow?: string[];
|
|
256
|
+
/** When true, deny anything not in `requireApproval` or `autoAllow`. Default false. */
|
|
64
257
|
denyByDefault?: boolean;
|
|
258
|
+
/**
|
|
259
|
+
* Optional self-contained deadline (ms): if `approve` hasn't resolved by then, deny. Belt-and-
|
|
260
|
+
* suspenders for **direct** callers — the Runner already races `check` against the task signal, so
|
|
261
|
+
* a Runner-driven task is bounded regardless; this protects a caller invoking `check()` without a
|
|
262
|
+
* signal. OMIT to wait indefinitely on `approve` — omission is the only spelling of "no deadline"
|
|
263
|
+
* (CLS-A-9): a written-down `0` is the tightest deadline (deny at once), and a non-finite value is
|
|
264
|
+
* refused at construction.
|
|
265
|
+
*/
|
|
65
266
|
approvalTimeoutMs?: number;
|
|
66
267
|
}): NamedToolPolicy;
|
|
268
|
+
/**
|
|
269
|
+
* Combine policies with the three-state fold **deny > ask > allow** (design/37): the WORST outcome
|
|
270
|
+
* across all policies wins. A `deny` short-circuits (nothing can override it); an `ask` does NOT
|
|
271
|
+
* short-circuit — scanning continues, because a later policy may still `deny` (which outranks ask).
|
|
272
|
+
* With no deny, the first `ask` wins; with neither, `allow`.
|
|
273
|
+
*
|
|
274
|
+
* **Idempotency requirement:** because the fold continues past an `ask` to look for a later `deny`, a
|
|
275
|
+
* policy's `check()` can be invoked even after an earlier policy returned `ask`. `check()` MUST be
|
|
276
|
+
* idempotent — repeated calls with the same {@link ToolCallRequest} return the same decision and
|
|
277
|
+
* accumulate no side effects (e.g. don't fire a duplicate approval notification on each call).
|
|
278
|
+
*/
|
|
67
279
|
export declare function combinePolicies(...policies: ToolPolicy[]): ToolPolicy;
|
|
280
|
+
/**
|
|
281
|
+
* The shell tools whose `{ command }` arg a coarse command-name policy parses. Other tools are out of scope.
|
|
282
|
+
*
|
|
283
|
+
* RB-130 (2026-07-25, defect probe): `Monitor` belongs here. It takes a `command` and runs it through the
|
|
284
|
+
* SAME `env.spawnBackground` seam as Bash, and prepare-task's own note says so in as many words — "Monitor
|
|
285
|
+
* runs an arbitrary shell `command` through the SAME env seam — it must sit behind the SAME shellGate
|
|
286
|
+
* tighten (else it becomes a policy side-door around a gated Bash)". The shellGate half was implemented;
|
|
287
|
+
* this half — the two ALWAYS-ON, core-owned parity gates that a caller's policy cannot remove — was keyed
|
|
288
|
+
* on a list containing only "Bash". The probe drove the whole thing end to end: the identical
|
|
289
|
+
* `rm -rf $(cat targets)` was denied as Bash and executed as Monitor, deleting a real directory with no
|
|
290
|
+
* gate at all; the same substitution makes `rm -rf ~/.ai-agent/sessions` a way to erase the audit trail.
|
|
291
|
+
*/
|
|
292
|
+
/**
|
|
293
|
+
* RB-153 (server [1708]): EXPORTED. A downstream governance layer keeps its own copy of this list so its
|
|
294
|
+
* per-command ask-list gates the same tools core does, and it had no way to read the real one — its guard
|
|
295
|
+
* had to probe a hand-written candidate list of names, which stays green for any name nobody thought to
|
|
296
|
+
* put in it. The list itself is the fact; publishing it removes the guess.
|
|
297
|
+
*/
|
|
68
298
|
export declare const COARSE_SHELL_TOOLS: string[];
|
|
299
|
+
/**
|
|
300
|
+
* design/center §10 — a COARSE allow/deny gate keyed on the LEADING command NAME (`argv[0]`) of a single
|
|
301
|
+
* simple shell command. It reuses the ONE shared simple-command parser
|
|
302
|
+
* ({@link import("../tools/fs/index.js").parseLeadingCommandName}) — it does NOT re-implement argv[0] parsing
|
|
303
|
+
* (a second parser would drift and open a bypass). For a `bash`/`bash_readonly` call it extracts the leading
|
|
304
|
+
* command name and:
|
|
305
|
+
* - if the name is in `deny` → `deny` (deny-wins, matching {@link createAllowDenyPolicy}; NOT last-match-wins,
|
|
306
|
+
* which would fight {@link combinePolicies}'s deny>ask>allow fold);
|
|
307
|
+
* - else if `allow` is provided and the name is NOT in it → `defaultAction` (`"ask"` default, or `"deny"`);
|
|
308
|
+
* - else → `allow`.
|
|
309
|
+
* A command the parser cannot reduce to a single bare name (it has shell operators / a path-prefix / a leading
|
|
310
|
+
* env-assignment) is treated by `defaultAction` (fail-toward-gate): such a command is exactly what would bypass
|
|
311
|
+
* an argv[0] filter, so it should not silently `allow`. NON-shell tools are out of scope → `allow` (this gate
|
|
312
|
+
* only speaks about shell command names; compose it with other policies for the rest).
|
|
313
|
+
*
|
|
314
|
+
* **core ships NO opinionated command list** — only this mechanism. The actual `allow`/`deny` rule set is
|
|
315
|
+
* injected by the profile/config/deployment.
|
|
316
|
+
*
|
|
317
|
+
* ⚠️ **NOT A SANDBOX — coarse filter / defense-in-depth only.** This matches `argv[0]` NAME and nothing else,
|
|
318
|
+
* so the bypass surface is large and the gate MUST NOT be relied on as containment:
|
|
319
|
+
* - command substitution / subshells (`$(curl …)`, backticks), pipes, redirects, `;`/`&&` chaining — all
|
|
320
|
+
* rejected as un-parseable here (→ `defaultAction`), so they don't sneak past `allow`, but that is a GATE
|
|
321
|
+
* not a guarantee of safety;
|
|
322
|
+
* - an indirection wrapper runs an arbitrary inner program under an allowlisted `argv[0]`: `sh -c '…'`,
|
|
323
|
+
* `env FOO=bar curl …`, `sudo rm …`, `timeout 5 curl …`, `xargs curl`, `find . -exec rm {} \;`,
|
|
324
|
+
* `python -c '…'`, `npm run <script>`, `git <subcommand>` — the inner action is INVISIBLE to an
|
|
325
|
+
* argv[0]-name filter. Allowlisting any such wrapper effectively allowlists everything it can launch.
|
|
326
|
+
* Real isolation is the deployment's sandboxed `executionEnv` (a remote/E2B container with no egress, a
|
|
327
|
+
* read-only FS, dropped capabilities). Use this only as a cheap first-line coarse filter layered over that.
|
|
328
|
+
*
|
|
329
|
+
* 🪤 **TRAP #1 — `TaskSpec.toolPolicy` OVERRIDES (does not merge) `RunnerDeps.toolPolicy`.** A consumer that
|
|
330
|
+
* sets `TaskSpec.toolPolicy = createCoarseCommandNamePolicy(…)` directly **silently discards the deployment's
|
|
331
|
+
* baseline policy** (the runner does `spec.toolPolicy ?? deps.toolPolicy`). To LAYER this on top of a baseline
|
|
332
|
+
* you MUST compose explicitly: `combinePolicies(deploymentBaseline, createCoarseCommandNamePolicy(…))`
|
|
333
|
+
* (deny-wins — both policies' denies still fire). {@link tightenTaskSpec} does this for you.
|
|
334
|
+
*
|
|
335
|
+
* 🪤 **TRAP #2 — under `TaskSpec.shellGate: "classify"`, a plain `ask` from this policy is promoted to a
|
|
336
|
+
* NON-budgetable `irreversible_ask`.** `shellGate:"classify"` statically marks `bash` `irreversibility:"maybe"`;
|
|
337
|
+
* the safety gate keys the checkpoint axis on that STATIC tool mark (not on `decisionReason`), so a `bash`
|
|
338
|
+
* command that doesn't prove reversible suspends as `irreversible_ask` — which a budget-aware escalation
|
|
339
|
+
* resolver will NEVER auto-approve. Net: combining this policy's `ask` with `shellGate:"classify"` does NOT
|
|
340
|
+
* give you a budgetable normal-ask on `bash`; it gives a hard human-approval suspend. Choose `shellGate` and a
|
|
341
|
+
* `defaultAction:"ask"` deliberately.
|
|
342
|
+
*/
|
|
69
343
|
export declare function createCoarseCommandNamePolicy(opts: {
|
|
344
|
+
/** Command names (argv[0]) explicitly allowed. If provided, a name NOT listed falls to `defaultAction`. */
|
|
70
345
|
allow?: string[];
|
|
346
|
+
/** Command names (argv[0]) explicitly denied — `deny` always wins (checked before `allow`). */
|
|
71
347
|
deny?: string[];
|
|
348
|
+
/** What to do for a command not matched by `allow` (or un-parseable): `"ask"` (default) or `"deny"`. */
|
|
72
349
|
defaultAction?: "ask" | "deny";
|
|
350
|
+
/** Override the shell tool names this gate parses (default `Bash` — bash + bash_readonly share the CC name). */
|
|
73
351
|
tools?: string[];
|
|
74
352
|
}): ToolPolicy;
|
|
75
353
|
export declare function findUnverifiableRecursiveDelete(command: string, safeVars?: ReadonlySet<string>): string | undefined;
|
|
354
|
+
/**
|
|
355
|
+
* CC 220 "Unverifiable Deletion Target" parity (auto-mode rule): ASK on a recursive+forced delete whose
|
|
356
|
+
* target is a variable / substitution that cannot be resolved from the command itself — fail-closed in the
|
|
357
|
+
* sense that with no live classifier/approver the ask degrades to deny (see {@link PermissionResult}'s
|
|
358
|
+
* `ask` doc), never to allow. See {@link findUnverifiableRecursiveDelete} for exact firing conditions. The
|
|
359
|
+
* message carries the CC-sanctioned remediation (re-run with the resolved LITERAL path written into the
|
|
360
|
+
* command, or assign the variable in the same command) — it doubles as the `askMessage` a classifier sees.
|
|
361
|
+
*
|
|
362
|
+
* RB-203 (2026-07-26): this used to be an unconditional `deny`, on the theory that the CC rule text forbids
|
|
363
|
+
* auto-allow («must be explicitly approved … cannot be auto-allowed by a permission rule»).
|
|
364
|
+
*
|
|
365
|
+
* RB-341 (2026-07-29) re-checked that citation against the 220 corpus and corrected it in BOTH directions.
|
|
366
|
+
* The RB-203 note claimed the phrase "traces to the 206 bundle; it does not appear anywhere in the 220
|
|
367
|
+
* corpus for THIS rule" — that sentence was wrong and is retracted. The phrase has 8 hits in 220, and two
|
|
368
|
+
* of them are this exact rule's own message text: `pretty220` 461365 (the `rm -rf $UNSET/*`
|
|
369
|
+
* variable-expansion arm, verbatim «e.g. `rm -rf $UNSET/*` becomes `rm -rf /*`. This requires explicit
|
|
370
|
+
* approval and cannot be auto-allowed by permission rules.») and 461444 (its command-substitution twin).
|
|
371
|
+
* Five more are the sibling deterministic `rm`/`rmdir` arms (457337/457364/457379/457387/457402) and one is
|
|
372
|
+
* an unrelated `find` rule (249564).
|
|
373
|
+
*
|
|
374
|
+
* The `ask` decision survives that correction, on a stronger anchor than the one RB-203 used:
|
|
375
|
+
*
|
|
376
|
+
* - **It is not a deny in 220 either.** Every one of those messages is built by the same constructor
|
|
377
|
+
* (`T7e`, 457298), whose `behavior` is literally `"ask"` — a deterministic gate that ASKS. The phrase
|
|
378
|
+
* scopes to permission RULES: no static allow rule may clear the gate. sema's equivalent is
|
|
379
|
+
* `combinePolicies`'s deny > ask > allow fold — an `allow` from any composed policy loses to this ask,
|
|
380
|
+
* in either composition order (pinned in tool-policy.test.ts).
|
|
381
|
+
* - **A live classifier MAY clear it, in 220 as here.** `T7e` marks the reason `classifierApprovable:
|
|
382
|
+
* false`, but pairs it with `circuitBreaker: "dangerousRemoval"`, and 220's auto-mode gate diverts an
|
|
383
|
+
* ask away from the classifier only when `!classifierApprovable && !(circuitBreaker !== undefined &&
|
|
384
|
+
* isAutoModePermissionSurface(ctx))` (604049-604053). The circuit-breaker arm exempts exactly this
|
|
385
|
+
* family, so on the auto-mode surface the classifier DOES adjudicate it. That is consistent with the
|
|
386
|
+
* rule's listing in the classifier prompt's **SOFT BLOCK** bucket ("destructive or irreversible — User
|
|
387
|
+
* Intent Rule CAN clear these", 519698 / rule text 519726), escapable when the user's own words (or an
|
|
388
|
+
* agent proposal they affirmed) name the exact target — the same design sema's classifier prompt already
|
|
389
|
+
* implements verbatim (`auto-mode-prompt-assets.ts`, unchanged). A `classifierApprovable:false` reason
|
|
390
|
+
* WITHOUT a `circuitBreaker` is the shape that genuinely forbids the classifier — e.g. the design-agent
|
|
391
|
+
* consent ASK at 480999/481016, which takes the fallback-to-human path this rule does not. This rule is
|
|
392
|
+
* not that shape, so "follow `classifierApprovable:false` literally" would be STRICTER than CC.
|
|
393
|
+
*
|
|
394
|
+
* So a hard `deny` was wrong twice over: it short-circuited `combinePolicies`'s fold before a live
|
|
395
|
+
* classifier ever ran, and CC's classifier does run here. `ask` reuses the existing generic per-ask
|
|
396
|
+
* classifier arm (`hooks.ts`, `decision.action === "ask"`): a `block` verdict still denies
|
|
397
|
+
* (`decisionReason: "classifier"`, fully audited), an `allow` verdict still requires a live classifier to
|
|
398
|
+
* have actually cleared it, and "no classifier configured" still means deny.
|
|
399
|
+
*
|
|
400
|
+
* codex review (confirmed P1): the one piece of NEW plumbing this DOES need — `requiresRealApproval: true`
|
|
401
|
+
* (see {@link PermissionResult}'s `ask` doc) — closes a real gap the first cut of this fix missed. A
|
|
402
|
+
* deployment using the documented `onAsk: "allow"` bypass mode (sandbox-is-the-boundary posture, the
|
|
403
|
+
* shape a sandboxed autonomy container runs) would otherwise have this rule's `ask` rubber-stamped by that blanket
|
|
404
|
+
* configuration with NO classifier ever consulted and NO judgment of any kind applied — silently WEAKER
|
|
405
|
+
* than the unconditional deny it replaced, for exactly the deployments that opted into the most permissive
|
|
406
|
+
* mode for OTHER, unrelated reasons. `requiresRealApproval` makes `resolveAsk` treat a blanket
|
|
407
|
+
* `onAsk:"allow"` as equivalent to no approver at all for this specific ask (deny, same as headless) while
|
|
408
|
+
* leaving every other path untouched: a live classifier (tried first, unaffected), a real approver
|
|
409
|
+
* CALLBACK (genuine per-call judgment, even one that usually says yes), and "no classifier + no approver"
|
|
410
|
+
* (already denied). Core wires this policy ALWAYS-ON in the runner's gate composition (prepare-task); it is
|
|
411
|
+
* exported so deployments can also compose/test it directly.
|
|
412
|
+
*
|
|
413
|
+
* RB-341: `requiresRealApproval` also turns out to be the correct sema analog of the one thing
|
|
414
|
+
* `classifierApprovable: false` still buys in 220 that a `circuitBreaker` does NOT take back — 220's
|
|
415
|
+
* bypassPermissions arm refuses to auto-allow an ask carrying `circuitBreaker === "dangerousRemoval"`
|
|
416
|
+
* (603856-603869), i.e. a blanket MODE setting cannot clear it, only judgment can. That is exactly the
|
|
417
|
+
* `onAsk:"allow"` refusal above, so no new hard bit is owed. The field's remaining 220 effects have no core
|
|
418
|
+
* surface to attach to: it suppresses the "always allow / don't ask again" affordance in the CC permission
|
|
419
|
+
* dialog (908517 / 909563) and re-attaches a matching user `ask` rule on the auto-mode surface (461507).
|
|
420
|
+
* Core has neither a persisted always-allow surface nor rule re-attachment — noted for whichever UI layer
|
|
421
|
+
* grows one.
|
|
422
|
+
*/
|
|
76
423
|
export declare function createUnverifiableDeletePolicy(opts?: {
|
|
424
|
+
/** Extra variable names treated as well-known-safe roots, ADDED to the default set
|
|
425
|
+
* `TMPDIR`/`HOME`/`PWD` ({@link UNVERIFIABLE_DELETE_SAFE_VARS} — RB-396-a: this doc used to claim
|
|
426
|
+
* the default was `TMPDIR` alone, reading STRICTER than the gate really is; `HOME`/`PWD` are a
|
|
427
|
+
* registered sema divergence from CC's temp-only carve-out, see the RB-340 note there). */
|
|
77
428
|
safeVars?: readonly string[];
|
|
429
|
+
/** Override the shell tool names this gate parses (default `Bash`). */
|
|
78
430
|
tools?: string[];
|
|
79
431
|
}): ToolPolicy;
|
|
80
432
|
export declare function createTranscriptIntegrityPolicy(opts?: {
|
|
433
|
+
/** Transcript directories to protect. Default: `($AGENT_DATA_DIR ?? ~/.ai-agent)/sessions`. */
|
|
81
434
|
sessionsDirs?: readonly string[];
|
|
435
|
+
/** argv[0] allowlist for read-only access to the transcript dir (default {@link BASH_READONLY_DEFAULT_ALLOW}). */
|
|
82
436
|
readAllow?: readonly string[];
|
|
437
|
+
/** Override the shell tool names this gate parses (default `Bash`). */
|
|
83
438
|
tools?: string[];
|
|
84
439
|
}): ToolPolicy;
|
|
440
|
+
/**
|
|
441
|
+
* Provenance of the DELEGATION whose child raised an ask (ruled 2026-08-04) — filled by the delegation
|
|
442
|
+
* tool when it forwards the parent run's approver into a child, never by the child itself (it rides the
|
|
443
|
+
* trusted `ToolExecuteContext.onAsk` seat, which no tool argument reaches).
|
|
444
|
+
*
|
|
445
|
+
* The INNERMOST (issuing) frame wins: a grandchild's ask carries the grandchild's own spawn facts, not
|
|
446
|
+
* the intermediate one's — each delegation forwards an already-stamped request verbatim.
|
|
447
|
+
*
|
|
448
|
+
* Relation to the sibling source-identity fields on {@link AskRequest}: `fromSubagent`/`sourceAgentName`
|
|
449
|
+
* answer "a delegated child asked, and this is its display identity" from the CHILD's own prepare; this
|
|
450
|
+
* one answers "which delegation CALL it belongs to" from the SPAWNER's side — the correlation an approver
|
|
451
|
+
* UI needs to attach the approval card to the Agent card the operator is already looking at.
|
|
452
|
+
*/
|
|
85
453
|
export interface AskDelegationProvenance {
|
|
454
|
+
/** The spawning tool call in the PARENT run (`ToolExecuteContext.toolCallId` at spawn time) — the
|
|
455
|
+
* delegation's stable identity, minted by the engine. */
|
|
86
456
|
readonly parentToolCallId: string;
|
|
457
|
+
/** Delegation nesting depth of the ISSUING child: 1 = a child of the run that owns the approver,
|
|
458
|
+
* 2 = its grandchild, … (as counted by the delegation-tool tree that spawned it). */
|
|
87
459
|
readonly depth: number;
|
|
460
|
+
/** The explicit spawn name / agent-definition name of the issuing child, when it has one.
|
|
461
|
+
* **UNTRUSTED-for-display** (the spawning model chooses `name`): redact + bound before rendering,
|
|
462
|
+
* never adjudication input — same posture as {@link AskRequest.sourceAgentName}. */
|
|
88
463
|
readonly agentName?: string;
|
|
89
464
|
}
|
|
465
|
+
/** The structured context an `onAsk` approver receives for an `ask` decision (design/37). */
|
|
90
466
|
export interface AskRequest {
|
|
91
467
|
toolName: string;
|
|
92
468
|
toolCallId: string;
|
|
469
|
+
/** The (post-rewrite) args the tool would run with. */
|
|
93
470
|
args: unknown;
|
|
471
|
+
/** [1245] — the tool's approval display projection of {@link args} (AgentTool.approvalPreview),
|
|
472
|
+
* clamped + control-char-sanitized by the gate. **UNTRUSTED, ADVISORY display metadata**: render
|
|
473
|
+
* with contextual escaping and show {@link args} alongside — the preview can misrepresent the
|
|
474
|
+
* executable action and never replaces args. Never adjudication input. */
|
|
94
475
|
readonly preview?: unknown;
|
|
476
|
+
/** Canonical digest of {@link args} as presented in THIS ask, computed by the engine's one
|
|
477
|
+
* `boundInputHashOf` — the same digest a durable park binds its checkpoint to, so an aggregating
|
|
478
|
+
* approver can reconcile a synchronous ask row against a parked checkpoint row for the same call
|
|
479
|
+
* by `(toolCallId, hash)` equality. RECONCILIATION metadata only, never adjudication input: it
|
|
480
|
+
* repeats for two asks over identical args, and an `updatedInput` edit round re-mints it over the
|
|
481
|
+
* edited args. Filled at the `resolveAsk` chokepoint (present for every wired-approver call, so a
|
|
482
|
+
* mint site added later is covered by construction); optional on the type because a deployment may
|
|
483
|
+
* invoke its approver function directly. */
|
|
95
484
|
readonly boundInputHash?: string;
|
|
485
|
+
/**
|
|
486
|
+
* design/179 §4 — the persistable allow-rule forms this exact call could be covered by, so a surface can
|
|
487
|
+
* offer "allow, and stop asking me this" with something concrete behind it. Present only when a
|
|
488
|
+
* persisted allow-rule lane is armed AND the call is one the lane can speak for: a compound, a
|
|
489
|
+
* redirection or a substitution yields NO suggestion, which is the honest answer rather than an option
|
|
490
|
+
* that would be refused on redemption.
|
|
491
|
+
*
|
|
492
|
+
* ADVISORY display metadata, never adjudication input, and never a rule by itself: minting one is a
|
|
493
|
+
* separate act that goes through the approval-record protocol, so a surface that ignores this field
|
|
494
|
+
* changes nothing about what is allowed.
|
|
495
|
+
*/
|
|
96
496
|
readonly ruleSuggestions?: readonly import("./permission-rule-model.js").RuleSuggestion[];
|
|
497
|
+
/** The human/model-readable prompt explaining what needs approval. */
|
|
97
498
|
message: string;
|
|
499
|
+
/** Runner-filled source identity (design S1d §1): the end-user {@link AskRequest} issuing task's
|
|
500
|
+
* `principal` (design/62). An AGGREGATING `onAsk` (one approver fanning over N delegated workers)
|
|
501
|
+
* attributes asks per-user by this. Worker/tool cannot set it (not a tool arg). Undefined ⇒ no principal.
|
|
502
|
+
* A non-aggregating `onAsk` simply ignores it (additive, no-op). `readonly`: Runner-populated metadata,
|
|
503
|
+
* not a caller/worker-settable field. Populated ONLY on the synchronous `resolveAsk`/`onAsk` path — a
|
|
504
|
+
* durable suspend/checkpoint flow does NOT invoke `onAsk` on the suspend side, so v1 ask-aggregation
|
|
505
|
+
* requires `checkpointStore` unset (design S1d §1.4 P-a). */
|
|
98
506
|
readonly principal?: string;
|
|
507
|
+
/** Runner-filled source-task identity (= the issuing task's session id). An aggregating `onAsk` uses it
|
|
508
|
+
* to tell which worker an ask came from (nested grandchildren each carry their own session id).
|
|
509
|
+
* **worker-unforgeable for Runner-created delegated subagents** (a child never sets sessionId — the
|
|
510
|
+
* Runner mints it); a top-level caller MAY continue its own session id via `TaskSpec.sessionId`, so this
|
|
511
|
+
* is NOT a global "never forgeable" run id — aggregation only aggregates delegated workers, the context
|
|
512
|
+
* where it holds (design S1d §1.3). `readonly` + same sync-path-only / P-a caveat as `principal`.
|
|
513
|
+
* Undefined ⇒ no source task id. **NOT a subagent discriminator** ([1546] MED-1: the HOST's own asks
|
|
514
|
+
* carry it too — it is always the issuing task's session id); "from a background agent" attribution
|
|
515
|
+
* keys on {@link fromSubagent}, never on this field's presence. */
|
|
99
516
|
readonly sourceTaskId?: string;
|
|
517
|
+
/** design/153 §1 (RB-39②) — Runner-filled: present (`true`) exactly when the gate raising this ask
|
|
518
|
+
* belongs to a DELEGATED SUBAGENT (the prepareTask `isSubagent` fact — trusted `internals.parentTaskId`
|
|
519
|
+
* presence; a child cannot forge or suppress it, internals never ride a TaskSpec). Undefined ⇒ the
|
|
520
|
+
* host / a top-level task. THE explicit "from a background agent" discriminator (replaces presence-
|
|
521
|
+
* or equality-heuristics on {@link sourceTaskId}). `readonly`, sync-path-only, S1d posture. */
|
|
100
522
|
readonly fromSubagent?: true;
|
|
523
|
+
/** design/153 §1 — Runner-filled: the issuing task's display identity (a subagent's explicit agent
|
|
524
|
+
* name, else its agent-type; undefined for the host and unnamed children). **UNTRUSTED-for-display**
|
|
525
|
+
* (the spawning model chooses names): redact + bound before rendering; never adjudication input.
|
|
526
|
+
* `readonly`, same posture as {@link fromSubagent}. */
|
|
101
527
|
readonly sourceAgentName?: string;
|
|
528
|
+
/** RB-203 (codex review, confirmed P1) — carried from the originating {@link PermissionResult}'s ask
|
|
529
|
+
* variant of the same name: `true` ⇒ {@link resolveAsk} must not let a blanket `onAsk: "allow"`
|
|
530
|
+
* clear this ask (see that field's doc). `readonly`, filled by the gate from the decision, never a
|
|
531
|
+
* caller/worker-settable field. */
|
|
102
532
|
readonly requiresRealApproval?: boolean;
|
|
533
|
+
/** Engine-judged risk axes of the action awaiting approval, for the human decision surface: a
|
|
534
|
+
* coarse `requiresRealApproval` cannot tell "cannot be undone" from "data leaves the machine",
|
|
535
|
+
* and those call for different scrutiny. Filled by the gate from the SAME resolved axes the
|
|
536
|
+
* safety tightens read (tool declarations + caller `toolAxes` folds) — never derived from tool
|
|
537
|
+
* names, never caller/worker-settable. `irreversible: true` covers both the declared-`"always"`
|
|
538
|
+
* and the `"maybe"` (unproven-reversible) tiers. ABSENT — the whole object or either member —
|
|
539
|
+
* means the engine did not judge that axis: render it as unjudged, never fold absence to `false`. */
|
|
103
540
|
readonly riskAxes?: {
|
|
104
541
|
readonly irreversible?: boolean;
|
|
105
542
|
readonly egress?: boolean;
|
|
106
543
|
};
|
|
544
|
+
/** ruled 2026-08-04 — present exactly when this ask was raised inside a DELEGATED child whose approver
|
|
545
|
+
* is the ancestor run's (the `ToolExecuteContext.onAsk` seat the delegation tool forwards). Additive:
|
|
546
|
+
* an approver that ignores it is unaffected; a durable park/suspend flow never invokes `onAsk` at all,
|
|
547
|
+
* so this — like `principal`/`sourceTaskId` — exists only on the synchronous resolution path.
|
|
548
|
+
* See {@link AskDelegationProvenance} for the trust posture of each member. */
|
|
107
549
|
readonly delegation?: AskDelegationProvenance;
|
|
108
550
|
}
|
|
551
|
+
/**
|
|
552
|
+
* How an `ask` decision is resolved when a policy/hook requests human confirmation (design/37):
|
|
553
|
+
* - `"deny"` (and the default when omitted) — **headless auto-deny**: no approver, so `ask` resolves
|
|
554
|
+
* deterministically to `deny` with a model-readable reason. The safe default for stateless automation.
|
|
555
|
+
* - `"allow"` — auto-approve every `ask` (e.g. a trusted batch run).
|
|
556
|
+
* - a function — await an operator's decision (true=allow, false=deny). `signal` fires when the task
|
|
557
|
+
* aborts; race your wait against it so an unanswered ask is released at the deadline, not hung.
|
|
558
|
+
* G1 three-value ([871]①): the function may also return `"unavailable"` — an affirmative "no operator
|
|
559
|
+
* is reachable for THIS ask right now" (judged PER-ASK inside the callback, not at wire time). It is a
|
|
560
|
+
* ROUTING verdict, not a decision: the gate re-routes the ask onto the durable park leg (same behavior
|
|
561
|
+
* as if no live approver were wired — checkpoint + suspend, the 1.293 fallback), and when no park
|
|
562
|
+
* facility is armed the ask falls to the headless auto-deny (fail-closed). This lets a durable
|
|
563
|
+
* deployment wire ONE callback that serves live synchronous three-choice cards while attached AND
|
|
564
|
+
* still lands asks in the durable approval inbox when the operator goes away.
|
|
565
|
+
*
|
|
566
|
+
* **Contract:** the function MUST be fail-closed (a throw → deny, surfacing the real cause), idempotent
|
|
567
|
+
* for a given request, and tolerant of being called after the task signal aborted. `"unavailable"` MUST
|
|
568
|
+
* only be returned when NO operator interaction happened (a partial interaction that then reported
|
|
569
|
+
* unavailable could double-resolve the same approval once the park re-surfaces it).
|
|
570
|
+
*/
|
|
109
571
|
export type OnAsk = "deny" | "allow" | ((req: AskRequest, signal?: AbortSignal) => AskOutcome | Promise<AskOutcome>);
|
|
572
|
+
/**
|
|
573
|
+
* What an `onAsk` approver may return ([1458]/[1462] object arm):
|
|
574
|
+
* - `boolean` — plain verdict (true=allow, false=deny). STRICT fold (RB-482 #17, server bridge
|
|
575
|
+
* zero-ripple confirmed): only the literal `true` approves; an out-of-contract truthy from an
|
|
576
|
+
* untyped bridge is a fail-closed deny naming the defect (the historical truthy leniency was a
|
|
577
|
+
* fail-open on the security face with no live producer).
|
|
578
|
+
* - `"unavailable"` — the G1 per-ask routing verdict (see {@link OnAsk}).
|
|
579
|
+
* - `{ allow, updatedInput? }` — verdict PLUS an operator EDIT of the presented args
|
|
580
|
+
* (whole-replacement form, e.g. ctrl+g "edit script in $EDITOR"): the human approved a MODIFIED
|
|
581
|
+
* action, and executing the un-edited args would betray that consent. `allow` folds STRICTLY
|
|
582
|
+
* (`allow === true`) — an object arm is a deliberate caller, so no truthy leniency — and
|
|
583
|
+
* `updatedInput` is honored only on allow (a deny edit never executes anything). The edit is
|
|
584
|
+
* applied as the resolved decision's own rewrite: the gate re-validates it against the tool
|
|
585
|
+
* schema exactly like a hook/policy rewrite.
|
|
586
|
+
*/
|
|
110
587
|
export type AskOutcome = boolean | "unavailable" | {
|
|
111
588
|
allow: boolean;
|
|
112
589
|
updatedInput?: unknown;
|
|
113
590
|
};
|
|
591
|
+
/**
|
|
592
|
+
* ruled 2026-08-04 — forward an approver into a delegated child, stamping every ask it raises with the
|
|
593
|
+
* delegation it came from ({@link AskDelegationProvenance}).
|
|
594
|
+
*
|
|
595
|
+
* Only the FUNCTION form is wrapped: `"allow"`/`"deny"` are policy SETTINGS, not approvers, and
|
|
596
|
+
* {@link resolveAsk} reads them structurally — wrapping would invent an approver where the deployment
|
|
597
|
+
* declared a blanket mode.
|
|
598
|
+
*
|
|
599
|
+
* An ask that ALREADY carries provenance passes through untouched: chained down a delegation tree, the
|
|
600
|
+
* INNERMOST (actually issuing) frame is the one the approver must see, and each outer hop would
|
|
601
|
+
* otherwise overwrite it with its own shallower one.
|
|
602
|
+
*/
|
|
114
603
|
export declare function withDelegationProvenance(onAsk: OnAsk, delegation: AskDelegationProvenance): OnAsk;
|
|
604
|
+
/**
|
|
605
|
+
* ruled 2026-08-04 — the APPROVER BEHIND a possibly-forwarded `onAsk`: the identity that answers
|
|
606
|
+
* "is this the same human/UI?" across delegation hops.
|
|
607
|
+
*
|
|
608
|
+
* Consumers compare approvers by function reference to decide whether one consultation's consent covers
|
|
609
|
+
* another (the RB-40 duplicate-frame collapse). A provenance wrapper is a different function object but
|
|
610
|
+
* the same decision-maker, so a bare `===` would ask one operator the same question twice for one tool
|
|
611
|
+
* call. Never used for authority (it grants nothing); only for "these two consultations are the same
|
|
612
|
+
* consultation". A non-wrapper value (including `"allow"`/`"deny"`/undefined) is its own identity.
|
|
613
|
+
*/
|
|
115
614
|
export declare function askApproverIdentity(onAsk: unknown): unknown;
|
|
615
|
+
/** EXACT structural clone for the approval boundary (alias isolation) — fail-closed, never lossy,
|
|
616
|
+
* never identity: a JSON round-trip would silently DROP unclonable members (presented ≠ executing =
|
|
617
|
+
* consent misrepresentation) and an identity fallback would hand the approver the live executing
|
|
618
|
+
* object (in-place mutation + TOCTOU). Tool args are model-JSON in practice, so failure is exotic —
|
|
619
|
+
* and exotic means deny, not leak.
|
|
620
|
+
*
|
|
621
|
+
* Exported for the DURABLE half of the same boundary (the runner's park mint): a checkpoint row holds
|
|
622
|
+
* the args a human will approve and a resume will execute, so it needs exactly this snapshot — and
|
|
623
|
+
* exactly this refusal when the value cannot be one. Not part of the package's public surface
|
|
624
|
+
* (index.ts does not re-export it); one implementation so the two halves cannot drift on what
|
|
625
|
+
* "safely presentable" means. */
|
|
116
626
|
export declare function tryCloneArgs<T>(v: T): {
|
|
117
627
|
ok: true;
|
|
118
628
|
value: T;
|
|
@@ -121,9 +631,54 @@ export declare function tryCloneArgs<T>(v: T): {
|
|
|
121
631
|
reason: string;
|
|
122
632
|
cause?: unknown;
|
|
123
633
|
};
|
|
634
|
+
/**
|
|
635
|
+
* A label for a value that was THROWN at us, safe to put in a fail-closed refusal. Never coerces: `String(x)`
|
|
636
|
+
* throws on a null-prototype object or a hostile `toString`/`Symbol.toPrimitive`, and the thrower here is
|
|
637
|
+
* deployment-supplied (a getter inside the args can throw any object at `structuredClone`, an approver can
|
|
638
|
+
* throw one at the gate). A coercion failure inside the catch would escape `resolveAsk` as a raw TypeError —
|
|
639
|
+
* turning a classified fail-closed DENY into an unclassified crash, i.e. the failing input escaping the very
|
|
640
|
+
* classification the refusal exists to give.
|
|
641
|
+
*
|
|
642
|
+
* The result is CONTAINED, not just described. Every caller interpolates it into a refusal that reaches
|
|
643
|
+
* the model inside a `<system-reminder>` frame, and the text is not ours: a `DataCloneError` renders the
|
|
644
|
+
* offending value INTO its message (`structuredClone` of a function yields that function's SOURCE), and
|
|
645
|
+
* a deployment approver throws whatever it likes. A rewrite handing over a function whose body contains
|
|
646
|
+
* `</system-reminder>` would otherwise close the trusted frame and continue as instructions — the exact
|
|
647
|
+
* threat `inlineUntrusted` exists for. So the description is one line, neutralized and capped here, at
|
|
648
|
+
* the single point where a thrown value becomes prose; the RAW exception is unaffected and still reaches
|
|
649
|
+
* the deployment's own error face, which is where an operator reads the untruncated story.
|
|
650
|
+
*
|
|
651
|
+
* Exported for the durable half of the same boundary (the runner's park mint), which now has a SECOND
|
|
652
|
+
* way a deployment-supplied value can throw at capture time — the target backend's own codec refusing to
|
|
653
|
+
* encode it. One containment point, so the two refusals cannot differ on how much of a hostile value's
|
|
654
|
+
* text they let through. Not part of the package's public surface.
|
|
655
|
+
*/
|
|
124
656
|
export declare function describeThrown(err: unknown): string;
|
|
657
|
+
/**
|
|
658
|
+
* A {@link resolveAsk} result: always a TERMINAL `allow`/`deny` (never `ask`). `approverUnavailable`
|
|
659
|
+
* is the out-of-band G1 three-value marker: the live approver returned `"unavailable"` for this ask —
|
|
660
|
+
* the carried `deny` is the FAIL-CLOSED FALLBACK, and the gate may instead re-route the ask onto the
|
|
661
|
+
* durable park leg (the only consumer; everywhere else the result reads as a plain deny).
|
|
662
|
+
*/
|
|
125
663
|
export type ResolvedAsk = PermissionResult & {
|
|
126
664
|
approverUnavailable?: true;
|
|
665
|
+
/** [1462] r5 — the EXACT data snapshot the approver was shown (the `structuredClone` of the
|
|
666
|
+
* presented args). On a plain approval (no edit) the gate EXECUTES this snapshot, not the original
|
|
667
|
+
* object: a stateful getter or an external alias must not be able to make the executed action
|
|
668
|
+
* differ from the approved one (shown == executed, by construction). Set only on the
|
|
669
|
+
* function-approver path (string modes present nothing). */
|
|
127
670
|
presentedInput?: unknown;
|
|
128
671
|
};
|
|
672
|
+
/**
|
|
673
|
+
* Resolve an `ask` decision to a terminal `allow`/`deny` via {@link OnAsk}. Centralizes the headless
|
|
674
|
+
* auto-deny default, fail-closed error handling, and stable deny reasons so every ask site is
|
|
675
|
+
* consistent. Never returns `ask`.
|
|
676
|
+
*
|
|
677
|
+
* Every arm that ENDED A WAIT names what ended it ({@link ApprovalSettledBy}, per-arm, at the arm):
|
|
678
|
+
* the approver's own verdicts are `"human"`, and the fail-closed ends around them (abort, a throw, an
|
|
679
|
+
* "unavailable" report, an unclonable presentation, an out-of-contract value) are `"aborted"`. The
|
|
680
|
+
* three POSTURE arms at the top — blanket `"allow"`, its `requiresRealApproval` refusal, and the
|
|
681
|
+
* headless auto-deny — carry NO source on purpose: nobody was asked, so there is no wait for anyone to
|
|
682
|
+
* have ended, and `decisionReason: "mode"` is already the honest word for what produced them.
|
|
683
|
+
*/
|
|
129
684
|
export declare function resolveAsk(req: AskRequest, onAsk: OnAsk | undefined, signal?: AbortSignal): Promise<ResolvedAsk>;
|