@sema-agent/core 7.48.0 → 7.49.1
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 +457 -0
- package/README.md +2 -2
- package/dist/agents/cascade.d.ts +2 -5
- package/dist/agents/child-failure.d.ts +20 -0
- package/dist/agents/child-failure.js +28 -0
- package/dist/agents/cross-session-ref.d.ts +11 -3
- package/dist/agents/cross-session-ref.js +6 -0
- package/dist/agents/cumulative-stats.d.ts +12 -15
- package/dist/agents/cumulative-stats.js +1 -1
- package/dist/agents/extra-tool-names.js +1 -1
- package/dist/agents/inherited-tool-pool.d.ts +17 -13
- package/dist/agents/inherited-tool-pool.js +4 -3
- package/dist/agents/peer-session-drain.d.ts +3 -2
- package/dist/agents/peer-session-drain.js +5 -4
- package/dist/agents/send-message-tool.js +2 -9
- package/dist/agents/subagent.d.ts +10 -29
- package/dist/agents/subagent.js +65 -53
- package/dist/agents/suspend-guard.d.ts +1 -1
- package/dist/agents/tool-filter.d.ts +76 -65
- package/dist/agents/tool-filter.js +122 -92
- package/dist/agents/verify.d.ts +4 -7
- package/dist/agents/verify.js +6 -7
- package/dist/bench/metrics.d.ts +1 -2
- package/dist/brain/anthropic.js +133 -79
- package/dist/brain/errors.d.ts +53 -6
- package/dist/brain/errors.js +22 -2
- package/dist/brain/input-too-long.d.ts +40 -19
- package/dist/brain/input-too-long.js +3 -16
- package/dist/brain/open-responses.js +19 -10
- package/dist/brain/openai.js +123 -32
- package/dist/brain/provider-dialect.d.ts +214 -0
- package/dist/brain/provider-dialect.js +186 -0
- package/dist/brain/request-params.d.ts +27 -8
- package/dist/brain/request-params.js +7 -12
- package/dist/brain/request-route.d.ts +84 -0
- package/dist/brain/request-route.js +41 -0
- package/dist/brain/retry.d.ts +8 -0
- package/dist/brain/retry.js +10 -4
- package/dist/brain/route-adjudicator.d.ts +7 -0
- package/dist/brain/route-adjudicator.js +5 -1
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +11 -0
- package/dist/brain/stream-engine.d.ts +52 -1
- package/dist/brain/stream-engine.js +81 -24
- package/dist/brain/stream-shared.d.ts +57 -11
- package/dist/brain/stream-shared.js +28 -2
- package/dist/core/a2a.d.ts +1 -0
- package/dist/core/agent-config-dir.js +3 -2
- package/dist/core/allow-entry.d.ts +21 -12
- package/dist/core/allow-entry.js +38 -31
- package/dist/core/arg-summary.d.ts +21 -28
- package/dist/core/arg-summary.js +235 -88
- package/dist/core/ask-origin.d.ts +42 -24
- package/dist/core/ask-origin.js +18 -13
- package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/auto-mode-prompt.d.ts +11 -1
- package/dist/core/auto-mode-prompt.js +13 -10
- package/dist/core/auto-mode-rebuild.d.ts +7 -0
- package/dist/core/auto-mode-rebuild.js +4 -1
- package/dist/core/canonical-json.d.ts +3 -0
- package/dist/core/canonical-json.js +2 -1
- package/dist/core/checkpoint-requirements.d.ts +892 -0
- package/dist/core/checkpoint-requirements.js +333 -0
- package/dist/core/checkpoint-store.d.ts +94 -65
- package/dist/core/checkpoint-store.js +14 -26
- package/dist/core/child-clamp-seats.d.ts +228 -69
- package/dist/core/child-clamp-seats.js +211 -17
- package/dist/core/classifier-unavailable-arm.d.ts +5 -1
- package/dist/core/classifier-unavailable-arm.js +3 -3
- package/dist/core/compliance.d.ts +3 -0
- package/dist/core/compliance.js +9 -4
- package/dist/core/credential-vocabulary.d.ts +140 -0
- package/dist/core/credential-vocabulary.js +131 -0
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/effective-path-target.d.ts +73 -16
- package/dist/core/effective-path-target.js +63 -33
- package/dist/core/engine-notice.d.ts +43 -11
- package/dist/core/file-history-store.js +2 -2
- package/dist/core/fs-write-gate-policy.d.ts +4 -0
- package/dist/core/fs-write-gate-policy.js +22 -5
- package/dist/core/gate-bounded-await.d.ts +28 -13
- package/dist/core/gate-bounded-await.js +41 -4
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +24 -25
- package/dist/core/gate-lanes.js +16 -15
- package/dist/core/gate-outcome.d.ts +20 -5
- package/dist/core/gate-outcome.js +5 -0
- package/dist/core/governance-codes.d.ts +11 -4
- package/dist/core/governance-codes.js +14 -3
- package/dist/core/hooks.d.ts +21 -0
- package/dist/core/locked-config.d.ts +8 -0
- package/dist/core/locked-config.js +14 -2
- package/dist/core/lsp.js +3 -5
- package/dist/core/mailbox-store.d.ts +3 -4
- package/dist/core/mcp-connection-pool.d.ts +75 -0
- package/dist/core/mcp-connection-pool.js +128 -0
- package/dist/core/mcp-failure.d.ts +2 -1
- package/dist/core/mcp-failure.js +13 -2
- package/dist/core/mcp.d.ts +4 -0
- package/dist/core/mcp.js +70 -43
- package/dist/core/memory-engine/content-origin.js +2 -14
- package/dist/core/memory-engine/engine.d.ts +32 -22
- package/dist/core/memory-engine/engine.js +103 -55
- package/dist/core/memory-engine/file-backend.d.ts +13 -30
- package/dist/core/memory-engine/file-backend.js +37 -252
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +139 -9
- package/dist/core/memory-engine/layout.js +350 -7
- package/dist/core/memory-engine/scope-contract.d.ts +10 -0
- package/dist/core/memory-engine/scope-contract.js +8 -0
- package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
- package/dist/core/memory-engine/session-incarnation.js +5 -2
- package/dist/core/memory-engine/types.d.ts +10 -1
- package/dist/core/memory.js +5 -17
- package/dist/core/model-seat.d.ts +4 -4
- package/dist/core/model-seat.js +1 -1
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +19 -0
- package/dist/core/namespaced-rule-name.d.ts +29 -0
- package/dist/core/namespaced-rule-name.js +52 -0
- package/dist/core/park-selfcheck.d.ts +1 -1
- package/dist/core/park-selfcheck.js +16 -6
- package/dist/core/path-guard-rows.d.ts +99 -0
- package/dist/core/path-guard-rows.js +45 -0
- package/dist/core/path-identity.d.ts +22 -16
- package/dist/core/path-identity.js +10 -10
- package/dist/core/path-rule-binding.d.ts +2 -1
- package/dist/core/path-rule-binding.js +3 -1
- package/dist/core/pause-registry.d.ts +16 -2
- package/dist/core/pause-registry.js +6 -0
- package/dist/core/permission-rule-consent.js +0 -7
- package/dist/core/permission-rule-model.d.ts +68 -24
- package/dist/core/permission-rule-model.js +105 -24
- package/dist/core/permission-rule-store.js +2 -2
- package/dist/core/permission-rules.d.ts +3 -30
- package/dist/core/permission-rules.js +4 -54
- package/dist/core/read-root-candidate.d.ts +1 -3
- package/dist/core/read-root-candidate.js +4 -15
- package/dist/core/real-approval.d.ts +4 -3
- package/dist/core/retired-keys.d.ts +13 -0
- package/dist/core/retired-keys.js +14 -0
- package/dist/core/roles.d.ts +2 -3
- package/dist/core/roles.js +15 -6
- package/dist/core/runner/assemble-result.d.ts +0 -7
- package/dist/core/runner/assemble-result.js +19 -31
- package/dist/core/runner/caller-roster.d.ts +78 -0
- package/dist/core/runner/caller-roster.js +219 -0
- package/dist/core/runner/checkpoint-scope.d.ts +16 -16
- package/dist/core/runner/checkpoint-scope.js +2 -2
- package/dist/core/runner/child-tree.js +2 -2
- package/dist/core/runner/contracts.d.ts +68 -35
- package/dist/core/runner/decide-continuation.d.ts +51 -3
- package/dist/core/runner/decide-continuation.js +76 -21
- package/dist/core/runner/denial-limit-arms.d.ts +17 -5
- package/dist/core/runner/denial-limit-arms.js +11 -9
- package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
- package/dist/core/runner/extra-body-dropped-seat.js +22 -0
- package/dist/core/runner/finish-reason-seat.d.ts +9 -0
- package/dist/core/runner/finish-reason-seat.js +40 -0
- package/dist/core/runner/gate-exit.d.ts +44 -32
- package/dist/core/runner/gate-exit.js +112 -25
- package/dist/core/runner/inherited-ask-grants.js +6 -4
- package/dist/core/runner/mcp-redial.d.ts +3 -3
- package/dist/core/runner/mcp-redial.js +3 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
- package/dist/core/runner/permission-rule-lanes.js +5 -4
- package/dist/core/runner/prepare-artifact.d.ts +4 -0
- package/dist/core/runner/prepare-artifact.js +2 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
- package/dist/core/runner/prepare-ask-lane.js +12 -6
- package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
- package/dist/core/runner/prepare-boundary-parks.js +4 -7
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
- package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
- package/dist/core/runner/prepare-config-doors.d.ts +9 -9
- package/dist/core/runner/prepare-config-doors.js +10 -5
- package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
- package/dist/core/runner/prepare-defer-classify.js +5 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-delegation-surface.js +3 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
- package/dist/core/runner/prepare-gate-stations.js +9 -7
- package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
- package/dist/core/runner/prepare-hands-readface.js +7 -7
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
- package/dist/core/runner/prepare-inherited-gate.js +14 -15
- package/dist/core/runner/prepare-listings.d.ts +7 -24
- package/dist/core/runner/prepare-listings.js +4 -5
- package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
- package/dist/core/runner/prepare-memory-engine-session.js +4 -3
- package/dist/core/runner/prepare-memory.d.ts +6 -0
- package/dist/core/runner/prepare-memory.js +13 -13
- package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
- package/dist/core/runner/prepare-offload-wrappers.js +3 -3
- package/dist/core/runner/prepare-park-ask.d.ts +7 -8
- package/dist/core/runner/prepare-park-ask.js +17 -10
- package/dist/core/runner/prepare-policy-chain.js +24 -44
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +3 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -4
- package/dist/core/runner/prepare-run-refs.d.ts +3 -0
- package/dist/core/runner/prepare-run-refs.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
- package/dist/core/runner/prepare-suspend-saga.js +28 -12
- package/dist/core/runner/prepare-task.d.ts +1 -1
- package/dist/core/runner/prepare-task.js +67 -56
- package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
- package/dist/core/runner/prepare-wiring-manifest.js +5 -8
- package/dist/core/runner/resume-apply.js +7 -14
- package/dist/core/runner/resume-checkpoint-screen.js +11 -4
- package/dist/core/runner/resume-internals-and-config.js +2 -2
- package/dist/core/runner/resume-policy-outcome.js +5 -32
- package/dist/core/runner/resume-review-outcome.js +4 -1
- package/dist/core/runner/retired-runner-deps.d.ts +6 -0
- package/dist/core/runner/retired-runner-deps.js +10 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -0
- package/dist/core/runner/run-brain-sinks.js +5 -2
- package/dist/core/runner/run-harness-handlers.js +29 -36
- package/dist/core/runner/run-leg.d.ts +0 -2
- package/dist/core/runner/run-leg.js +32 -33
- package/dist/core/runner/run-terminal-adoption.js +4 -3
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-rule-policy.js +5 -5
- package/dist/core/runner/stream-settle-backstop.js +7 -4
- package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
- package/dist/core/runner/sub-agent-deny-lists.js +111 -80
- package/dist/core/runner/terminal-account.d.ts +48 -0
- package/dist/core/runner/terminal-account.js +186 -0
- package/dist/core/runner/tool-end-body.d.ts +54 -17
- package/dist/core/runner/tool-end-body.js +27 -2
- package/dist/core/runner/tool-face-overlay.d.ts +3 -1
- package/dist/core/runner/tool-face-overlay.js +6 -4
- package/dist/core/runner/tool-occurrence.d.ts +106 -0
- package/dist/core/runner/tool-occurrence.js +123 -0
- package/dist/core/runner/tool-progress-lane.d.ts +16 -8
- package/dist/core/runner/tool-progress-lane.js +25 -34
- package/dist/core/runner/tool-turn-repair-seat.d.ts +28 -4
- package/dist/core/runner/tool-turn-repair-seat.js +36 -13
- package/dist/core/runner/turn-attachments.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +21 -9
- package/dist/core/runner/write-protection-station.js +20 -17
- package/dist/core/runner-deps.d.ts +12 -22
- package/dist/core/secret-env.d.ts +16 -5
- package/dist/core/secret-env.js +23 -63
- package/dist/core/sensitive-path-policy.d.ts +19 -18
- package/dist/core/sensitive-path-policy.js +73 -49
- package/dist/core/session-reconcile.d.ts +3 -0
- package/dist/core/session-reconcile.js +5 -4
- package/dist/core/session-store.d.ts +5 -0
- package/dist/core/session-store.js +12 -0
- package/dist/core/session.d.ts +13 -0
- package/dist/core/shared-memory/normalize.d.ts +17 -4
- package/dist/core/shared-memory/normalize.js +7 -7
- package/dist/core/shell-lexer.js +5 -4
- package/dist/core/shell-wrapper-projection.js +1 -1
- package/dist/core/skill-grant.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +2 -2
- package/dist/core/task-event.d.ts +59 -5
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +42 -9
- package/dist/core/terminal-cause.d.ts +94 -11
- package/dist/core/tighten-task-spec.d.ts +5 -4
- package/dist/core/tighten-task-spec.js +20 -25
- package/dist/core/tool-catalog-entries.d.ts +5 -7
- package/dist/core/tool-catalog-entries.js +14 -15
- package/dist/core/tool-face.d.ts +47 -0
- package/dist/core/tool-face.js +5 -0
- package/dist/core/tool-model-gate.d.ts +5 -5
- package/dist/core/tool-name-aliases.d.ts +26 -2
- package/dist/core/tool-name-aliases.js +13 -0
- package/dist/core/tool-name-list.d.ts +30 -0
- package/dist/core/tool-name-list.js +55 -0
- package/dist/core/tool-name-readings.d.ts +1 -9
- package/dist/core/tool-name-readings.js +1 -3
- package/dist/core/tool-policy.d.ts +195 -85
- package/dist/core/tool-policy.js +165 -380
- package/dist/core/tool-registry.d.ts +44 -1
- package/dist/core/tool-registry.js +26 -0
- package/dist/core/tool-roster.d.ts +19 -1
- package/dist/core/tool-roster.js +21 -2
- package/dist/core/tool-spec-members.d.ts +45 -0
- package/dist/core/tool-spec-members.js +169 -0
- package/dist/core/tool-spec.d.ts +46 -8
- package/dist/core/tools.d.ts +6 -2
- package/dist/core/tools.js +8 -4
- package/dist/core/untrusted-egress.js +29 -26
- package/dist/core/untrusted-text.d.ts +13 -10
- package/dist/core/untrusted-text.js +6 -44
- package/dist/core/workflow-journal-store.d.ts +4 -1
- package/dist/core/write-protect.d.ts +65 -29
- package/dist/core/write-protect.js +235 -177
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
- package/dist/engine/execution-env/node-execution-env.js +16 -38
- package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
- package/dist/engine/execution-env/symlink-chain.js +32 -0
- package/dist/engine/harness/types.d.ts +7 -0
- package/dist/engine/llm/tool-turns.d.ts +3 -0
- package/dist/engine/llm/tool-turns.js +1 -0
- package/dist/engine/llm/types.d.ts +59 -23
- package/dist/engine/loop/agent-loop.js +16 -2
- package/dist/engine/session/memory-repo.js +11 -3
- package/dist/engine/session/repo-utils.d.ts +8 -0
- package/dist/engine/session/repo-utils.js +13 -0
- package/dist/index.d.ts +20 -23
- package/dist/index.js +17 -20
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/governance-baseline-validity.js +1 -1
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +16 -35
- package/dist/orchestration/run-workflow-tool.js +38 -78
- package/dist/orchestration/workflow-governance.d.ts +21 -25
- package/dist/orchestration/workflow-governance.js +38 -78
- package/dist/orchestration/workflow-primitives.d.ts +7 -22
- package/dist/orchestration/workflow-primitives.js +5 -12
- package/dist/orchestration/workflow-types.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +61 -11
- package/dist/orchestration/workflow.js +189 -117
- package/dist/scenarios/full-body.d.ts +1 -1
- package/dist/shell/lex.d.ts +0 -21
- package/dist/shell/lex.js +250 -68
- package/dist/shell/shell-words.d.ts +35 -0
- package/dist/shell/shell-words.js +65 -0
- package/dist/stores/file/checkpoint-store.d.ts +5 -5
- package/dist/stores/file/checkpoint-store.js +5 -2
- package/dist/stores/file/index.d.ts +0 -8
- package/dist/stores/file/index.js +0 -12
- package/dist/stores/file/session-store.d.ts +3 -0
- package/dist/stores/file/session-store.js +44 -19
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/bash-program-position.d.ts +12 -4
- package/dist/tools/fs/bash-program-position.js +32 -9
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/bash-readonly-classifier.js +8 -7
- package/dist/tools/fs/containment-face.d.ts +4 -0
- package/dist/tools/fs/containment-face.js +3 -0
- package/dist/tools/fs/fs-shared.d.ts +10 -0
- package/dist/tools/fs/fs-shared.js +18 -0
- package/dist/tools/fs/fs-write.js +4 -2
- package/dist/tools/fs/index.d.ts +1 -1
- package/dist/tools/fs/program-read-model.d.ts +46 -20
- package/dist/tools/fs/program-read-model.js +50 -20
- package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
- package/dist/tools/fs/program-read-model.rows.js +16 -15
- package/dist/tools/fs/read-deny-home.d.ts +33 -47
- package/dist/tools/fs/read-deny-home.js +35 -49
- package/dist/tools/fs/read-deny.d.ts +23 -22
- package/dist/tools/fs/read-deny.js +114 -89
- package/dist/tools/fs/removal-targets.d.ts +56 -23
- package/dist/tools/fs/removal-targets.js +65 -87
- package/dist/tools/fs/safety.d.ts +29 -22
- package/dist/tools/fs/safety.js +17 -11
- package/dist/tools/fs/search.js +10 -8
- package/dist/tools/fs/shell-read-argv.js +1 -1
- package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
- package/dist/tools/fs/shell-read-bindings.js +324 -86
- package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
- package/dist/tools/fs/shell-read-builtins.js +43 -0
- package/dist/tools/fs/shell-read-check.d.ts +15 -1
- package/dist/tools/fs/shell-read-check.js +67 -43
- package/dist/tools/fs/shell-read-establish.js +6 -6
- package/dist/tools/fs/shell-read-functions.d.ts +22 -0
- package/dist/tools/fs/shell-read-functions.js +29 -0
- package/dist/tools/fs/shell-read-judge.d.ts +51 -18
- package/dist/tools/fs/shell-read-judge.js +40 -4
- package/dist/tools/fs/shell-read-plan.d.ts +12 -6
- package/dist/tools/fs/shell-read-plan.js +118 -113
- package/dist/tools/fs/shell-read-start.d.ts +29 -6
- package/dist/tools/fs/shell-read-start.js +16 -9
- package/dist/tools/fs/shell-read-word.js +4 -0
- package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
- package/dist/tools/fs/shell-read-workdir.js +281 -0
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
- package/dist/tools/fs/shell-read-write-targets.js +14 -5
- package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
- package/dist/tools/fs/shell-reentry-text.js +3 -11
- package/dist/tools/task-list.d.ts +1 -2
- package/dist/tools/web.js +1 -1
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +107 -143
- package/wire-changes/core@7.49.0.json +4765 -0
- package/dist/agents/teacher.d.ts +0 -159
- package/dist/agents/teacher.js +0 -577
- package/dist/agents/team.d.ts +0 -226
- package/dist/agents/team.js +0 -257
- package/dist/core/strategy-store.d.ts +0 -238
- package/dist/core/strategy-store.js +0 -253
- package/dist/orchestration/builtin-workflows.d.ts +0 -133
- package/dist/orchestration/builtin-workflows.js +0 -159
- package/dist/scenarios/env.d.ts +0 -40
- package/dist/scenarios/env.js +0 -39
- package/dist/scenarios/scenario-registry.d.ts +0 -110
- package/dist/scenarios/scenario-registry.js +0 -140
- package/dist/scenarios/teacher-quickstart.d.ts +0 -40
- package/dist/scenarios/teacher-quickstart.js +0 -12
- package/dist/stores/cc/lockfile.d.ts +0 -10
- package/dist/stores/cc/lockfile.js +0 -98
- package/dist/stores/cc/mailbox-store.d.ts +0 -20
- package/dist/stores/cc/mailbox-store.js +0 -255
- package/dist/stores/cc/roster-adapter.d.ts +0 -12
- package/dist/stores/cc/roster-adapter.js +0 -117
- package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
- package/dist/stores/cc/sidecar-transcript.js +0 -264
- package/dist/stores/cc/task-list-store.d.ts +0 -2
- package/dist/stores/cc/task-list-store.js +0 -125
- package/dist/stores/file/strategy-store.d.ts +0 -97
- package/dist/stores/file/strategy-store.js +0 -341
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { canonicalizeTarget, isAbsoluteForFamily,
|
|
1
|
+
import { anchorSpelling, canonicalizeTarget, familyFor, hasWin32AliasedComponent, isAbsoluteForFamily, normalizeAbsPathLexically, pathFamilyOf, pathIdentityOf, spellingOfIdentity, win32NamespaceScreen } from "../tools/fs/safety.js";
|
|
2
2
|
import { declaredPathTargetOf, pathTargetValue, protectivePathTargetOf } from "./tool-registry.js";
|
|
3
3
|
import { symlinkChainHops } from "./path-identity.js";
|
|
4
4
|
import { DEFAULT_GATE_AWAIT_TIMEOUT_MS, withGateTimeout } from "./gate-bounded-await.js";
|
|
5
|
+
import { thrownText } from "./thrown-value.js";
|
|
5
6
|
export function pathTargetBaseOf(pt, bases) {
|
|
6
7
|
return (pt?.base ?? "cwd") === "root" ? bases.root : (bases.cwd ?? bases.root);
|
|
7
8
|
}
|
|
8
|
-
export function splitAbsoluteGlobPattern(pattern,
|
|
9
|
+
export function splitAbsoluteGlobPattern(pattern, tree) {
|
|
10
|
+
const family = tree ?? familyFor("own", pattern);
|
|
9
11
|
const screened = win32NamespaceScreen(pattern, family);
|
|
10
12
|
if (!screened.ok)
|
|
11
13
|
return { refused: screened.refuse };
|
|
@@ -31,10 +33,8 @@ export function effectivePathTargetOf(call, pt, bases) {
|
|
|
31
33
|
if ("refused" in spelling)
|
|
32
34
|
return { kind: "refused", reason: spelling.refused };
|
|
33
35
|
if (spelling.spelled !== undefined)
|
|
34
|
-
return
|
|
35
|
-
|
|
36
|
-
const family = pathFamilyOf(bases);
|
|
37
|
-
return declaredBase !== undefined && isAbsoluteForFamily(family, declaredBase) ? readingOf(pathIdentityOf(declaredBase, family, bases.root ?? bases.cwd)) : unreadableBase(declaredBase);
|
|
36
|
+
return placeSpelling(spelling.spelled, spelling.base, bases);
|
|
37
|
+
return spelling.base !== undefined && isAbsoluteForFamily(readingFamilyOf(bases, spelling.base), spelling.base) ? placeSpelling(spelling.base, undefined, bases) : unreadableBase(spelling.base);
|
|
38
38
|
}
|
|
39
39
|
export function effectivePathSpellingOf(call, pt, bases) {
|
|
40
40
|
if (pt === undefined)
|
|
@@ -55,36 +55,58 @@ export function effectivePathSpellingOf(call, pt, bases) {
|
|
|
55
55
|
}
|
|
56
56
|
return { base: declaredBase };
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
const family =
|
|
58
|
+
export function placeSpelling(spelled, declaredBase, bases) {
|
|
59
|
+
const family = readingFamilyOf(bases, spelled);
|
|
60
60
|
const screened = win32NamespaceScreen(spelled, family);
|
|
61
61
|
if (!screened.ok)
|
|
62
62
|
return { kind: "refused", reason: screened.refuse };
|
|
63
63
|
const tree = bases.root ?? bases.cwd;
|
|
64
64
|
if (isAbsoluteForFamily(family, screened.spelled))
|
|
65
|
-
return readingOf(pathIdentityOf(screened.spelled, family, tree));
|
|
66
|
-
if (declaredBase === undefined ||
|
|
65
|
+
return readingOf(pathIdentityOf(screened.spelled, family, tree), family);
|
|
66
|
+
if (declaredBase === undefined || !isAbsoluteForFamily(family, declaredBase))
|
|
67
67
|
return unreadableBase(declaredBase);
|
|
68
|
-
return readingOf(pathIdentityOf(
|
|
68
|
+
return readingOf(pathIdentityOf(anchorSpelling(family, declaredBase, screened.spelled), family, tree), family);
|
|
69
|
+
}
|
|
70
|
+
export function readingFamilyOf(bases, spelled) {
|
|
71
|
+
return pathFamilyOf(bases) ?? familyFor("own", spelled);
|
|
69
72
|
}
|
|
70
|
-
function readingOf(r) {
|
|
73
|
+
function readingOf(r, family) {
|
|
71
74
|
if (r.ok)
|
|
72
|
-
return { kind: "path", identity: r.identity };
|
|
75
|
+
return { kind: "path", identity: r.identity, family };
|
|
73
76
|
return r.reason === "relative" || r.reason === "unanchored" ? undefined : { kind: "refused", reason: r.reason };
|
|
74
77
|
}
|
|
75
78
|
function unreadableBase(base) {
|
|
76
79
|
return { kind: "unreadable", reason: base === undefined ? "the call's path is relative to a base that was not supplied" : `the base this call resolves against (${JSON.stringify(base)}) is not a fully-qualified path of this tree's family` };
|
|
77
80
|
}
|
|
78
|
-
export
|
|
79
|
-
|
|
81
|
+
export const READ_ROOT_CANDIDATE_DIR_MAX = 1024;
|
|
82
|
+
export function validatePath(value, contract) {
|
|
83
|
+
if (typeof value !== "string" || !isAbsoluteForFamily("own", value))
|
|
84
|
+
return undefined;
|
|
85
|
+
if (contract.intent === "validate-coordinate")
|
|
86
|
+
return value;
|
|
87
|
+
if (value.length > READ_ROOT_CANDIDATE_DIR_MAX)
|
|
88
|
+
return undefined;
|
|
89
|
+
if (/[\u0000-\u001f\u007f\u2028\u2029]/.test(value))
|
|
90
|
+
return undefined;
|
|
91
|
+
const folded = normalizeAbsPathLexically(value);
|
|
92
|
+
if (folded !== value || normalizeAbsPathLexically(`${value}/..`) === value)
|
|
93
|
+
return undefined;
|
|
94
|
+
if (hasWin32AliasedComponent(value))
|
|
95
|
+
return undefined;
|
|
96
|
+
return win32NamespaceScreen(value, familyFor("own", value)).ok ? value : undefined;
|
|
97
|
+
}
|
|
98
|
+
export async function readPath(env, spelled, base, bases, contract, signal) {
|
|
99
|
+
const lexical = placeSpelling(spelled, base, bases);
|
|
80
100
|
const family = pathFamilyOf(bases);
|
|
81
|
-
if (env === undefined || family === undefined || lexical?.kind === "unreadable")
|
|
101
|
+
if (contract.views === "lexical" || env === undefined || family === undefined || lexical?.kind === "unreadable")
|
|
82
102
|
return { lexical, hops: [] };
|
|
83
103
|
const canonical = await canonicalizeTarget(env, spelled, signal, family, base);
|
|
84
104
|
const climbs = (s) => s !== undefined && (family === "win" ? /(^|[\\/])\.\.([\\/]|$)/ : /(^|\/)\.\.(\/|$)/).test(s);
|
|
85
105
|
const followsALink = canonical.ok && (climbs(spelled) || climbs(base) || lexical?.kind !== "path" || absoluteTargetIdentityOf(canonical.key, bases) !== lexical.identity);
|
|
86
|
-
const
|
|
87
|
-
|
|
106
|
+
const chain = contract.views === "chain" && followsALink
|
|
107
|
+
? await withGateTimeout(symlinkChainHops(env, spelled, signal, family, base), DEFAULT_GATE_AWAIT_TIMEOUT_MS, signal, "canonicalChain").catch((err) => ({ ok: false, cause: thrownText(err), asked: true }))
|
|
108
|
+
: { ok: true, hops: [] };
|
|
109
|
+
return chain.ok ? { lexical, canonical, hops: chain.hops } : { lexical, canonical, hops: [], hopsUnread: true };
|
|
88
110
|
}
|
|
89
111
|
export function absoluteTargetIdentityOf(spelled, bases) {
|
|
90
112
|
const r = pathIdentityOf(spelled, pathFamilyOf(bases), bases.root ?? bases.cwd);
|
|
@@ -94,7 +116,6 @@ const READ_FOR = new WeakMap();
|
|
|
94
116
|
const REREAD = new WeakMap();
|
|
95
117
|
export async function readCallTarget(env, call, signal, leads) {
|
|
96
118
|
const bases = { ...(call.root !== undefined ? { root: call.root } : {}), ...(call.cwd !== undefined ? { cwd: call.cwd } : {}) };
|
|
97
|
-
const family = pathFamilyOf(bases);
|
|
98
119
|
const views = new Map();
|
|
99
120
|
const viewOf = (pt) => {
|
|
100
121
|
const sel = effectivePathSpellingOf(call, pt, bases);
|
|
@@ -102,7 +123,7 @@ export async function readCallTarget(env, call, signal, leads) {
|
|
|
102
123
|
return Promise.resolve(undefined);
|
|
103
124
|
if ("refused" in sel)
|
|
104
125
|
return Promise.resolve({ kind: "refused", reason: sel.refused });
|
|
105
|
-
const target = sel.spelled !== undefined ? { spelled: sel.spelled, base: sel.base } : sel.base !== undefined && isAbsoluteForFamily(
|
|
126
|
+
const target = sel.spelled !== undefined ? { spelled: sel.spelled, base: sel.base } : sel.base !== undefined && isAbsoluteForFamily(readingFamilyOf(bases, sel.base), sel.base) ? { spelled: sel.base, base: undefined } : undefined;
|
|
106
127
|
if (target === undefined)
|
|
107
128
|
return Promise.resolve(unreadableBase(sel.base));
|
|
108
129
|
const { spelled, base } = target;
|
|
@@ -110,9 +131,9 @@ export async function readCallTarget(env, call, signal, leads) {
|
|
|
110
131
|
const prior = views.get(key);
|
|
111
132
|
if (prior !== undefined)
|
|
112
133
|
return prior;
|
|
113
|
-
const read =
|
|
114
|
-
.catch(() => ({ lexical:
|
|
115
|
-
.then(
|
|
134
|
+
const read = readPath(env, spelled, base, bases, { intent: "resolve", views: "chain" }, signal)
|
|
135
|
+
.catch((err) => ({ lexical: placeSpelling(spelled, base, bases), canonical: { ok: false, message: `the environment threw resolving the target: ${thrownText(err)}` }, hops: [] }))
|
|
136
|
+
.then(viewFrom);
|
|
116
137
|
views.set(key, read);
|
|
117
138
|
return read;
|
|
118
139
|
};
|
|
@@ -130,13 +151,14 @@ export function withArgsReading(req, args, signal) {
|
|
|
130
151
|
const reread = reading === undefined ? undefined : REREAD.get(reading);
|
|
131
152
|
return reread === undefined ? undefined : reread(args, signal).then((targetReading) => ({ ...req, args, targetReading }));
|
|
132
153
|
}
|
|
133
|
-
function viewFrom(v
|
|
154
|
+
function viewFrom(v) {
|
|
134
155
|
if (v.lexical === undefined)
|
|
135
156
|
return undefined;
|
|
136
157
|
if (v.lexical.kind !== "path")
|
|
137
158
|
return Object.freeze({ ...v.lexical });
|
|
138
159
|
const canonical = v.canonical?.ok === true ? v.canonical.key : undefined;
|
|
139
|
-
|
|
160
|
+
const unread = (v.canonical !== undefined && !v.canonical.ok) || v.hopsUnread === true;
|
|
161
|
+
return Object.freeze({ kind: "path", lexical: spellingOfIdentity(v.lexical.identity, v.lexical.family), ...(canonical !== undefined ? { canonical } : {}), ...(v.hops.length > 0 ? { hops: Object.freeze([...v.hops]) } : {}), ...(unread ? { unread: true } : {}) });
|
|
140
162
|
}
|
|
141
163
|
export function callTargetReadingOf(req) {
|
|
142
164
|
const r = req.targetReading;
|
|
@@ -149,21 +171,29 @@ export function callTargetViewsOf(req, direction, bare = {}) {
|
|
|
149
171
|
if (v === undefined || v.kind === "refused")
|
|
150
172
|
return undefined;
|
|
151
173
|
if (v.kind === "unreadable")
|
|
152
|
-
return {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
174
|
+
return { views: [], unreadable: v.reason };
|
|
175
|
+
if (direction === "allow" && (v.canonical === undefined || v.unread === true))
|
|
176
|
+
return { views: [], unreadable: ALLOW_UNRESOLVED };
|
|
177
|
+
const views = [{ path: v.lexical, kind: "lexical" }];
|
|
178
|
+
const seen = (p) => views.some((w) => w.path === p);
|
|
179
|
+
if (v.canonical !== undefined && !seen(v.canonical))
|
|
180
|
+
views.push({ path: v.canonical, kind: "canonical" });
|
|
181
|
+
for (const hop of v.hops ?? [])
|
|
182
|
+
if (!seen(hop))
|
|
183
|
+
views.push({ path: hop, kind: "hop" });
|
|
184
|
+
return { views };
|
|
158
185
|
}
|
|
159
186
|
const own = req.root !== undefined || req.cwd !== undefined ? { ...(req.root !== undefined ? { root: req.root } : {}), ...(req.cwd !== undefined ? { cwd: req.cwd } : {}) } : bare;
|
|
160
187
|
const target = effectivePathTargetOf(req, direction === "tighten" ? protectivePathTargetOf(req) : declaredPathTargetOf(req), own);
|
|
161
188
|
if (target === undefined || target.kind === "refused")
|
|
162
189
|
return undefined;
|
|
163
190
|
if (target.kind === "unreadable")
|
|
164
|
-
return {
|
|
165
|
-
|
|
191
|
+
return { views: [], unreadable: target.reason };
|
|
192
|
+
if (direction === "allow")
|
|
193
|
+
return { views: [], unreadable: ALLOW_UNRESOLVED };
|
|
194
|
+
return { views: [{ path: spellingOfIdentity(target.identity, target.family), kind: "lexical" }] };
|
|
166
195
|
}
|
|
196
|
+
const ALLOW_UNRESOLVED = "where the target resolves was not read, so no allow by path can speak for it";
|
|
167
197
|
export function legCallTargetStamp(leg) {
|
|
168
198
|
const taken = new WeakMap();
|
|
169
199
|
return (req, signal) => {
|
|
@@ -34,11 +34,14 @@ export interface EngineNotice {
|
|
|
34
34
|
* prepared leg, never per judgment and never re-fired for a mid-run roster delta; absent ⇒ the judge
|
|
35
35
|
* has its target view, or no covered write tool was mounted AT PREPARE, or there is no judge —
|
|
36
36
|
* `wiringManifest.writeProtection` reports the judge's reading either way.
|
|
37
|
-
* - `"config.
|
|
38
|
-
* and
|
|
39
|
-
* threw
|
|
40
|
-
*
|
|
41
|
-
*
|
|
37
|
+
* - `"config.path_view_unresolved"` (#869; 7.48.0 `config.write_protection_unresolved`) — this leg's write-protection judge HAS a target view
|
|
38
|
+
* and one SOURCE of a judgment did not answer: the environment refused a spelling, could not follow a link,
|
|
39
|
+
* threw, or did not answer within the gate's deadline — on the target, its link chain or a root's key — or
|
|
40
|
+
* a deployment policy's guarded write rows did not come back. A target whose real destination (or chain)
|
|
41
|
+
* could not be determined is refused where the table has rows; an auxiliary source is absent on its own (a
|
|
42
|
+
* root exempts and places nothing; rows that did not come back are held, so the writes they could guard are
|
|
43
|
+
* not placed); every row an answering source met stays met — the judge's absence law. The disclosure is
|
|
44
|
+
* where a deployment learns its environment is the reason. Announce, never narrow — no verdict moves because of this notice; the
|
|
42
45
|
* verdict already moved when the environment failed to answer. Audience `operator`.
|
|
43
46
|
* `detail: { reason, cause, sessionId, runId }` — `reason` is `"unresolved-symlink"` (a link whose
|
|
44
47
|
* real target is unknowable) or `"unresolvable-target"` (everything else: a refused spelling, an
|
|
@@ -60,11 +63,12 @@ export interface EngineNotice {
|
|
|
60
63
|
* - `"permission.allowed_tool_not_granted"` — an allow list holds entries that grant (or refuse) nothing: a loaded skill's
|
|
61
64
|
* `allowed-tools` / `disallowed-tools`, the request's `TaskSpec.allowedTools`, the deployment's `RunnerDeps.allowedTools`.
|
|
62
65
|
* `*` (it voids an allow list; on a deny list it reads as nothing and the rest still refuses), `mcp__*` (no server
|
|
63
|
-
* named), a
|
|
66
|
+
* named), a rule on a tool with no such rule form (an allow by path on a tool other than `Read` / `Edit`, a deny by host),
|
|
67
|
+
* a shape the rule grammar refuses, a tool name stale against the run's roster. The run goes on and asks for those tools
|
|
64
68
|
* as usual. Audience `user`; once per prepared task for the skill and request lists (`detail.sessionId` present), once
|
|
65
69
|
* per Runner for the deployment's (at construction, no session). `detail: { sessionId?, entries: [{ source, entry,
|
|
66
70
|
* reason, skill?, list? }] }` (`source` ∈ `skill` / `request` / `deployment`; `skill` and `list` only on a skill's;
|
|
67
|
-
* `reason` ∈
|
|
71
|
+
* `reason` ∈ {@link import("./allow-entry.js").ALLOW_ENTRY_INERT_REASONS}).
|
|
68
72
|
* - `"skills.listing_truncated"` — the `<skills>` disclosure block did not fit its byte budget, so
|
|
69
73
|
* at least one skill is listed without its description (`nameOnly`) or, in the pathological case,
|
|
70
74
|
* not listed at all (`dropped`); the `Skill` tool still serves every one of them. Audience
|
|
@@ -269,6 +273,27 @@ export interface EngineNotice {
|
|
|
269
273
|
* `"charset"` (a control byte, a space, a non-ASCII unit or `~`), `"length"` (admitted characters, over 128)
|
|
270
274
|
* or `"duplicate"` (a renamed later call); `rawLength` present for the two shape reasons only; never the raw
|
|
271
275
|
* bytes. Absent ⇒ no call of the run was folded.
|
|
276
|
+
* - `"route.finish_reason_unknown"` (#1457) — the provider ended a response with a stream-end word (an
|
|
277
|
+
* OpenAI-family `finish_reason`) the brain does not read. The turn is kept — its text and the stop its content
|
|
278
|
+
* implies — and the word rides `AssistantMessage.finishReasonUnknown` (and, when the run completes on that turn,
|
|
279
|
+
* `terminal.detail`); the notice is what keeps the keep from being a silent clean stop. ONCE PER LEG PER WORD.
|
|
280
|
+
* Audience `user` (the person reading the answer judges whether it is whole); `detail: { finishReason,
|
|
281
|
+
* sessionId, runId }` — the word in the provider echo shape, `?` when it had bytes outside it.
|
|
282
|
+
* - `"route.stream_end_ignored"` (#1457) — the provider's stream sent more after its first terminal statement, on
|
|
283
|
+
* either wire: a later ending (OpenAI-family `finish_reason`, Anthropic `stop_reason`), error frame or content (a
|
|
284
|
+
* delta, a block, a new message). The first ending decided the turn and nothing after it was added
|
|
285
|
+
* (`AssistantMessage.streamEndIgnored`). ONCE PER LEG PER (statement, word). Audience `user`; `detail: {
|
|
286
|
+
* statement: "ending" | "error" | "content", word, frames, sessionId, runId }` — `word` the first such frame's
|
|
287
|
+
* (for content, its kind), `frames` how many came.
|
|
288
|
+
* - `"route.extra_body_reserved_dropped"` (#1520) — a request's `Model.extraBody` carried keys the wire adapter
|
|
289
|
+
* sets itself (`temperature`, `max_tokens`, `stop`, the thinking-enable keys, `messages`, `tools`, …), so the
|
|
290
|
+
* adapter stripped them and the request went out with the engine's value (or without the key); core wins, and
|
|
291
|
+
* that is said. One reading at the one strip site — the model spec of the task, a model spec a host brain
|
|
292
|
+
* rewrote for a single request, and the leg's internal calls (the compaction summary, mid-task or at the end of
|
|
293
|
+
* the task, and a side query fired from a tool) are announced alike. Advisory: the turn
|
|
294
|
+
* runs. ONCE PER LEG PER (api, key set) — a deployment fact, not a request fact. Audience `operator`;
|
|
295
|
+
* `detail: { keys, api, modelId, sessionId, runId }` — `keys` the key NAMES in `extraBody`'s order (never a
|
|
296
|
+
* value), `api` the wire the adapter speaks, `modelId` the catalog id the request was sent as.
|
|
272
297
|
* - `"context.tool_turn_repaired"` (#1224) — a provider request was built from a transcript that breaks the
|
|
273
298
|
* tool-turn law, and the request view restored it (`engine/llm/tool-turns.ts`; the transcript is never
|
|
274
299
|
* rewritten): a block after an assistant's tool calls moved ahead of them (`trailing_text`), a result recorded
|
|
@@ -284,13 +309,20 @@ export interface EngineNotice {
|
|
|
284
309
|
* the run and announced on the first. Absent ⇒ every request of the run already had the structure.
|
|
285
310
|
* - `"task.tool_turn_incomplete"` (#1230) — the person's line for a tool turn the model was handed incomplete, beside
|
|
286
311
|
* the note the model itself reads. `detail.cause` (closed `TOOL_TURN_INCOMPLETE_CAUSES`): `truncated` — calls whose
|
|
287
|
-
* arguments were cut before they parsed, dropped (they did not run;
|
|
288
|
-
*
|
|
312
|
+
* arguments were cut before they parsed, dropped (they did not run); `unnamed` — calls that arrived with no tool
|
|
313
|
+
* name, dropped the same way; `bad_frame` — streamed response frames
|
|
289
314
|
* that could not be read, dropped (the response may be missing content); `missing_result_synthesized` — a
|
|
290
315
|
* call of this run with no recorded result, which the request view closed as interrupted, outcome unknown (the
|
|
291
316
|
* `missing_result` repair above; a call that went unanswered before the run began is the transcript's history and
|
|
292
|
-
* is on that operator line only). Audience `"user"`; `detail: { cause, count, toolCallIds?, sessionId, runId }` —
|
|
293
|
-
* `count` the calls (or frames) of that cause in the turn or request that first showed it; `
|
|
317
|
+
* is on that operator line only). Audience `"user"`; `detail: { cause, count, outcome?, toolCallIds?, sessionId, runId }` —
|
|
318
|
+
* `count` the calls (or frames) of that cause in the turn or request that first showed it; `outcome` (#1640) on
|
|
319
|
+
* `truncated` / `unnamed` only, and only where the turn's own message states it: `"terminal"` — the lane failed
|
|
320
|
+
* the run on those calls (its dropped-calls account is on the failed turn; the terminal's `detail.kind` is
|
|
321
|
+
* `model_output_invalid`), the sentence says the run ended; `"reissued"` — the turn goes on by the loop's turn
|
|
322
|
+
* rules (it carries a tool call, or stopped to call a tool, or stopped at the output cap) and the next request
|
|
323
|
+
* asks the model to re-issue them. ABSENT is a fact, not missing data: the message does not say what became of the
|
|
324
|
+
* run (a refusal, an abort, a completed turn with nothing to run, a torn stream the loop may resume), and the
|
|
325
|
+
* sentence then stops at "so they did not run". Once for the cause that first showed it; `toolCallIds` on
|
|
294
326
|
* `missing_result_synthesized` only, each id in the provider echo shape (a stored id outside it is not shown;
|
|
295
327
|
* `count` still counts it). Closed-set words, a count and call ids only: never a tool name, an argument or the
|
|
296
328
|
* note's text. ONCE PER RUN PER CAUSE. Absent ⇒ nothing of that cause reached the model.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { thrownText } from "./thrown-value.js";
|
|
3
|
-
import { isAbsoluteForFamily,
|
|
3
|
+
import { isAbsoluteForFamily, isWinFormPath, pathFamilyOf, relativeInEveryFamily } from "../tools/fs/safety.js";
|
|
4
4
|
import { fileHistoryBoundariesToKeep, resolveFileHistoryRetention } from "./file-history-retention.js";
|
|
5
5
|
const normSlash = (p) => p.replace(/\\/g, "/");
|
|
6
6
|
const stripTrailSep = (p) => (isWinFormPath(p) ? p.replace(/[\\/]+$/, "") : p.replace(/\/+$/, ""));
|
|
@@ -20,7 +20,7 @@ function joinUnder(root, rel) {
|
|
|
20
20
|
return stripTrailSep(root) + (win ? "\\" : "/") + (win ? rel.replace(/\//g, "\\") : rel);
|
|
21
21
|
}
|
|
22
22
|
function isUnsafeRelPathLike(relN) {
|
|
23
|
-
return
|
|
23
|
+
return !relativeInEveryFamily(relN) || relN.split("/").includes("..");
|
|
24
24
|
}
|
|
25
25
|
function parentDirOf(absPath) {
|
|
26
26
|
const win = isWinFormPath(absPath);
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { ExecutionEnv } from "../internal/harness-types.js";
|
|
2
2
|
import type { PermissionResult, ToolPolicy } from "./tool-policy.js";
|
|
3
|
+
import { type PathGuardRow } from "./path-guard-rows.js";
|
|
4
|
+
/** One write domain SOURCE as an allow row of the one table: it reaches every location at or below one of its admitted keys.
|
|
5
|
+
* The write gate's three sources, and a session rule's `allowDirs` (the confinement that admits a write only inside them). */
|
|
6
|
+
export declare function domainRow(source: "advertised" | "configured" | "accepted" | "session", dirs: readonly string[]): PathGuardRow;
|
|
3
7
|
/** design/388 B22 — the identity triple the exemption probe hands the store beside the name. */
|
|
4
8
|
export interface ToolCallIdentity {
|
|
5
9
|
capabilityId: string;
|
|
@@ -3,6 +3,20 @@ import { isWithin } from "./runner/session-rule-policy.js";
|
|
|
3
3
|
import { swallowedFenceRoot } from "./runner/advertised-writable-dirs.js";
|
|
4
4
|
import { declaredPathTargetOf, isProtectedWrite } from "./tool-registry.js";
|
|
5
5
|
import { pathTargetBaseOf } from "./effective-path-target.js";
|
|
6
|
+
import { judgePathRows } from "./path-guard-rows.js";
|
|
7
|
+
export function domainRow(source, dirs) {
|
|
8
|
+
return {
|
|
9
|
+
name: `write domain (${source})`,
|
|
10
|
+
grammar: { kind: "domain", dirs, source },
|
|
11
|
+
polarity: "allow",
|
|
12
|
+
faces: ["write"],
|
|
13
|
+
placement: "anywhere",
|
|
14
|
+
fold: "exact",
|
|
15
|
+
exemptible: false,
|
|
16
|
+
origin: source === "advertised" ? "builtin" : "addition",
|
|
17
|
+
reach: (view) => (dirs.some((dir) => isWithin(dir, view.path)) ? { reach: "reached" } : { reach: "not_reached" }),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
6
20
|
const ask = (message) => ({ action: "ask", message, decisionReason: "rule" });
|
|
7
21
|
function absoluteRootOf(rootPath, envCwd) {
|
|
8
22
|
return rootPath === undefined ? undefined : lexicalViewOf(rootPath, envCwd);
|
|
@@ -56,10 +70,12 @@ export function createFsWriteGatePolicy(opts) {
|
|
|
56
70
|
if (!canon.ok) {
|
|
57
71
|
return ask(`write to "${path}" requires approval: its real target could not be resolved (${canon.message})${advisory}`);
|
|
58
72
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
73
|
+
const advertised = req.advertisedWritableRoots ?? [];
|
|
74
|
+
const targetViews = { views: [{ path: canon.key, kind: "canonical" }] };
|
|
75
|
+
const admitted = { configured: [], accepted: [] };
|
|
76
|
+
const admits = () => judgePathRows([domainRow("advertised", advertised), domainRow("configured", admitted.configured), domainRow("accepted", admitted.accepted)], targetViews, "allow") !== undefined;
|
|
77
|
+
if (admits())
|
|
78
|
+
return { action: "allow" };
|
|
63
79
|
let fenceRootsCanonical;
|
|
64
80
|
let refusedDomain;
|
|
65
81
|
for (const [dirs, structural] of [
|
|
@@ -87,7 +103,8 @@ export function createFsWriteGatePolicy(opts) {
|
|
|
87
103
|
continue;
|
|
88
104
|
}
|
|
89
105
|
}
|
|
90
|
-
|
|
106
|
+
(structural ? admitted.configured : admitted.accepted).push(dir.key);
|
|
107
|
+
if (admits())
|
|
91
108
|
return { action: "allow" };
|
|
92
109
|
}
|
|
93
110
|
}
|
|
@@ -35,19 +35,34 @@ export declare const DEFAULT_GATE_AWAIT_TIMEOUT_MS = 30000;
|
|
|
35
35
|
export declare function createGateDeadline(input: {
|
|
36
36
|
approvalTimeoutMs?: number;
|
|
37
37
|
}, notifier: Parameters<typeof traceHookCrash>[2]): () => number;
|
|
38
|
+
/** What ONE source of a judgment answered: its value, or its absence and why (it threw — synchronously or not — or did not
|
|
39
|
+
* answer before the judgment's signal ended the wait; `gateWaitFailureOf(cause)` says which wait ended it). */
|
|
40
|
+
export type SourceAnswer<T> = {
|
|
41
|
+
readonly ok: true;
|
|
42
|
+
readonly value: T;
|
|
43
|
+
} | {
|
|
44
|
+
readonly ok: false;
|
|
45
|
+
readonly cause: unknown;
|
|
46
|
+
};
|
|
38
47
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
* THE one way a source enters a path judgment — an environment lookup (the real target, the link chain, a root's key) or a
|
|
49
|
+
* provider of rows (a deployment's guarded write rows): asked, bounded by the signal the judgment was handed (the gate's
|
|
50
|
+
* deadline), and SETTLED — never thrown. A source that fails or does not answer in time is absent on its own (its view does not
|
|
51
|
+
* vote, its root exempts nothing, its rows are held unplaced), and every other source's answer stands: no source's failure
|
|
52
|
+
* reaches the judgment as a whole. No signal (a host calling a judge directly) ⇒ bounded by {@link DEFAULT_GATE_AWAIT_TIMEOUT_MS}.
|
|
53
|
+
*/
|
|
54
|
+
export declare function fromSource<T>(ask: () => Promise<T>, signal: AbortSignal | undefined, label: string): Promise<SourceAnswer<T>>;
|
|
55
|
+
/**
|
|
56
|
+
* The write-protection judgment at both of its gate call sites. The gate's ONE deadline is handed DOWN as the judgment's
|
|
57
|
+
* signal, so it bounds each of the judgment's sources on its own ({@link fromSource}): a view that did not answer in time takes no
|
|
58
|
+
* part, an exemption root whose key did not come back exempts nothing, and a row a view already met stays met — the one
|
|
59
|
+
* absence law of every path table, per lookup. `judge` returns `null` synchronously for a call it does not cover (no deadline
|
|
60
|
+
* is armed, no seat read); `undefined` is returned then.
|
|
46
61
|
*
|
|
47
|
-
*
|
|
48
|
-
* a
|
|
49
|
-
*
|
|
50
|
-
* the
|
|
51
|
-
*
|
|
62
|
+
* The wait here is the LIVENESS net for a judgment that does not observe the signal it was handed, and it ends one turn of the
|
|
63
|
+
* event loop AFTER the deadline: a judgment whose every lookup races the signal (the engine's) has settled by then with what it
|
|
64
|
+
* found, so the net never stands in for its answer. A judgment that never came back, or threw, determined nothing about where
|
|
65
|
+
* the write lands, and the table it judges for has rows: `unresolvable` (the one absence law's target arm — refused), reported
|
|
66
|
+
* as a deployment callback failing.
|
|
52
67
|
*/
|
|
53
|
-
export declare function awaitWriteProtectionJudgment(
|
|
68
|
+
export declare function awaitWriteProtectionJudgment(judge: (signal: AbortSignal) => Promise<WriteProtectionVerdict> | null, deadlineMs: () => number, signal?: AbortSignal, onFailure?: (err: unknown) => void): Promise<WriteProtectionVerdict | undefined>;
|
|
@@ -23,7 +23,15 @@ export function withGateTimeout(p, ms, signal, label = "reversibilityProbe") {
|
|
|
23
23
|
signal?.removeEventListener("abort", onAbort);
|
|
24
24
|
fn(v);
|
|
25
25
|
};
|
|
26
|
-
const onAbort = () =>
|
|
26
|
+
const onAbort = () => {
|
|
27
|
+
const reason = signal?.reason;
|
|
28
|
+
const ended = gateWaitFailureOf(reason) !== undefined
|
|
29
|
+
? reason
|
|
30
|
+
: reason?.name === "TimeoutError"
|
|
31
|
+
? gateWaitError(`${label} timed out (its deadline elapsed)`, "timeout")
|
|
32
|
+
: gateWaitError(`${label} aborted (task ended)`, "aborted");
|
|
33
|
+
done(reject, ended);
|
|
34
|
+
};
|
|
27
35
|
const timer = ms !== undefined
|
|
28
36
|
? setTimeout(() => done(reject, gateWaitError(`${label} timed out after ${ms}ms`, "timeout")), ms)
|
|
29
37
|
: undefined;
|
|
@@ -53,12 +61,41 @@ export function createGateDeadline(input, notifier) {
|
|
|
53
61
|
return resolved;
|
|
54
62
|
};
|
|
55
63
|
}
|
|
56
|
-
export async function
|
|
64
|
+
export async function fromSource(ask, signal, label) {
|
|
57
65
|
try {
|
|
58
|
-
return await withGateTimeout(
|
|
66
|
+
return { ok: true, value: await withGateTimeout(Promise.resolve().then(ask), signal === undefined ? DEFAULT_GATE_AWAIT_TIMEOUT_MS : undefined, signal, label) };
|
|
67
|
+
}
|
|
68
|
+
catch (cause) {
|
|
69
|
+
return { ok: false, cause };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export async function awaitWriteProtectionJudgment(judge, deadlineMs, signal, onFailure) {
|
|
73
|
+
const deadline = new AbortController();
|
|
74
|
+
const judged = judge(deadline.signal);
|
|
75
|
+
if (judged === null)
|
|
76
|
+
return undefined;
|
|
77
|
+
const ms = deadlineMs();
|
|
78
|
+
const net = new AbortController();
|
|
79
|
+
const endBoth = (reason) => {
|
|
80
|
+
if (!deadline.signal.aborted)
|
|
81
|
+
deadline.abort(reason);
|
|
82
|
+
setImmediate(() => net.abort(reason));
|
|
83
|
+
};
|
|
84
|
+
const timer = setTimeout(() => endBoth(gateWaitError(`writeProtectionJudge timed out after ${ms}ms`, "timeout")), ms);
|
|
85
|
+
const onTaskAbort = () => endBoth(gateWaitError("writeProtectionJudge aborted (task ended)", "aborted"));
|
|
86
|
+
if (signal?.aborted === true)
|
|
87
|
+
onTaskAbort();
|
|
88
|
+
else
|
|
89
|
+
signal?.addEventListener("abort", onTaskAbort);
|
|
90
|
+
try {
|
|
91
|
+
return await withGateTimeout(judged, undefined, net.signal, "writeProtectionJudge");
|
|
59
92
|
}
|
|
60
93
|
catch (err) {
|
|
61
94
|
onFailure?.(err);
|
|
62
|
-
return { kind: "unresolvable", cause: thrownText(err)
|
|
95
|
+
return { kind: "unresolvable", cause: `the write-protection judgment did not answer: ${thrownText(err)}`, unresolvedSymlink: false };
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
signal?.removeEventListener("abort", onTaskAbort);
|
|
63
100
|
}
|
|
64
101
|
}
|
package/dist/core/gate-fold.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GatePass } from "./runner/gate-exit.js";
|
|
2
2
|
import type { ToolGateResult } from "./hooks.js";
|
|
3
3
|
/**
|
|
4
4
|
* Run the fold over the pass: adjudicate, fold the hook-ask, tighten. Writes `req` (re-minted over the FINAL
|
package/dist/core/gate-fold.js
CHANGED
|
@@ -2,9 +2,8 @@ import { inlineUntrusted } from "./untrusted-text.js";
|
|
|
2
2
|
import { markTightenMessage } from "./safety-axis-vocab.js";
|
|
3
3
|
import { PROBE_REASON_MAX, normalizeProbeCause } from "./checkpoint-store.js";
|
|
4
4
|
import { normalizeReadRootCandidate } from "./read-root-candidate.js";
|
|
5
|
-
import { passAskFace } from "./runner/gate-exit.js";
|
|
6
5
|
import { traceHookCrash } from "./gate-crash-trace.js";
|
|
7
|
-
import { writeProtectionMandated, writeProtectionTightenDecision
|
|
6
|
+
import { writeProtectionMandated, writeProtectionTightenDecision } from "./write-protect.js";
|
|
8
7
|
import { createGateDeadline, awaitWriteProtectionJudgment, gateWaitFailureOf, withGateTimeout } from "./gate-bounded-await.js";
|
|
9
8
|
import { thrownText } from "./thrown-value.js";
|
|
10
9
|
import { refuseOutOfContractDecision } from "./tool-policy.js";
|
|
@@ -18,10 +17,11 @@ export async function runGateFold(pass) {
|
|
|
18
17
|
pass.req = await stamped;
|
|
19
18
|
pass.decision = adjudicate ? refuseOutOfContractDecision(await (callSignal !== undefined ? adjudicate(pass.req, callSignal) : adjudicate(pass.req))) : { action: "allow" };
|
|
20
19
|
{
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const read = ledger.fromDecision(pass.decision);
|
|
21
|
+
pass.decision = read.decision;
|
|
22
|
+
if (read.deniedBy !== undefined)
|
|
23
|
+
pass.deniedBy = read.deniedBy;
|
|
24
|
+
if (read.deniedBy !== undefined)
|
|
25
25
|
pass.denyCause = ledger.causeOf(pass.decision);
|
|
26
26
|
const attributed = ledger.classifierRoundOf(pass.decision);
|
|
27
27
|
if (attributed !== undefined)
|
|
@@ -154,21 +154,18 @@ export async function runGateFold(pass) {
|
|
|
154
154
|
}
|
|
155
155
|
const writeProtectionStanding = pass.decision.action;
|
|
156
156
|
if ((writeProtectionStanding === "allow" || writeProtectionStanding === "ask") && input.writeProtectionCheck !== undefined) {
|
|
157
|
-
const
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
157
|
+
const check = input.writeProtectionCheck;
|
|
158
|
+
const judgedArgs = pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput;
|
|
159
|
+
const verdict = await awaitWriteProtectionJudgment((deadline) => check(toolName, judgedArgs, pass.req.face, input.trackedCwd?.(), deadline), boundedAwaitDeadlineMs, pass.callSignal ?? input.abortSignal, (err) => {
|
|
160
|
+
const kind = gateWaitFailureOf(err);
|
|
161
|
+
if (kind === "aborted" || input.abortSignal?.aborted === true)
|
|
162
|
+
return;
|
|
163
|
+
traceHookCrash(input, new Error(`write-protection judge ${kind === "timeout" ? "timed out" : "threw"} for tool "${toolName}" (toolCallId ${toolCallId}) — this call's write target could not be judged: ${thrownText(err)}`), notifier);
|
|
164
|
+
});
|
|
166
165
|
if (verdict !== undefined && writeProtectionMandated(verdict))
|
|
167
166
|
pass.writeProtected = true;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const decision = verdict === undefined ? undefined : writeProtectionTightenDecision(toolName, verdict, passAskFace(pass));
|
|
171
|
-
if (decision !== undefined && writeProtectionStanding === "allow") {
|
|
167
|
+
const decision = verdict === undefined ? undefined : writeProtectionTightenDecision(toolName, verdict);
|
|
168
|
+
if (decision !== undefined && (writeProtectionStanding === "allow" || decision.action === "deny")) {
|
|
172
169
|
pass.decision = decision;
|
|
173
170
|
if (decision.action === "ask")
|
|
174
171
|
pass.tightenedBy = "safety";
|
|
@@ -182,10 +179,10 @@ export async function runGateFold(pass) {
|
|
|
182
179
|
}
|
|
183
180
|
return await pass.afterFold(pass);
|
|
184
181
|
}
|
|
185
|
-
function shellReadAskMessage(toolName,
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
function shellReadAskMessage(toolName, verdict) {
|
|
183
|
+
if (verdict.finding !== "outside_roots")
|
|
184
|
+
return `tool "${toolName}" reads where the session's read boundary could not establish what is read — explicit approval required`;
|
|
185
|
+
return `tool "${toolName}" ${verdict.face === "write" ? "writes" : "reads"} outside the directories allowed for this session — explicit approval required`;
|
|
189
186
|
}
|
|
190
187
|
function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
191
188
|
const account = verdict.sentence !== undefined && verdict.sentence.trim().length > 0 ? inlineUntrusted(verdict.sentence, PROBE_REASON_MAX) : undefined;
|
|
@@ -193,6 +190,8 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
193
190
|
pass.shellWritesPlaced = true;
|
|
194
191
|
if (verdict.writeProtected === true)
|
|
195
192
|
pass.writeProtected = true;
|
|
193
|
+
if (verdict.targetUnresolved === true)
|
|
194
|
+
pass.targetUnresolved = true;
|
|
196
195
|
if (verdict.unplacedOptions !== undefined)
|
|
197
196
|
pass.shellUnplacedOptions = verdict.unplacedOptions;
|
|
198
197
|
if (verdict.finding === "unestablishable" || verdict.finding === "declined" || verdict.unestablished === true)
|
|
@@ -217,7 +216,7 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
217
216
|
const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
|
|
218
217
|
pass.decision = {
|
|
219
218
|
action: "ask",
|
|
220
|
-
message: shellReadAskMessage(toolName, verdict
|
|
219
|
+
message: shellReadAskMessage(toolName, verdict),
|
|
221
220
|
decisionReason: "safety",
|
|
222
221
|
probeMandated: true,
|
|
223
222
|
...(account !== undefined ? { probeReason: account } : {}),
|
|
@@ -236,7 +235,7 @@ function applyShellReadVerdict(pass, verdict, toolName, shellGated) {
|
|
|
236
235
|
const candidate = normalizeReadRootCandidate(verdict.readRootCandidate);
|
|
237
236
|
pass.decision = {
|
|
238
237
|
action: "ask",
|
|
239
|
-
message: shellReadAskMessage(toolName, verdict
|
|
238
|
+
message: shellReadAskMessage(toolName, verdict),
|
|
240
239
|
decisionReason: "safety",
|
|
241
240
|
...(account !== undefined ? { probeReason: account } : {}),
|
|
242
241
|
...(candidate !== undefined ? { probeReadRootCandidate: candidate } : {}),
|