@sema-agent/core 7.52.0 → 7.54.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 +470 -0
- package/LICENSE +3 -1
- package/README.md +3 -1
- package/dist/agents/cross-session-envelope.d.ts +8 -0
- package/dist/agents/cross-session-envelope.js +6 -0
- package/dist/agents/cross-session-judge.d.ts +21 -1
- package/dist/agents/cross-session-judge.js +8 -0
- package/dist/agents/cross-session-ref.d.ts +5 -0
- package/dist/agents/cross-session-ref.js +1 -0
- package/dist/agents/org-delivery-gate.d.ts +122 -0
- package/dist/agents/org-delivery-gate.js +69 -0
- package/dist/agents/peer-held-queue.d.ts +9 -4
- package/dist/agents/peer-held-queue.js +6 -5
- package/dist/agents/peer-session-drain.d.ts +35 -6
- package/dist/agents/peer-session-drain.js +271 -182
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +6 -5
- package/dist/agents/subagent.js +117 -83
- package/dist/agents/tool-filter.d.ts +25 -4
- package/dist/agents/tool-filter.js +13 -3
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +4 -4
- package/dist/brain/model-presets.js +2 -1
- package/dist/brain/route-adjudicator.d.ts +6 -0
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +33 -14
- package/dist/core/allow-entry.d.ts +3 -1
- package/dist/core/allow-entry.js +3 -2
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +106 -50
- package/dist/core/auto-compaction.js +69 -53
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +60 -36
- package/dist/core/checkpoint-store.js +7 -6
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/compliance.js +3 -1
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +28 -6
- package/dist/core/effective-path-target.js +28 -2
- package/dist/core/engine-notice.d.ts +47 -4
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +13 -4
- package/dist/core/gate-lanes.js +41 -34
- package/dist/core/gate-outcome.d.ts +18 -9
- package/dist/core/governance-codes.d.ts +9 -2
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hands-band-screen.d.ts +7 -0
- package/dist/core/hands-band-screen.js +32 -0
- package/dist/core/hooks.d.ts +21 -19
- package/dist/core/hooks.js +6 -5
- package/dist/core/locked-config.d.ts +110 -31
- package/dist/core/locked-config.js +155 -42
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +152 -17
- package/dist/core/mcp-server-spec.js +223 -40
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +59 -54
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +9 -6
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +16 -26
- package/dist/core/mode-policy.js +5 -18
- package/dist/core/mods/kernel/dispatch.js +13 -15
- package/dist/core/mods/kernel/events.d.ts +9 -6
- package/dist/core/mods/kernel/events.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +41 -11
- package/dist/core/mods/kernel/receive.js +124 -54
- package/dist/core/mods/kernel/site-rules.d.ts +80 -15
- package/dist/core/mods/kernel/site-rules.js +232 -40
- package/dist/core/mods/stations.d.ts +0 -6
- package/dist/core/mods/stations.js +0 -7
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +71 -2
- package/dist/core/own-property-receipt.d.ts +13 -0
- package/dist/core/own-property-receipt.js +3 -1
- package/dist/core/parent-spec-seat.d.ts +12 -15
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +87 -15
- package/dist/core/permission-rule-model.js +87 -8
- package/dist/core/permission-rule-org.d.ts +200 -33
- package/dist/core/permission-rule-org.js +217 -91
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +8 -2
- package/dist/core/retired-keys.js +12 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +34 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +77 -34
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
- package/dist/core/runner/permission-rule-lanes.js +22 -10
- package/dist/core/runner/person-path-rows.d.ts +5 -3
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +58 -15
- package/dist/core/runner/prepare-config-doors.js +167 -146
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +8 -7
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +3 -2
- package/dist/core/runner/prepare-listings.d.ts +1 -1
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
- package/dist/core/runner/prepare-memory-engine-session.js +19 -6
- package/dist/core/runner/prepare-memory.d.ts +3 -2
- package/dist/core/runner/prepare-memory.js +6 -2
- package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
- package/dist/core/runner/prepare-offload-wrappers.js +2 -1
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -19
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +6 -4
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-assembly.js +20 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
- package/dist/core/runner/prepare-prompt-inputs.js +6 -3
- package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
- package/dist/core/runner/prepare-protocol-tools.js +19 -12
- package/dist/core/runner/prepare-question-face.d.ts +4 -2
- package/dist/core/runner/prepare-question-face.js +4 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +22 -19
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
- package/dist/core/runner/prepare-wiring-manifest.js +9 -6
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +16 -14
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
- package/dist/core/runner/resume-internals-and-config.js +3 -8
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +97 -43
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +21 -9
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
- package/dist/core/runner/sub-agent-deny-lists.js +7 -5
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +37 -22
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +44 -6
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +7 -7
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +67 -23
- package/dist/core/tool-policy.js +72 -60
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +23 -0
- package/dist/core/untrusted-text.js +10 -10
- package/dist/core/user-attachment.d.ts +56 -2
- package/dist/core/user-attachment.js +139 -56
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +10 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +17 -5
- package/dist/engine/loop/types.d.ts +7 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +37 -17
- package/dist/index.js +31 -14
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/artifact-store.d.ts +44 -9
- package/dist/prompt-assembly/artifact-store.js +38 -12
- package/dist/prompt-assembly/artifact.d.ts +12 -11
- package/dist/prompt-assembly/artifact.js +52 -21
- package/dist/prompt-assembly/assemble.d.ts +2 -0
- package/dist/prompt-assembly/assemble.js +2 -1
- package/dist/prompt-assembly/catalog/index.js +2 -1
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/composer.d.ts +2 -0
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/overlay.d.ts +21 -11
- package/dist/prompt-assembly/overlay.js +57 -19
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +41 -4
- package/dist/prompts/default.d.ts +1 -12
- package/dist/prompts/default.js +0 -3
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +14 -3
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5651 -5457
- package/wire-changes/core@7.53.0.json +1968 -0
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
package/dist/shell/lex.js
CHANGED
|
@@ -2,13 +2,14 @@ import { shellWordsOf } from "./shell-words.js";
|
|
|
2
2
|
export const SHELL_LEX_DIALECT = "bash";
|
|
3
3
|
export const QUOTE_KINDS = Object.freeze(["'", '"', "$'", '$"', "\\"]);
|
|
4
4
|
export const EXPANSION_KINDS = Object.freeze(["parameter", "command", "process", "arithmetic", "tilde", "brace", "glob"]);
|
|
5
|
-
export const UNRESOLVED_REASONS = Object.freeze(["ansi_c_escape", "locale_string", "parameter_text", "subscript_text", "compound_array_value"]);
|
|
5
|
+
export const UNRESOLVED_REASONS = Object.freeze(["ansi_c_escape", "locale_string", "parameter_text", "subscript_text", "compound_array_value", "trailing_backslash"]);
|
|
6
6
|
export const UNRESOLVED_SENTENCE = {
|
|
7
7
|
ansi_c_escape: "an ANSI-C quoted word carries an escape this lexer does not fold",
|
|
8
8
|
locale_string: "a locale-translated string carries text this lexer does not read",
|
|
9
9
|
parameter_text: "a parameter expansion carries text this lexer does not read",
|
|
10
10
|
subscript_text: "a subscript carries text this lexer does not read",
|
|
11
11
|
compound_array_value: "a compound assignment value is a list this lexer does not read",
|
|
12
|
+
trailing_backslash: "a backslash ends the command, which the shell versions read differently (3.2 drops it, 5 keeps it)",
|
|
12
13
|
};
|
|
13
14
|
export const PARSE_FAILURE_REASONS = Object.freeze([
|
|
14
15
|
"unterminated_single_quote",
|
|
@@ -19,6 +20,7 @@ export const PARSE_FAILURE_REASONS = Object.freeze([
|
|
|
19
20
|
"unterminated_command_substitution",
|
|
20
21
|
"unterminated_process_substitution",
|
|
21
22
|
"unterminated_parameter_expansion",
|
|
23
|
+
"unterminated_arithmetic_expansion",
|
|
22
24
|
"unterminated_heredoc",
|
|
23
25
|
"undelimited_substitution",
|
|
24
26
|
"redirect_without_target",
|
|
@@ -34,6 +36,7 @@ export const PARSE_FAILURE_SENTENCE = {
|
|
|
34
36
|
unterminated_command_substitution: "a command substitution never terminates",
|
|
35
37
|
unterminated_process_substitution: "a process substitution never terminates",
|
|
36
38
|
unterminated_parameter_expansion: "a parameter expansion never terminates",
|
|
39
|
+
unterminated_arithmetic_expansion: "an arithmetic expansion never terminates",
|
|
37
40
|
unterminated_heredoc: "a here-document body never terminates",
|
|
38
41
|
undelimited_substitution: "a command substitution carries a construct this lexer cannot delimit",
|
|
39
42
|
redirect_without_target: "a redirection names no target",
|
|
@@ -71,13 +74,14 @@ export const SUBSTITUTION_PLACEHOLDER = " subst";
|
|
|
71
74
|
export const SHELL_CONTROL_PREFIXES = shellWordsOf("control_prefix");
|
|
72
75
|
const COMPOUND_OPERAND_COMMANDS = new Set(["alias", "declare", "eval", "export", "let", "local", "readonly", "typeset"]);
|
|
73
76
|
const GROUP_WORDS = shellWordsOf("group");
|
|
77
|
+
const SCOPE_OPEN_WORDS = shellWordsOf("scope_open");
|
|
74
78
|
const DEFINITION_WORDS = shellWordsOf("definition");
|
|
75
79
|
const BACKGROUND_WORDS = shellWordsOf("background");
|
|
76
80
|
const COMPOUND_OPEN_WORDS = shellWordsOf("compound_open");
|
|
77
81
|
const CASE_ARM_WORDS = shellWordsOf("case_arms");
|
|
78
82
|
const TIMER_WORDS = shellWordsOf("timer");
|
|
79
83
|
export function dollarOpensQuote(text, at) {
|
|
80
|
-
const next = text[at + 1];
|
|
84
|
+
const next = text[past(text, at + 1)];
|
|
81
85
|
if (next !== "'" && next !== '"')
|
|
82
86
|
return false;
|
|
83
87
|
let run = 0;
|
|
@@ -218,7 +222,7 @@ function heredocHeaderAt(text, from, dash, op) {
|
|
|
218
222
|
return fail("heredoc_without_delimiter", op);
|
|
219
223
|
if (/[~[]/.test(raw))
|
|
220
224
|
return "undelimited";
|
|
221
|
-
const lexed = scan(raw, true);
|
|
225
|
+
const lexed = scan(raw, true, [firstSegment(raw)], 0);
|
|
222
226
|
const tokens = "command" in lexed && lexed.command.segments.length === 1 ? lexed.command.segments[0].tokens : [];
|
|
223
227
|
const word = tokens.length === 1 ? tokens[0] : undefined;
|
|
224
228
|
if (word?.kind !== "word")
|
|
@@ -228,8 +232,9 @@ function heredocHeaderAt(text, from, dash, op) {
|
|
|
228
232
|
}
|
|
229
233
|
const BASH_READING = { heredoc: true, startComment: true };
|
|
230
234
|
const BASH32_READINGS = [{ heredoc: false, startComment: true }, { heredoc: false, startComment: false }];
|
|
235
|
+
const ARITHMETIC_READING = { heredoc: false, startComment: true, arithmetic: true };
|
|
231
236
|
const BODY_NESTING_MAX = 64;
|
|
232
|
-
function walkBody(text, open, reading, inDouble, level
|
|
237
|
+
function walkBody(text, open, reading, inDouble, level) {
|
|
233
238
|
if (level > BODY_NESTING_MAX)
|
|
234
239
|
return "undelimited";
|
|
235
240
|
let depth = 0;
|
|
@@ -237,9 +242,10 @@ function walkBody(text, open, reading, inDouble, level = 0) {
|
|
|
237
242
|
let wordStart = true;
|
|
238
243
|
let word = "";
|
|
239
244
|
let heredoc = false;
|
|
245
|
+
let innerClose;
|
|
240
246
|
const owed = [];
|
|
241
247
|
const nested = (at, dq) => {
|
|
242
|
-
const inner = walkBody(text, at, reading, dq, level + 1);
|
|
248
|
+
const inner = walkBody(text, at, reading.arithmetic === true ? BASH_READING : reading, dq, level + 1);
|
|
243
249
|
if (typeof inner === "object" && "end" in inner) {
|
|
244
250
|
heredoc ||= inner.heredoc;
|
|
245
251
|
return inner.end - 1;
|
|
@@ -278,6 +284,13 @@ function walkBody(text, open, reading, inDouble, level = 0) {
|
|
|
278
284
|
continue;
|
|
279
285
|
}
|
|
280
286
|
if (c === "$" && text[k] === "{") {
|
|
287
|
+
if (opensCurrentShellSubstitution(text, k)) {
|
|
288
|
+
const run = currentShellSubstitutionEnd(text, k, level + 1);
|
|
289
|
+
if (typeof run !== "object" || !("end" in run))
|
|
290
|
+
return run;
|
|
291
|
+
j = run.end - 1;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
281
294
|
const close = braceExpansionEnd(text, k);
|
|
282
295
|
if (close === undefined)
|
|
283
296
|
return "unterminated";
|
|
@@ -356,7 +369,16 @@ function walkBody(text, open, reading, inDouble, level = 0) {
|
|
|
356
369
|
word = "$";
|
|
357
370
|
continue;
|
|
358
371
|
}
|
|
359
|
-
if (reading.heredoc && c === "$" && text[k] === "{") {
|
|
372
|
+
if ((reading.heredoc || reading.arithmetic === true) && c === "$" && text[k] === "{") {
|
|
373
|
+
if (opensCurrentShellSubstitution(text, k)) {
|
|
374
|
+
const run = currentShellSubstitutionEnd(text, k, level + 1);
|
|
375
|
+
if (typeof run !== "object" || !("end" in run))
|
|
376
|
+
return run;
|
|
377
|
+
j = run.end - 1;
|
|
378
|
+
wordStart = false;
|
|
379
|
+
word = "";
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
360
382
|
const close = braceExpansionEnd(text, k);
|
|
361
383
|
if (close === undefined)
|
|
362
384
|
return "unterminated";
|
|
@@ -383,8 +405,10 @@ function walkBody(text, open, reading, inDouble, level = 0) {
|
|
|
383
405
|
depth++;
|
|
384
406
|
else if (c === ")") {
|
|
385
407
|
depth--;
|
|
408
|
+
if (depth === 1)
|
|
409
|
+
innerClose ??= j;
|
|
386
410
|
if (depth === 0)
|
|
387
|
-
return owed.length > 0 ? "undelimited" : { end: j + 1, heredoc };
|
|
411
|
+
return owed.length > 0 ? "undelimited" : { end: j + 1, heredoc, ...(innerClose !== undefined ? { innerClose } : {}) };
|
|
388
412
|
}
|
|
389
413
|
if (!reading.heredoc) {
|
|
390
414
|
wordStart = j === open ? reading.startComment && !inDouble && level === 0 : c === " " || c === "\t" || c === "\n";
|
|
@@ -398,18 +422,29 @@ function walkBody(text, open, reading, inDouble, level = 0) {
|
|
|
398
422
|
}
|
|
399
423
|
return "unterminated";
|
|
400
424
|
}
|
|
401
|
-
function substitutionBodyEnd(text, open, inDouble) {
|
|
402
|
-
const
|
|
425
|
+
function substitutionBodyEnd(text, open, inDouble, level) {
|
|
426
|
+
const arithmetic = arithmeticWalk(text, open, inDouble, level);
|
|
427
|
+
if (arithmetic !== undefined)
|
|
428
|
+
return { end: arithmetic.end, arithmetic: true };
|
|
429
|
+
const read = walkBody(text, open, BASH_READING, inDouble, level);
|
|
403
430
|
if (typeof read !== "object" || !("end" in read))
|
|
404
431
|
return read;
|
|
405
432
|
if (!read.heredoc)
|
|
406
|
-
return read.end;
|
|
433
|
+
return { end: read.end, arithmetic: false };
|
|
407
434
|
for (const reading of BASH32_READINGS) {
|
|
408
|
-
const counted = walkBody(text, open, reading, inDouble);
|
|
435
|
+
const counted = walkBody(text, open, reading, inDouble, level);
|
|
409
436
|
if (counted !== "unterminated" && !(typeof counted === "object" && "end" in counted && counted.end === read.end))
|
|
410
437
|
return "undelimited";
|
|
411
438
|
}
|
|
412
|
-
return read.end;
|
|
439
|
+
return { end: read.end, arithmetic: false };
|
|
440
|
+
}
|
|
441
|
+
function arithmeticWalk(text, open, inDouble, level) {
|
|
442
|
+
if (text[past(text, open + 1)] !== "(")
|
|
443
|
+
return undefined;
|
|
444
|
+
const read = walkBody(text, open, ARITHMETIC_READING, inDouble, level);
|
|
445
|
+
if (typeof read !== "object" || !("end" in read) || read.heredoc || read.innerClose === undefined)
|
|
446
|
+
return undefined;
|
|
447
|
+
return past(text, read.innerClose + 1) === read.end - 1 ? { end: read.end, heredoc: false } : undefined;
|
|
413
448
|
}
|
|
414
449
|
function braceExpansionEnd(text, open) {
|
|
415
450
|
let quoted;
|
|
@@ -435,7 +470,47 @@ function braceExpansionEnd(text, open) {
|
|
|
435
470
|
}
|
|
436
471
|
return undefined;
|
|
437
472
|
}
|
|
438
|
-
function
|
|
473
|
+
function opensCurrentShellSubstitution(text, open) {
|
|
474
|
+
const after = text[open + 1];
|
|
475
|
+
return after === "|" || after === " " || after === "\t" || after === "\n";
|
|
476
|
+
}
|
|
477
|
+
function currentShellSubstitutionEnd(text, open, level) {
|
|
478
|
+
if (level > BODY_NESTING_MAX)
|
|
479
|
+
return "undelimited";
|
|
480
|
+
const list = { from: open + (text[open + 1] === "|" ? 2 : 1), groups: 0 };
|
|
481
|
+
const read = scan(text, false, [firstSegment(text)], level, list);
|
|
482
|
+
if ("parseFailure" in read)
|
|
483
|
+
return read;
|
|
484
|
+
return list.closed === undefined ? "undelimited" : { end: list.closed, from: list.from };
|
|
485
|
+
}
|
|
486
|
+
function bracketExpansionEnd(text, open) {
|
|
487
|
+
let depth = 0;
|
|
488
|
+
let quoted;
|
|
489
|
+
for (let j = open; j < text.length; j++) {
|
|
490
|
+
const c = text[j];
|
|
491
|
+
if (quoted !== undefined) {
|
|
492
|
+
if (c === "\\" && quoted === '"')
|
|
493
|
+
j++;
|
|
494
|
+
else if (c === quoted)
|
|
495
|
+
quoted = undefined;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
if (c === "\\") {
|
|
499
|
+
j++;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
if (c === "'" || c === '"') {
|
|
503
|
+
quoted = c;
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
if (c === "[")
|
|
507
|
+
depth++;
|
|
508
|
+
else if (c === "]" && --depth === 0)
|
|
509
|
+
return j + 1;
|
|
510
|
+
}
|
|
511
|
+
return undefined;
|
|
512
|
+
}
|
|
513
|
+
function matchedParen(text, open, level) {
|
|
439
514
|
let depth = 0;
|
|
440
515
|
let quoted;
|
|
441
516
|
for (let j = open; j < text.length; j++) {
|
|
@@ -463,6 +538,13 @@ function matchedParen(text, open) {
|
|
|
463
538
|
continue;
|
|
464
539
|
}
|
|
465
540
|
if (c === "$" && text[j + 1] === "{") {
|
|
541
|
+
if (opensCurrentShellSubstitution(text, j + 1)) {
|
|
542
|
+
const run = currentShellSubstitutionEnd(text, j + 1, level + 1);
|
|
543
|
+
if (typeof run !== "object" || !("end" in run))
|
|
544
|
+
return run === "undelimited" ? fail("undelimited_substitution", j) : run;
|
|
545
|
+
j = run.end - 1;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
466
548
|
const close = braceExpansionEnd(text, j + 1);
|
|
467
549
|
if (close === undefined)
|
|
468
550
|
return undefined;
|
|
@@ -477,9 +559,12 @@ function matchedParen(text, open) {
|
|
|
477
559
|
return undefined;
|
|
478
560
|
}
|
|
479
561
|
const UNREADABLE_EXPANSION_TEXT = /[$`()<>{\\]/;
|
|
480
|
-
const
|
|
562
|
+
const PARAMETER = String.raw `(?:[A-Za-z_][A-Za-z0-9_]*|\d+|[*@#?$!-])`;
|
|
563
|
+
const PARAMETER_HEAD = new RegExp(String.raw `^[#!]?${PARAMETER}`);
|
|
564
|
+
const EXPANSION_NAME = new RegExp(String.raw `^[#!]?(${PARAMETER})`);
|
|
481
565
|
const BARE_PARAMETER = /^(?:[A-Za-z_][A-Za-z0-9_]*|\d|[@*#?$!0-])/;
|
|
482
566
|
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
567
|
+
const PER_ELEMENT_BODY = /^!?@|\[@\]|^![^}]*@$/;
|
|
483
568
|
const NAME_HEAD = /^[A-Za-z_][A-Za-z0-9_]*/;
|
|
484
569
|
function backtickBody(source, open) {
|
|
485
570
|
let body = "";
|
|
@@ -501,7 +586,7 @@ function backtickBody(source, open) {
|
|
|
501
586
|
}
|
|
502
587
|
return undefined;
|
|
503
588
|
}
|
|
504
|
-
export function
|
|
589
|
+
export function expansionsInHeredocBody(body) {
|
|
505
590
|
const out = [];
|
|
506
591
|
for (let i = 0; i < body.length; i++) {
|
|
507
592
|
const ch = body[i];
|
|
@@ -513,20 +598,121 @@ export function substitutionsInHeredocBody(body) {
|
|
|
513
598
|
const tick = backtickBody(body, i);
|
|
514
599
|
if (tick === undefined)
|
|
515
600
|
return undefined;
|
|
516
|
-
out.push({
|
|
601
|
+
out.push({ expansion: { kind: "command", yields: "one", body: tick.body } });
|
|
517
602
|
i = tick.close;
|
|
518
603
|
continue;
|
|
519
604
|
}
|
|
520
|
-
if (ch
|
|
521
|
-
|
|
522
|
-
|
|
605
|
+
if (ch !== "$")
|
|
606
|
+
continue;
|
|
607
|
+
const open = body[i + 1];
|
|
608
|
+
if (open === "(") {
|
|
609
|
+
const close = substitutionBodyEnd(body, i + 1, true, 0);
|
|
610
|
+
if (typeof close !== "object" || !("end" in close))
|
|
611
|
+
return undefined;
|
|
612
|
+
out.push({ expansion: { kind: close.arithmetic ? "arithmetic" : "command", yields: "one", body: body.slice(i + 2, close.end - 1) } });
|
|
613
|
+
i = close.end - 1;
|
|
614
|
+
}
|
|
615
|
+
else if (open === "[") {
|
|
616
|
+
const end = bracketExpansionEnd(body, i + 1);
|
|
617
|
+
if (end === undefined)
|
|
523
618
|
return undefined;
|
|
524
|
-
out.push({ body: body.slice(i + 2, end - 1)
|
|
619
|
+
out.push({ expansion: { kind: "arithmetic", yields: "one", body: body.slice(i + 2, end - 1) } });
|
|
525
620
|
i = end - 1;
|
|
526
621
|
}
|
|
622
|
+
else if (open === "{") {
|
|
623
|
+
if (opensCurrentShellSubstitution(body, i + 1)) {
|
|
624
|
+
const run = currentShellSubstitutionEnd(body, i + 1, 1);
|
|
625
|
+
if (typeof run !== "object" || !("end" in run))
|
|
626
|
+
return undefined;
|
|
627
|
+
out.push({ expansion: { kind: "command", yields: "one", body: body.slice(run.from, run.end - 1) }, currentShell: true });
|
|
628
|
+
i = run.end - 1;
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
const end = braceExpansionEnd(body, i + 1);
|
|
632
|
+
if (end === undefined)
|
|
633
|
+
return undefined;
|
|
634
|
+
const text = body.slice(i + 2, end - 1);
|
|
635
|
+
const name = EXPANSION_NAME.exec(text)?.[1];
|
|
636
|
+
out.push({ expansion: { kind: "parameter", yields: "one", body: text, ...(name !== undefined ? { name } : {}) }, ...(UNREADABLE_EXPANSION_TEXT.test(text) ? { unresolved: "parameter_text" } : {}) });
|
|
637
|
+
i = end - 1;
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
const head = BARE_PARAMETER.exec(body.slice(i + 1, i + 65))?.[0];
|
|
641
|
+
if (head === undefined)
|
|
642
|
+
continue;
|
|
643
|
+
out.push({ expansion: { kind: "parameter", yields: "one", name: head } });
|
|
644
|
+
i += head.length;
|
|
645
|
+
}
|
|
527
646
|
}
|
|
528
647
|
return out;
|
|
529
648
|
}
|
|
649
|
+
export function substitutionsInHeredocBody(body) {
|
|
650
|
+
const all = expansionsInHeredocBody(body);
|
|
651
|
+
if (all === undefined)
|
|
652
|
+
return undefined;
|
|
653
|
+
return all.flatMap(({ expansion: e, currentShell }) => (e.kind === "command" || e.kind === "arithmetic" ? [{ body: e.body ?? "", kind: e.kind, ...(currentShell === true ? { currentShell } : {}) }] : []));
|
|
654
|
+
}
|
|
655
|
+
export function heredocBodyHidesRun(body) {
|
|
656
|
+
const all = expansionsInHeredocBody(body);
|
|
657
|
+
return all === undefined || /[<>]\(/.test(body) || all.some((x) => x.unresolved !== undefined || expansionHidesRun(x.expansion));
|
|
658
|
+
}
|
|
659
|
+
const SUBSTITUTION_OPENER = /\$\(|`|<\(|>\(|\$\[/;
|
|
660
|
+
export function parameterArithmeticTexts(body) {
|
|
661
|
+
const text = body.replace(/\\\n/g, "");
|
|
662
|
+
const head = PARAMETER_HEAD.exec(text);
|
|
663
|
+
if (head === null)
|
|
664
|
+
return {};
|
|
665
|
+
let rest = text.slice(head[0].length);
|
|
666
|
+
let subscript;
|
|
667
|
+
if (rest.startsWith("[")) {
|
|
668
|
+
const close = rest.indexOf("]");
|
|
669
|
+
subscript = rest.slice(1, close < 0 ? undefined : close);
|
|
670
|
+
rest = close < 0 ? "" : rest.slice(close + 1);
|
|
671
|
+
}
|
|
672
|
+
const offset = /^:(?![-=+?])(.*)$/s.exec(rest)?.[1];
|
|
673
|
+
return { ...(subscript !== undefined ? { subscript } : {}), ...(offset !== undefined ? { offset } : {}) };
|
|
674
|
+
}
|
|
675
|
+
function bodyEvaluatesText(body) {
|
|
676
|
+
const { subscript, offset } = parameterArithmeticTexts(body);
|
|
677
|
+
return (subscript !== undefined && /[A-Za-z_$]/.test(subscript)) || (offset !== undefined && /^[^}]*[A-Za-z_$]/.test(offset));
|
|
678
|
+
}
|
|
679
|
+
function nestedBodyEvaluatesText(text) {
|
|
680
|
+
for (let i = text.indexOf("${"); i >= 0; i = text.indexOf("${", i + 1))
|
|
681
|
+
if (bodyEvaluatesText(text.slice(i + 2)))
|
|
682
|
+
return true;
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
const TRANSFORM_FORM = new RegExp(String.raw `^${PARAMETER}(?:\[(?:'[^']*'|"(?:[^"\\]|\\.)*"|\\.|[^\]'"\\])*\])?@([A-Za-z])$`, "s");
|
|
686
|
+
const RESPELLING_TRANSFORMS = new Set(["Q", "E", "A", "K", "k", "a", "U", "u", "L"]);
|
|
687
|
+
const NAME_OR_KEY_LIST = /^![A-Za-z_][A-Za-z0-9_]*(?:[*@]|\[[@*]\])$/;
|
|
688
|
+
const PLAIN_ARITHMETIC = /^[\s\d+\-*/%&|^~!<>=?:,()]*$/;
|
|
689
|
+
export function expansionHidesRun(e) {
|
|
690
|
+
if (e.kind === "command" || e.kind === "process" || e.inner?.some(expansionHidesRun) === true)
|
|
691
|
+
return true;
|
|
692
|
+
const body = e.body?.replace(/\\\n/g, "");
|
|
693
|
+
if (body === undefined)
|
|
694
|
+
return false;
|
|
695
|
+
if (e.kind === "arithmetic")
|
|
696
|
+
return !PLAIN_ARITHMETIC.test(body);
|
|
697
|
+
return SUBSTITUTION_OPENER.test(body) || (e.kind === "parameter" && (bodyEvaluatesText(body) || parameterRereadsValue(body))) || nestedBodyEvaluatesText(body);
|
|
698
|
+
}
|
|
699
|
+
export function compoundValueHidesRun(w) {
|
|
700
|
+
return w.assignment?.form === "compound" && /\$(?!')|`|\[[^\]]*[$`A-Za-z_]/.test(w.assignment.value.raw);
|
|
701
|
+
}
|
|
702
|
+
export function transformEvaluates(body) {
|
|
703
|
+
const transform = TRANSFORM_FORM.exec(body)?.[1];
|
|
704
|
+
return transform !== undefined && !RESPELLING_TRANSFORMS.has(transform);
|
|
705
|
+
}
|
|
706
|
+
export function parameterRereadsValue(body) {
|
|
707
|
+
const text = body.replace(/\\\n/g, "");
|
|
708
|
+
return (text.startsWith("!") && !NAME_OR_KEY_LIST.test(text)) || transformEvaluates(text);
|
|
709
|
+
}
|
|
710
|
+
export function arithmeticTextIsPlain(text) {
|
|
711
|
+
return PLAIN_ARITHMETIC.test(text.replace(/\\\n/g, ""));
|
|
712
|
+
}
|
|
713
|
+
export function namesRedirectDescriptor(word, next) {
|
|
714
|
+
return next?.kind === "redirect" && word.expansions.length === 0 && word.quotedSpans.length === 0 && /^\{[A-Za-z_][A-Za-z0-9_]*\}$/.test(word.raw);
|
|
715
|
+
}
|
|
530
716
|
export function literalTextOf(pieces) {
|
|
531
717
|
return pieces.every((q) => q.literal !== undefined) ? pieces.map((q) => q.literal).join("") : undefined;
|
|
532
718
|
}
|
|
@@ -717,7 +903,8 @@ class WordBuilder {
|
|
|
717
903
|
const covering = this.pieces.find((p) => p.literal !== undefined && p.rawStart <= from && p.rawEnd >= to);
|
|
718
904
|
if (covering === undefined)
|
|
719
905
|
return;
|
|
720
|
-
|
|
906
|
+
const body = this.raw.slice(from, to);
|
|
907
|
+
this.carve(from, to, { kind: "tilde", yields: /[*?[]/.test(body) ? "many" : "one", body });
|
|
721
908
|
}
|
|
722
909
|
carveBraceAndGlob() {
|
|
723
910
|
const inExp = this.inExpansion();
|
|
@@ -816,6 +1003,14 @@ class WordBuilder {
|
|
|
816
1003
|
k = close;
|
|
817
1004
|
}
|
|
818
1005
|
}
|
|
1006
|
+
const enclosed = this.pieces.filter((p) => p.expansion !== undefined);
|
|
1007
|
+
if (enclosed.length > 0) {
|
|
1008
|
+
for (const r of ranges) {
|
|
1009
|
+
const inner = enclosed.filter((p) => p.rawStart >= r.from && p.rawEnd <= r.to).map((p) => p.expansion);
|
|
1010
|
+
if (inner.length > 0)
|
|
1011
|
+
r.exp = { ...r.exp, inner };
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
819
1014
|
this.carveAll(ranges);
|
|
820
1015
|
}
|
|
821
1016
|
readAssignment() {
|
|
@@ -955,9 +1150,8 @@ class WordBuilder {
|
|
|
955
1150
|
};
|
|
956
1151
|
}
|
|
957
1152
|
}
|
|
958
|
-
function scan(source, connectorsAreText) {
|
|
1153
|
+
function scan(source, connectorsAreText, segments, level, list) {
|
|
959
1154
|
const split = !connectorsAreText;
|
|
960
|
-
const segments = [{ start: 0, end: source.length, connector: "start", tokens: [], substitutions: [] }];
|
|
961
1155
|
const current = () => segments[segments.length - 1];
|
|
962
1156
|
const pendingHeredocs = [];
|
|
963
1157
|
let pendingRedirect;
|
|
@@ -981,7 +1175,7 @@ function scan(source, connectorsAreText) {
|
|
|
981
1175
|
const take = (ch, src) => w.emit(ch, ch, quotedBy(), src, src + 1);
|
|
982
1176
|
const substitution = (from, to, body, kind) => {
|
|
983
1177
|
const by = quotedBy();
|
|
984
|
-
w.opaque(source.slice(from, to), SUBSTITUTION_PLACEHOLDER, by, from, to, { kind, yields: kind
|
|
1178
|
+
w.opaque(source.slice(from, to), SUBSTITUTION_PLACEHOLDER, by, from, to, { kind, yields: kind !== "process" && by === undefined ? "many" : "one", body });
|
|
985
1179
|
current().substitutions.push(body);
|
|
986
1180
|
};
|
|
987
1181
|
const resetPosition = () => { acceptable = true; commandWord = undefined; afterLeadingRedirect = false; assignmentSeen = false; subscriptsClosed = false; timeGrammar = undefined; definitionName = false; coprocWord = undefined; };
|
|
@@ -1038,6 +1232,8 @@ function scan(source, connectorsAreText) {
|
|
|
1038
1232
|
return undefined;
|
|
1039
1233
|
}
|
|
1040
1234
|
if (acceptable && bare && (SHELL_CONTROL_PREFIXES.has(word.folded) || GROUP_WORDS.has(word.folded))) {
|
|
1235
|
+
if (list !== undefined && GROUP_WORDS.has(word.folded))
|
|
1236
|
+
list.groups += SCOPE_OPEN_WORDS.has(word.folded) ? 1 : -1;
|
|
1041
1237
|
timeGrammar = TIMER_WORDS.has(word.folded) ? "opt" : undefined;
|
|
1042
1238
|
coprocWord = undefined;
|
|
1043
1239
|
return undefined;
|
|
@@ -1088,7 +1284,7 @@ function scan(source, connectorsAreText) {
|
|
|
1088
1284
|
pendingHeredocs.length = 0;
|
|
1089
1285
|
return read.resume;
|
|
1090
1286
|
};
|
|
1091
|
-
for (let i = 0; i < source.length; i++) {
|
|
1287
|
+
for (let i = list?.from ?? 0; i < source.length; i++) {
|
|
1092
1288
|
if (!inSingle) {
|
|
1093
1289
|
const j = past(source, i);
|
|
1094
1290
|
if (j >= source.length)
|
|
@@ -1096,6 +1292,12 @@ function scan(source, connectorsAreText) {
|
|
|
1096
1292
|
i = j;
|
|
1097
1293
|
}
|
|
1098
1294
|
const ch = source[i];
|
|
1295
|
+
if (list !== undefined && ch === "}" && list.groups === 0 && !inSingle && !inDouble && !w.started && acceptable && pendingRedirect === undefined && pendingHeredoc === undefined) {
|
|
1296
|
+
if (pendingHeredocs.length > 0)
|
|
1297
|
+
return fail("undelimited_substitution", i);
|
|
1298
|
+
list.closed = i + 1;
|
|
1299
|
+
return { command: { segments: [], substitutions: [] } };
|
|
1300
|
+
}
|
|
1099
1301
|
if (ch === "$" && !inSingle && !inDouble && dollarOpensQuote(source, i)) {
|
|
1100
1302
|
const q = next(i);
|
|
1101
1303
|
if (source[q] === '"') {
|
|
@@ -1198,7 +1400,8 @@ function scan(source, connectorsAreText) {
|
|
|
1198
1400
|
if (ch === "\\") {
|
|
1199
1401
|
const escaped = source[i + 1];
|
|
1200
1402
|
if (escaped === undefined) {
|
|
1201
|
-
|
|
1403
|
+
w.mark("trailing_backslash", w.raw.length);
|
|
1404
|
+
w.opaque(ch, ch, "\\", i, i + 1, undefined);
|
|
1202
1405
|
continue;
|
|
1203
1406
|
}
|
|
1204
1407
|
if (inDouble && !"$`\"\\".includes(escaped))
|
|
@@ -1217,15 +1420,31 @@ function scan(source, connectorsAreText) {
|
|
|
1217
1420
|
continue;
|
|
1218
1421
|
}
|
|
1219
1422
|
if (ch === "$" && source[n1] === "(") {
|
|
1220
|
-
const
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1423
|
+
const close = substitutionBodyEnd(source, n1, inDouble, level);
|
|
1424
|
+
if (typeof close !== "object" || !("end" in close))
|
|
1425
|
+
return close === "unterminated" ? fail("unterminated_command_substitution", i) : close === "undelimited" ? fail("undelimited_substitution", i) : close;
|
|
1426
|
+
substitution(i, close.end, source.slice(n1 + 1, close.end - 1), close.arithmetic ? "arithmetic" : "command");
|
|
1427
|
+
i = close.end - 1;
|
|
1428
|
+
continue;
|
|
1429
|
+
}
|
|
1430
|
+
if (ch === "$" && source[n1] === "[") {
|
|
1431
|
+
const end = bracketExpansionEnd(source, n1);
|
|
1432
|
+
if (end === undefined)
|
|
1433
|
+
return fail("unterminated_arithmetic_expansion", i);
|
|
1434
|
+
substitution(i, end, source.slice(n1 + 1, end - 1), "arithmetic");
|
|
1225
1435
|
i = end - 1;
|
|
1226
1436
|
continue;
|
|
1227
1437
|
}
|
|
1228
1438
|
if (ch === "$" && source[n1] === "{") {
|
|
1439
|
+
if (opensCurrentShellSubstitution(source, n1)) {
|
|
1440
|
+
const run = currentShellSubstitutionEnd(source, n1, level + 1);
|
|
1441
|
+
if (typeof run !== "object" || !("end" in run))
|
|
1442
|
+
return run === "undelimited" ? fail("undelimited_substitution", i) : run;
|
|
1443
|
+
substitution(i, run.end, source.slice(run.from, run.end - 1), "command");
|
|
1444
|
+
(current().currentShell ??= []).push(source.slice(run.from, run.end - 1));
|
|
1445
|
+
i = run.end - 1;
|
|
1446
|
+
continue;
|
|
1447
|
+
}
|
|
1229
1448
|
const end = braceExpansionEnd(source, n1);
|
|
1230
1449
|
if (end === undefined)
|
|
1231
1450
|
return fail("unterminated_parameter_expansion", i);
|
|
@@ -1234,7 +1453,7 @@ function scan(source, connectorsAreText) {
|
|
|
1234
1453
|
const name = EXPANSION_NAME.exec(body)?.[1];
|
|
1235
1454
|
if (UNREADABLE_EXPANSION_TEXT.test(body))
|
|
1236
1455
|
w.mark("parameter_text", w.raw.length);
|
|
1237
|
-
w.opaque(text, text, quotedBy(), i, end, { kind: "parameter", yields: inDouble ? "one" : "many", body, ...(name !== undefined ? { name } : {}) });
|
|
1456
|
+
w.opaque(text, text, quotedBy(), i, end, { kind: "parameter", yields: inDouble && !PER_ELEMENT_BODY.test(body) ? "one" : "many", body, ...(name !== undefined ? { name } : {}) });
|
|
1238
1457
|
i = end - 1;
|
|
1239
1458
|
continue;
|
|
1240
1459
|
}
|
|
@@ -1242,7 +1461,7 @@ function scan(source, connectorsAreText) {
|
|
|
1242
1461
|
const head = BARE_PARAMETER.exec(source.slice(n1, n1 + 64))?.[0];
|
|
1243
1462
|
if (head !== undefined) {
|
|
1244
1463
|
const text = source.slice(i, n1 + head.length);
|
|
1245
|
-
w.opaque(text, text, quotedBy(), i, n1 + head.length, { kind: "parameter", yields: inDouble ? "one" : "many", name: head });
|
|
1464
|
+
w.opaque(text, text, quotedBy(), i, n1 + head.length, { kind: "parameter", yields: inDouble && head !== "@" ? "one" : "many", name: head });
|
|
1246
1465
|
i = n1 + head.length - 1;
|
|
1247
1466
|
continue;
|
|
1248
1467
|
}
|
|
@@ -1252,18 +1471,21 @@ function scan(source, connectorsAreText) {
|
|
|
1252
1471
|
continue;
|
|
1253
1472
|
}
|
|
1254
1473
|
if ((ch === "<" || ch === ">") && source[n1] === "(") {
|
|
1255
|
-
const
|
|
1256
|
-
if (typeof
|
|
1257
|
-
return
|
|
1258
|
-
substitution(i, end, source.slice(n1 + 1, end - 1), "process");
|
|
1259
|
-
i = end - 1;
|
|
1474
|
+
const close = substitutionBodyEnd(source, n1, false, level);
|
|
1475
|
+
if (typeof close !== "object" || !("end" in close))
|
|
1476
|
+
return close === "unterminated" ? fail("unterminated_process_substitution", i) : close === "undelimited" ? fail("undelimited_substitution", i) : close;
|
|
1477
|
+
substitution(i, close.end, source.slice(n1 + 1, close.end - 1), "process");
|
|
1478
|
+
i = close.end - 1;
|
|
1260
1479
|
continue;
|
|
1261
1480
|
}
|
|
1262
1481
|
if (ch === "(" && w.started && w.isAssignmentHead() && (acceptable || (commandWord !== undefined && COMPOUND_OPERAND_COMMANDS.has(commandWord)))) {
|
|
1263
|
-
const end = matchedParen(source, i);
|
|
1482
|
+
const end = matchedParen(source, i, level);
|
|
1264
1483
|
if (end === undefined)
|
|
1265
1484
|
return fail("unterminated_compound_value", i);
|
|
1266
|
-
|
|
1485
|
+
if (typeof end !== "number")
|
|
1486
|
+
return end;
|
|
1487
|
+
const value = source.slice(i + 1, end - 1);
|
|
1488
|
+
const inner = scan(value, true, [firstSegment(value)], level);
|
|
1267
1489
|
if ("parseFailure" in inner)
|
|
1268
1490
|
return fail(inner.parseFailure.reason, i + 1 + inner.parseFailure.at);
|
|
1269
1491
|
const text = source.slice(i, end);
|
|
@@ -1271,6 +1493,9 @@ function scan(source, connectorsAreText) {
|
|
|
1271
1493
|
w.opaque(text, text, undefined, i, end, undefined);
|
|
1272
1494
|
w.compound = true;
|
|
1273
1495
|
current().substitutions.push(...inner.command.substitutions);
|
|
1496
|
+
const runsHere = inner.command.segments.flatMap((s) => s.currentShell ?? []);
|
|
1497
|
+
if (runsHere.length > 0)
|
|
1498
|
+
(current().currentShell ??= []).push(...runsHere);
|
|
1274
1499
|
i = end - 1;
|
|
1275
1500
|
continue;
|
|
1276
1501
|
}
|
|
@@ -1350,6 +1575,11 @@ function scan(source, connectorsAreText) {
|
|
|
1350
1575
|
i = n1;
|
|
1351
1576
|
continue;
|
|
1352
1577
|
}
|
|
1578
|
+
if (ch === "<" && source[n1] === ">") {
|
|
1579
|
+
pendingRedirect = { op: "<>", ...written };
|
|
1580
|
+
i = n1;
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1353
1583
|
if (ch === ">" && (source[n1] === ">" || source[n1] === "|")) {
|
|
1354
1584
|
pendingRedirect = { op: source[n1] === ">" ? ">>" : ">", ...written };
|
|
1355
1585
|
i = n1;
|
|
@@ -1406,18 +1636,22 @@ function scan(source, connectorsAreText) {
|
|
|
1406
1636
|
return tail;
|
|
1407
1637
|
if (pendingHeredocs.length > 0)
|
|
1408
1638
|
return fail("unterminated_heredoc", source.length);
|
|
1409
|
-
const out = segments.map((s) => (
|
|
1410
|
-
text: source.slice(s.start, s.end),
|
|
1411
|
-
connector: s.connector,
|
|
1412
|
-
...(s.pipesStderr ? { pipesStderr: true } : {}),
|
|
1413
|
-
tokens: s.tokens,
|
|
1414
|
-
substitutions: s.substitutions,
|
|
1415
|
-
}));
|
|
1639
|
+
const out = segments.map((s) => segmentView(source, s));
|
|
1416
1640
|
return { command: { segments: out, substitutions: out.flatMap((s) => s.substitutions) } };
|
|
1417
1641
|
}
|
|
1642
|
+
const firstSegment = (source) => ({ start: 0, end: source.length, connector: "start", tokens: [], substitutions: [] });
|
|
1643
|
+
const segmentView = (source, s) => ({
|
|
1644
|
+
text: source.slice(s.start, s.end),
|
|
1645
|
+
connector: s.connector,
|
|
1646
|
+
...(s.pipesStderr ? { pipesStderr: true } : {}),
|
|
1647
|
+
tokens: s.tokens,
|
|
1648
|
+
substitutions: s.substitutions,
|
|
1649
|
+
...(s.currentShell !== undefined ? { currentShell: s.currentShell } : {}),
|
|
1650
|
+
});
|
|
1418
1651
|
export function lexShell(source) {
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1652
|
+
const segments = [firstSegment(source)];
|
|
1653
|
+
const pass = scan(source, false, segments, 0);
|
|
1654
|
+
return "parseFailure" in pass ? { ...pass, readBefore: segments.map((s) => segmentView(source, s)) } : pass.command;
|
|
1421
1655
|
}
|
|
1422
1656
|
export function lexShellText(source) {
|
|
1423
1657
|
const lexed = lexShell(source);
|
|
@@ -14,6 +14,7 @@ import type { RosterStore } from "../../agents/roster-store.js";
|
|
|
14
14
|
import type { SessionPolicyStore } from "../../core/session-policy-store.js";
|
|
15
15
|
import type { WorkflowJournalStore } from "../../core/workflow-journal-store.js";
|
|
16
16
|
import type { UsageWindowStore } from "../../core/usage-window-store.js";
|
|
17
|
+
import type { EngineStorageBackend } from "../../core/engine-storage-backend.js";
|
|
17
18
|
export { FileCheckpointStore, type FileCheckpointStoreOptions } from "./checkpoint-store.js";
|
|
18
19
|
export { FileMemoryStore } from "./memory-store.js";
|
|
19
20
|
export { FileSessionRepo, type FileSessionRepoOptions } from "./session-store.js";
|
|
@@ -29,9 +30,10 @@ export { processFingerprint, isProcessLive, type ProcessFingerprint } from "./fs
|
|
|
29
30
|
export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootAdoptionFile, ROOT_ADOPTION_FILE, type AdoptionErrorCode, type AdoptionSource, type AdoptionReport, type AdoptionReceipt, type AdoptionLegReport, type AffectedDeploymentConfig, type RootAdoptionFile, } from "./adoption/marker.js";
|
|
30
31
|
export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdoptionQuarantine, readAdoptionStatus, type AdoptionStatus, type AdoptLocalDataRootOptions, type AdoptLocalDataRootResult, type AdoptionCarriageLeg, type AdoptionCarriageLegContext, type AdoptionConfigWitnessReceipt, } from "./adoption/adopt.js";
|
|
31
32
|
/**
|
|
32
|
-
* design/80 — the file-backed
|
|
33
|
-
*
|
|
34
|
-
*
|
|
33
|
+
* design/80 — the file-backed {@link EngineStorageBackend} for the local (TOC) single-user binary, selected
|
|
34
|
+
* purely by what the embedder injects into `RunnerDeps` (no engine change). Construct one over a single data
|
|
35
|
+
* root and pass its members into the `RunnerDeps` seats of the same names (every member of the contract is
|
|
36
|
+
* one; the class's extra members — `root`, `memoryStore`, `consolidationLock` — are not seats):
|
|
35
37
|
*
|
|
36
38
|
* ```ts
|
|
37
39
|
* const backend = new FileStorageBackend(); // ~/.ai-agent (or $AGENT_DATA_DIR)
|
|
@@ -39,8 +41,8 @@ export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdopt
|
|
|
39
41
|
* brain,
|
|
40
42
|
* sessionStore: backend.sessionStore,
|
|
41
43
|
* checkpointStore: backend.checkpointStore,
|
|
42
|
-
* memoryStore: backend.memoryStore,
|
|
43
44
|
* toolResultStore: backend.toolResultStore,
|
|
45
|
+
* // …and the other seats the contract names (sessionPolicyStore, fileHistoryStore, …)
|
|
44
46
|
* });
|
|
45
47
|
* // …on shutdown:
|
|
46
48
|
* await backend.dispose();
|
|
@@ -122,8 +124,8 @@ export type FileStorageCorruptReadInfo = CorruptReadInfo & {
|
|
|
122
124
|
/** Present only when the read was keyed by a principal. */
|
|
123
125
|
principal?: string;
|
|
124
126
|
};
|
|
125
|
-
export declare class FileStorageBackend {
|
|
126
|
-
/** The resolved, canonical data root
|
|
127
|
+
export declare class FileStorageBackend implements EngineStorageBackend {
|
|
128
|
+
/** The resolved, canonical data root every store of this backend lives under. */
|
|
127
129
|
readonly root: string;
|
|
128
130
|
readonly sessionStore: SessionStore;
|
|
129
131
|
readonly checkpointStore: CheckpointStore;
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
import type { PersistedRule, RuleTombstone } from "../../core/permission-rule-model.js";
|
|
53
53
|
import type { DurableRulePartition, DurableRulePartitionProvider, PermissionRuleWriter, QuarantinedRuleAdd, RuleOwner, RuleSyncFrontier, StoredRules, WritableDurableRulePartition } from "../../core/permission-rule-store.js";
|
|
54
54
|
import { PERMISSION_RULE_WRITER } from "../../core/permission-rule-store.js";
|
|
55
|
-
import type
|
|
55
|
+
import { type OrgRuleStatePersistence, type PersistedOrgRuleState } from "../../core/permission-rule-org.js";
|
|
56
56
|
import type { StoreDurability, StoreFidelity } from "../../core/checkpoint-store.js";
|
|
57
57
|
/**
|
|
58
58
|
* The on-disk shape of one bucket. `schemaVersion` is the only field a future reader may rely on before
|