@sema-agent/core 7.48.0 → 7.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +418 -0
- package/README.md +2 -2
- package/dist/agents/cascade.d.ts +2 -5
- package/dist/agents/child-failure.d.ts +20 -0
- package/dist/agents/child-failure.js +28 -0
- package/dist/agents/cross-session-ref.d.ts +11 -3
- package/dist/agents/cross-session-ref.js +6 -0
- package/dist/agents/cumulative-stats.d.ts +12 -15
- package/dist/agents/cumulative-stats.js +1 -1
- package/dist/agents/extra-tool-names.js +1 -1
- package/dist/agents/inherited-tool-pool.d.ts +17 -13
- package/dist/agents/inherited-tool-pool.js +4 -3
- package/dist/agents/peer-session-drain.d.ts +3 -2
- package/dist/agents/peer-session-drain.js +5 -4
- package/dist/agents/send-message-tool.js +2 -9
- package/dist/agents/subagent.d.ts +10 -29
- package/dist/agents/subagent.js +65 -53
- package/dist/agents/suspend-guard.d.ts +1 -1
- package/dist/agents/tool-filter.d.ts +76 -65
- package/dist/agents/tool-filter.js +122 -92
- package/dist/agents/verify.d.ts +4 -7
- package/dist/agents/verify.js +6 -7
- package/dist/bench/metrics.d.ts +1 -2
- package/dist/brain/anthropic.js +133 -79
- package/dist/brain/errors.d.ts +53 -6
- package/dist/brain/errors.js +22 -2
- package/dist/brain/input-too-long.d.ts +40 -19
- package/dist/brain/input-too-long.js +3 -16
- package/dist/brain/open-responses.js +19 -10
- package/dist/brain/openai.js +123 -32
- package/dist/brain/provider-dialect.d.ts +214 -0
- package/dist/brain/provider-dialect.js +186 -0
- package/dist/brain/request-params.d.ts +27 -8
- package/dist/brain/request-params.js +7 -12
- package/dist/brain/request-route.d.ts +84 -0
- package/dist/brain/request-route.js +41 -0
- package/dist/brain/retry.d.ts +8 -0
- package/dist/brain/retry.js +10 -4
- package/dist/brain/route-adjudicator.d.ts +7 -0
- package/dist/brain/route-adjudicator.js +5 -1
- package/dist/brain/status-sink.d.ts +20 -0
- package/dist/brain/status-sink.js +11 -0
- package/dist/brain/stream-engine.d.ts +52 -1
- package/dist/brain/stream-engine.js +81 -24
- package/dist/brain/stream-shared.d.ts +57 -11
- package/dist/brain/stream-shared.js +28 -2
- package/dist/core/a2a.d.ts +1 -0
- package/dist/core/agent-config-dir.js +3 -2
- package/dist/core/allow-entry.d.ts +21 -12
- package/dist/core/allow-entry.js +38 -31
- package/dist/core/arg-summary.d.ts +17 -24
- package/dist/core/arg-summary.js +169 -68
- package/dist/core/ask-origin.d.ts +42 -24
- package/dist/core/ask-origin.js +18 -13
- package/dist/core/auto-mode-prompt-assets.d.ts +2 -2
- package/dist/core/auto-mode-prompt-assets.js +1 -1
- package/dist/core/auto-mode-prompt.d.ts +11 -1
- package/dist/core/auto-mode-prompt.js +13 -10
- package/dist/core/auto-mode-rebuild.d.ts +7 -0
- package/dist/core/auto-mode-rebuild.js +4 -1
- package/dist/core/canonical-json.d.ts +3 -0
- package/dist/core/canonical-json.js +2 -1
- package/dist/core/checkpoint-requirements.d.ts +892 -0
- package/dist/core/checkpoint-requirements.js +333 -0
- package/dist/core/checkpoint-store.d.ts +94 -65
- package/dist/core/checkpoint-store.js +14 -26
- package/dist/core/child-clamp-seats.d.ts +228 -69
- package/dist/core/child-clamp-seats.js +211 -17
- package/dist/core/classifier-unavailable-arm.d.ts +5 -1
- package/dist/core/classifier-unavailable-arm.js +3 -3
- package/dist/core/compliance.d.ts +3 -0
- package/dist/core/compliance.js +9 -4
- package/dist/core/credential-vocabulary.d.ts +140 -0
- package/dist/core/credential-vocabulary.js +131 -0
- package/dist/core/decision-receipt.js +1 -1
- package/dist/core/effective-path-target.d.ts +73 -16
- package/dist/core/effective-path-target.js +63 -33
- package/dist/core/engine-notice.d.ts +32 -7
- package/dist/core/file-history-store.js +2 -2
- package/dist/core/fs-write-gate-policy.d.ts +4 -0
- package/dist/core/fs-write-gate-policy.js +22 -5
- package/dist/core/gate-bounded-await.d.ts +28 -13
- package/dist/core/gate-bounded-await.js +41 -4
- package/dist/core/gate-fold.d.ts +1 -1
- package/dist/core/gate-fold.js +24 -25
- package/dist/core/gate-lanes.js +16 -15
- package/dist/core/gate-outcome.d.ts +20 -5
- package/dist/core/gate-outcome.js +5 -0
- package/dist/core/governance-codes.d.ts +11 -4
- package/dist/core/governance-codes.js +14 -3
- package/dist/core/hooks.d.ts +4 -0
- package/dist/core/locked-config.d.ts +8 -0
- package/dist/core/locked-config.js +14 -2
- package/dist/core/lsp.js +3 -5
- package/dist/core/mailbox-store.d.ts +3 -4
- package/dist/core/mcp-connection-pool.d.ts +75 -0
- package/dist/core/mcp-connection-pool.js +128 -0
- package/dist/core/mcp-failure.d.ts +2 -1
- package/dist/core/mcp-failure.js +13 -2
- package/dist/core/mcp.d.ts +4 -0
- package/dist/core/mcp.js +70 -43
- package/dist/core/memory-engine/content-origin.js +2 -14
- package/dist/core/memory-engine/engine.d.ts +32 -22
- package/dist/core/memory-engine/engine.js +103 -55
- package/dist/core/memory-engine/file-backend.d.ts +13 -30
- package/dist/core/memory-engine/file-backend.js +37 -252
- package/dist/core/memory-engine/index.d.ts +1 -1
- package/dist/core/memory-engine/index.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +139 -9
- package/dist/core/memory-engine/layout.js +350 -7
- package/dist/core/memory-engine/scope-contract.d.ts +10 -0
- package/dist/core/memory-engine/scope-contract.js +8 -0
- package/dist/core/memory-engine/session-incarnation.d.ts +14 -4
- package/dist/core/memory-engine/session-incarnation.js +5 -2
- package/dist/core/memory-engine/types.d.ts +10 -1
- package/dist/core/memory.js +5 -17
- package/dist/core/model-seat.d.ts +4 -4
- package/dist/core/model-seat.js +1 -1
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +19 -0
- package/dist/core/namespaced-rule-name.d.ts +29 -0
- package/dist/core/namespaced-rule-name.js +52 -0
- package/dist/core/park-selfcheck.d.ts +1 -1
- package/dist/core/park-selfcheck.js +16 -6
- package/dist/core/path-guard-rows.d.ts +99 -0
- package/dist/core/path-guard-rows.js +45 -0
- package/dist/core/path-identity.d.ts +22 -16
- package/dist/core/path-identity.js +10 -10
- package/dist/core/path-rule-binding.d.ts +2 -1
- package/dist/core/path-rule-binding.js +3 -1
- package/dist/core/pause-registry.d.ts +16 -2
- package/dist/core/pause-registry.js +6 -0
- package/dist/core/permission-rule-consent.js +0 -7
- package/dist/core/permission-rule-model.d.ts +68 -24
- package/dist/core/permission-rule-model.js +105 -24
- package/dist/core/permission-rule-store.js +2 -2
- package/dist/core/permission-rules.d.ts +3 -30
- package/dist/core/permission-rules.js +4 -54
- package/dist/core/read-root-candidate.d.ts +1 -3
- package/dist/core/read-root-candidate.js +4 -15
- package/dist/core/real-approval.d.ts +4 -3
- package/dist/core/retired-keys.d.ts +13 -0
- package/dist/core/retired-keys.js +14 -0
- package/dist/core/roles.d.ts +2 -3
- package/dist/core/roles.js +15 -6
- package/dist/core/runner/assemble-result.d.ts +0 -7
- package/dist/core/runner/assemble-result.js +19 -31
- package/dist/core/runner/caller-roster.d.ts +78 -0
- package/dist/core/runner/caller-roster.js +219 -0
- package/dist/core/runner/checkpoint-scope.d.ts +16 -16
- package/dist/core/runner/checkpoint-scope.js +2 -2
- package/dist/core/runner/child-tree.js +2 -2
- package/dist/core/runner/contracts.d.ts +68 -35
- package/dist/core/runner/decide-continuation.d.ts +51 -3
- package/dist/core/runner/decide-continuation.js +76 -21
- package/dist/core/runner/denial-limit-arms.d.ts +17 -5
- package/dist/core/runner/denial-limit-arms.js +11 -9
- package/dist/core/runner/extra-body-dropped-seat.d.ts +8 -0
- package/dist/core/runner/extra-body-dropped-seat.js +22 -0
- package/dist/core/runner/finish-reason-seat.d.ts +9 -0
- package/dist/core/runner/finish-reason-seat.js +40 -0
- package/dist/core/runner/gate-exit.d.ts +44 -32
- package/dist/core/runner/gate-exit.js +112 -25
- package/dist/core/runner/inherited-ask-grants.js +6 -4
- package/dist/core/runner/mcp-redial.d.ts +3 -3
- package/dist/core/runner/mcp-redial.js +3 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +1 -2
- package/dist/core/runner/permission-rule-lanes.js +5 -4
- package/dist/core/runner/prepare-artifact.d.ts +4 -0
- package/dist/core/runner/prepare-artifact.js +2 -1
- package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
- package/dist/core/runner/prepare-ask-lane.js +12 -6
- package/dist/core/runner/prepare-boundary-parks.d.ts +5 -8
- package/dist/core/runner/prepare-boundary-parks.js +4 -7
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +11 -15
- package/dist/core/runner/prepare-caps-and-workflow.js +19 -27
- package/dist/core/runner/prepare-config-doors.d.ts +9 -9
- package/dist/core/runner/prepare-config-doors.js +10 -5
- package/dist/core/runner/prepare-defer-classify.d.ts +2 -2
- package/dist/core/runner/prepare-defer-classify.js +5 -3
- package/dist/core/runner/prepare-delegation-surface.d.ts +1 -1
- package/dist/core/runner/prepare-delegation-surface.js +3 -3
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -4
- package/dist/core/runner/prepare-gate-stations.js +9 -7
- package/dist/core/runner/prepare-hands-readface.d.ts +7 -7
- package/dist/core/runner/prepare-hands-readface.js +7 -7
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -6
- package/dist/core/runner/prepare-inherited-gate.js +14 -15
- package/dist/core/runner/prepare-listings.d.ts +7 -24
- package/dist/core/runner/prepare-listings.js +4 -5
- package/dist/core/runner/prepare-memory-engine-session.d.ts +2 -0
- package/dist/core/runner/prepare-memory-engine-session.js +4 -3
- package/dist/core/runner/prepare-memory.d.ts +6 -0
- package/dist/core/runner/prepare-memory.js +13 -13
- package/dist/core/runner/prepare-offload-wrappers.d.ts +5 -0
- package/dist/core/runner/prepare-offload-wrappers.js +3 -3
- package/dist/core/runner/prepare-park-ask.d.ts +7 -8
- package/dist/core/runner/prepare-park-ask.js +17 -10
- package/dist/core/runner/prepare-policy-chain.js +24 -44
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +3 -4
- package/dist/core/runner/prepare-protocol-tools.d.ts +9 -3
- package/dist/core/runner/prepare-protocol-tools.js +3 -4
- package/dist/core/runner/prepare-run-refs.d.ts +3 -0
- package/dist/core/runner/prepare-run-refs.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +4 -8
- package/dist/core/runner/prepare-safety-scan.js +1 -2
- package/dist/core/runner/prepare-suspend-saga.d.ts +7 -1
- package/dist/core/runner/prepare-suspend-saga.js +28 -12
- package/dist/core/runner/prepare-task.d.ts +1 -1
- package/dist/core/runner/prepare-task.js +67 -56
- package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -10
- package/dist/core/runner/prepare-wiring-manifest.js +5 -8
- package/dist/core/runner/resume-apply.js +7 -14
- package/dist/core/runner/resume-checkpoint-screen.js +11 -4
- package/dist/core/runner/resume-internals-and-config.js +2 -2
- package/dist/core/runner/resume-policy-outcome.js +5 -32
- package/dist/core/runner/resume-review-outcome.js +4 -1
- package/dist/core/runner/retired-runner-deps.d.ts +6 -0
- package/dist/core/runner/retired-runner-deps.js +10 -1
- package/dist/core/runner/run-brain-sinks.d.ts +4 -0
- package/dist/core/runner/run-brain-sinks.js +5 -2
- package/dist/core/runner/run-harness-handlers.js +27 -34
- package/dist/core/runner/run-leg.d.ts +0 -2
- package/dist/core/runner/run-leg.js +32 -33
- package/dist/core/runner/run-terminal-adoption.js +4 -3
- package/dist/core/runner/runtask.js +8 -8
- package/dist/core/runner/session-rule-policy.js +5 -5
- package/dist/core/runner/stream-settle-backstop.js +7 -4
- package/dist/core/runner/sub-agent-deny-lists.d.ts +51 -12
- package/dist/core/runner/sub-agent-deny-lists.js +111 -80
- package/dist/core/runner/terminal-account.d.ts +48 -0
- package/dist/core/runner/terminal-account.js +186 -0
- package/dist/core/runner/tool-end-body.d.ts +54 -17
- package/dist/core/runner/tool-end-body.js +27 -2
- package/dist/core/runner/tool-face-overlay.d.ts +3 -1
- package/dist/core/runner/tool-face-overlay.js +6 -4
- package/dist/core/runner/tool-occurrence.d.ts +106 -0
- package/dist/core/runner/tool-occurrence.js +123 -0
- package/dist/core/runner/tool-progress-lane.d.ts +16 -8
- package/dist/core/runner/tool-progress-lane.js +25 -34
- package/dist/core/runner/turn-attachments.d.ts +1 -1
- package/dist/core/runner/write-protection-station.d.ts +21 -9
- package/dist/core/runner/write-protection-station.js +20 -17
- package/dist/core/runner-deps.d.ts +12 -22
- package/dist/core/secret-env.d.ts +16 -5
- package/dist/core/secret-env.js +23 -63
- package/dist/core/sensitive-path-policy.d.ts +19 -18
- package/dist/core/sensitive-path-policy.js +73 -49
- package/dist/core/session-reconcile.d.ts +3 -0
- package/dist/core/session-reconcile.js +5 -4
- package/dist/core/session-store.d.ts +5 -0
- package/dist/core/session-store.js +12 -0
- package/dist/core/session.d.ts +13 -0
- package/dist/core/shared-memory/normalize.d.ts +17 -4
- package/dist/core/shared-memory/normalize.js +7 -7
- package/dist/core/shell-lexer.js +5 -4
- package/dist/core/skill-grant.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +13 -0
- package/dist/core/store-contracts/mailbox-store-contract.d.ts +7 -14
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +27 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +92 -0
- package/dist/core/stub-env.d.ts +2 -0
- package/dist/core/stub-env.js +1 -0
- package/dist/core/synthetic-read-verdict.js +2 -2
- package/dist/core/task-event.d.ts +59 -5
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +42 -9
- package/dist/core/terminal-cause.d.ts +94 -11
- package/dist/core/tighten-task-spec.d.ts +5 -4
- package/dist/core/tighten-task-spec.js +20 -25
- package/dist/core/tool-catalog-entries.d.ts +5 -7
- package/dist/core/tool-catalog-entries.js +14 -15
- package/dist/core/tool-face.d.ts +47 -0
- package/dist/core/tool-face.js +5 -0
- package/dist/core/tool-model-gate.d.ts +5 -5
- package/dist/core/tool-name-aliases.d.ts +26 -2
- package/dist/core/tool-name-aliases.js +13 -0
- package/dist/core/tool-name-list.d.ts +30 -0
- package/dist/core/tool-name-list.js +55 -0
- package/dist/core/tool-name-readings.d.ts +1 -9
- package/dist/core/tool-name-readings.js +1 -3
- package/dist/core/tool-policy.d.ts +195 -85
- package/dist/core/tool-policy.js +165 -380
- package/dist/core/tool-registry.d.ts +44 -1
- package/dist/core/tool-registry.js +26 -0
- package/dist/core/tool-roster.d.ts +19 -1
- package/dist/core/tool-roster.js +21 -2
- package/dist/core/tool-spec-members.d.ts +45 -0
- package/dist/core/tool-spec-members.js +169 -0
- package/dist/core/tool-spec.d.ts +46 -8
- package/dist/core/tools.d.ts +6 -2
- package/dist/core/tools.js +8 -4
- package/dist/core/untrusted-egress.js +29 -26
- package/dist/core/untrusted-text.d.ts +13 -10
- package/dist/core/untrusted-text.js +6 -44
- package/dist/core/workflow-journal-store.d.ts +4 -1
- package/dist/core/write-protect.d.ts +65 -29
- package/dist/core/write-protect.js +235 -177
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +5 -23
- package/dist/engine/execution-env/node-execution-env.js +16 -38
- package/dist/engine/execution-env/symlink-chain.d.ts +23 -0
- package/dist/engine/execution-env/symlink-chain.js +32 -0
- package/dist/engine/harness/types.d.ts +7 -0
- package/dist/engine/llm/tool-turns.d.ts +3 -0
- package/dist/engine/llm/tool-turns.js +1 -0
- package/dist/engine/llm/types.d.ts +59 -23
- package/dist/engine/loop/agent-loop.js +16 -2
- package/dist/engine/session/memory-repo.js +11 -3
- package/dist/engine/session/repo-utils.d.ts +8 -0
- package/dist/engine/session/repo-utils.js +13 -0
- package/dist/index.d.ts +20 -23
- package/dist/index.js +17 -20
- package/dist/internal/harness.d.ts +1 -1
- package/dist/internal/harness.js +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/governance-baseline-validity.js +1 -1
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +16 -35
- package/dist/orchestration/run-workflow-tool.js +38 -78
- package/dist/orchestration/workflow-governance.d.ts +21 -25
- package/dist/orchestration/workflow-governance.js +38 -78
- package/dist/orchestration/workflow-primitives.d.ts +7 -22
- package/dist/orchestration/workflow-primitives.js +5 -12
- package/dist/orchestration/workflow-types.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +61 -11
- package/dist/orchestration/workflow.js +189 -117
- package/dist/scenarios/full-body.d.ts +1 -1
- package/dist/shell/lex.d.ts +0 -21
- package/dist/shell/lex.js +250 -68
- package/dist/shell/shell-words.d.ts +35 -0
- package/dist/shell/shell-words.js +65 -0
- package/dist/stores/file/checkpoint-store.d.ts +5 -5
- package/dist/stores/file/checkpoint-store.js +5 -2
- package/dist/stores/file/index.d.ts +0 -8
- package/dist/stores/file/index.js +0 -12
- package/dist/stores/file/session-store.d.ts +3 -0
- package/dist/stores/file/session-store.js +44 -19
- package/dist/tools/artifact/artifact-tool.js +2 -0
- package/dist/tools/fs/bash-program-position.d.ts +10 -3
- package/dist/tools/fs/bash-program-position.js +21 -9
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
- package/dist/tools/fs/bash-readonly-classifier.js +8 -7
- package/dist/tools/fs/containment-face.d.ts +4 -0
- package/dist/tools/fs/containment-face.js +3 -0
- package/dist/tools/fs/fs-shared.d.ts +10 -0
- package/dist/tools/fs/fs-shared.js +18 -0
- package/dist/tools/fs/fs-write.js +4 -2
- package/dist/tools/fs/index.d.ts +1 -1
- package/dist/tools/fs/program-read-model.d.ts +39 -18
- package/dist/tools/fs/program-read-model.js +29 -19
- package/dist/tools/fs/program-read-model.rows.d.ts +0 -14
- package/dist/tools/fs/program-read-model.rows.js +5 -5
- package/dist/tools/fs/read-deny-home.d.ts +33 -47
- package/dist/tools/fs/read-deny-home.js +35 -49
- package/dist/tools/fs/read-deny.d.ts +23 -22
- package/dist/tools/fs/read-deny.js +114 -89
- package/dist/tools/fs/removal-targets.d.ts +56 -23
- package/dist/tools/fs/removal-targets.js +65 -87
- package/dist/tools/fs/safety.d.ts +29 -22
- package/dist/tools/fs/safety.js +17 -11
- package/dist/tools/fs/search.js +10 -8
- package/dist/tools/fs/shell-read-argv.js +1 -1
- package/dist/tools/fs/shell-read-bindings.d.ts +169 -37
- package/dist/tools/fs/shell-read-bindings.js +324 -86
- package/dist/tools/fs/shell-read-builtins.d.ts +35 -0
- package/dist/tools/fs/shell-read-builtins.js +43 -0
- package/dist/tools/fs/shell-read-check.d.ts +15 -1
- package/dist/tools/fs/shell-read-check.js +51 -42
- package/dist/tools/fs/shell-read-establish.js +6 -6
- package/dist/tools/fs/shell-read-functions.d.ts +22 -0
- package/dist/tools/fs/shell-read-functions.js +29 -0
- package/dist/tools/fs/shell-read-judge.d.ts +48 -18
- package/dist/tools/fs/shell-read-judge.js +33 -4
- package/dist/tools/fs/shell-read-plan.d.ts +12 -6
- package/dist/tools/fs/shell-read-plan.js +118 -113
- package/dist/tools/fs/shell-read-start.d.ts +29 -6
- package/dist/tools/fs/shell-read-start.js +16 -9
- package/dist/tools/fs/shell-read-word.js +4 -0
- package/dist/tools/fs/shell-read-workdir.d.ts +156 -0
- package/dist/tools/fs/shell-read-workdir.js +281 -0
- package/dist/tools/fs/shell-read-write-targets.d.ts +5 -2
- package/dist/tools/fs/shell-read-write-targets.js +14 -5
- package/dist/tools/fs/shell-reentry-text.d.ts +4 -6
- package/dist/tools/fs/shell-reentry-text.js +3 -11
- package/dist/tools/task-list.d.ts +1 -2
- package/dist/tools/web.js +1 -1
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +107 -143
- package/wire-changes/core@7.49.0.json +4765 -0
- package/dist/agents/teacher.d.ts +0 -159
- package/dist/agents/teacher.js +0 -577
- package/dist/agents/team.d.ts +0 -226
- package/dist/agents/team.js +0 -257
- package/dist/core/strategy-store.d.ts +0 -238
- package/dist/core/strategy-store.js +0 -253
- package/dist/orchestration/builtin-workflows.d.ts +0 -133
- package/dist/orchestration/builtin-workflows.js +0 -159
- package/dist/scenarios/env.d.ts +0 -40
- package/dist/scenarios/env.js +0 -39
- package/dist/scenarios/scenario-registry.d.ts +0 -110
- package/dist/scenarios/scenario-registry.js +0 -140
- package/dist/scenarios/teacher-quickstart.d.ts +0 -40
- package/dist/scenarios/teacher-quickstart.js +0 -12
- package/dist/stores/cc/lockfile.d.ts +0 -10
- package/dist/stores/cc/lockfile.js +0 -98
- package/dist/stores/cc/mailbox-store.d.ts +0 -20
- package/dist/stores/cc/mailbox-store.js +0 -255
- package/dist/stores/cc/roster-adapter.d.ts +0 -12
- package/dist/stores/cc/roster-adapter.js +0 -117
- package/dist/stores/cc/sidecar-transcript.d.ts +0 -97
- package/dist/stores/cc/sidecar-transcript.js +0 -264
- package/dist/stores/cc/task-list-store.d.ts +0 -2
- package/dist/stores/cc/task-list-store.js +0 -125
- package/dist/stores/file/strategy-store.d.ts +0 -97
- package/dist/stores/file/strategy-store.js +0 -341
|
@@ -107,6 +107,19 @@ export declare function deriveControlPlaneDir(configRoot: string, key: string):
|
|
|
107
107
|
* memory dir would strand one of the two on every alias-reached mount. Safe to canonicalize here —
|
|
108
108
|
* the key input is the host-declared repo root, not a directory the model can replace. */
|
|
109
109
|
export declare function deriveRepoControlPlaneDir(configRoot: string, repoRoot: string): string;
|
|
110
|
+
/**
|
|
111
|
+
* THE control plane of the memory store at `dir` — the one reading every opener (the file backend, the
|
|
112
|
+
* engine, the runner's plane assembly) and {@link reanchorMemoryStoreRoot} resolve through, so the plane a
|
|
113
|
+
* store's root anchor is read from is the plane it was written to. A backend that pins its own control
|
|
114
|
+
* plane (`pinnedBy.controlPlaneRoot` — the file backend) wins, else the explicit `controlDir`, else the
|
|
115
|
+
* derivation off the config root ({@link deriveControlPlaneDir}) — preceded by the one-shot move of a plane
|
|
116
|
+
* minted under the canonical key ({@link adoptCanonicalKeyedControlDir}), which is why that arm is not pure.
|
|
117
|
+
*/
|
|
118
|
+
export declare function effectiveControlRootOf(dir: string, opts?: {
|
|
119
|
+
controlDir?: string;
|
|
120
|
+
pinnedBy?: unknown;
|
|
121
|
+
onIncident?: MemoryPartitionIncidentSink;
|
|
122
|
+
}): string;
|
|
110
123
|
/**
|
|
111
124
|
* Resolve the memory-engine config root: explicit (`RunnerDeps.memoryEngineDir`) → `AGENT_DATA_DIR`
|
|
112
125
|
* env → `~/.ai-agent` (the same default family as the file stores' `resolveDataRoot`; re-stated here
|
|
@@ -277,11 +290,17 @@ declare const SCOPE_HOME_FORM_PHRASE: {
|
|
|
277
290
|
readonly other: "a special file";
|
|
278
291
|
};
|
|
279
292
|
export type HomeFormPhraseCoversEveryForm = AssertAllKeysHandled<Exclude<ScopeHomeForm, keyof typeof SCOPE_HOME_FORM_PHRASE>>;
|
|
280
|
-
/** What a store-form refusal carries beside its sentence.
|
|
281
|
-
*
|
|
293
|
+
/** What a store-form refusal carries beside its sentence. Host paths live here and never in the sentence;
|
|
294
|
+
* `form` is present on {@link SCOPE_HOME_NOT_DIRECTORY} only; `controlDir`, `recorded` and `now` are present
|
|
295
|
+
* together on a moved store root only ({@link storeRootMovedRefusal}): the control plane whose root anchor
|
|
296
|
+
* refused (the `controlDir` to hand {@link reanchorMemoryStoreRoot}), the physical root the anchor records,
|
|
297
|
+
* and where the root resolves now. */
|
|
282
298
|
export type StoreFormRefusalDetail = {
|
|
283
299
|
readonly path: string;
|
|
284
300
|
readonly form?: ScopeHomeForm;
|
|
301
|
+
readonly controlDir?: string;
|
|
302
|
+
readonly recorded?: string;
|
|
303
|
+
readonly now?: string;
|
|
285
304
|
};
|
|
286
305
|
/** A refusal the store's physical form earns: a plain `Error` (never the control-plane-damage class —
|
|
287
306
|
* the engine's own account is intact, the layout it was handed is not the layout it needs) carrying a
|
|
@@ -293,14 +312,28 @@ export type StoreFormRefusal = Error & {
|
|
|
293
312
|
/** Seat 1 — an act the store's physical form refuses: `act` names what was refused (no path), `path` is the
|
|
294
313
|
* target whose directory resolves outside the store ({@link landsOutsideStore}). */
|
|
295
314
|
export declare function storeActRefusal(act: string, path: string): StoreFormRefusal;
|
|
296
|
-
/** Seat 2 — the store root
|
|
297
|
-
* the root's spelling.
|
|
298
|
-
|
|
315
|
+
/** Seat 2 — the store root no longer resolves to the physical root its control plane's anchor records
|
|
316
|
+
* ({@link anchorStoreRoot}); `path` is the root's spelling. The remedy names its arguments by their
|
|
317
|
+
* `detail` keys, so the sentence stays path-free and the call is still copyable. */
|
|
318
|
+
export declare function storeRootMovedRefusal(path: string, anchor: {
|
|
319
|
+
controlDir: string;
|
|
320
|
+
recorded: string;
|
|
321
|
+
now: string;
|
|
322
|
+
}): StoreFormRefusal;
|
|
323
|
+
/** Seat 2, the root gone: the anchored root no longer exists while its control plane holds a store's account
|
|
324
|
+
* ({@link anchorStoreRoot}). A missing root lands where it would be created — the recorded one — so only
|
|
325
|
+
* its absence tells a store moved away (or deleted) from one never opened; the root is not re-created. */
|
|
326
|
+
export declare function storeRootAbsentRefusal(path: string, anchor: {
|
|
327
|
+
controlDir: string;
|
|
328
|
+
recorded: string;
|
|
329
|
+
now: string;
|
|
330
|
+
}): StoreFormRefusal;
|
|
299
331
|
/** Seat 3 — a scope home that is not a real directory. */
|
|
300
332
|
export declare function scopeHomeRefusal(form: ScopeHomeForm, path: string): StoreFormRefusal;
|
|
301
333
|
/** Where an act at `p` lands: the physical path of its normalized spelling (the spelling a child path
|
|
302
334
|
* joined under it carries), a MISSING tail rejoined under the deepest existing directory (what the act
|
|
303
|
-
* creates)
|
|
335
|
+
* creates) — a dangling link on that tail followed to where it points (what the act would create through
|
|
336
|
+
* it). Any other resolution fault (EACCES, ELOOP, ENOTDIR) is THROWN as itself: an act that
|
|
304
337
|
* cannot be placed is not performed — a failed resolution never implies the act would fail too
|
|
305
338
|
* (a link whose own mode refuses `realpath` is still followed by `unlink` and `rename`). */
|
|
306
339
|
export declare function landingPathOf(p: string): string;
|
|
@@ -320,6 +353,103 @@ export declare function landingPathOf(p: string): string;
|
|
|
320
353
|
export declare function landsOutsideStore(physicalRoot: string, target: string): boolean;
|
|
321
354
|
/** mkdir -p convenience used by the engine/backend (0o700 like the file stores). */
|
|
322
355
|
export declare function ensureDirExists(dir: string): void;
|
|
356
|
+
/** The committed-rev ledger's file name (the file backend's account). Named here because the anchor reads
|
|
357
|
+
* its presence as "this control plane already holds a store". */
|
|
358
|
+
export declare const LEDGER_FILE = "revs.json";
|
|
359
|
+
/** The control-plane file recording the store root's physical path ({@link anchorStoreRoot}). */
|
|
360
|
+
export declare const ROOT_ANCHOR_FILE = "root-anchor.json";
|
|
361
|
+
/** What an ABSENT anchor means: a control plane holding nothing records the root (a first open); one already
|
|
362
|
+
* holding a store backfills while the arm is open and refuses once it is not. */
|
|
363
|
+
export declare function absentAnchorReading(controlPlaneHoldsStore: boolean, backfillArmOpen?: boolean): "record" | "backfill" | "refuse";
|
|
364
|
+
/** Options of {@link anchorStoreRoot}. */
|
|
365
|
+
export interface AnchorStoreRootOptions {
|
|
366
|
+
/** Where `memory.root_anchor_backfilled` goes. */
|
|
367
|
+
onIncident?: MemoryPartitionIncidentSink;
|
|
368
|
+
/** The clock `recordedAt` reads (the opener's injected clock). */
|
|
369
|
+
now?: () => number;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* THE store-root check, run by every opener (a file backend's construction, an engine's mount) and at the
|
|
373
|
+
* head of every face that acts on the store: where the root `dir` physically resolves NOW, against the
|
|
374
|
+
* anchor its control plane records. Equal ⇒ the anchored root, the one every act at a store path is judged
|
|
375
|
+
* against. Unequal ⇒ {@link storeRootMovedRefusal}; equal but the root gone while the control plane holds a
|
|
376
|
+
* store ⇒ {@link storeRootAbsentRefusal} — both thrown before anything in the store is written or the root is
|
|
377
|
+
* created (only the anchor answers where the root is; a `mkdir` in its place does not). No anchor ⇒ {@link absentAnchorReading}, decided under the anchor's lock (a racing opener
|
|
378
|
+
* that recorded it first is judged against): a control plane holding nothing creates the root and records
|
|
379
|
+
* it; one already holding a store backfills it and discloses `memory.root_anchor_backfilled` (its root may
|
|
380
|
+
* already have been re-pointed — undecidable, said). Nothing is kept between calls: the anchor is read every
|
|
381
|
+
* time, so a re-anchor ({@link reanchorMemoryStoreRoot}) reaches every live holder at its next face.
|
|
382
|
+
*/
|
|
383
|
+
export declare function anchorStoreRoot(dir: string, controlDir: string, opts?: AnchorStoreRootOptions): string;
|
|
384
|
+
/** The redo journal a File store's transaction writes as its commit marker (control plane). */
|
|
385
|
+
export declare const STORE_JOURNAL_FILE = "journal.json";
|
|
386
|
+
/** The transaction lock's directory in the control plane; `owner` inside holds the holder's token. */
|
|
387
|
+
export declare const STORE_TXN_LOCK_DIR = "txn.lock";
|
|
388
|
+
/** A lock older than this is a crashed holder (stolen; the journal recovery inside the lock makes the steal safe). */
|
|
389
|
+
export declare const TXN_LOCK_STALE_MS = 30000;
|
|
390
|
+
/** Test hook: small constants so a crash-window leg does not really wait 15–30 s. */
|
|
391
|
+
export interface TxnLockTimings {
|
|
392
|
+
staleMs?: number;
|
|
393
|
+
waitMs?: number;
|
|
394
|
+
stealGraceMs?: number;
|
|
395
|
+
}
|
|
396
|
+
/** A held transaction lock: its token, and a release that removes the lock only while the token is still ours. */
|
|
397
|
+
export interface StoreTxnLock {
|
|
398
|
+
readonly token: string;
|
|
399
|
+
readonly release: () => void;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* One attempt at the store's transaction lock (synchronous): the lock, or `undefined` while another holder has
|
|
403
|
+
* it. Only the lock directory's EEXIST is contention; every other failure — the control plane unmakeable, a
|
|
404
|
+
* probe or steal that faults, an occupant that is not a directory — throws {@link ControlPlaneCorruptError}
|
|
405
|
+
* (a fault is never read as "busy, retry later"). Every acquisition writes an owner token (crypto-random)
|
|
406
|
+
* before it returns. A held lock past its stale line (`now` against its mtime) that carries a token is a
|
|
407
|
+
* crashed holder: stolen single-winner (an atomic rename to a unique tombstone; a racer's lost rename is
|
|
408
|
+
* ENOENT) and re-attempted through a normal `mkdir` — never a bare rm + mkdir. A tokenless lock is a
|
|
409
|
+
* mid-acquisition, never stolen. `observed` hears each held lock's mtime (a waiter's deadline extension).
|
|
410
|
+
*/
|
|
411
|
+
export declare function tryStoreTxnLock(controlDir: string, opts: {
|
|
412
|
+
now: () => number;
|
|
413
|
+
staleMs?: number;
|
|
414
|
+
observed?: (mtimeMs: number) => void;
|
|
415
|
+
}): StoreTxnLock | undefined;
|
|
416
|
+
/** The commit boundary of a store transaction: the lock still names `token` — an absent or unreadable owner (a
|
|
417
|
+
* stolen, tombstoned lock) is lost too. A holder that stalled past the stale line was stolen from; acting on
|
|
418
|
+
* would overwrite the stealer's transaction. */
|
|
419
|
+
export declare function assertStoreTxnLockOwnership(controlDir: string, token: string): void;
|
|
420
|
+
/** Wait for the store's transaction lock: one {@link tryStoreTxnLock} per round, paced 20–60 ms (the wait
|
|
421
|
+
* yields the event loop every round), until the deadline — `waitMs`, extended to an observed lock's stale
|
|
422
|
+
* line plus the steal grace. Past it: a loud timeout. */
|
|
423
|
+
export declare function acquireStoreTxnLock(controlDir: string, opts: {
|
|
424
|
+
now: () => number;
|
|
425
|
+
timings?: TxnLockTimings;
|
|
426
|
+
}): Promise<StoreTxnLock>;
|
|
427
|
+
/** What {@link reanchorMemoryStoreRoot} changed. */
|
|
428
|
+
export interface StoreRootReanchor {
|
|
429
|
+
/** The physical root the anchor recorded before; absent when no readable anchor stood. */
|
|
430
|
+
readonly from?: string;
|
|
431
|
+
/** The physical root it records now. */
|
|
432
|
+
readonly to: string;
|
|
433
|
+
/** The control plane the anchor lives in. */
|
|
434
|
+
readonly controlDir: string;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* The ONE way a recorded root anchor changes: point it at where `dir` resolves now — a store moved on
|
|
438
|
+
* purpose, or an anchor that is damaged. `opts.controlDir` names the store's control plane exactly as its
|
|
439
|
+
* opener does (the explicit `controlDir` the backend / engine was given, absent for the derived one) and
|
|
440
|
+
* resolves through the same reading ({@link effectiveControlRootOf}). Refused (`config.memory_reanchor`) when
|
|
441
|
+
* `dir` is not an existing directory, and when that control plane holds neither an anchor nor a store — a
|
|
442
|
+
* mistaken `controlDir` would otherwise record an anchor no opener reads. Moves nothing and says nothing
|
|
443
|
+
* about whether the directory holds the same store. A re-anchor is a transaction of the store: it holds the
|
|
444
|
+
* store's transaction lock ({@link acquireStoreTxnLock}; a commit in progress is waited for, never crossed) and
|
|
445
|
+
* is refused while a committed transaction is pending recovery (its journal names paths under the recorded
|
|
446
|
+
* root: replayed there first, never carried over). Every live holder judges against the new anchor at its
|
|
447
|
+
* next face. Discloses `memory.root_reanchored` on `opts.onIncident`.
|
|
448
|
+
*/
|
|
449
|
+
export declare function reanchorMemoryStoreRoot(dir: string, opts?: {
|
|
450
|
+
controlDir?: string;
|
|
451
|
+
onIncident?: MemoryPartitionIncidentSink;
|
|
452
|
+
}): Promise<StoreRootReanchor>;
|
|
323
453
|
/** The one remedy every surfaced permission refusal carries — `undefined` unless `err` is a write
|
|
324
454
|
* the file system refused on PERMISSIONS (`EACCES` / `EPERM`) at a path INSIDE `memoryDir` (a
|
|
325
455
|
* refusal elsewhere — a control plane kept outside the store — is not this store's to fix). The
|
|
@@ -446,9 +576,9 @@ export interface SidecarLockOptions {
|
|
|
446
576
|
* Wait-bound (ruled 2026-08-04): EVERY round runs the same three steps — attempt, diagnose, then
|
|
447
577
|
* the deadline check and the pause. The two "retry immediately" shortcuts this loop used to take
|
|
448
578
|
* (holder released between mkdir and stat; steal attempted) skipped both of the last two, so a
|
|
449
|
-
* condition that keeps answering the same way
|
|
450
|
-
*
|
|
451
|
-
*
|
|
579
|
+
* condition that keeps answering the same way spun this synchronous loop at full speed and never
|
|
580
|
+
* reached its own cap. Only a held lock (EEXIST) is waited on: a lock directory that cannot be created
|
|
581
|
+
* (read-only mount, full volume, revoked permission, a missing parent) throws its own error at once. */
|
|
452
582
|
export declare function acquireSidecarLock(lockDir: string, opts?: SidecarLockOptions): string;
|
|
453
583
|
/** 证伪式复审 L2-analog: re-verify the owner token at the COMMIT POINT — a stolen-from holder
|
|
454
584
|
* aborts instead of writing over the stealer. A FOREIGN token always aborts (positive proof the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { closeSync, constants as fsConstants, copyFileSync, existsSync, fstatSync, fsyncSync, ftruncateSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, utimesSync, writeFileSync, writeSync } from "node:fs";
|
|
1
|
+
import { closeSync, constants as fsConstants, copyFileSync, existsSync, fstatSync, fsyncSync, ftruncateSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, utimesSync, writeFileSync, writeSync } from "node:fs";
|
|
2
2
|
const { O_WRONLY, O_RDONLY, O_CREAT, O_NOFOLLOW, O_NONBLOCK, O_EXCL } = fsConstants;
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
5
|
import { basename, dirname, isAbsolute, join, resolve, sep } from "node:path";
|
|
6
6
|
import { MEMORY_ORIGIN_CAUSES } from "./types.js";
|
|
7
7
|
import { physicalPathOf, physicalPathOfExisting, priorCallerCasedPathOf } from "../physical-path.js";
|
|
@@ -187,6 +187,16 @@ export function deriveControlPlaneDir(configRoot, key) {
|
|
|
187
187
|
export function deriveRepoControlPlaneDir(configRoot, repoRoot) {
|
|
188
188
|
return join(configRoot, deriveRepoKey(repoRoot), CONTROL_PLANE_DIR);
|
|
189
189
|
}
|
|
190
|
+
export function effectiveControlRootOf(dir, opts = {}) {
|
|
191
|
+
const pinned = opts.pinnedBy?.controlPlaneRoot;
|
|
192
|
+
if (typeof pinned === "string" && pinned !== "")
|
|
193
|
+
return pinned;
|
|
194
|
+
if (opts.controlDir !== undefined)
|
|
195
|
+
return opts.controlDir;
|
|
196
|
+
const configRoot = resolveMemoryEngineRoot();
|
|
197
|
+
adoptCanonicalKeyedControlDir(configRoot, dir, opts.onIncident);
|
|
198
|
+
return deriveControlPlaneDir(configRoot, dir);
|
|
199
|
+
}
|
|
190
200
|
export function resolveMemoryEngineRoot(explicit) {
|
|
191
201
|
const raw = explicit ?? process.env.AGENT_DATA_DIR ?? join(homedir(), ".ai-agent");
|
|
192
202
|
return isAbsolute(raw) ? raw : resolve(raw);
|
|
@@ -749,21 +759,45 @@ function storeFormRefusal(code, sentence, detail) {
|
|
|
749
759
|
export function storeActRefusal(act, path) {
|
|
750
760
|
return storeFormRefusal(TARGET_OUTSIDE_STORE, `${act} was refused — its directory resolves outside the store root; not performed`, { path });
|
|
751
761
|
}
|
|
752
|
-
export function storeRootMovedRefusal(
|
|
753
|
-
return storeFormRefusal(TARGET_OUTSIDE_STORE,
|
|
762
|
+
export function storeRootMovedRefusal(path, anchor) {
|
|
763
|
+
return storeFormRefusal(TARGET_OUTSIDE_STORE, "the store root now resolves to a different directory than the one its control plane records — refused, nothing in the store was written; put the directory back, or, if the store was moved on purpose, call reanchorMemoryStoreRoot(detail.path, { controlDir: detail.controlDir }) and reopen", { path, controlDir: anchor.controlDir, recorded: anchor.recorded, now: anchor.now });
|
|
764
|
+
}
|
|
765
|
+
export function storeRootAbsentRefusal(path, anchor) {
|
|
766
|
+
return storeFormRefusal(TARGET_OUTSIDE_STORE, "the store root no longer exists where its control plane records it — refused, nothing in the store was written; put the directory back, or, if the store was moved on purpose, call reanchorMemoryStoreRoot with its new directory and { controlDir: detail.controlDir }; to start over in place, create the directory, then call reanchorMemoryStoreRoot(detail.path, { controlDir: detail.controlDir }) and reopen", { path, controlDir: anchor.controlDir, recorded: anchor.recorded, now: anchor.now });
|
|
754
767
|
}
|
|
755
768
|
export function scopeHomeRefusal(form, path) {
|
|
756
769
|
return storeFormRefusal(SCOPE_HOME_NOT_DIRECTORY, `a scope home must be a real directory, but this one is ${SCOPE_HOME_FORM_PHRASE[form]} — refused (fail-closed); put the real directory back`, { path, form });
|
|
757
770
|
}
|
|
758
771
|
export function landingPathOf(p) {
|
|
759
|
-
|
|
772
|
+
return landingPathWithin(resolve(p), 0);
|
|
773
|
+
}
|
|
774
|
+
const MAX_LANDING_LINK_HOPS = 40;
|
|
775
|
+
function landingPathWithin(normalized, hops) {
|
|
760
776
|
try {
|
|
761
777
|
return physicalPathOf(normalized);
|
|
762
778
|
}
|
|
763
779
|
catch (err) {
|
|
764
780
|
if (err.code !== "ENOENT")
|
|
765
781
|
throw err;
|
|
766
|
-
|
|
782
|
+
}
|
|
783
|
+
const tail = [];
|
|
784
|
+
for (let cur = normalized;;) {
|
|
785
|
+
const st = lstatOrAbsent(cur);
|
|
786
|
+
if (st?.isSymbolicLink() === true) {
|
|
787
|
+
if (hops >= MAX_LANDING_LINK_HOPS) {
|
|
788
|
+
const e = new Error(`ELOOP: too many symbolic links resolving ${normalized}`);
|
|
789
|
+
e.code = "ELOOP";
|
|
790
|
+
throw e;
|
|
791
|
+
}
|
|
792
|
+
return landingPathWithin(join(resolve(dirname(cur), readlinkSync(cur)), ...[...tail].reverse()), hops + 1);
|
|
793
|
+
}
|
|
794
|
+
if (st !== undefined)
|
|
795
|
+
return canonicalize(normalized);
|
|
796
|
+
const parent = dirname(cur);
|
|
797
|
+
if (parent === cur)
|
|
798
|
+
return normalized;
|
|
799
|
+
tail.push(basename(cur));
|
|
800
|
+
cur = parent;
|
|
767
801
|
}
|
|
768
802
|
}
|
|
769
803
|
export function landsOutsideStore(physicalRoot, target) {
|
|
@@ -774,6 +808,313 @@ export function ensureDirExists(dir) {
|
|
|
774
808
|
if (!existsSync(dir))
|
|
775
809
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
776
810
|
}
|
|
811
|
+
export const LEDGER_FILE = "revs.json";
|
|
812
|
+
export const ROOT_ANCHOR_FILE = "root-anchor.json";
|
|
813
|
+
const ANCHOR_BACKFILL_ARM_OPEN = true;
|
|
814
|
+
export function absentAnchorReading(controlPlaneHoldsStore, backfillArmOpen = ANCHOR_BACKFILL_ARM_OPEN) {
|
|
815
|
+
if (!controlPlaneHoldsStore)
|
|
816
|
+
return "record";
|
|
817
|
+
return backfillArmOpen ? "backfill" : "refuse";
|
|
818
|
+
}
|
|
819
|
+
function reanchorRemedy(dir, controlDir) {
|
|
820
|
+
return `once the store root is where it belongs, call reanchorMemoryStoreRoot(${JSON.stringify(dir)}, { controlDir: ${JSON.stringify(controlDir)} }) and reopen`;
|
|
821
|
+
}
|
|
822
|
+
function damagedAnchorError(controlDir, dir, why, cause) {
|
|
823
|
+
return new ControlPlaneCorruptError(`memory store root anchor ${join(controlDir, ROOT_ANCHOR_FILE)} is damaged (${why}) — the store root cannot be checked against it, so nothing in the store was opened; ${reanchorRemedy(dir, controlDir)}`, cause !== undefined ? { cause } : undefined);
|
|
824
|
+
}
|
|
825
|
+
function readStoreRootAnchor(controlDir, dir) {
|
|
826
|
+
let raw;
|
|
827
|
+
let fd;
|
|
828
|
+
try {
|
|
829
|
+
fd = openSync(join(controlDir, ROOT_ANCHOR_FILE), O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
|
|
830
|
+
if (!fstatSync(fd).isFile())
|
|
831
|
+
throw damagedAnchorError(controlDir, dir, "not a regular file");
|
|
832
|
+
raw = readFileSync(fd, "utf8");
|
|
833
|
+
}
|
|
834
|
+
catch (err) {
|
|
835
|
+
if (err instanceof ControlPlaneCorruptError)
|
|
836
|
+
throw err;
|
|
837
|
+
const code = err.code;
|
|
838
|
+
if (code === "ENOENT" && fd === undefined)
|
|
839
|
+
return undefined;
|
|
840
|
+
throw damagedAnchorError(controlDir, dir, code === "ELOOP" ? "a symbolic link, not the record" : `unreadable: ${code ?? thrownLabel(err)}`, err);
|
|
841
|
+
}
|
|
842
|
+
finally {
|
|
843
|
+
if (fd !== undefined)
|
|
844
|
+
closeSync(fd);
|
|
845
|
+
}
|
|
846
|
+
let parsed;
|
|
847
|
+
try {
|
|
848
|
+
parsed = JSON.parse(raw);
|
|
849
|
+
}
|
|
850
|
+
catch (err) {
|
|
851
|
+
throw damagedAnchorError(controlDir, dir, "not JSON", err);
|
|
852
|
+
}
|
|
853
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
854
|
+
throw damagedAnchorError(controlDir, dir, "not an object");
|
|
855
|
+
const a = parsed;
|
|
856
|
+
if (a.v !== 1)
|
|
857
|
+
throw damagedAnchorError(controlDir, dir, `unknown version ${JSON.stringify(a.v) ?? typeof a.v}`);
|
|
858
|
+
if (typeof a.realpath !== "string" || !isAbsolute(a.realpath))
|
|
859
|
+
throw damagedAnchorError(controlDir, dir, "realpath is not an absolute path");
|
|
860
|
+
if (typeof a.spelling !== "string" || typeof a.recordedAt !== "number" || !Number.isFinite(a.recordedAt))
|
|
861
|
+
throw damagedAnchorError(controlDir, dir, "spelling / recordedAt out of shape");
|
|
862
|
+
return { v: 1, realpath: a.realpath, spelling: a.spelling, recordedAt: a.recordedAt };
|
|
863
|
+
}
|
|
864
|
+
function controlPlaneHoldsStore(controlDir) {
|
|
865
|
+
return lstatOrAbsent(join(controlDir, SCOPES_FILE)) !== undefined || lstatOrAbsent(join(controlDir, LEDGER_FILE)) !== undefined;
|
|
866
|
+
}
|
|
867
|
+
function judgeAgainstAnchor(dir, controlDir, anchor) {
|
|
868
|
+
const now = landingPathOf(dir);
|
|
869
|
+
if (now !== anchor.realpath)
|
|
870
|
+
throw storeRootMovedRefusal(dir, { controlDir, recorded: anchor.realpath, now });
|
|
871
|
+
if (lstatOrAbsent(now) === undefined && controlPlaneHoldsStore(controlDir))
|
|
872
|
+
throw storeRootAbsentRefusal(dir, { controlDir, recorded: anchor.realpath, now });
|
|
873
|
+
return now;
|
|
874
|
+
}
|
|
875
|
+
function writeStoreRootAnchor(controlDir, lock, token, anchor) {
|
|
876
|
+
assertSidecarLockOwnership(lock, token, "memory store root anchor", "strict");
|
|
877
|
+
atomicWriteFileSync(join(controlDir, ROOT_ANCHOR_FILE), `${JSON.stringify(anchor, null, 2)}\n`);
|
|
878
|
+
}
|
|
879
|
+
export function anchorStoreRoot(dir, controlDir, opts = {}) {
|
|
880
|
+
const anchor = readStoreRootAnchor(controlDir, dir);
|
|
881
|
+
if (anchor !== undefined)
|
|
882
|
+
return judgeAgainstAnchor(dir, controlDir, anchor);
|
|
883
|
+
ensureDirExists(controlDir);
|
|
884
|
+
const lock = join(controlDir, `${ROOT_ANCHOR_FILE}.lock`);
|
|
885
|
+
const token = acquireSidecarLock(lock, { onDeadline: "throw" });
|
|
886
|
+
try {
|
|
887
|
+
const raced = readStoreRootAnchor(controlDir, dir);
|
|
888
|
+
if (raced !== undefined)
|
|
889
|
+
return judgeAgainstAnchor(dir, controlDir, raced);
|
|
890
|
+
const reading = absentAnchorReading(controlPlaneHoldsStore(controlDir));
|
|
891
|
+
if (reading === "refuse")
|
|
892
|
+
throw damagedAnchorError(controlDir, dir, "absent, while the control plane holds a store");
|
|
893
|
+
ensureDirExists(dir);
|
|
894
|
+
const realpath = landingPathOf(dir);
|
|
895
|
+
writeStoreRootAnchor(controlDir, lock, token, { v: 1, realpath, spelling: dir, recordedAt: (opts.now ?? Date.now)() });
|
|
896
|
+
if (reading === "backfill") {
|
|
897
|
+
discloseLayoutIncident(opts.onIncident, "memory.root_anchor_backfilled", `memory store root anchor recorded for a store that had none: ${dir} resolves to ${realpath} (control plane ${controlDir}) — from now on the store opens only there; where the root resolved before this open cannot be told`);
|
|
898
|
+
}
|
|
899
|
+
return realpath;
|
|
900
|
+
}
|
|
901
|
+
finally {
|
|
902
|
+
releaseSidecarLock(lock, token);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
export const STORE_JOURNAL_FILE = "journal.json";
|
|
906
|
+
export const STORE_TXN_LOCK_DIR = "txn.lock";
|
|
907
|
+
export const TXN_LOCK_STALE_MS = 30_000;
|
|
908
|
+
const TXN_LOCK_WAIT_MS = 15_000;
|
|
909
|
+
const TXN_LOCK_STEAL_GRACE_MS = 250;
|
|
910
|
+
export function tryStoreTxnLock(controlDir, opts) {
|
|
911
|
+
const lockDir = join(controlDir, STORE_TXN_LOCK_DIR);
|
|
912
|
+
const ownerPath = join(lockDir, "owner");
|
|
913
|
+
const staleMs = opts.staleMs ?? TXN_LOCK_STALE_MS;
|
|
914
|
+
const faultText = (err) => err.code ?? "io error";
|
|
915
|
+
const tryMkdir = () => {
|
|
916
|
+
try {
|
|
917
|
+
mkdirSync(controlDir, { recursive: true });
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
throw new ControlPlaneCorruptError(`memory control-plane root could not be created (${faultText(err)}) at ${controlDir} — a lock-acquisition fault is not contention (fail-closed)`, { cause: err });
|
|
921
|
+
}
|
|
922
|
+
try {
|
|
923
|
+
mkdirSync(lockDir);
|
|
924
|
+
return true;
|
|
925
|
+
}
|
|
926
|
+
catch (err) {
|
|
927
|
+
if (err.code === "EEXIST")
|
|
928
|
+
return false;
|
|
929
|
+
throw new ControlPlaneCorruptError(`memory txn lock could not be created (${faultText(err)}) at ${lockDir} — a lock-acquisition fault is not contention (fail-closed)`, { cause: err });
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
let acquired = tryMkdir();
|
|
933
|
+
if (!acquired) {
|
|
934
|
+
let mtimeMs;
|
|
935
|
+
try {
|
|
936
|
+
mtimeMs = statSync(lockDir).mtimeMs;
|
|
937
|
+
opts.observed?.(mtimeMs);
|
|
938
|
+
}
|
|
939
|
+
catch (err) {
|
|
940
|
+
if (err.code !== "ENOENT") {
|
|
941
|
+
throw new ControlPlaneCorruptError(`memory txn lock state could not be probed (${faultText(err)}) at ${lockDir} — a probe failure is not contention (fail-closed)`, { cause: err });
|
|
942
|
+
}
|
|
943
|
+
let occupant;
|
|
944
|
+
try {
|
|
945
|
+
occupant = lstatSync(lockDir);
|
|
946
|
+
}
|
|
947
|
+
catch (lerr) {
|
|
948
|
+
if (lerr.code !== "ENOENT") {
|
|
949
|
+
throw new ControlPlaneCorruptError(`memory txn lock re-probe failed (${faultText(lerr)}) at ${lockDir} — a probe failure is not contention (fail-closed)`, { cause: lerr });
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (occupant !== undefined && !occupant.isDirectory()) {
|
|
953
|
+
throw new ControlPlaneCorruptError(`memory txn lock path is occupied by an invalid node (a dangling symlink?) at ${lockDir} — not contention and not a release race; remove the occupant (fail-closed)`, { cause: err });
|
|
954
|
+
}
|
|
955
|
+
mtimeMs = undefined;
|
|
956
|
+
}
|
|
957
|
+
if (mtimeMs !== undefined && opts.now() - mtimeMs > staleMs) {
|
|
958
|
+
let tokenPresent = false;
|
|
959
|
+
try {
|
|
960
|
+
statSync(ownerPath);
|
|
961
|
+
tokenPresent = true;
|
|
962
|
+
}
|
|
963
|
+
catch (err) {
|
|
964
|
+
if (err.code !== "ENOENT") {
|
|
965
|
+
throw new ControlPlaneCorruptError(`memory txn lock owner token could not be probed (${faultText(err)}) at ${ownerPath} — a probe failure is not a mid-acquisition (fail-closed)`, { cause: err });
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (tokenPresent) {
|
|
969
|
+
const tomb = join(controlDir, `${STORE_TXN_LOCK_DIR}.stale-${randomUUID()}`);
|
|
970
|
+
let stolen = false;
|
|
971
|
+
try {
|
|
972
|
+
renameSync(lockDir, tomb);
|
|
973
|
+
stolen = true;
|
|
974
|
+
}
|
|
975
|
+
catch (err) {
|
|
976
|
+
if (err.code !== "ENOENT") {
|
|
977
|
+
throw new ControlPlaneCorruptError(`memory txn lock stale-steal rename failed (${faultText(err)}) at ${lockDir} — a rename fault is not a lost race (fail-closed)`, { cause: err });
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
if (stolen) {
|
|
981
|
+
rmSync(tomb, { recursive: true, force: true });
|
|
982
|
+
acquired = tryMkdir();
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
if (!acquired)
|
|
987
|
+
return undefined;
|
|
988
|
+
}
|
|
989
|
+
const token = randomUUID();
|
|
990
|
+
try {
|
|
991
|
+
const fd = openSync(ownerPath, "w", 0o600);
|
|
992
|
+
try {
|
|
993
|
+
writeAllSync(fd, token);
|
|
994
|
+
fsyncSync(fd);
|
|
995
|
+
}
|
|
996
|
+
finally {
|
|
997
|
+
closeSync(fd);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
catch (err) {
|
|
1001
|
+
try {
|
|
1002
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
1003
|
+
}
|
|
1004
|
+
catch {
|
|
1005
|
+
}
|
|
1006
|
+
throw new Error(`memory txn lock owner token could not be written at ${ownerPath}: ${thrownText(err)}`);
|
|
1007
|
+
}
|
|
1008
|
+
return {
|
|
1009
|
+
token,
|
|
1010
|
+
release: () => {
|
|
1011
|
+
try {
|
|
1012
|
+
if (readFileSync(ownerPath, "utf8") !== token)
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
catch {
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
try {
|
|
1019
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
1020
|
+
}
|
|
1021
|
+
catch {
|
|
1022
|
+
}
|
|
1023
|
+
},
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
export function assertStoreTxnLockOwnership(controlDir, token) {
|
|
1027
|
+
let held;
|
|
1028
|
+
try {
|
|
1029
|
+
held = readFileSync(join(controlDir, STORE_TXN_LOCK_DIR, "owner"), "utf8");
|
|
1030
|
+
}
|
|
1031
|
+
catch {
|
|
1032
|
+
held = undefined;
|
|
1033
|
+
}
|
|
1034
|
+
if (held !== token) {
|
|
1035
|
+
throw new ControlPlaneCorruptError("txn lock ownership lost before commit (holder stalled past the stale deadline and was stolen from?) — transaction aborted, nothing was committed", { facet: "lock-ownership" });
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
export async function acquireStoreTxnLock(controlDir, opts) {
|
|
1039
|
+
const staleMs = opts.timings?.staleMs ?? TXN_LOCK_STALE_MS;
|
|
1040
|
+
const waitMs = opts.timings?.waitMs ?? TXN_LOCK_WAIT_MS;
|
|
1041
|
+
const stealGraceMs = opts.timings?.stealGraceMs ?? TXN_LOCK_STEAL_GRACE_MS;
|
|
1042
|
+
let deadline = Date.now() + waitMs;
|
|
1043
|
+
for (;;) {
|
|
1044
|
+
const lock = tryStoreTxnLock(controlDir, { now: opts.now, staleMs, observed: (mtimeMs) => (deadline = Math.max(deadline, mtimeMs + staleMs + stealGraceMs)) });
|
|
1045
|
+
if (lock !== undefined)
|
|
1046
|
+
return lock;
|
|
1047
|
+
if (Date.now() > deadline) {
|
|
1048
|
+
throw new Error(`memory txn lock timeout (${waitMs}ms, extended to the lock's stale line) at ${join(controlDir, STORE_TXN_LOCK_DIR)} — another writer is wedged?`);
|
|
1049
|
+
}
|
|
1050
|
+
await new Promise((r) => setTimeout(r, 20 + Math.floor(Math.random() * 40)));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
function reanchorDestination(dir) {
|
|
1054
|
+
let to;
|
|
1055
|
+
try {
|
|
1056
|
+
to = physicalPathOf(resolve(dir));
|
|
1057
|
+
}
|
|
1058
|
+
catch (err) {
|
|
1059
|
+
throw reanchorRefusal(`the store root ${JSON.stringify(dir)} does not resolve (${err.code ?? thrownLabel(err)}) — put the directory in place first`);
|
|
1060
|
+
}
|
|
1061
|
+
if (lstatOrAbsent(to)?.isDirectory() !== true)
|
|
1062
|
+
throw reanchorRefusal(`the store root ${JSON.stringify(dir)} resolves to ${to}, which is not a directory`);
|
|
1063
|
+
return to;
|
|
1064
|
+
}
|
|
1065
|
+
function reanchorRefusal(sentence) {
|
|
1066
|
+
const e = new Error(`reanchorMemoryStoreRoot: ${sentence}`);
|
|
1067
|
+
e.code = "config.memory_reanchor";
|
|
1068
|
+
return e;
|
|
1069
|
+
}
|
|
1070
|
+
export async function reanchorMemoryStoreRoot(dir, opts = {}) {
|
|
1071
|
+
const controlDir = effectiveControlRootOf(dir, { controlDir: opts.controlDir, onIncident: opts.onIncident });
|
|
1072
|
+
const to = reanchorDestination(dir);
|
|
1073
|
+
const lock = join(controlDir, `${ROOT_ANCHOR_FILE}.lock`);
|
|
1074
|
+
if (lstatOrAbsent(join(controlDir, ROOT_ANCHOR_FILE)) === undefined && !controlPlaneHoldsStore(controlDir)) {
|
|
1075
|
+
throw reanchorRefusal(`the control plane ${controlDir} holds no store and no root anchor — nothing to re-anchor; pass the controlDir this store's backend / engine is opened with`);
|
|
1076
|
+
}
|
|
1077
|
+
const txn = await acquireStoreTxnLock(controlDir, { now: Date.now });
|
|
1078
|
+
let from;
|
|
1079
|
+
try {
|
|
1080
|
+
const token = acquireSidecarLock(lock, { onDeadline: "throw" });
|
|
1081
|
+
try {
|
|
1082
|
+
try {
|
|
1083
|
+
from = readStoreRootAnchor(controlDir, dir)?.realpath;
|
|
1084
|
+
}
|
|
1085
|
+
catch {
|
|
1086
|
+
from = undefined;
|
|
1087
|
+
}
|
|
1088
|
+
try {
|
|
1089
|
+
assertStoreTxnLockOwnership(controlDir, txn.token);
|
|
1090
|
+
}
|
|
1091
|
+
catch {
|
|
1092
|
+
throw reanchorRefusal(`the store's transaction lock was lost while re-anchoring (held past its stale line and taken by another writer) — nothing changed; retry (control plane ${controlDir})`);
|
|
1093
|
+
}
|
|
1094
|
+
if (lstatOrAbsent(join(controlDir, STORE_JOURNAL_FILE)) !== undefined) {
|
|
1095
|
+
throw reanchorRefusal(`a committed transaction is still pending recovery at the recorded root — put the store back at ${from ?? "the root it was last opened at"}, open it once so the journal replays, then re-anchor (control plane ${controlDir})`);
|
|
1096
|
+
}
|
|
1097
|
+
let still;
|
|
1098
|
+
try {
|
|
1099
|
+
still = reanchorDestination(dir);
|
|
1100
|
+
}
|
|
1101
|
+
catch {
|
|
1102
|
+
still = undefined;
|
|
1103
|
+
}
|
|
1104
|
+
if (still !== to)
|
|
1105
|
+
throw reanchorRefusal(`the store root ${JSON.stringify(dir)} moved while re-anchoring (it resolved to ${to} when the call began) — nothing changed; retry`);
|
|
1106
|
+
writeStoreRootAnchor(controlDir, lock, token, { v: 1, realpath: to, spelling: dir, recordedAt: Date.now() });
|
|
1107
|
+
}
|
|
1108
|
+
finally {
|
|
1109
|
+
releaseSidecarLock(lock, token);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
finally {
|
|
1113
|
+
txn.release();
|
|
1114
|
+
}
|
|
1115
|
+
discloseLayoutIncident(opts.onIncident, "memory.root_reanchored", `memory store root re-anchored: ${dir} now opens at ${to}${from !== undefined ? ` (was ${from})` : ""} — control plane ${controlDir}`);
|
|
1116
|
+
return from !== undefined ? { from, to, controlDir } : { to, controlDir };
|
|
1117
|
+
}
|
|
777
1118
|
export function permissionRemedyOf(err, memoryDir) {
|
|
778
1119
|
const e = typeof err === "object" && err !== null ? err : undefined;
|
|
779
1120
|
if (e === undefined || (e.code !== "EACCES" && e.code !== "EPERM") || typeof e.path !== "string" || !isContainedIn(memoryDir, e.path))
|
|
@@ -965,7 +1306,9 @@ export function acquireSidecarLock(lockDir, opts = {}) {
|
|
|
965
1306
|
}
|
|
966
1307
|
return token;
|
|
967
1308
|
}
|
|
968
|
-
catch {
|
|
1309
|
+
catch (err) {
|
|
1310
|
+
if (err.code !== "EEXIST")
|
|
1311
|
+
throw err;
|
|
969
1312
|
}
|
|
970
1313
|
try {
|
|
971
1314
|
const age = Date.now() - statSync(lockDir).mtimeMs;
|
|
@@ -48,6 +48,16 @@ export declare function formatUserProjScope(principal: string, projectId: string
|
|
|
48
48
|
* opaque behavior. NEVER call this on a deployment that has not opted in (see module header).
|
|
49
49
|
*/
|
|
50
50
|
export declare function parseScopeKey(key: string): ParsedScopeKey;
|
|
51
|
+
/**
|
|
52
|
+
* THE org-scope judge for a host that admits, stores or routes org keys: is `key` a well-formed v2 org
|
|
53
|
+
* scope — `org:` followed by ONE encoded segment ({@link encodeScopeSegment}'s alphabet, at most
|
|
54
|
+
* {@link SCOPE_SEGMENT_MAX_ENCODED} encoded characters, canonical spelling)? It is {@link parseScopeKey}'s own
|
|
55
|
+
* reading, asked as a yes/no: a malformed `org:` key (an unencoded non-ASCII character, an over-long
|
|
56
|
+
* segment, a non-canonical escape) answers `false` here where `parseScopeKey` would throw, and a key of any
|
|
57
|
+
* other kind (`user:`, `proj:`, an unprefixed opaque string) answers `false` too. A prefix-plus-any-non-space
|
|
58
|
+
* pattern restated outside core answers a different question and disagrees on exactly those inputs.
|
|
59
|
+
*/
|
|
60
|
+
export declare function isOrgScopeKey(key: string): boolean;
|
|
51
61
|
/** True when a v2-parsed key belongs to a PERSONAL plane (`user:` / `userproj:`). */
|
|
52
62
|
export declare function isPersonalScope(parsed: ParsedScopeKey): boolean;
|
|
53
63
|
/** True when the key's AUTHORITY is central (design/142 §2 表: user/userproj/org rows) — these keys
|
|
@@ -111,6 +111,14 @@ export function parseScopeKey(key) {
|
|
|
111
111
|
}
|
|
112
112
|
return { kind: "legacy", raw: key };
|
|
113
113
|
}
|
|
114
|
+
export function isOrgScopeKey(key) {
|
|
115
|
+
try {
|
|
116
|
+
return parseScopeKey(key).kind === "org";
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
114
122
|
export function isPersonalScope(parsed) {
|
|
115
123
|
return parsed.kind === "user" || parsed.kind === "userproj";
|
|
116
124
|
}
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { type MemoryPartitionIncidentSink, type SessionIdentityRead } from "./layout.js";
|
|
2
|
+
/** The seat's resolver shape ({@link createSessionIncarnationSeat}). */
|
|
3
|
+
export type SessionIncarnationResolver = (session: {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
}) => string | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* The resolver a Runner hands its engines, built from the ACQUIRED session's own row cells — the object
|
|
8
|
+
* the run's transcript lives in, so the seat and the transcript never name two occupants (a second
|
|
9
|
+
* lookup by id can answer a row that replaced it). `own` = that session's `incarnation`; a LINEAGE id
|
|
10
|
+
* answers the occupant recorded with the lineage (`lineage`, e.g. the fork's `forkedFromIncarnation`),
|
|
11
|
+
* never whoever holds that id now. Everything else, and an absent own token, is unknown (binds).
|
|
12
|
+
*/
|
|
13
|
+
export declare function sessionIncarnationResolver(sessionId: string, own: string | undefined, lineage: ReadonlyMap<string, string>): SessionIncarnationResolver;
|
|
2
14
|
/** The current occupant's token, and the identity seat a per-session record read is made under. */
|
|
3
15
|
export interface SessionIncarnationSeat {
|
|
4
16
|
incarnationOf(sessionId: string): string | undefined;
|
|
5
17
|
identityRead(sessionId: string): SessionIdentityRead;
|
|
6
18
|
}
|
|
7
|
-
/** Build the seat over a
|
|
19
|
+
/** Build the seat over a resolver (absent ⇒ nothing stamped, nothing asked, every record binds
|
|
8
20
|
* by id — the pre-incarnation answer). Both disclosures are DEDUPED on the axis their fact belongs to: the resolver
|
|
9
21
|
* fault once per engine (a wiring fact), a separation once per session id (a fact about that id). */
|
|
10
22
|
export declare function createSessionIncarnationSeat(input: {
|
|
11
|
-
resolve:
|
|
12
|
-
sessionId: string;
|
|
13
|
-
}) => string | undefined) | undefined;
|
|
23
|
+
resolve: SessionIncarnationResolver | undefined;
|
|
14
24
|
onIncident: MemoryPartitionIncidentSink | undefined;
|
|
15
25
|
}): SessionIncarnationSeat;
|
|
16
26
|
/** Remember an in-process record under its session id, FIRST-WINS PER IDENTITY: this map is the
|