@sema-agent/core 7.48.0 → 7.49.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 +418 -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 +17 -24
- package/dist/core/arg-summary.js +169 -68
- 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 +32 -7
- 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 +4 -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 +27 -34
- 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/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/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 +10 -3
- package/dist/tools/fs/bash-program-position.js +21 -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 +39 -18
- package/dist/tools/fs/program-read-model.js +29 -19
- package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
- package/dist/tools/fs/program-read-model.rows.js +5 -5
- 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 +51 -42
- 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 +48 -18
- package/dist/tools/fs/shell-read-judge.js +33 -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,9 +1,9 @@
|
|
|
1
1
|
import { planShellReads } from "./shell-read-plan.js";
|
|
2
2
|
import { literalTextOf } from "../../shell/lex.js";
|
|
3
3
|
import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isAbsoluteForFamily, isWinFormPath, normalizeAbsPathLexically } from "./safety.js";
|
|
5
5
|
import { launchedCommands, launchedReadings, reentryText, scriptFileAt, spellLaunched } from "./shell-reentry-text.js";
|
|
6
|
-
import {
|
|
6
|
+
import { readProgramPosition } from "./bash-program-position.js";
|
|
7
7
|
import { bashClassifyDefaultAllow } from "./bash-readonly-classifier.js";
|
|
8
8
|
import { programArgs } from "./shell-read-write-targets.js";
|
|
9
9
|
import { implementationsOf, programRow, runsShellText, selectedOptions, writeReadings } from "./program-read-model.js";
|
|
@@ -25,16 +25,16 @@ function driveOf(path, key) {
|
|
|
25
25
|
return isWinFormPath(path) && key.length >= 2 && key[1] === ":" ? key.slice(0, 2) : "";
|
|
26
26
|
}
|
|
27
27
|
export function dangerousRemovalOf(path, seat) {
|
|
28
|
-
if (!
|
|
28
|
+
if (!isAbsoluteForFamily("own", path))
|
|
29
29
|
return undefined;
|
|
30
30
|
const k = removalKey(path);
|
|
31
31
|
const rest = k.slice(driveOf(path, k).length);
|
|
32
32
|
if (rest === "/" || /^\/\/[^/]+\/[^/]+$/.test(k))
|
|
33
33
|
return "filesystem_root";
|
|
34
|
-
if (seat.homes.some((h) =>
|
|
34
|
+
if (seat.homes.some((h) => isAbsoluteForFamily("own", h) && removalKey(h) === k))
|
|
35
35
|
return "home";
|
|
36
36
|
const prefix = k.endsWith("/") ? k : `${k}/`;
|
|
37
|
-
if (seat.workspace.some((w) =>
|
|
37
|
+
if (seat.workspace.some((w) => isAbsoluteForFamily("own", w) && (removalKey(w) === k || removalKey(w).startsWith(prefix))))
|
|
38
38
|
return "workspace";
|
|
39
39
|
if (/^\/[^/]+$/.test(rest))
|
|
40
40
|
return "top_level";
|
|
@@ -56,53 +56,17 @@ function removalKindOf(read, seat) {
|
|
|
56
56
|
}
|
|
57
57
|
return read.established === "unestablishable" && tildeNamesAHome(read.candidate.spelled) ? "home" : undefined;
|
|
58
58
|
}
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const [head, name] = segment.argv;
|
|
71
|
-
if (isShellSyntaxWord(head, LOOP_LIST_HEADS) && name !== undefined && NAME.test(name.folded)) {
|
|
72
|
-
const at = segment.argv.findIndex((w, i) => i > 1 && w.folded === "in");
|
|
73
|
-
const words = at < 0 ? [undefined] : segment.argv.slice(at + 1).map((w) => literalTextOf(w.pieces));
|
|
74
|
-
for (const v of words.length > 0 ? words : [undefined])
|
|
75
|
-
bind(name.folded, v);
|
|
76
|
-
}
|
|
77
|
-
if (head !== undefined && NAME_BINDERS.has(head.folded))
|
|
78
|
-
for (const w of segment.argv.slice(1))
|
|
79
|
-
if (w.assignment === undefined && NAME.test(w.folded))
|
|
80
|
-
bind(w.folded, undefined);
|
|
81
|
-
}
|
|
82
|
-
return out;
|
|
83
|
-
}
|
|
84
|
-
const BOUND_SPELLINGS_MAX = 64;
|
|
85
|
-
function boundSpellingsOf(word, bindings) {
|
|
86
|
-
const named = word.pieces.filter((q) => q.literal === undefined);
|
|
87
|
-
if (named.length === 0 || !named.some((q) => q.expansion?.kind === "parameter" && q.expansion.name !== undefined && bindings.has(q.expansion.name)))
|
|
88
|
-
return undefined;
|
|
89
|
-
let spellings = [""];
|
|
90
|
-
for (const q of word.pieces) {
|
|
91
|
-
if (q.literal !== undefined) {
|
|
92
|
-
spellings = spellings.map((sp) => sp + q.literal);
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
const name = q.expansion?.kind === "parameter" && (q.expansion.body === undefined || q.expansion.body === q.expansion.name) ? q.expansion.name : undefined;
|
|
96
|
-
const values = name !== undefined ? bindings.get(name) : undefined;
|
|
97
|
-
if (name === undefined || values === undefined)
|
|
98
|
-
return { unreadable: q.expansion?.name ?? word.raw };
|
|
99
|
-
if (values.some((v) => v === undefined || (q.quotedBy === undefined && /\s/.test(v))))
|
|
100
|
-
return { unreadable: name };
|
|
101
|
-
spellings = spellings.flatMap((sp) => values.map((v) => sp + v));
|
|
102
|
-
if (spellings.length > BOUND_SPELLINGS_MAX)
|
|
103
|
-
return { unreadable: name };
|
|
104
|
-
}
|
|
105
|
-
return { spellings };
|
|
59
|
+
export const KNOWN_SAFE_ROOTS = Object.freeze(["TMPDIR", "HOME"]);
|
|
60
|
+
function belowKnownSafeRoot(word, safe, segment) {
|
|
61
|
+
const [head, ...rest] = word.pieces;
|
|
62
|
+
const e = head?.expansion;
|
|
63
|
+
const name = e?.kind === "parameter" && (e.body === undefined || e.body === e.name) ? e.name : undefined;
|
|
64
|
+
if (name === undefined || !safe.has(name) || segment.rebound === "all" || segment.rebound.has(name))
|
|
65
|
+
return false;
|
|
66
|
+
if (rest.some((p) => p.literal === undefined))
|
|
67
|
+
return false;
|
|
68
|
+
const below = rest.map((p) => p.literal).join("");
|
|
69
|
+
return /^\/[^*?[\]]+$/.test(below) && !below.split("/").includes("..");
|
|
106
70
|
}
|
|
107
71
|
function recursiveForce(row, args) {
|
|
108
72
|
return implementationsOf(row).some((view) => {
|
|
@@ -110,9 +74,11 @@ function recursiveForce(row, args) {
|
|
|
110
74
|
return selected.some((o) => o.selects === "traversal") && selected.some((o) => o.mode === "forced");
|
|
111
75
|
});
|
|
112
76
|
}
|
|
113
|
-
export function removalFindingsOf(established, seat) {
|
|
77
|
+
export function removalFindingsOf(established, seat, safeRoots = KNOWN_SAFE_ROOTS, enclosingRelocated = false) {
|
|
78
|
+
if (unreadPlan(established.plan))
|
|
79
|
+
return [{ guard: "unverifiable_shell_text", program: "bash", text: established.plan.unreadable, source: "unread" }];
|
|
114
80
|
const out = [];
|
|
115
|
-
const
|
|
81
|
+
const safe = new Set(safeRoots);
|
|
116
82
|
for (const segment of established.plan.segments) {
|
|
117
83
|
const program = segment.verb?.basename;
|
|
118
84
|
const row = program !== undefined && REMOVAL_COMMAND_SET.has(program) ? programRow(program) : undefined;
|
|
@@ -121,45 +87,41 @@ export function removalFindingsOf(established, seat) {
|
|
|
121
87
|
const spelled = args.map((w) => w.spelled);
|
|
122
88
|
const removed = new Set(writeReadings(row, spelled).flatMap((r) => r.written.map((w) => w.at)));
|
|
123
89
|
const options = new Set(args.filter((_, at) => !removed.has(at)).map((w) => w.raw));
|
|
90
|
+
const forced = recursiveForce(row, spelled);
|
|
91
|
+
if (forced && segment.reentry === "argv")
|
|
92
|
+
out.push({ guard: "unverifiable_delete", program, operand: segment.text.trim(), source: "stream" });
|
|
93
|
+
const relocated = enclosingRelocated || readProgramPosition(segment.argv).launcherMovesBase;
|
|
124
94
|
for (const read of established.reads.get(segment) ?? []) {
|
|
125
95
|
if (read.candidate.face !== "write" || options.has(read.candidate.raw))
|
|
126
96
|
continue;
|
|
127
97
|
const kind = removalKindOf(read, seat);
|
|
128
98
|
if (kind !== undefined) {
|
|
129
|
-
|
|
99
|
+
const untracked = read.candidate.bases === "unmodelled" ? established.plan.segments.find((s) => s.bases === "unmodelled")?.text.trim() : undefined;
|
|
100
|
+
out.push({ guard: "dangerous_delete", kind, program, operand: read.candidate.raw, target: read.target ?? read.candidate.floorSpelled ?? read.candidate.spelled, ...(untracked !== undefined ? { untrackedFrom: untracked } : {}) });
|
|
130
101
|
continue;
|
|
131
102
|
}
|
|
132
|
-
if (read.established !== "unestablishable")
|
|
103
|
+
if (!forced || read.established !== "unestablishable" || (read.candidate.expands !== "unresolvable" && !relocated))
|
|
133
104
|
continue;
|
|
134
105
|
const word = segment.argv.find((w) => w.raw === read.candidate.raw);
|
|
135
|
-
|
|
136
|
-
if (bound === undefined)
|
|
106
|
+
if (word !== undefined && belowKnownSafeRoot(word, safe, segment))
|
|
137
107
|
continue;
|
|
138
|
-
|
|
139
|
-
if (recursiveForce(row, spelled))
|
|
140
|
-
out.push({ guard: "unverifiable_delete", program, operand: read.candidate.raw, name: bound.unreadable });
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
const bases = segment.bases === "unmodelled" ? (read.candidate.floorBases ?? []) : segment.bases;
|
|
144
|
-
for (const spelled of bound.spellings) {
|
|
145
|
-
const views = isAbsolutePathForm(spelled) ? [spelled] : bases.map((base) => `${base}/${spelled}`);
|
|
146
|
-
for (const view of views) {
|
|
147
|
-
const hit = dangerousRemovalOf(view, seat);
|
|
148
|
-
if (hit === undefined)
|
|
149
|
-
continue;
|
|
150
|
-
out.push({ guard: "dangerous_delete", kind: hit, program, operand: read.candidate.raw, target: normalizeAbsPathLexically(view) });
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
108
|
+
out.push({ guard: "unverifiable_delete", program, operand: read.candidate.raw, source: read.candidate.expands === "unresolvable" ? "rewritten" : "relocated" });
|
|
154
109
|
}
|
|
155
110
|
}
|
|
156
111
|
const script = runtimeScriptOf(segment);
|
|
157
112
|
if (script !== undefined && program !== undefined)
|
|
158
|
-
out.push({ guard: "
|
|
113
|
+
out.push({ guard: "unverifiable_shell_text", program, text: script, source: "produced" });
|
|
114
|
+
if (programUnread(segment))
|
|
115
|
+
out.push({ guard: "unverifiable_shell_text", program: segment.launcherChain[0] ?? segment.text.trim(), text: segment.text.trim(), source: "unread" });
|
|
116
|
+
const handedRelocated = enclosingRelocated || readProgramPosition(segment.argv).launcherMovesBase;
|
|
159
117
|
for (const nested of segment.nested) {
|
|
118
|
+
if (unreadPlan(nested)) {
|
|
119
|
+
out.push({ guard: "unverifiable_shell_text", program: program ?? segment.text.trim(), text: segment.text.trim(), source: "unread" });
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
160
122
|
const sub = established.nested.get(nested);
|
|
161
123
|
if (sub !== undefined)
|
|
162
|
-
out.push(...removalFindingsOf(sub, seat));
|
|
124
|
+
out.push(...removalFindingsOf(sub, seat, safeRoots, handedRelocated));
|
|
163
125
|
}
|
|
164
126
|
}
|
|
165
127
|
return out;
|
|
@@ -187,38 +149,54 @@ function runtimeScriptOf(segment) {
|
|
|
187
149
|
const named = pos.program !== undefined && pos.refusal === undefined ? [{ shell: program.basename, words: segment.argv.slice(pos.program.index + 1).map((_, k) => spell(pos.program.index + 1 + k)) }] : [];
|
|
188
150
|
const launched = launchedCommands(segment.argv, pos).flatMap((c) => {
|
|
189
151
|
const shell = launchedReadings(segment.argv, c).shell;
|
|
190
|
-
return shell === undefined ? [] : spellLaunched(segment.argv, c.args, { word: spell })
|
|
152
|
+
return shell === undefined ? [] : [{ shell, words: spellLaunched(segment.argv, c.args, { word: spell }) }];
|
|
191
153
|
});
|
|
192
154
|
const texts = [...named, ...launched].flatMap(({ shell, words }) => [reentryText(shell, words), ...(segment.stdin ?? []).map((s) => reentryText(shell, words, s.literal ?? `${MARK}${s.from}`))]);
|
|
193
155
|
const text = texts.find((t) => t?.includes(MARK) === true);
|
|
194
156
|
return text === undefined ? undefined : text.split(MARK).join("");
|
|
195
157
|
}
|
|
158
|
+
const unreadPlan = (plan) => plan.unreadable !== undefined && plan.segments.length === 0;
|
|
159
|
+
const programUnread = (s) => s.declines.includes("unreadable_program_position");
|
|
196
160
|
export function planRunsRemoval(plan) {
|
|
197
|
-
return plan.segments.some((s) => (s.verb !== undefined && REMOVAL_COMMAND_SET.has(s.verb.basename)) || runtimeScriptOf(s) !== undefined || s.nested.some(planRunsRemoval));
|
|
161
|
+
return unreadPlan(plan) || plan.segments.some((s) => (s.verb !== undefined && REMOVAL_COMMAND_SET.has(s.verb.basename)) || runtimeScriptOf(s) !== undefined || programUnread(s) || s.nested.some(planRunsRemoval));
|
|
198
162
|
}
|
|
199
163
|
const DANGEROUS_REMOVAL_SENTENCE = {
|
|
200
164
|
filesystem_root: (p, t) => `\`${p}\` would remove the filesystem root (${t})`,
|
|
201
165
|
home: (p, t) => `\`${p}\` would remove a home directory (${t})`,
|
|
202
166
|
workspace: (p, t) => `\`${p}\` would remove a workspace directory — the task root, the working directory or an additional working directory — or one of its ancestors (${t})`,
|
|
203
167
|
top_level: (p, t) => `\`${p}\` would remove a top-level system directory (${t})`,
|
|
204
|
-
|
|
168
|
+
};
|
|
169
|
+
const UNVERIFIABLE_REMOVAL_SENTENCE = {
|
|
170
|
+
rewritten: (p, o) => `\`${p}\` recursive+force target ${o} is rewritten by the shell from a value this command does not settle (a name with no value here or one it sets in a form the guard cannot read, a substitution, a parameter operator) — the deleted path cannot be verified from this command`,
|
|
171
|
+
stream: (p, o) => `\`${p}\` recursive+force takes its targets from the stream it is fed (${o}) — the deleted paths cannot be verified from this command`,
|
|
172
|
+
relocated: (p, o) => `\`${p}\` recursive+force target ${o} is relative to a directory a launcher option moved the program into, which this command does not settle — the deleted path cannot be verified from this command`,
|
|
173
|
+
};
|
|
174
|
+
const UNREADABLE_TEXT_SENTENCE = {
|
|
175
|
+
produced: (p, t) => `\`${p}\` runs shell text that is built only when the command runs (${t}) — the text this shell will run cannot be read by the engine, so whether it removes anything is unknown`,
|
|
176
|
+
unread: (p, t) => `\`${p}\` runs shell text this guard cannot read (${t}) — the text this shell will run cannot be read by the engine, so whether it removes anything is unknown`,
|
|
205
177
|
};
|
|
206
178
|
function verdictOf(findings) {
|
|
207
|
-
for (const f of findings)
|
|
208
|
-
if (f.guard
|
|
209
|
-
|
|
179
|
+
for (const f of findings) {
|
|
180
|
+
if (f.guard !== "dangerous_delete")
|
|
181
|
+
continue;
|
|
182
|
+
const untracked = f.untrackedFrom === undefined ? "" : ` — the working directory is not tracked from \`${inlineUntrusted(f.untrackedFrom, 120)}\` on (a directory change before it cannot be followed), so this target was judged where the command stood when tracking stopped`;
|
|
183
|
+
return { guard: f.guard, text: `${DANGEROUS_REMOVAL_SENTENCE[f.kind](f.program, inlineUntrusted(f.target, 200))}${untracked}` };
|
|
184
|
+
}
|
|
210
185
|
for (const f of findings)
|
|
211
186
|
if (f.guard === "unverifiable_delete")
|
|
212
|
-
return { guard: f.guard, text:
|
|
187
|
+
return { guard: f.guard, text: UNVERIFIABLE_REMOVAL_SENTENCE[f.source](f.program, inlineUntrusted(f.operand, 200)) };
|
|
188
|
+
for (const f of findings)
|
|
189
|
+
if (f.guard === "unverifiable_shell_text")
|
|
190
|
+
return { guard: f.guard, text: UNREADABLE_TEXT_SENTENCE[f.source](f.program, inlineUntrusted(f.text, 200)) };
|
|
213
191
|
return undefined;
|
|
214
192
|
}
|
|
215
193
|
const REMOVAL_RESOLVE_TIMEOUT_MS = 10_000;
|
|
216
|
-
export function removalReadingOf(command, req, seat) {
|
|
194
|
+
export function removalReadingOf(command, req, seat, safeRoots = KNOWN_SAFE_ROOTS) {
|
|
217
195
|
const homeDir = seat?.env?.homeDir;
|
|
218
196
|
const cwd = req.cwd ?? req.root ?? "";
|
|
219
197
|
const roots = req.root !== undefined ? [req.root] : cwd !== "" ? [cwd] : [];
|
|
220
198
|
const boundary = { roots, ...(cwd !== "" ? { cwd } : {}), ...(homeDir !== undefined ? { homeDir } : {}) };
|
|
221
|
-
const plan = planShellReads(command, { readers: new Set(bashClassifyDefaultAllow()), cwd, roots, ...(homeDir !== undefined ? { homeDir } : {}) });
|
|
199
|
+
const plan = planShellReads(command, { readers: new Set(bashClassifyDefaultAllow()), cwd, roots, cdPath: seat?.env?.cdPath ?? "unknown", ...(homeDir !== undefined ? { homeDir } : {}) });
|
|
222
200
|
if (!planRunsRemoval(plan))
|
|
223
201
|
return undefined;
|
|
224
202
|
return {
|
|
@@ -229,11 +207,11 @@ export function removalReadingOf(command, req, seat) {
|
|
|
229
207
|
homes: [...(homeDir !== undefined ? [homeDir] : []), ...(resolved !== undefined && resolved.ok ? [resolved.value] : [])],
|
|
230
208
|
workspace: [...(req.root !== undefined ? [req.root] : []), ...(req.cwd !== undefined ? [req.cwd] : []), ...(seat?.additionalRoots?.() ?? [])],
|
|
231
209
|
};
|
|
232
|
-
const lexical = removalFindingsOf(establishShellReadsLexically(plan, boundary), removalSeat);
|
|
210
|
+
const lexical = removalFindingsOf(establishShellReadsLexically(plan, boundary), removalSeat, safeRoots);
|
|
233
211
|
if (lexical.some((f) => f.guard === "dangerous_delete") || env === undefined || roots.length === 0)
|
|
234
212
|
return verdictOf(lexical);
|
|
235
213
|
const established = await resolvedOrUndefined(createShellReadEstablisher(env, roots, { rootsCanonical: true }).establish(plan, boundary, signal), signal);
|
|
236
|
-
return verdictOf(established === undefined ? lexical : [...removalFindingsOf(established, removalSeat), ...lexical]);
|
|
214
|
+
return verdictOf(established === undefined ? lexical : [...removalFindingsOf(established, removalSeat, safeRoots), ...lexical]);
|
|
237
215
|
},
|
|
238
216
|
};
|
|
239
217
|
}
|
|
@@ -10,7 +10,8 @@ import { protectivePathTargetOf, type ToolCallLike } from "../../core/tool-regis
|
|
|
10
10
|
* hole) or fail-closed (deny a legitimate write). Single source.
|
|
11
11
|
*
|
|
12
12
|
* The `path` arm is deliberately BROADER than what Read/Edit/Write accept: their schema requires
|
|
13
|
-
* `file_path`
|
|
13
|
+
* `file_path` (fs-shared.ts FILE_PATH_PARAMS; Write alone repairs the `path` spelling onto it BEFORE validation,
|
|
14
|
+
* `coerceWriteArguments`, so a gate never sees the alias there), but this reader is
|
|
14
15
|
* shared with gates that judge OTHER tool vocabularies — Glob's real `path` parameter, deployment-authored tools —
|
|
15
16
|
* and a gate must never see LESS than the tool it is confining might act on. So the asymmetry is the design: the
|
|
16
17
|
* schema decides what a caller may send, this decides what gets judged, and this side over-reads on purpose.
|
|
@@ -114,21 +115,12 @@ export interface FsViolation {
|
|
|
114
115
|
message: string;
|
|
115
116
|
}
|
|
116
117
|
/**
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* coordinate leaves every other copy judging the same string differently, and this predicate gates a
|
|
122
|
-
* security fence (frozen-path deny, readonly-boundary containment) as well as URI key minting.
|
|
123
|
-
* Callers that need a family the predicate does not cover must widen it HERE, not locally.
|
|
124
|
-
*
|
|
125
|
-
* The UNC arm (`\\host\share\…`) is the shape that drift produced: held privately in one consumer, it
|
|
126
|
-
* made that consumer resolve a UNC path as absolute while a sibling prefixed it with the task root —
|
|
127
|
-
* two URI keys for one file. Folding it in here settles the disagreement in the direction the rest of
|
|
128
|
-
* this file takes: a literal `\\host\share\…` is win-form (see {@link isWinFormPath}) and `within()`
|
|
129
|
-
* lands it outside every POSIX/drive root, i.e. a location the working directory does not contain.
|
|
118
|
+
* Is a spelling relative in EVERY family — neither `/`- nor `\`-rooted and carrying no drive letter (not even the
|
|
119
|
+
* drive-relative `C:x`)? The tamper check of a recorded relative key reads this (a record that is absolute, rooted or
|
|
120
|
+
* drive-bearing in ANY family is refused there): the opposite stance from {@link isAbsoluteForFamily}, which answers
|
|
121
|
+
* one family's question, so it is a separate, named predicate rather than a mode of that one.
|
|
130
122
|
*/
|
|
131
|
-
export declare function
|
|
123
|
+
export declare function relativeInEveryFamily(p: string): boolean;
|
|
132
124
|
/** Does this absolute spelling name the opening process's STANDARD INPUT (`/dev/stdin`, `/dev/fd/0`, `/proc/<pid>/fd/0`),
|
|
133
125
|
* folded lexically first (`/dev/./stdin`, `/dev//fd/0`)? */
|
|
134
126
|
export declare function namesStandardInput(path: string): boolean;
|
|
@@ -306,13 +298,19 @@ export declare function pathFamilyOf(bases: {
|
|
|
306
298
|
* reads it. The ONE UNC recognizer behind {@link isAbsoluteForFamily}, {@link pathIdentityOf} and
|
|
307
299
|
* {@link joinForFamily}. */
|
|
308
300
|
export declare function isUncSpelling(p: string): boolean;
|
|
309
|
-
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
301
|
+
/** Where a reading takes its family from: a tree's ({@link PathFamily}), or `"own"` — an address with no tree to place
|
|
302
|
+
* it reads its OWN spelling as the family source (the {@link pathFamilyOf} of that spelling), so a treeless `C:\x` and a
|
|
303
|
+
* treeless `/x` are each read in their own family rather than one of them being declared relative. */
|
|
304
|
+
export type PathFamilySource = PathFamily | "own";
|
|
305
|
+
/** The family a {@link PathFamilySource} names for one spelling. */
|
|
306
|
+
export declare function familyFor(source: PathFamilySource, p: string): PathFamily;
|
|
307
|
+
/**
|
|
308
|
+
* FULLY QUALIFIED under the family — the ONE absoluteness predicate. win: drive-rooted (`C:\`/`C:/`) or UNC (a host AND a
|
|
309
|
+
* share: a bare `\\x` names no share and is no address) — a `/x` / `\x` is rooted-not-qualified and joins the base's drive
|
|
310
|
+
* or share root ({@link joinForFamily}), a `C:rel` is drive-relative. posix: `/`-rooted. `"own"`: the spelling's own
|
|
311
|
+
* family ({@link familyFor}) — the reading of an address no tree places.
|
|
312
|
+
*/
|
|
313
|
+
export declare function isAbsoluteForFamily(family: PathFamilySource, p: string): boolean;
|
|
316
314
|
/** The refusal words of {@link win32NamespaceScreen} — a closed set (docs/CLOSED-SETS.md). */
|
|
317
315
|
export declare const WIN32_NAMESPACE_REFUSALS: readonly ["device_namespace", "unmappable_namespace", "unc_on_posix_tree", "drive_relative"];
|
|
318
316
|
export type Win32NamespaceRefusal = (typeof WIN32_NAMESPACE_REFUSALS)[number];
|
|
@@ -436,6 +434,14 @@ export declare function foldTrailingSeparators(spelled: string, family: PathFami
|
|
|
436
434
|
* share root, anything else under the base with the base's own separator. posix = `/`-join.
|
|
437
435
|
*/
|
|
438
436
|
export declare function joinForFamily(family: PathFamily, base: string, rel: string): string;
|
|
437
|
+
/**
|
|
438
|
+
* THE anchor step of every path reading: a spelling fully qualified under the family stands as spelled; any other is joined
|
|
439
|
+
* to `base` ({@link joinForFamily}, unfolded). One definition, so "already absolute, therefore do not prepend a base" is
|
|
440
|
+
* decided in one place for every reader — the path prelude (`readPath`, effective-path-target.ts), the canonicalizer, a
|
|
441
|
+
* link's target against its parent, a search tool's root-relative output. Callers that need the namespace screen or an
|
|
442
|
+
* identity read the prelude; this is only its anchor.
|
|
443
|
+
*/
|
|
444
|
+
export declare function anchorSpelling(family: PathFamily, base: string, spelled: string): string;
|
|
439
445
|
/** The family-aware LEXICAL view of a possibly-relative spelling against a resolution base (no I/O,
|
|
440
446
|
* `.`/`..` folded via {@link normalizeAbsPathLexically}): the SECOND deny-judgment view. It asks
|
|
441
447
|
* "does the NAME land on a guarded path", complementing the canonical
|
|
@@ -456,6 +462,7 @@ export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, pat
|
|
|
456
462
|
readonly homeViews?: HomeViewSource;
|
|
457
463
|
matchTarget(canonicalKey: string, lexicalView?: string, opts?: {
|
|
458
464
|
readonly aliasResolved?: boolean;
|
|
465
|
+
readonly hops?: readonly string[];
|
|
459
466
|
}): {
|
|
460
467
|
pattern: string;
|
|
461
468
|
matchedView?: string;
|
package/dist/tools/fs/safety.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { readDenySentence } from "./read-deny.js";
|
|
3
3
|
import { homeViewsOf } from "./read-deny-home.js";
|
|
4
|
+
import { skipsRootsContainment } from "./containment-face.js";
|
|
4
5
|
import { sliceHeadSafe } from "../../core/surrogate-safe-slice.js";
|
|
5
6
|
import { pathTargetValue, protectivePathTargetOf } from "../../core/tool-registry.js";
|
|
6
|
-
import {
|
|
7
|
+
import { readPath } from "../../core/effective-path-target.js";
|
|
7
8
|
import { withGateTimeout, DEFAULT_GATE_AWAIT_TIMEOUT_MS } from "../../core/gate-bounded-await.js";
|
|
8
9
|
import { thrownText } from "../../core/thrown-value.js";
|
|
9
10
|
export function fileArgPath(args) {
|
|
@@ -25,8 +26,8 @@ export function sha256(content) {
|
|
|
25
26
|
return createHash("sha256").update(content, "utf8").digest("hex");
|
|
26
27
|
}
|
|
27
28
|
const SEP = "/";
|
|
28
|
-
export function
|
|
29
|
-
return p.startsWith("/") || /^[A-Za-z]
|
|
29
|
+
export function relativeInEveryFamily(p) {
|
|
30
|
+
return !(p.startsWith("/") || p.startsWith("\\") || /^[A-Za-z]:/.test(p));
|
|
30
31
|
}
|
|
31
32
|
function nativeSepOf(p) {
|
|
32
33
|
return isWinFormPath(p) && p.includes("\\") ? "\\" : "/";
|
|
@@ -314,8 +315,11 @@ export function pathFamilyOf(bases) {
|
|
|
314
315
|
export function isUncSpelling(p) {
|
|
315
316
|
return /^[\\/]{2}[^\\/]+[\\/]+[^\\/]/.test(p);
|
|
316
317
|
}
|
|
318
|
+
export function familyFor(source, p) {
|
|
319
|
+
return source === "own" ? (isWinFormPath(p) ? "win" : "posix") : source;
|
|
320
|
+
}
|
|
317
321
|
export function isAbsoluteForFamily(family, p) {
|
|
318
|
-
return family === "win" ? /^[A-Za-z]:[\\/]/.test(p) || isUncSpelling(p) : p.startsWith("/");
|
|
322
|
+
return familyFor(family, p) === "win" ? /^[A-Za-z]:[\\/]/.test(p) || isUncSpelling(p) : p.startsWith("/");
|
|
319
323
|
}
|
|
320
324
|
export const WIN32_NAMESPACE_REFUSALS = Object.freeze(["device_namespace", "unmappable_namespace", "unc_on_posix_tree", "drive_relative"]);
|
|
321
325
|
export const WIN32_NAMESPACE_REFUSAL_TEXT = {
|
|
@@ -445,9 +449,11 @@ export function joinForFamily(family, base, rel) {
|
|
|
445
449
|
}
|
|
446
450
|
return `${base.replace(/[\\/]+$/, "")}${base.includes("\\") ? "\\" : "/"}${rel}`;
|
|
447
451
|
}
|
|
452
|
+
export function anchorSpelling(family, base, spelled) {
|
|
453
|
+
return isAbsoluteForFamily(family, spelled) ? spelled : joinForFamily(family, base, spelled);
|
|
454
|
+
}
|
|
448
455
|
export function lexicalViewOf(spelled, base) {
|
|
449
|
-
|
|
450
|
-
return normalizeAbsPathLexically(isAbsoluteForFamily(family, spelled) ? spelled : joinForFamily(family, base, spelled));
|
|
456
|
+
return normalizeAbsPathLexically(anchorSpelling(pathFamilyOf({ root: base }), base, spelled));
|
|
451
457
|
}
|
|
452
458
|
function within(rootCanonical, p) {
|
|
453
459
|
if (!rootCanonical)
|
|
@@ -462,7 +468,7 @@ function within(rootCanonical, p) {
|
|
|
462
468
|
return pN.identity.startsWith(rootN.identity.endsWith(SEP) ? rootN.identity : rootN.identity + SEP);
|
|
463
469
|
}
|
|
464
470
|
export async function resolveKey(env, rootCanonical, path, signal, baseCwd, additionalRoots, exactFileReadExemption, readDeny, containmentFace) {
|
|
465
|
-
const views = await
|
|
471
|
+
const views = await readPath(env, path, baseCwd ?? rootCanonical, { root: rootCanonical, ...(baseCwd !== undefined ? { cwd: baseCwd } : {}) }, { intent: "resolve", views: readDeny !== undefined ? "chain" : "canonical" }, signal);
|
|
466
472
|
const canon = views.canonical ?? (await canonicalizeTarget(env, path, signal, pathFamilyOf({ root: rootCanonical }), baseCwd));
|
|
467
473
|
if (!canon.ok)
|
|
468
474
|
return { ok: false, violation: { code: "invalid", message: canon.message } };
|
|
@@ -473,7 +479,7 @@ export async function resolveKey(env, rootCanonical, path, signal, baseCwd, addi
|
|
|
473
479
|
}
|
|
474
480
|
if (readDeny !== undefined) {
|
|
475
481
|
const judged = { aliasResolved: canon.aliasResolved === true, hops: views.hops };
|
|
476
|
-
const lexical = views.lexical?.kind === "path" ? spellingOfIdentity(views.lexical.identity,
|
|
482
|
+
const lexical = views.lexical?.kind === "path" ? spellingOfIdentity(views.lexical.identity, views.lexical.family) : undefined;
|
|
477
483
|
let hit = readDeny.matchTarget(key, lexical, judged);
|
|
478
484
|
if (hit === null) {
|
|
479
485
|
const homeView = await homeViewsOf(env, readDeny, signal).of(key);
|
|
@@ -493,7 +499,7 @@ export async function resolveKey(env, rootCanonical, path, signal, baseCwd, addi
|
|
|
493
499
|
};
|
|
494
500
|
}
|
|
495
501
|
}
|
|
496
|
-
if (containmentFace
|
|
502
|
+
if (skipsRootsContainment(containmentFace)) {
|
|
497
503
|
if (isUncPath(key) && isWinFormPath(key) && !within(rootCanonical, key) && !additionalRootsCanonical?.some((r) => within(r, key))) {
|
|
498
504
|
return {
|
|
499
505
|
ok: false,
|
|
@@ -528,7 +534,7 @@ export async function canonicalizeTarget(env, path, signal, family, baseCwd) {
|
|
|
528
534
|
}
|
|
529
535
|
const unprefixed = nativeUncSpellingOf(family, screened.spelled);
|
|
530
536
|
const spelled = family === "posix" && unprefixed.startsWith("//") ? unprefixed.replace(/^\/+/, "/") : unprefixed;
|
|
531
|
-
const target = baseCwd
|
|
537
|
+
const target = baseCwd ? anchorSpelling(family, baseCwd, spelled) : spelled;
|
|
532
538
|
let thrownByProbe;
|
|
533
539
|
let seenThrow = false;
|
|
534
540
|
const probe = probeRealTarget(env, path, target, family, signal).catch((e) => {
|
|
@@ -593,7 +599,7 @@ async function probeRealTarget(env, path, target, family, signal) {
|
|
|
593
599
|
};
|
|
594
600
|
}
|
|
595
601
|
const hopSpelling = family === "win" ? screenedTarget.spelled : link.value;
|
|
596
|
-
const linkTarget =
|
|
602
|
+
const linkTarget = anchorSpelling(family, parentDir(abs), hopSpelling);
|
|
597
603
|
const reabs = await env.absolutePath(linkTarget, signal);
|
|
598
604
|
if (!reabs.ok) {
|
|
599
605
|
return { ok: false, message: `cannot resolve symlink target "${linkTarget}" for "${path}": ${reabs.error.message}`, unresolvedSymlink: true };
|
package/dist/tools/fs/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { delimitUntrusted } from "../../core/untrusted-text.js";
|
|
2
2
|
import { MAX_EXEC_OUTPUT_BYTES } from "../../core/exec-output-tail.js";
|
|
3
|
-
import {
|
|
3
|
+
import { anchorSpelling, hasBinaryExtension, isWinFormPath, pathFamilyOf } from "./safety.js";
|
|
4
4
|
import { homeViewsOf } from "./read-deny-home.js";
|
|
5
5
|
import { createEntryDenyJudge } from "./dir-entries.js";
|
|
6
6
|
import { thrownText } from "../../core/thrown-value.js";
|
|
@@ -781,7 +781,7 @@ export async function jsGrepDetailed(env, root, p, signal, guards, deny, denyOut
|
|
|
781
781
|
const ignore = await buildIgnore(env, root, signal);
|
|
782
782
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
783
783
|
const family = pathFamilyOf({ root });
|
|
784
|
-
const start = p.path ? (
|
|
784
|
+
const start = p.path ? anchorSpelling(family, root, p.path) : root;
|
|
785
785
|
let walked;
|
|
786
786
|
if (p.path) {
|
|
787
787
|
const info = await env.fileInfo(start, signal);
|
|
@@ -1062,7 +1062,7 @@ async function sortRgFilesByMtime(env, root, records, signal) {
|
|
|
1062
1062
|
const family = pathFamilyOf({ root });
|
|
1063
1063
|
const toAbs = (p) => {
|
|
1064
1064
|
const stripped = p.startsWith("./") ? p.slice(2) : p;
|
|
1065
|
-
return
|
|
1065
|
+
return anchorSpelling(family, root, stripped);
|
|
1066
1066
|
};
|
|
1067
1067
|
const paths = records.map((r) => r.path ?? r.text);
|
|
1068
1068
|
const infos = await Promise.all(paths.map((p) => env.fileInfo(toAbs(p), signal)));
|
|
@@ -1148,8 +1148,10 @@ export function rgOutputDenyTripwire(stdout, mode, judge, opts = {}) {
|
|
|
1148
1148
|
return { trip: false };
|
|
1149
1149
|
}
|
|
1150
1150
|
function rgRecordAbsolute(base) {
|
|
1151
|
-
|
|
1152
|
-
|
|
1151
|
+
if (base === undefined)
|
|
1152
|
+
return (p) => p;
|
|
1153
|
+
const family = pathFamilyOf({ root: base });
|
|
1154
|
+
return (p) => anchorSpelling(family, base, p.replace(/^\.[\\/]/, ""));
|
|
1153
1155
|
}
|
|
1154
1156
|
async function rgOutputDenyTripwireAt(env, stdout, mode, deny, opts, signal) {
|
|
1155
1157
|
const views = homeViewsOf(env, deny, signal);
|
|
@@ -1258,7 +1260,7 @@ export async function rgGrepDetailed(env, root, p, signal, deny) {
|
|
|
1258
1260
|
if (deny === undefined || deny.rgExclusionGlobs.length === 0)
|
|
1259
1261
|
return { note: "" };
|
|
1260
1262
|
if (p.path) {
|
|
1261
|
-
const startPath =
|
|
1263
|
+
const startPath = anchorSpelling(pathFamilyOf({ root }), root, p.path);
|
|
1262
1264
|
const info = await env.fileInfo(startPath, signal);
|
|
1263
1265
|
if (info.ok && info.value.kind === "file")
|
|
1264
1266
|
return { note: "" };
|
|
@@ -1333,7 +1335,7 @@ async function rgDenyExistenceProbe(env, root, deny, target, signal) {
|
|
|
1333
1335
|
}
|
|
1334
1336
|
}
|
|
1335
1337
|
export async function runGrepDetailed(env, root, p, signal, deny) {
|
|
1336
|
-
const scope = p.path ? (
|
|
1338
|
+
const scope = p.path ? anchorSpelling(pathFamilyOf({ root }), root, p.path) : root;
|
|
1337
1339
|
const unexcludableUnder = async () => {
|
|
1338
1340
|
if (deny?.unexcludableUnder === undefined)
|
|
1339
1341
|
return false;
|
|
@@ -1359,7 +1361,7 @@ export async function runGlobDetailed(env, root, pattern, opts = {}, signal) {
|
|
|
1359
1361
|
const baseIgnore = await buildIgnore(env, root, signal);
|
|
1360
1362
|
const rootPrefix = root.replace(/[\\/]+$/, "") + (root.includes("\\") ? "\\" : "/");
|
|
1361
1363
|
const family = pathFamilyOf({ root });
|
|
1362
|
-
const start = opts.path ? (
|
|
1364
|
+
const start = opts.path ? anchorSpelling(family, root, opts.path) : root;
|
|
1363
1365
|
if (opts.path !== undefined) {
|
|
1364
1366
|
const probe = await env.fileInfo(start, signal);
|
|
1365
1367
|
if (!probe.ok && probe.error.code === "not_found") {
|
|
@@ -92,7 +92,7 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
92
92
|
const noPathOperands = slotVerb !== undefined && opensNoOperand(slotVerb);
|
|
93
93
|
const expanding = new Set();
|
|
94
94
|
for (let j = from; j < toks.length; j++) {
|
|
95
|
-
if (launcherIndices.has(j))
|
|
95
|
+
if (launcherIndices.has(j) || message.has(j))
|
|
96
96
|
continue;
|
|
97
97
|
if (noPathOperands && j > argvStart && !evaluatesOperands(slotVerb))
|
|
98
98
|
break;
|