@sema-agent/core 7.55.0 → 7.56.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 +513 -0
- package/dist/agents/cascade.js +1 -1
- package/dist/agents/cc-peer-directory.js +1 -0
- package/dist/agents/child-model-seat.d.ts +0 -11
- package/dist/agents/child-model-seat.js +0 -3
- package/dist/agents/list-agents-tool.d.ts +3 -1
- package/dist/agents/list-agents-tool.js +7 -7
- package/dist/agents/peer-directory.d.ts +22 -4
- package/dist/agents/peer-directory.js +24 -2
- package/dist/agents/peer-session-drain.js +2 -2
- package/dist/agents/repair-loop.js +2 -2
- package/dist/agents/send-message-tool.js +4 -4
- package/dist/agents/subagent.d.ts +6 -4
- package/dist/agents/subagent.js +64 -60
- package/dist/agents/tool-filter.d.ts +7 -5
- package/dist/agents/tool-filter.js +12 -9
- package/dist/agents/verify.d.ts +3 -2
- package/dist/agents/verify.js +3 -3
- package/dist/brain/anthropic.js +30 -73
- package/dist/brain/media-degrade.d.ts +18 -7
- package/dist/brain/media-degrade.js +13 -2
- package/dist/brain/model-capability.d.ts +37 -0
- package/dist/brain/model-capability.js +34 -0
- package/dist/brain/model-presets.d.ts +2 -8
- package/dist/brain/model-presets.js +1 -6
- package/dist/brain/open-responses.js +13 -26
- package/dist/brain/openai.js +14 -87
- package/dist/brain/reasoning-request.d.ts +96 -0
- package/dist/brain/reasoning-request.js +174 -0
- package/dist/brain/reasoning.d.ts +11 -11
- package/dist/brain/reasoning.js +4 -3
- package/dist/brain/request-params.d.ts +7 -4
- package/dist/brain/request-params.js +7 -4
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +7 -0
- package/dist/core/a2a.d.ts +2 -1
- package/dist/core/a2a.js +19 -13
- package/dist/core/agent-definition.d.ts +10 -0
- package/dist/core/allow-entry.d.ts +20 -13
- package/dist/core/allow-entry.js +26 -22
- package/dist/core/allow-rule-shadow.d.ts +3 -3
- package/dist/core/ask-origin.d.ts +64 -18
- package/dist/core/ask-origin.js +63 -23
- package/dist/core/ask-question.d.ts +51 -8
- package/dist/core/ask-question.js +3 -4
- package/dist/core/ask-unresolvable-notice.d.ts +8 -3
- package/dist/core/ask-unresolvable-notice.js +16 -2
- package/dist/core/checkpoint-generation.d.ts +53 -0
- package/dist/core/checkpoint-generation.js +35 -0
- package/dist/core/checkpoint-queries.d.ts +180 -0
- package/dist/core/checkpoint-queries.js +272 -0
- package/dist/core/checkpoint-requirements.d.ts +13 -1
- package/dist/core/checkpoint-requirements.js +4 -0
- package/dist/core/checkpoint-store.d.ts +88 -24
- package/dist/core/checkpoint-store.js +24 -9
- package/dist/core/cross-boundary-taint.d.ts +6 -5
- package/dist/core/cross-boundary-taint.js +1 -3
- package/dist/core/decision-receipt.d.ts +37 -3
- package/dist/core/decision-receipt.js +17 -17
- package/dist/core/delegation-not-started.d.ts +6 -0
- package/dist/core/delegation-not-started.js +17 -0
- package/dist/core/engine-attestation.d.ts +93 -0
- package/dist/core/engine-attestation.js +70 -0
- package/dist/core/engine-capabilities.d.ts +4 -1
- package/dist/core/engine-capabilities.js +1 -1
- package/dist/core/engine-notice.d.ts +30 -11
- package/dist/core/file-history-store.d.ts +90 -14
- package/dist/core/file-history-store.js +23 -15
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +22 -10
- package/dist/core/gate-lanes.js +73 -64
- package/dist/core/gate-outcome.d.ts +26 -5
- package/dist/core/gate-outcome.js +26 -0
- package/dist/core/governance-codes.d.ts +5 -1
- package/dist/core/governance-codes.js +6 -0
- package/dist/core/hooks.d.ts +17 -16
- package/dist/core/hooks.js +3 -1
- package/dist/core/host-floor.d.ts +128 -0
- package/dist/core/host-floor.js +206 -0
- package/dist/core/host-target.d.ts +38 -3
- package/dist/core/host-target.js +38 -5
- package/dist/core/mcp.d.ts +5 -1
- package/dist/core/mcp.js +67 -41
- package/dist/core/memory-engine/delegation-settlement.js +15 -24
- package/dist/core/memory-engine/engine.js +4 -4
- package/dist/core/memory-engine/layout.d.ts +60 -8
- package/dist/core/memory-engine/layout.js +65 -6
- package/dist/core/model-seat.d.ts +10 -3
- package/dist/core/mods/classic-events.d.ts +67 -0
- package/dist/core/mods/classic-events.js +1 -0
- package/dist/core/mods/dollar.d.ts +13 -0
- package/dist/core/mods/extension-call.d.ts +31 -0
- package/dist/core/mods/extension-call.js +43 -0
- package/dist/core/mods/kernel/dispatch.d.ts +20 -3
- package/dist/core/mods/kernel/dispatch.js +140 -69
- package/dist/core/mods/kernel/events.d.ts +47 -11
- package/dist/core/mods/kernel/events.js +66 -42
- package/dist/core/mods/kernel/index.d.ts +4 -4
- package/dist/core/mods/kernel/index.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +39 -5
- package/dist/core/mods/kernel/receive.js +290 -17
- package/dist/core/mods/kernel/registration.d.ts +33 -2
- package/dist/core/mods/kernel/registration.js +6 -7
- package/dist/core/mods/kernel/site-rules.d.ts +44 -16
- package/dist/core/mods/kernel/site-rules.js +24 -42
- package/dist/core/mods/spec-seats.d.ts +69 -0
- package/dist/core/mods/spec-seats.js +114 -0
- package/dist/core/mods/stations.d.ts +28 -8
- package/dist/core/mods/stations.js +29 -13
- package/dist/core/mods/tool-call.d.ts +79 -0
- package/dist/core/mods/tool-call.js +152 -0
- package/dist/core/namespaced-rule-name.d.ts +32 -38
- package/dist/core/namespaced-rule-name.js +29 -36
- package/dist/core/parent-spec-seat.d.ts +6 -1
- package/dist/core/parent-spec-seat.js +2 -0
- package/dist/core/park-selfcheck.js +1 -0
- package/dist/core/permission-rule-consent.d.ts +19 -0
- package/dist/core/permission-rule-consent.js +116 -26
- package/dist/core/permission-rule-model.d.ts +14 -3
- package/dist/core/permission-rule-model.js +39 -24
- package/dist/core/permission-rule-org.d.ts +6 -2
- package/dist/core/permission-rule-org.js +7 -3
- package/dist/core/permission-rule-provider.d.ts +5 -2
- package/dist/core/permission-rule-provider.js +41 -11
- package/dist/core/permission-rule-store.d.ts +3 -2
- package/dist/core/permission-rule-store.js +11 -2
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rule-syntax.d.ts +5 -4
- package/dist/core/permission-rule-syntax.js +2 -2
- package/dist/core/permission-rules.d.ts +4 -4
- package/dist/core/permission-rules.js +11 -20
- package/dist/core/persisted-rule-arms.d.ts +2 -2
- package/dist/core/persisted-rule-arms.js +10 -12
- package/dist/core/principal-name.d.ts +20 -0
- package/dist/core/principal-name.js +22 -0
- package/dist/core/prompt-section-seat.js +4 -6
- package/dist/core/protocol-http-auth.d.ts +26 -5
- package/dist/core/protocol-http-auth.js +137 -4
- package/dist/core/retired-keys.d.ts +16 -0
- package/dist/core/retired-keys.js +16 -4
- package/dist/core/rewrite-rejudge.d.ts +60 -0
- package/dist/core/rewrite-rejudge.js +36 -0
- package/dist/core/roles.d.ts +28 -1
- package/dist/core/roles.js +31 -19
- package/dist/core/rule-lane-reads.d.ts +20 -15
- package/dist/core/rule-lane-reads.js +45 -17
- package/dist/core/rule-owner.d.ts +3 -3
- package/dist/core/rule-owner.js +3 -2
- package/dist/core/runner/announce-once-ledger.d.ts +14 -0
- package/dist/core/runner/announce-once-ledger.js +5 -0
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/call-hook-stations.d.ts +3 -2
- package/dist/core/runner/caller-roster.d.ts +16 -4
- package/dist/core/runner/caller-roster.js +33 -6
- package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
- package/dist/core/runner/capability-withheld-seat.js +24 -0
- package/dist/core/runner/classifier-ladder.d.ts +7 -9
- package/dist/core/runner/classifier-ladder.js +3 -3
- package/dist/core/runner/construction-doors.js +3 -0
- package/dist/core/runner/contracts.d.ts +28 -25
- package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
- package/dist/core/runner/cross-boundary-lane.js +40 -27
- package/dist/core/runner/denial-limit-arms.d.ts +2 -2
- package/dist/core/runner/denial-limit-arms.js +1 -1
- package/dist/core/runner/file-history-request.d.ts +18 -0
- package/dist/core/runner/file-history-request.js +21 -13
- package/dist/core/runner/file-history-restore.d.ts +45 -0
- package/dist/core/runner/file-history-restore.js +46 -0
- package/dist/core/runner/gate-exit.d.ts +3 -3
- package/dist/core/runner/gate-exit.js +4 -3
- package/dist/core/runner/image.d.ts +7 -17
- package/dist/core/runner/image.js +9 -60
- package/dist/core/runner/permission-rule-lanes.d.ts +4 -4
- package/dist/core/runner/permission-rule-lanes.js +26 -10
- package/dist/core/runner/person-path-rows.d.ts +12 -9
- package/dist/core/runner/person-path-rows.js +18 -7
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
- package/dist/core/runner/prepare-ask-lane.js +5 -2
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
- package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
- package/dist/core/runner/prepare-config-doors.d.ts +29 -38
- package/dist/core/runner/prepare-config-doors.js +42 -25
- package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
- package/dist/core/runner/prepare-defer-classify.js +7 -8
- package/dist/core/runner/prepare-file-history.d.ts +48 -8
- package/dist/core/runner/prepare-file-history.js +7 -39
- package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
- package/dist/core/runner/prepare-gate-stations.js +10 -1
- package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
- package/dist/core/runner/prepare-hands-readface.js +15 -14
- package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
- package/dist/core/runner/prepare-inherited-gate.js +5 -3
- package/dist/core/runner/prepare-memory-engine-session.js +1 -1
- package/dist/core/runner/prepare-park-ask.js +5 -5
- package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
- package/dist/core/runner/prepare-policy-chain.js +65 -72
- package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
- package/dist/core/runner/prepare-prompt-assembly.js +10 -8
- package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
- package/dist/core/runner/prepare-prompt-inputs.js +3 -5
- package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
- package/dist/core/runner/prepare-protocol-tools.js +3 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-safety-scan.js +0 -17
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
- package/dist/core/runner/prepare-suspend-saga.js +5 -6
- package/dist/core/runner/prepare-task.d.ts +1 -1
- package/dist/core/runner/prepare-task.js +29 -20
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
- package/dist/core/runner/prepare-tool-disclosure-mount.js +20 -16
- package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
- package/dist/core/runner/prepare-turn-wiring.js +2 -7
- package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
- package/dist/core/runner/prepare-wiring-manifest.js +3 -3
- package/dist/core/runner/resume-admission.js +1 -1
- package/dist/core/runner/resume-apply.js +11 -12
- package/dist/core/runner/resume-checkpoint-screen.js +3 -0
- package/dist/core/runner/resume-claim.d.ts +4 -2
- package/dist/core/runner/resume-claim.js +15 -8
- package/dist/core/runner/retired-runner-deps.js +1 -0
- package/dist/core/runner/rewind-files.d.ts +15 -0
- package/dist/core/runner/rewind-files.js +132 -0
- package/dist/core/runner/run-attachment-seats.js +2 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -1
- package/dist/core/runner/run-brain-sinks.js +4 -2
- package/dist/core/runner/run-harness-handlers.js +12 -4
- package/dist/core/runner/run-leg.d.ts +1 -1
- package/dist/core/runner/run-leg.js +30 -18
- package/dist/core/runner/run-settle-and-teardown.js +2 -1
- package/dist/core/runner/run-turn-boundary.js +1 -10
- package/dist/core/runner/runtask.d.ts +3 -0
- package/dist/core/runner/runtask.js +8 -9
- package/dist/core/runner/session-read-file-states.d.ts +15 -0
- package/dist/core/runner/session-read-file-states.js +28 -0
- package/dist/core/runner/session-rule-policy.js +4 -3
- package/dist/core/runner/shell-env-withheld.d.ts +33 -0
- package/dist/core/runner/shell-env-withheld.js +51 -0
- package/dist/core/runner/skills-seat.js +6 -2
- package/dist/core/runner/stream-settle-backstop.js +1 -1
- package/dist/core/runner/sub-agent-deny-lists.js +4 -7
- package/dist/core/runner/synthetic-tools.d.ts +6 -0
- package/dist/core/runner/synthetic-tools.js +4 -1
- package/dist/core/runner/tool-disclosure.d.ts +10 -12
- package/dist/core/runner/tool-disclosure.js +1 -3
- package/dist/core/runner/tool-end-body.d.ts +1 -1
- package/dist/core/runner/tool-end-body.js +10 -9
- package/dist/core/runner/tool-not-executed.d.ts +5 -0
- package/dist/core/runner/tool-not-executed.js +11 -0
- package/dist/core/runner/tool-occurrence.d.ts +8 -0
- package/dist/core/runner/tool-occurrence.js +7 -0
- package/dist/core/runner/turn-attachments.d.ts +33 -15
- package/dist/core/runner/turn-attachments.js +62 -37
- package/dist/core/runner-deps.d.ts +5 -5
- package/dist/core/safety-axis-vocab.d.ts +6 -4
- package/dist/core/safety-axis-vocab.js +6 -5
- package/dist/core/safety-merge-corpus.js +11 -3
- package/dist/core/secret-env.d.ts +26 -3
- package/dist/core/secret-env.js +44 -8
- package/dist/core/select-model.js +3 -3
- package/dist/core/session-policy-store.d.ts +27 -15
- package/dist/core/session-policy-store.js +156 -36
- package/dist/core/session-store.d.ts +29 -10
- package/dist/core/session-store.js +51 -19
- package/dist/core/session.d.ts +82 -16
- package/dist/core/session.js +53 -0
- package/dist/core/shell-read-silence.d.ts +11 -12
- package/dist/core/shell-read-silence.js +9 -5
- package/dist/core/shell-run-candidates.js +3 -1
- package/dist/core/shell-wrapper-projection.js +1 -1
- package/dist/core/shell-wrapper-table.d.ts +14 -7
- package/dist/core/shell-wrapper-table.js +5 -4
- package/dist/core/side-query.js +10 -1
- package/dist/core/skill-grant.d.ts +7 -2
- package/dist/core/skill-grant.js +5 -0
- package/dist/core/skills-directory.js +6 -2
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +140 -2
- package/dist/core/store-contracts/file-history-store-contract.js +31 -1
- package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
- package/dist/core/store-contracts/peer-directory-contract.js +14 -2
- package/dist/core/store-contracts/session-repo-contract.js +51 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
- package/dist/core/store-contracts/session-store-contract.js +150 -14
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +3 -3
- package/dist/core/task-event.d.ts +32 -4
- package/dist/core/task-notification.d.ts +16 -12
- package/dist/core/task-registry.d.ts +9 -0
- package/dist/core/task-registry.js +11 -1
- package/dist/core/task-result.d.ts +18 -0
- package/dist/core/task-spec.d.ts +18 -13
- package/dist/core/tighten-task-spec.js +2 -1
- package/dist/core/tool-catalog-entries.d.ts +17 -0
- package/dist/core/tool-catalog-entries.js +13 -2
- package/dist/core/tool-check-reading.d.ts +11 -0
- package/dist/core/tool-check-reading.js +11 -6
- package/dist/core/tool-model-gate.d.ts +2 -2
- package/dist/core/tool-name-aliases.d.ts +16 -16
- package/dist/core/tool-name-aliases.js +13 -19
- package/dist/core/tool-name-readings.d.ts +5 -35
- package/dist/core/tool-name-readings.js +1 -9
- package/dist/core/tool-policy.d.ts +68 -198
- package/dist/core/tool-policy.js +149 -198
- package/dist/core/tool-result-store.js +3 -0
- package/dist/core/tool-roster.d.ts +14 -19
- package/dist/core/tool-roster.js +11 -44
- package/dist/core/tool-spec-members.js +7 -2
- package/dist/core/tool-spec.d.ts +19 -11
- package/dist/core/tools.js +49 -9
- package/dist/core/trace.d.ts +2 -2
- package/dist/core/types.d.ts +1 -1
- package/dist/core/user-attachment.d.ts +8 -1
- package/dist/core/user-attachment.js +64 -4
- package/dist/core/wiring-manifest.d.ts +9 -0
- package/dist/core/wiring-manifest.js +1 -0
- package/dist/core/workflow-journal-store.js +1 -1
- package/dist/engine/compaction/compaction.js +3 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
- package/dist/engine/execution-env/node-execution-env.js +11 -2
- package/dist/engine/harness/agent-harness.d.ts +25 -1
- package/dist/engine/harness/agent-harness.js +54 -7
- package/dist/engine/harness/types.d.ts +29 -2
- package/dist/engine/llm/types.d.ts +28 -11
- package/dist/engine/loop/agent-loop.d.ts +22 -0
- package/dist/engine/loop/agent-loop.js +16 -26
- package/dist/engine/loop/types.d.ts +16 -6
- package/dist/engine/session/memory-repo.d.ts +9 -2
- package/dist/engine/session/memory-repo.js +11 -1
- package/dist/engine/session/repo-utils.d.ts +6 -5
- package/dist/engine/session/repo-utils.js +14 -6
- package/dist/index.d.ts +22 -10
- package/dist/index.js +15 -7
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +6 -4
- package/dist/orchestration/run-workflow-tool.js +5 -3
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +36 -18
- package/dist/prompt-assembly/artifact.d.ts +2 -2
- package/dist/prompt-assembly/artifact.js +5 -3
- package/dist/prompt-assembly/assemble.d.ts +3 -2
- package/dist/prompt-assembly/assemble.js +1 -1
- package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
- package/dist/prompt-assembly/catalog/schema.js +34 -2
- package/dist/prompt-assembly/catalog/sections.js +0 -1
- package/dist/prompt-assembly/composer.d.ts +3 -1
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/prompt-assembly/overlay.js +3 -3
- package/dist/prompt-assembly/renderers.d.ts +1 -1
- package/dist/prompt-assembly/renderers.js +0 -3
- package/dist/prompt-assembly/role-base.d.ts +15 -0
- package/dist/prompt-assembly/role-base.js +9 -0
- package/dist/prompt-assembly/select.d.ts +39 -14
- package/dist/prompt-assembly/select.js +47 -16
- package/dist/prompt-assembly/sugar.d.ts +17 -11
- package/dist/prompt-assembly/sugar.js +8 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
- package/dist/prompt-assembly/tool-catalog.js +114 -4
- package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
- package/dist/prompt-assembly/turn-snapshot.js +0 -3
- package/dist/prompt-assembly/types.d.ts +0 -7
- package/dist/scenarios/full-body.d.ts +11 -11
- package/dist/scenarios/full-body.js +4 -3
- package/dist/shell/lex.js +10 -1
- package/dist/stores/file/adoption/adopt.js +4 -3
- package/dist/stores/file/adoption/marker.js +3 -2
- package/dist/stores/file/checkpoint-store.d.ts +21 -0
- package/dist/stores/file/checkpoint-store.js +38 -6
- package/dist/stores/file/file-history-store.js +6 -7
- package/dist/stores/file/index.js +2 -1
- package/dist/stores/file/permission-rule-adopt.js +4 -3
- package/dist/stores/file/permission-rule-store.js +11 -5
- package/dist/stores/file/session-store.d.ts +29 -6
- package/dist/stores/file/session-store.js +42 -50
- package/dist/tools/artifact/artifact-tool.js +3 -2
- package/dist/tools/fs/bash-program-position.d.ts +19 -2
- package/dist/tools/fs/bash-program-position.js +56 -9
- package/dist/tools/fs/fs-bash.js +5 -5
- package/dist/tools/fs/fs-glob.d.ts +86 -0
- package/dist/tools/fs/fs-glob.js +226 -0
- package/dist/tools/fs/fs-read.js +14 -14
- package/dist/tools/fs/fs-search-tools.js +7 -7
- package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
- package/dist/tools/fs/pattern-kill-guard.js +397 -0
- package/dist/tools/fs/pdf.d.ts +9 -6
- package/dist/tools/fs/pdf.js +3 -3
- package/dist/tools/fs/program-read-model.d.ts +57 -7
- package/dist/tools/fs/program-read-model.js +11 -1
- package/dist/tools/fs/program-read-model.rows.js +78 -21
- package/dist/tools/fs/read-deny-home.js +3 -2
- package/dist/tools/fs/removal-targets.d.ts +17 -7
- package/dist/tools/fs/removal-targets.js +47 -20
- package/dist/tools/fs/search.d.ts +10 -0
- package/dist/tools/fs/search.js +20 -26
- package/dist/tools/fs/shell-read-argv.js +89 -12
- package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
- package/dist/tools/fs/shell-read-bindings.js +41 -0
- package/dist/tools/fs/shell-read-check.js +6 -19
- package/dist/tools/fs/shell-read-environment.d.ts +5 -1
- package/dist/tools/fs/shell-read-environment.js +3 -2
- package/dist/tools/fs/shell-read-establish.d.ts +15 -0
- package/dist/tools/fs/shell-read-establish.js +19 -20
- package/dist/tools/fs/shell-read-plan.js +24 -16
- package/dist/tools/fs/shell-read-start.d.ts +6 -1
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
- package/dist/tools/fs/shell-read-write-targets.js +2 -3
- package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
- package/dist/tools/fs/shell-reentry-text.js +40 -2
- package/dist/tools/todo.js +63 -63
- package/dist/tools/web.d.ts +19 -14
- package/dist/tools/web.js +38 -55
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +143 -5
- package/wire-changes/core@7.56.0.json +3891 -0
- package/wire-changes/mods-kernel@7.56.0.json +303 -0
|
@@ -21,9 +21,46 @@ function mayOwnNextWord(row, tok) {
|
|
|
21
21
|
return k === tok.length;
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
|
+
class OperandBase {
|
|
25
|
+
base;
|
|
26
|
+
taken = [];
|
|
27
|
+
move(spec, value, settled, at) {
|
|
28
|
+
if (spec?.rebases !== true)
|
|
29
|
+
return;
|
|
30
|
+
if (!settled)
|
|
31
|
+
this.base = "unsettled";
|
|
32
|
+
else if (namesOwnPlace(value))
|
|
33
|
+
this.base = value;
|
|
34
|
+
else if (this.base !== "unsettled")
|
|
35
|
+
this.base = this.base === undefined ? value : joinSpelling(this.base, value);
|
|
36
|
+
if (typeof this.base === "string" && this.base !== "unsettled")
|
|
37
|
+
this.taken.push({ at, base: this.base });
|
|
38
|
+
}
|
|
39
|
+
of(r) {
|
|
40
|
+
if (this.base === undefined || namesOwnPlace(r.folded))
|
|
41
|
+
return r;
|
|
42
|
+
if (this.base === "unsettled" || r.expands !== false)
|
|
43
|
+
return { ...r, expands: "unresolvable" };
|
|
44
|
+
return { word: r.word, raw: r.raw, folded: joinSpelling(this.base, r.folded), expands: false };
|
|
45
|
+
}
|
|
46
|
+
covers(unsettled) {
|
|
47
|
+
const out = new Set();
|
|
48
|
+
for (const u of unsettled) {
|
|
49
|
+
if (namesOwnPlace(u.folded) || u.folded.split("/").includes(".."))
|
|
50
|
+
continue;
|
|
51
|
+
for (const t of this.taken)
|
|
52
|
+
if (t.at < u.at)
|
|
53
|
+
out.add(t.base);
|
|
54
|
+
}
|
|
55
|
+
return [...out].map((b) => readOfText(b));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const namesOwnPlace = (spelled) => spelled.startsWith("/") || spelled.startsWith("~");
|
|
59
|
+
const joinSpelling = (base, rel) => (base.endsWith("/") ? `${base}${rel}` : `${base}/${rel}`);
|
|
24
60
|
const rootValue = (spec) => spec?.walks === true || spec?.delivers === "operands";
|
|
25
61
|
class RootsGathered {
|
|
26
62
|
positional = [];
|
|
63
|
+
opened = new Map();
|
|
27
64
|
places = [];
|
|
28
65
|
maybeValues = new Set();
|
|
29
66
|
stdinOperands = 0;
|
|
@@ -50,16 +87,23 @@ class RootsGathered {
|
|
|
50
87
|
if (this.maybeValues.has(r))
|
|
51
88
|
this.slotOwned = true;
|
|
52
89
|
}
|
|
53
|
-
operand(r, namesPath, stdin) {
|
|
90
|
+
operand(r, namesPath, stdin, opened = r) {
|
|
54
91
|
if (stdin) {
|
|
55
92
|
if (!this.maybeValues.has(r))
|
|
56
93
|
this.stdinOperands++;
|
|
57
94
|
}
|
|
58
|
-
else if (namesPath)
|
|
95
|
+
else if (namesPath) {
|
|
59
96
|
this.positional.push(r);
|
|
97
|
+
if (opened !== r)
|
|
98
|
+
this.opened.set(r, opened);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
cover(place) {
|
|
102
|
+
this.places.push(bare(place, "traversal_root"));
|
|
60
103
|
}
|
|
61
104
|
restart() {
|
|
62
105
|
this.positional.length = 0;
|
|
106
|
+
this.opened.clear();
|
|
63
107
|
this.places.length = 0;
|
|
64
108
|
this.stdinOperands = 0;
|
|
65
109
|
this.slotOwned = false;
|
|
@@ -71,7 +115,7 @@ class RootsGathered {
|
|
|
71
115
|
const reads = this.unsettled
|
|
72
116
|
? [...this.positional, ...(this.slotWord !== undefined ? [this.slotWord] : []), ...(walksCwdWithoutOperand(row) ? [readOfText(".")] : [])]
|
|
73
117
|
: walksCwdWithoutOperand(row) && leftOver <= (this.slotOwned ? 1 : 0) ? [...this.positional, readOfText(".")] : [...this.positional];
|
|
74
|
-
return [...reads.map((r) => bare(r, "traversal_root")), ...this.places];
|
|
118
|
+
return [...reads.map((r) => bare(this.opened.get(r) ?? r, "traversal_root")), ...this.places];
|
|
75
119
|
}
|
|
76
120
|
}
|
|
77
121
|
export const programTextSentence = (language) => `runs inline ${language} program text, which may open files this station does not read`;
|
|
@@ -178,6 +222,9 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
178
222
|
pushAssignment(reads, toks[j].word, provenance);
|
|
179
223
|
}
|
|
180
224
|
const gathered = new RootsGathered();
|
|
225
|
+
let base = new OperandBase();
|
|
226
|
+
const valueAt = new Set();
|
|
227
|
+
const unsettledAt = [];
|
|
181
228
|
let slotWord;
|
|
182
229
|
const pastOperand = new Set();
|
|
183
230
|
let globs = "expanded";
|
|
@@ -251,6 +298,8 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
251
298
|
walkFrom = argvStart + 2 + sub.at;
|
|
252
299
|
relocated = sub.relocated;
|
|
253
300
|
gathered.restart();
|
|
301
|
+
base = new OperandBase();
|
|
302
|
+
unsettledAt.length = 0;
|
|
254
303
|
walk(sub.row, walkFrom, toks.length, true);
|
|
255
304
|
}
|
|
256
305
|
else
|
|
@@ -268,10 +317,12 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
268
317
|
return;
|
|
269
318
|
case "dash-word-operand":
|
|
270
319
|
pastOperand.add(j);
|
|
271
|
-
reads.push(bare(r, provenance));
|
|
320
|
+
reads.push(bare(base.of(r), provenance));
|
|
272
321
|
speculate(start, "whole");
|
|
273
322
|
return;
|
|
274
323
|
case "value": {
|
|
324
|
+
base.move(e.spec, r.folded, e.consumed && r.expands === false, j);
|
|
325
|
+
valueAt.add(j);
|
|
275
326
|
if (!e.consumed) {
|
|
276
327
|
gathered.value(r, e, false);
|
|
277
328
|
if (r.expands !== "unresolvable")
|
|
@@ -299,19 +350,23 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
299
350
|
return;
|
|
300
351
|
}
|
|
301
352
|
{
|
|
353
|
+
base.move(e.reading.spec, literalTildeSpelling(e.reading.attached), r.expands === false, j);
|
|
302
354
|
const named = roleReads(r, "option_value", literalTildeSpelling(e.reading.attached), e.reading.role, globs, ctx, pastOperand.has(j));
|
|
303
355
|
reads.push(...named);
|
|
304
356
|
gathered.attached(named, e.reading.spec);
|
|
305
357
|
}
|
|
306
358
|
return;
|
|
307
359
|
case "operand": {
|
|
308
|
-
const role = e.dash === undefined ? (e.slot ?? e.role) : undefined;
|
|
309
|
-
const named = role !== undefined ? roleReads(r, provenance, r.folded, role, globs, ctx) : [bare(r, provenance)];
|
|
310
360
|
const inSlot = j === slotWord;
|
|
361
|
+
const o = inSlot || e.dash !== undefined ? r : base.of(r);
|
|
362
|
+
const role = e.dash === undefined ? (e.slot ?? e.role) : undefined;
|
|
363
|
+
const named = role !== undefined ? roleReads(o, provenance, o.folded, role, globs, ctx) : [bare(o, provenance)];
|
|
311
364
|
if (inSlot)
|
|
312
365
|
gathered.slot(r);
|
|
313
366
|
else
|
|
314
|
-
gathered.operand(r, named.some((c) => c.denyOnly !== true), e.dash === "stdin");
|
|
367
|
+
gathered.operand(r, named.some((c) => c.denyOnly !== true), e.dash === "stdin", o);
|
|
368
|
+
if (!inSlot && e.dash === undefined && r.expands !== false)
|
|
369
|
+
unsettledAt.push({ at: j, folded: r.folded });
|
|
315
370
|
reads.push(...named);
|
|
316
371
|
speculate(start, r.word.assignment !== undefined ? "whole" : "containment");
|
|
317
372
|
const values = reads.length;
|
|
@@ -323,6 +378,11 @@ export function unlistedWords(reads, toks, from, launcherIndices, provenance, ct
|
|
|
323
378
|
}
|
|
324
379
|
}
|
|
325
380
|
if (walkRow !== undefined && argv !== undefined && selectsContentsTraversal(walkRow, toks.slice(walkFrom).map((x) => x.folded))) {
|
|
381
|
+
for (const j of expanding)
|
|
382
|
+
if (j >= walkFrom && !valueAt.has(j))
|
|
383
|
+
unsettledAt.push({ at: j, folded: toks[j].folded });
|
|
384
|
+
for (const place of base.covers(unsettledAt))
|
|
385
|
+
gathered.cover(place);
|
|
326
386
|
for (const root of gathered.roots(walkRow))
|
|
327
387
|
reads.push(relocated ? { ...root, expands: "unresolvable" } : root);
|
|
328
388
|
}
|
|
@@ -372,6 +432,9 @@ function walkListed(row, argReads, first, last, expanding, reads, ctx, relocated
|
|
|
372
432
|
const slice = argReads.slice(first, last);
|
|
373
433
|
const args = slice.map((r) => r.folded);
|
|
374
434
|
const gathered = new RootsGathered();
|
|
435
|
+
const base = new OperandBase();
|
|
436
|
+
const valueAt = new Set();
|
|
437
|
+
const unsettledAt = [];
|
|
375
438
|
let unexplained = false;
|
|
376
439
|
const globs = valuesAreLiteral(row, args) ? "literal" : "expanded";
|
|
377
440
|
noteDeliveredOperands(row, args, ctx);
|
|
@@ -391,9 +454,11 @@ function walkListed(row, argReads, first, last, expanding, reads, ctx, relocated
|
|
|
391
454
|
break;
|
|
392
455
|
case "dash-word-operand":
|
|
393
456
|
pastOperand.add(e.at);
|
|
394
|
-
reads.push(bare(slice[e.at], "operand"));
|
|
457
|
+
reads.push(bare(base.of(slice[e.at]), "operand"));
|
|
395
458
|
break;
|
|
396
459
|
case "value": {
|
|
460
|
+
base.move(e.spec, t, e.consumed && slice[e.at].expands === false, e.at);
|
|
461
|
+
valueAt.add(e.at);
|
|
397
462
|
if (expanding.has(first + e.at))
|
|
398
463
|
break;
|
|
399
464
|
gathered.value(slice[e.at], e, opensPath(offer(e.at, t, e.role, "option_value", !e.consumed)));
|
|
@@ -409,6 +474,7 @@ function walkListed(row, argReads, first, last, expanding, reads, ctx, relocated
|
|
|
409
474
|
reads.push(bare(slice[e.at], "option_value", payload));
|
|
410
475
|
break;
|
|
411
476
|
}
|
|
477
|
+
base.move(e.reading.spec, literalTildeSpelling(e.reading.attached), slice[e.at].expands === false, e.at);
|
|
412
478
|
gathered.attached(offer(e.at, literalTildeSpelling(e.reading.attached), e.reading.role, "option_value", pastOperand.has(e.at)), e.reading.spec);
|
|
413
479
|
break;
|
|
414
480
|
case "operand": {
|
|
@@ -428,11 +494,17 @@ function walkListed(row, argReads, first, last, expanding, reads, ctx, relocated
|
|
|
428
494
|
break;
|
|
429
495
|
}
|
|
430
496
|
let opens = true;
|
|
431
|
-
|
|
432
|
-
|
|
497
|
+
const o = base.of(slice[e.at]);
|
|
498
|
+
if (e.role !== undefined) {
|
|
499
|
+
const named = roleReads(o, "operand", o.folded, e.role, globs, ctx);
|
|
500
|
+
reads.push(...named);
|
|
501
|
+
opens = opensPath(named);
|
|
502
|
+
}
|
|
433
503
|
else
|
|
434
|
-
reads.push(bare(
|
|
435
|
-
gathered.operand(slice[e.at], opens, false);
|
|
504
|
+
reads.push(bare(o, "operand"));
|
|
505
|
+
gathered.operand(slice[e.at], opens, false, o);
|
|
506
|
+
if (slice[e.at].expands !== false)
|
|
507
|
+
unsettledAt.push({ at: e.at, folded: t });
|
|
436
508
|
if (row?.operands?.assignmentArguments !== "not-paths")
|
|
437
509
|
pushAssignment(reads, slice[e.at].word, "operand");
|
|
438
510
|
break;
|
|
@@ -444,6 +516,11 @@ function walkListed(row, argReads, first, last, expanding, reads, ctx, relocated
|
|
|
444
516
|
reads[i] = { ...reads[i], speculative: "containment" };
|
|
445
517
|
}
|
|
446
518
|
if (row !== undefined && selectsContentsTraversal(row, args)) {
|
|
519
|
+
for (let k = 0; k < slice.length; k++)
|
|
520
|
+
if (expanding.has(first + k) && !valueAt.has(k))
|
|
521
|
+
unsettledAt.push({ at: k, folded: args[k] });
|
|
522
|
+
for (const place of base.covers(unsettledAt))
|
|
523
|
+
gathered.cover(place);
|
|
447
524
|
for (const root of gathered.roots(row))
|
|
448
525
|
reads.push(relocated ? { ...root, expands: "unresolvable" } : root);
|
|
449
526
|
}
|
|
@@ -106,6 +106,37 @@ export declare const functionKey: (name: string) => string;
|
|
|
106
106
|
/** What a function name is at a reader: `defined` — it certainly is one; `absent` — it certainly is not; `maybe` — a branch,
|
|
107
107
|
* a loop, a body that may not have run, a removal that may not have found it. */
|
|
108
108
|
export type FunctionState = "defined" | "maybe" | "absent";
|
|
109
|
+
/** The function names a segment exports to child shells — the `-f` function flag with export (`export` always exports;
|
|
110
|
+
* `declare` / `typeset` need `-x`), its bare-name operands. A child `bash -c` inherits them as functions
|
|
111
|
+
* ({@link inheritedExportedFunctions}); their definitions are text this reader does not hold, so a call to one shadows
|
|
112
|
+
* the builtin of the name (#1628). */
|
|
113
|
+
export declare function exportedFunctionNames(argv: readonly LexedWord[]): string[];
|
|
114
|
+
/** A function the CHILD inherits through its ENVIRONMENT: bash exports a function as a `BASH_FUNC_<name>%%` variable
|
|
115
|
+
* (older bashes `BASH_FUNC_<name>()`), and a child reading that variable from its environment defines `<name>` as a
|
|
116
|
+
* function whose body the engine cannot read. Delivered on a child's env by `env BASH_FUNC_x%%=… cmd` (env's own
|
|
117
|
+
* assignment grammar accepts the `%%` name the shell's does not). Each such assignment word of a segment names an
|
|
118
|
+
* inherited function — the same law as {@link exportedFunctionNames}, a different delivery; a value the shell rewrites
|
|
119
|
+
* (`env "BASH_FUNC_$n%%=…"`) names a function the text cannot settle and is not tracked (KL-1628-a). */
|
|
120
|
+
export declare function envFunctionNames(argv: readonly LexedWord[]): string[];
|
|
121
|
+
/** Whether the BODY of a function a child shell inherits is text the engine read: `read` — the text (or a shell above it)
|
|
122
|
+
* defines the function it exports (`f(){ …; }; export -f f`, `declare -fx f`), so the body's segments are read where it
|
|
123
|
+
* is defined; `unread` — delivered on an environment (`BASH_FUNC_f%%=…`, {@link envFunctionNames}), or exported with no
|
|
124
|
+
* definition the text holds (one a `source` or an `eval` made): a body nobody read. */
|
|
125
|
+
export type InheritedBody = "read" | "unread";
|
|
126
|
+
/** The functions a text's child shells inherit, each with its {@link InheritedBody}: what the shell running the text
|
|
127
|
+
* inherited; then each name the text exports — `read` where the text defines it, else what it was inherited as, else
|
|
128
|
+
* `unread`; then each name it delivers on an environment, `unread` whatever else holds it. */
|
|
129
|
+
export declare function inheritedFunctionsOf(segments: readonly {
|
|
130
|
+
readonly argv: readonly LexedWord[];
|
|
131
|
+
readonly defines: readonly string[];
|
|
132
|
+
}[], inherited: ReadonlyMap<string, InheritedBody> | undefined): ReadonlyMap<string, InheritedBody>;
|
|
133
|
+
/** What a child shell (`bash -c`) inherits from a parent that EXPORTED functions ({@link exportedFunctionNames}): each
|
|
134
|
+
* such name is a `defined` function in the child — bash looks a function up before the builtin of its name, so
|
|
135
|
+
* `declare X=…` run under an exported `declare` function is the FUNCTION (it binds nothing), not the declaration
|
|
136
|
+
* builtin. Every other function key is `absent` (a child inherits only exported functions), every builtin enabled;
|
|
137
|
+
* the child holds none of their bodies, so a call to one may change any name (`bound: "all"`). The existing binding
|
|
138
|
+
* carrier ({@link PlanStart.names}), not a second table (#1628). */
|
|
139
|
+
export declare function inheritedExportedFunctions(names: ReadonlyMap<string, InheritedBody>): InheritedFunctions;
|
|
109
140
|
/** One binding a segment makes: a name and what it now holds (`unknown` = made unknown). `prefix`: a binding that may or
|
|
110
141
|
* may not take effect (a prefix assignment to a special builtin, which may or may not outlive its command; an `unset` of a
|
|
111
142
|
* function, which a read-only function refuses). `loopVar`: a `for` loop's variable, held through its body. */
|
|
@@ -46,6 +46,47 @@ const isFunctionKey = (name) => name.startsWith(FUNCTION_KEY_PREFIX);
|
|
|
46
46
|
const FUNCTION_DEFINED = [{ spelled: "defined" }];
|
|
47
47
|
const FUNCTION_ABSENT = [{ spelled: "absent" }];
|
|
48
48
|
const isDefinedValue = (v) => v.spelled === "defined";
|
|
49
|
+
const EXPORT_FUNCTION_BUILTINS = new Set(["export", "declare", "typeset"]);
|
|
50
|
+
export function exportedFunctionNames(argv) {
|
|
51
|
+
const program = readProgramPosition(argv).program;
|
|
52
|
+
const prog = program?.basename;
|
|
53
|
+
if (program === undefined || prog === undefined || !EXPORT_FUNCTION_BUILTINS.has(prog))
|
|
54
|
+
return [];
|
|
55
|
+
const literal = (w) => w.expansions.length === 0;
|
|
56
|
+
const rest = argv.slice(program.index + 1);
|
|
57
|
+
const flags = new Set(rest.filter((w) => literal(w) && /^-[A-Za-z]+$/.test(w.folded)).flatMap((w) => [...w.folded.slice(1)]));
|
|
58
|
+
if (!flags.has("f") || !(prog === "export" || flags.has("x")))
|
|
59
|
+
return [];
|
|
60
|
+
return rest.filter((w) => literal(w) && w.assignment === undefined && /^[A-Za-z_][A-Za-z0-9_]*$/.test(w.folded)).map((w) => w.folded);
|
|
61
|
+
}
|
|
62
|
+
export function envFunctionNames(argv) {
|
|
63
|
+
const out = [];
|
|
64
|
+
for (const w of argv) {
|
|
65
|
+
if (w.expansions.length !== 0)
|
|
66
|
+
continue;
|
|
67
|
+
const m = /^BASH_FUNC_([A-Za-z_][A-Za-z0-9_]*)(?:%%|\(\))=/.exec(w.folded);
|
|
68
|
+
if (m !== null)
|
|
69
|
+
out.push(m[1]);
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
export function inheritedFunctionsOf(segments, inherited) {
|
|
74
|
+
const defined = new Set(segments.flatMap((s) => s.defines));
|
|
75
|
+
const out = new Map(inherited ?? []);
|
|
76
|
+
for (const s of segments)
|
|
77
|
+
for (const name of exportedFunctionNames(s.argv))
|
|
78
|
+
out.set(name, defined.has(name) ? "read" : out.get(name) ?? "unread");
|
|
79
|
+
for (const s of segments)
|
|
80
|
+
for (const name of envFunctionNames(s.argv))
|
|
81
|
+
out.set(name, "unread");
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
export function inheritedExportedFunctions(names) {
|
|
85
|
+
return {
|
|
86
|
+
start: (key) => (isFunctionKey(key) ? (names.has(key.slice(FUNCTION_KEY_PREFIX.length)) ? FUNCTION_DEFINED : FUNCTION_ABSENT) : BUILTIN_ENABLED),
|
|
87
|
+
bound: "all",
|
|
88
|
+
};
|
|
89
|
+
}
|
|
49
90
|
const ATTRIBUTE_KINDS = { integer: "integer", transformed: "transformed", frozen: "frozen" };
|
|
50
91
|
const EVERY_ATTRIBUTE = Object.values(ATTRIBUTE_KINDS).map((kind) => ({ kind }));
|
|
51
92
|
export function projectSegment(segment) {
|
|
@@ -3,7 +3,7 @@ import { errorResult } from "../../core/tools.js";
|
|
|
3
3
|
import { BASH_READONLY_CONFINEMENT_NOTE } from "./fs-shared.js";
|
|
4
4
|
import { isAbsoluteForFamily, normalizeAbsPathLexically, pathFamilyOf, violationDetails, withinAnyRoot } from "./safety.js";
|
|
5
5
|
import { checkedReadDenyHomes, fitMiddle, READ_DENY_SENTENCE_PART_MAX, readDenySentence } from "./read-deny.js";
|
|
6
|
-
import { NOT_AUTO_ALLOWED,
|
|
6
|
+
import { NOT_AUTO_ALLOWED, declinedProgramSentence } from "./bash-program-position.js";
|
|
7
7
|
import { bashClassifyDefaultAllow } from "./bash-readonly-classifier.js";
|
|
8
8
|
import { planShellReads } from "./shell-read-plan.js";
|
|
9
9
|
import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
|
|
@@ -12,10 +12,10 @@ import { anyOptionWord, programArgs } from "./shell-read-write-targets.js";
|
|
|
12
12
|
import { shellReadFaceWords } from "./shell-read-face.js";
|
|
13
13
|
import { passesUnasked } from "./shell-read-device.js";
|
|
14
14
|
import { programRow, selectedOptions } from "./program-read-model.js";
|
|
15
|
+
import { refusedByRemoval, SHELL_REMOVAL_COMMANDS } from "./removal-targets.js";
|
|
15
16
|
import { allFindings, anyFaceGuards, decideShellRead, denyRowAtOrBelow, foldShellReadFindings, judgeEstablishedPlan, readRootGrantCandidateOf, stationGuards, writeFaceGuards, } from "./shell-read-judge.js";
|
|
16
17
|
import { seatOf } from "../../core/tool-name-readings.js";
|
|
17
18
|
import { normalizeReadRootCandidate } from "../../core/read-root-candidate.js";
|
|
18
|
-
import { argvOf, lexShellText } from "../../shell/lex.js";
|
|
19
19
|
import { assertNoRetiredShellReadBoundaryKeys } from "../../core/retired-keys.js";
|
|
20
20
|
function containmentDetails(paths) {
|
|
21
21
|
return { type: "readonly_out_of_root", code: "readonly_out_of_root", paths };
|
|
@@ -26,7 +26,6 @@ function unestablishedDetails() {
|
|
|
26
26
|
function findingDetails(finding, paths) {
|
|
27
27
|
return finding === "unestablishable" || finding === "declined" || finding === "unanswered" ? unestablishedDetails() : containmentDetails(paths);
|
|
28
28
|
}
|
|
29
|
-
const REMOVAL_COMMANDS = new Set(["rm", "rmdir"]);
|
|
30
29
|
const WRITES_BENEATH = {
|
|
31
30
|
cp: () => true,
|
|
32
31
|
mv: () => true,
|
|
@@ -74,15 +73,16 @@ function writesPlacedOf(judged, boundary) {
|
|
|
74
73
|
if (UNPLACED_OPTIONS[verb]?.(programArgs(s.segment).map((w) => w.spelled)) === true)
|
|
75
74
|
return false;
|
|
76
75
|
const beneath = WRITES_BENEATH[verb]?.(s.segment) === true;
|
|
76
|
+
const removal = SHELL_REMOVAL_COMMANDS.includes(verb);
|
|
77
77
|
for (const f of s.findings) {
|
|
78
78
|
if (f.read.candidate.face !== "write")
|
|
79
79
|
continue;
|
|
80
80
|
const target = f.read.target;
|
|
81
81
|
if (f.read.established === "unestablishable" || target === undefined || isPattern(f) || f.kind !== "none" || (f.containment !== "inside" && f.containment !== "open"))
|
|
82
82
|
return false;
|
|
83
|
-
if (beneath && denyRowAtOrBelow(f.read, boundary, !
|
|
83
|
+
if (beneath && denyRowAtOrBelow(f.read, boundary, !removal))
|
|
84
84
|
return false;
|
|
85
|
-
if (
|
|
85
|
+
if (removal && !refusedByRemoval(f.read) && writeRoots.some((root) => withinAnyRoot([target], root)))
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
return true;
|
|
@@ -182,19 +182,6 @@ function shellCommandOf(args) {
|
|
|
182
182
|
const command = args?.command;
|
|
183
183
|
return typeof command === "string" ? command : undefined;
|
|
184
184
|
}
|
|
185
|
-
function declineSentence(segment) {
|
|
186
|
-
const lexed = lexShellText(segment.text);
|
|
187
|
-
if (!("reject" in lexed) && lexed.segments[0] !== undefined) {
|
|
188
|
-
const pos = readProgramPosition(argvOf(lexed.segments[0]));
|
|
189
|
-
if (pos.refusal !== undefined)
|
|
190
|
-
return programPositionRefusalSentence(pos.refusal);
|
|
191
|
-
if (pos.argvFromStdin) {
|
|
192
|
-
const runs = pos.program?.basename ?? "the program it runs";
|
|
193
|
-
return `"${segment.text.trim()}" hands ${runs} its operands on its standard input, which this station does not read ${NOT_AUTO_ALLOWED}`;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return `"${segment.text.trim()}" runs a program this station cannot name ${NOT_AUTO_ALLOWED}`;
|
|
197
|
-
}
|
|
198
185
|
const ACCOUNT_PART_MAX = READ_DENY_SENTENCE_PART_MAX;
|
|
199
186
|
const CAUSE_SPELLING_MAX = 64;
|
|
200
187
|
function fitCause(cause) {
|
|
@@ -236,7 +223,7 @@ function findingAccount(fold, boundary) {
|
|
|
236
223
|
return `the text given to ${reenteredPrograms(fold)} — as an argument, on standard input, or in the file it names — runs as shell text this station does not parse ${NOT_AUTO_ALLOWED}`;
|
|
237
224
|
return `the command's text could not be read as shell, so where it ${verb} cannot be established ${NOT_AUTO_ALLOWED}`;
|
|
238
225
|
case "declined":
|
|
239
|
-
return fold.declined !== undefined ?
|
|
226
|
+
return fold.declined !== undefined ? declinedProgramSentence(fold.declined.text) : `the station could not read which program runs ${NOT_AUTO_ALLOWED}`;
|
|
240
227
|
case "identity_changed":
|
|
241
228
|
return `"${fitMiddle(w?.read.candidate.raw ?? "?", ACCOUNT_PART_MAX)}" resolves to "${fitMiddle(w?.read.target ?? "?", ACCOUNT_PART_MAX)}" now, not where it resolved when this call was judged`;
|
|
242
229
|
case "deny_hit":
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* establisher and the write guards are handed an {@link ObservedFilesystem}, never the environment, so a lookup they make
|
|
10
10
|
* cannot escape the record.
|
|
11
11
|
*
|
|
12
|
-
* What is NOT a failure: a conclusive absence (`not_found`, `not_directory` — the answer is "nothing there"
|
|
12
|
+
* What is NOT a failure: a conclusive absence (`not_found`, `not_directory`, `name_too_long` — the answer is "nothing there", or
|
|
13
|
+
* "nothing can be there": the program that opens such a name fails the same way) and an adapter
|
|
13
14
|
* that has no filesystem surface (`not_supported` — its answer that there is no file face: a chain it answers so keeps the
|
|
14
15
|
* lexical reading). Everything else is, and is recorded wherever it falls — a resolver that answered nothing at all in the
|
|
15
16
|
* command included: a lookup that failed (`permission_denied`, `timeout`, `unknown`, a throw) is a resolver failing, whose
|
|
@@ -47,6 +48,9 @@ export interface ObservedEnvironment {
|
|
|
47
48
|
/** Records that came from outside the door: the declared roots' own lookup and the home views a read could not be placed against. */
|
|
48
49
|
adopt(records: readonly Incomplete[]): void;
|
|
49
50
|
}
|
|
51
|
+
/** The answers that say NOTHING IS THERE — no entry (`not_found`), nothing reachable under a non-directory (`not_directory`), a
|
|
52
|
+
* name the filesystem cannot hold (`name_too_long`): the station's one reading of an absence, wherever a lookup is read. */
|
|
53
|
+
export declare const isAbsence: (code: string) => boolean;
|
|
50
54
|
/** The declared roots, canonicalized ONCE per establisher (through the same door), with what that lookup could not finish —
|
|
51
55
|
* merged into every establishment. `known`: the caller already holds them as canonical identities and they are used verbatim
|
|
52
56
|
* (re-resolving one that was since swapped for a link would substitute the link's target for the root that was approved). */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { canonicalPathIsAuthoritative } from "../../core/remote-env.js";
|
|
2
2
|
const OBSERVED = Symbol("observedFilesystem");
|
|
3
|
-
const
|
|
3
|
+
export const isAbsence = (code) => code === "not_found" || code === "not_directory" || code === "name_too_long";
|
|
4
|
+
const conclusive = (code) => isAbsence(code) || code === "not_supported";
|
|
4
5
|
export function canonicalRootsOnce(env, readRoots, known) {
|
|
5
6
|
let once = known ? Promise.resolve({ roots: readRoots, incomplete: [] }) : undefined;
|
|
6
7
|
return (signal) => (once ??= (async () => {
|
|
@@ -21,7 +22,7 @@ export function observeEnvironment(env) {
|
|
|
21
22
|
const records = [];
|
|
22
23
|
const note = (op, path, what, code) => void records.push({ op, detail: `"${path}" ${what} (${code})` });
|
|
23
24
|
const watch = (op, path, what, ask) => new Promise((resolve) => resolve(ask())).then((r) => {
|
|
24
|
-
if (!r.ok && !
|
|
25
|
+
if (!r.ok && !conclusive(r.error.code))
|
|
25
26
|
note(op, path, what, r.error.code);
|
|
26
27
|
return r;
|
|
27
28
|
}, (e) => {
|
|
@@ -43,6 +43,7 @@ import { type ObservedEnvironment } from "./shell-read-environment.js";
|
|
|
43
43
|
import type { ShellReadPlan, ShellReadSegment } from "./shell-read-plan.js";
|
|
44
44
|
import type { EstablishedRead, ShellReadBoundary } from "./shell-read-judge.js";
|
|
45
45
|
import type { HomeViewSource } from "./read-deny-home.js";
|
|
46
|
+
import { type FsGlob } from "./fs-glob.js";
|
|
46
47
|
/**
|
|
47
48
|
* How many directories one glob operand may enumerate, and how many names it may
|
|
48
49
|
* match, before the leg gives up and answers `unestablishable`.
|
|
@@ -54,6 +55,20 @@ import type { HomeViewSource } from "./read-deny-home.js";
|
|
|
54
55
|
*/
|
|
55
56
|
export declare const MAX_GLOB_DIRS = 256;
|
|
56
57
|
export declare const MAX_GLOB_MATCHES = 8192;
|
|
58
|
+
/**
|
|
59
|
+
* Compile ONE path segment of a shell glob into a whole-name matcher (the engine in `fs-glob.ts`), or `undefined` when the
|
|
60
|
+
* pattern uses a construct this matcher does not model (the caller then fails closed).
|
|
61
|
+
*
|
|
62
|
+
* Modelled: `*` (any run of non-separator characters), `?` (one), and bracket expressions with `!`/`^`
|
|
63
|
+
* negation, `a-z` ranges, and a literal `]` in first position. A POSIX class (`[[:alpha:]]`) is deliberately widened to
|
|
64
|
+
* "any one character" rather than refused — the lexer spells such a class, and one holding a quoted character, `?` —
|
|
65
|
+
* over-matching only adds candidates to verify, the safe direction here, while refusing would cost a usable idiom.
|
|
66
|
+
*
|
|
67
|
+
* NOT modelled: a backslash. Its escaping semantics interact with the lexer's quote folding (which has
|
|
68
|
+
* already rewritten the token), so a segment carrying one is failed closed rather than guessed at. The
|
|
69
|
+
* leading-dot rule is not a property of the pattern's own text and lives in {@link globSegmentMatches}.
|
|
70
|
+
*/
|
|
71
|
+
export declare function compileGlobSegment(pattern: string): FsGlob | undefined;
|
|
57
72
|
/** The reads of one plan, established: per segment, in the plan's own order, with nested plans beside. */
|
|
58
73
|
export interface EstablishedPlan {
|
|
59
74
|
readonly plan: ShellReadPlan;
|
|
@@ -1,45 +1,44 @@
|
|
|
1
|
-
import { canonicalRootsOnce, observeEnvironment } from "./shell-read-environment.js";
|
|
1
|
+
import { canonicalRootsOnce, isAbsence, observeEnvironment } from "./shell-read-environment.js";
|
|
2
2
|
import { anchorSpelling, normalizeAbsPathLexically, pathFamilyOf } from "./safety.js";
|
|
3
3
|
import { boundaryIsTheSandbox } from "../../core/remote-env.js";
|
|
4
4
|
import { resolveOperandSpellings } from "./bash-readonly-classifier.js";
|
|
5
5
|
import { judgedCandidatesOf, sedBackupNames } from "./shell-read-write-targets.js";
|
|
6
6
|
import { movedReads, withHomeViews } from "./shell-read-identity.js";
|
|
7
7
|
import { passesUnasked } from "./shell-read-device.js";
|
|
8
|
+
import { compileFsGlob, fsGlobClass } from "./fs-glob.js";
|
|
8
9
|
const GLOB_METACHAR_RE = /[*?[]/;
|
|
9
10
|
export const MAX_GLOB_DIRS = 256;
|
|
10
11
|
export const MAX_GLOB_MATCHES = 8192;
|
|
11
12
|
const WRITE_LINK_HOPS = 32;
|
|
12
|
-
function compileGlobSegment(pattern) {
|
|
13
|
+
export function compileGlobSegment(pattern) {
|
|
13
14
|
if (pattern.includes("\\"))
|
|
14
15
|
return undefined;
|
|
15
|
-
|
|
16
|
+
const tokens = [];
|
|
16
17
|
for (let i = 0; i < pattern.length; i++) {
|
|
17
18
|
const ch = pattern[i];
|
|
18
19
|
if (ch === "*") {
|
|
19
|
-
|
|
20
|
+
tokens.push({ kind: "star" });
|
|
20
21
|
}
|
|
21
22
|
else if (ch === "?") {
|
|
22
|
-
|
|
23
|
+
tokens.push({ kind: "one" });
|
|
23
24
|
}
|
|
24
25
|
else if (ch === "[") {
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
26
|
+
const bracket = parseBracketExpression(pattern, i);
|
|
27
|
+
if (bracket === undefined)
|
|
28
|
+
tokens.push({ kind: "text", text: "[" });
|
|
28
29
|
else {
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const cls = fsGlobClass(bracket.source);
|
|
31
|
+
if (cls === undefined)
|
|
32
|
+
return undefined;
|
|
33
|
+
tokens.push({ kind: "class", class: cls });
|
|
34
|
+
i = bracket.end;
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
else {
|
|
34
|
-
|
|
38
|
+
tokens.push({ kind: "text", text: ch });
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
|
-
|
|
38
|
-
return new RegExp(`^${src}$`, "s");
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
41
|
+
return compileFsGlob(tokens, "start");
|
|
43
42
|
}
|
|
44
43
|
function parseBracketExpression(pattern, start) {
|
|
45
44
|
let i = start + 1;
|
|
@@ -248,7 +247,7 @@ function establishLegOver(seen, readRoots) {
|
|
|
248
247
|
return { value: canon.value, exact: true };
|
|
249
248
|
return { value: [canon.value.replace(TRAILING_SEP, ""), ...[...tail].reverse()].join("/"), exact: false, missing: allAbsent };
|
|
250
249
|
}
|
|
251
|
-
if (canon.error.code
|
|
250
|
+
if (!isAbsence(canon.error.code))
|
|
252
251
|
allAbsent = false;
|
|
253
252
|
tail.push(parts.pop());
|
|
254
253
|
}
|
|
@@ -339,7 +338,7 @@ function establishLegOver(seen, readRoots) {
|
|
|
339
338
|
return { unverifiable: `"${dir}" cannot be resolved to verify what "${seg}" would expand to` };
|
|
340
339
|
const listed = await env.listDir(canonDir?.value ?? dir, signal);
|
|
341
340
|
if (!listed.ok) {
|
|
342
|
-
if (listed.error.code
|
|
341
|
+
if (isAbsence(listed.error.code))
|
|
343
342
|
continue;
|
|
344
343
|
return { unverifiable: `"${dir}" cannot be enumerated to verify what "${seg}" would expand to (${listed.error.code})` };
|
|
345
344
|
}
|
|
@@ -414,7 +413,7 @@ function establishLegOver(seen, readRoots) {
|
|
|
414
413
|
return parent.missing === true ? name : undefined;
|
|
415
414
|
const entry = await env.fileInfo(joinUnder(parent.value, leaf), signal);
|
|
416
415
|
if (!entry.ok)
|
|
417
|
-
return entry.error.code
|
|
416
|
+
return isAbsence(entry.error.code) ? name : undefined;
|
|
418
417
|
if (entry.value.kind !== "symlink")
|
|
419
418
|
return name;
|
|
420
419
|
const link = await env.readLink?.(joinUnder(parent.value, leaf), signal);
|