@sema-ai/core 1.275.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5433 -0
- package/LICENSE +27 -0
- package/NOTICE.md +30 -0
- package/README.md +1040 -0
- package/dist/agents/agent-definition.d.ts +10 -0
- package/dist/agents/agent-definition.d.ts.map +1 -0
- package/dist/agents/agent-definition.js +18 -0
- package/dist/agents/agent-definition.js.map +1 -0
- package/dist/agents/builtin-agents.d.ts +69 -0
- package/dist/agents/builtin-agents.d.ts.map +1 -0
- package/dist/agents/builtin-agents.js +177 -0
- package/dist/agents/builtin-agents.js.map +1 -0
- package/dist/agents/cascade.d.ts +101 -0
- package/dist/agents/cascade.d.ts.map +1 -0
- package/dist/agents/cascade.js +189 -0
- package/dist/agents/cascade.js.map +1 -0
- package/dist/agents/observer.d.ts +209 -0
- package/dist/agents/observer.d.ts.map +1 -0
- package/dist/agents/observer.js +495 -0
- package/dist/agents/observer.js.map +1 -0
- package/dist/agents/repair-loop.d.ts +236 -0
- package/dist/agents/repair-loop.d.ts.map +1 -0
- package/dist/agents/repair-loop.js +293 -0
- package/dist/agents/repair-loop.js.map +1 -0
- package/dist/agents/session-util.d.ts +8 -0
- package/dist/agents/session-util.d.ts.map +1 -0
- package/dist/agents/session-util.js +9 -0
- package/dist/agents/session-util.js.map +1 -0
- package/dist/agents/subagent-steps.d.ts +93 -0
- package/dist/agents/subagent-steps.d.ts.map +1 -0
- package/dist/agents/subagent-steps.js +206 -0
- package/dist/agents/subagent-steps.js.map +1 -0
- package/dist/agents/subagent.d.ts +441 -0
- package/dist/agents/subagent.d.ts.map +1 -0
- package/dist/agents/subagent.js +2492 -0
- package/dist/agents/subagent.js.map +1 -0
- package/dist/agents/suspend-guard.d.ts +35 -0
- package/dist/agents/suspend-guard.d.ts.map +1 -0
- package/dist/agents/suspend-guard.js +48 -0
- package/dist/agents/suspend-guard.js.map +1 -0
- package/dist/agents/teacher.d.ts +137 -0
- package/dist/agents/teacher.d.ts.map +1 -0
- package/dist/agents/teacher.js +575 -0
- package/dist/agents/teacher.js.map +1 -0
- package/dist/agents/team.d.ts +211 -0
- package/dist/agents/team.d.ts.map +1 -0
- package/dist/agents/team.js +293 -0
- package/dist/agents/team.js.map +1 -0
- package/dist/agents/tool-filter.d.ts +29 -0
- package/dist/agents/tool-filter.d.ts.map +1 -0
- package/dist/agents/tool-filter.js +50 -0
- package/dist/agents/tool-filter.js.map +1 -0
- package/dist/agents/verify.d.ts +177 -0
- package/dist/agents/verify.d.ts.map +1 -0
- package/dist/agents/verify.js +305 -0
- package/dist/agents/verify.js.map +1 -0
- package/dist/bench/metrics.d.ts +714 -0
- package/dist/bench/metrics.d.ts.map +1 -0
- package/dist/bench/metrics.js +618 -0
- package/dist/bench/metrics.js.map +1 -0
- package/dist/bin/sema-tb.d.ts +3 -0
- package/dist/bin/sema-tb.d.ts.map +1 -0
- package/dist/bin/sema-tb.js +516 -0
- package/dist/bin/sema-tb.js.map +1 -0
- package/dist/bin/tb-env.d.ts +13 -0
- package/dist/bin/tb-env.d.ts.map +1 -0
- package/dist/bin/tb-env.js +26 -0
- package/dist/bin/tb-env.js.map +1 -0
- package/dist/brain/anthropic.d.ts +46 -0
- package/dist/brain/anthropic.d.ts.map +1 -0
- package/dist/brain/anthropic.js +830 -0
- package/dist/brain/anthropic.js.map +1 -0
- package/dist/brain/circuit-breaker.d.ts +46 -0
- package/dist/brain/circuit-breaker.d.ts.map +1 -0
- package/dist/brain/circuit-breaker.js +173 -0
- package/dist/brain/circuit-breaker.js.map +1 -0
- package/dist/brain/degrading.d.ts +98 -0
- package/dist/brain/degrading.d.ts.map +1 -0
- package/dist/brain/degrading.js +249 -0
- package/dist/brain/degrading.js.map +1 -0
- package/dist/brain/errors.d.ts +31 -0
- package/dist/brain/errors.d.ts.map +1 -0
- package/dist/brain/errors.js +58 -0
- package/dist/brain/errors.js.map +1 -0
- package/dist/brain/failover.d.ts +18 -0
- package/dist/brain/failover.d.ts.map +1 -0
- package/dist/brain/failover.js +118 -0
- package/dist/brain/failover.js.map +1 -0
- package/dist/brain/model-presets.d.ts +36 -0
- package/dist/brain/model-presets.d.ts.map +1 -0
- package/dist/brain/model-presets.js +54 -0
- package/dist/brain/model-presets.js.map +1 -0
- package/dist/brain/openai.d.ts +43 -0
- package/dist/brain/openai.d.ts.map +1 -0
- package/dist/brain/openai.js +784 -0
- package/dist/brain/openai.js.map +1 -0
- package/dist/brain/reasoning.d.ts +138 -0
- package/dist/brain/reasoning.d.ts.map +1 -0
- package/dist/brain/reasoning.js +146 -0
- package/dist/brain/reasoning.js.map +1 -0
- package/dist/brain/repetition.d.ts +60 -0
- package/dist/brain/repetition.d.ts.map +1 -0
- package/dist/brain/repetition.js +121 -0
- package/dist/brain/repetition.js.map +1 -0
- package/dist/brain/request-params.d.ts +29 -0
- package/dist/brain/request-params.d.ts.map +1 -0
- package/dist/brain/request-params.js +78 -0
- package/dist/brain/request-params.js.map +1 -0
- package/dist/brain/retry.d.ts +18 -0
- package/dist/brain/retry.d.ts.map +1 -0
- package/dist/brain/retry.js +42 -0
- package/dist/brain/retry.js.map +1 -0
- package/dist/brain/routing.d.ts +19 -0
- package/dist/brain/routing.d.ts.map +1 -0
- package/dist/brain/routing.js +44 -0
- package/dist/brain/routing.js.map +1 -0
- package/dist/brain/status-sink.d.ts +46 -0
- package/dist/brain/status-sink.d.ts.map +1 -0
- package/dist/brain/status-sink.js +36 -0
- package/dist/brain/status-sink.js.map +1 -0
- package/dist/brain/stream-engine.d.ts +85 -0
- package/dist/brain/stream-engine.d.ts.map +1 -0
- package/dist/brain/stream-engine.js +391 -0
- package/dist/brain/stream-engine.js.map +1 -0
- package/dist/brain/timeout.d.ts +44 -0
- package/dist/brain/timeout.d.ts.map +1 -0
- package/dist/brain/timeout.js +41 -0
- package/dist/brain/timeout.js.map +1 -0
- package/dist/brain/tool-call-repair.d.ts +15 -0
- package/dist/brain/tool-call-repair.d.ts.map +1 -0
- package/dist/brain/tool-call-repair.js +67 -0
- package/dist/brain/tool-call-repair.js.map +1 -0
- package/dist/brain/walltime.d.ts +14 -0
- package/dist/brain/walltime.d.ts.map +1 -0
- package/dist/brain/walltime.js +14 -0
- package/dist/brain/walltime.js.map +1 -0
- package/dist/core/arg-summary.d.ts +19 -0
- package/dist/core/arg-summary.d.ts.map +1 -0
- package/dist/core/arg-summary.js +96 -0
- package/dist/core/arg-summary.js.map +1 -0
- package/dist/core/ask-question.d.ts +113 -0
- package/dist/core/ask-question.d.ts.map +1 -0
- package/dist/core/ask-question.js +246 -0
- package/dist/core/ask-question.js.map +1 -0
- package/dist/core/auto-compaction.d.ts +341 -0
- package/dist/core/auto-compaction.d.ts.map +1 -0
- package/dist/core/auto-compaction.js +495 -0
- package/dist/core/auto-compaction.js.map +1 -0
- package/dist/core/auto-promote.d.ts +126 -0
- package/dist/core/auto-promote.d.ts.map +1 -0
- package/dist/core/auto-promote.js +171 -0
- package/dist/core/auto-promote.js.map +1 -0
- package/dist/core/background-shell.d.ts +128 -0
- package/dist/core/background-shell.d.ts.map +1 -0
- package/dist/core/background-shell.js +42 -0
- package/dist/core/background-shell.js.map +1 -0
- package/dist/core/cache-break-detector.d.ts +63 -0
- package/dist/core/cache-break-detector.d.ts.map +1 -0
- package/dist/core/cache-break-detector.js +0 -0
- package/dist/core/cache-break-detector.js.map +1 -0
- package/dist/core/canonical-json.d.ts +45 -0
- package/dist/core/canonical-json.d.ts.map +1 -0
- package/dist/core/canonical-json.js +132 -0
- package/dist/core/canonical-json.js.map +1 -0
- package/dist/core/checkpoint-store.d.ts +1101 -0
- package/dist/core/checkpoint-store.d.ts.map +1 -0
- package/dist/core/checkpoint-store.js +514 -0
- package/dist/core/checkpoint-store.js.map +1 -0
- package/dist/core/consolidate-scope.d.ts +94 -0
- package/dist/core/consolidate-scope.d.ts.map +1 -0
- package/dist/core/consolidate-scope.js +158 -0
- package/dist/core/consolidate-scope.js.map +1 -0
- package/dist/core/context-edit.d.ts +82 -0
- package/dist/core/context-edit.d.ts.map +1 -0
- package/dist/core/context-edit.js +149 -0
- package/dist/core/context-edit.js.map +1 -0
- package/dist/core/context-guard.d.ts +43 -0
- package/dist/core/context-guard.d.ts.map +1 -0
- package/dist/core/context-guard.js +171 -0
- package/dist/core/context-guard.js.map +1 -0
- package/dist/core/dynamic-recall.d.ts +100 -0
- package/dist/core/dynamic-recall.d.ts.map +1 -0
- package/dist/core/dynamic-recall.js +108 -0
- package/dist/core/dynamic-recall.js.map +1 -0
- package/dist/core/exec-gate.d.ts +74 -0
- package/dist/core/exec-gate.d.ts.map +1 -0
- package/dist/core/exec-gate.js +143 -0
- package/dist/core/exec-gate.js.map +1 -0
- package/dist/core/exec-output-tail.d.ts +37 -0
- package/dist/core/exec-output-tail.d.ts.map +1 -0
- package/dist/core/exec-output-tail.js +63 -0
- package/dist/core/exec-output-tail.js.map +1 -0
- package/dist/core/file-snapshot-store.d.ts +137 -0
- package/dist/core/file-snapshot-store.d.ts.map +1 -0
- package/dist/core/file-snapshot-store.js +319 -0
- package/dist/core/file-snapshot-store.js.map +1 -0
- package/dist/core/git-worktree-env.d.ts +41 -0
- package/dist/core/git-worktree-env.d.ts.map +1 -0
- package/dist/core/git-worktree-env.js +64 -0
- package/dist/core/git-worktree-env.js.map +1 -0
- package/dist/core/hooks.d.ts +372 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +269 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/lsp-diagnostics.d.ts +74 -0
- package/dist/core/lsp-diagnostics.d.ts.map +1 -0
- package/dist/core/lsp-diagnostics.js +125 -0
- package/dist/core/lsp-diagnostics.js.map +1 -0
- package/dist/core/lsp-protocol.d.ts +28 -0
- package/dist/core/lsp-protocol.d.ts.map +1 -0
- package/dist/core/lsp-protocol.js +179 -0
- package/dist/core/lsp-protocol.js.map +1 -0
- package/dist/core/lsp-session.d.ts +56 -0
- package/dist/core/lsp-session.d.ts.map +1 -0
- package/dist/core/lsp-session.js +185 -0
- package/dist/core/lsp-session.js.map +1 -0
- package/dist/core/lsp.d.ts +132 -0
- package/dist/core/lsp.d.ts.map +1 -0
- package/dist/core/lsp.js +147 -0
- package/dist/core/lsp.js.map +1 -0
- package/dist/core/mcp.d.ts +294 -0
- package/dist/core/mcp.d.ts.map +1 -0
- package/dist/core/mcp.js +992 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/media-byte-cap.d.ts +34 -0
- package/dist/core/media-byte-cap.d.ts.map +1 -0
- package/dist/core/media-byte-cap.js +76 -0
- package/dist/core/media-byte-cap.js.map +1 -0
- package/dist/core/memory-engine/data-plane.d.ts +103 -0
- package/dist/core/memory-engine/data-plane.d.ts.map +1 -0
- package/dist/core/memory-engine/data-plane.js +272 -0
- package/dist/core/memory-engine/data-plane.js.map +1 -0
- package/dist/core/memory-engine/dual-root.d.ts +40 -0
- package/dist/core/memory-engine/dual-root.d.ts.map +1 -0
- package/dist/core/memory-engine/dual-root.js +95 -0
- package/dist/core/memory-engine/dual-root.js.map +1 -0
- package/dist/core/memory-engine/engine.d.ts +161 -0
- package/dist/core/memory-engine/engine.d.ts.map +1 -0
- package/dist/core/memory-engine/engine.js +1110 -0
- package/dist/core/memory-engine/engine.js.map +1 -0
- package/dist/core/memory-engine/file-backend.d.ts +162 -0
- package/dist/core/memory-engine/file-backend.d.ts.map +1 -0
- package/dist/core/memory-engine/file-backend.js +948 -0
- package/dist/core/memory-engine/file-backend.js.map +1 -0
- package/dist/core/memory-engine/frontmatter.d.ts +24 -0
- package/dist/core/memory-engine/frontmatter.d.ts.map +1 -0
- package/dist/core/memory-engine/frontmatter.js +135 -0
- package/dist/core/memory-engine/frontmatter.js.map +1 -0
- package/dist/core/memory-engine/index.d.ts +13 -0
- package/dist/core/memory-engine/index.d.ts.map +1 -0
- package/dist/core/memory-engine/index.js +28 -0
- package/dist/core/memory-engine/index.js.map +1 -0
- package/dist/core/memory-engine/layout.d.ts +123 -0
- package/dist/core/memory-engine/layout.d.ts.map +1 -0
- package/dist/core/memory-engine/layout.js +643 -0
- package/dist/core/memory-engine/layout.js.map +1 -0
- package/dist/core/memory-engine/memory-backend-contract.d.ts +22 -0
- package/dist/core/memory-engine/memory-backend-contract.d.ts.map +1 -0
- package/dist/core/memory-engine/memory-backend-contract.js +271 -0
- package/dist/core/memory-engine/memory-backend-contract.js.map +1 -0
- package/dist/core/memory-engine/migrate.d.ts +17 -0
- package/dist/core/memory-engine/migrate.d.ts.map +1 -0
- package/dist/core/memory-engine/migrate.js +35 -0
- package/dist/core/memory-engine/migrate.js.map +1 -0
- package/dist/core/memory-engine/scan.d.ts +20 -0
- package/dist/core/memory-engine/scan.d.ts.map +1 -0
- package/dist/core/memory-engine/scan.js +84 -0
- package/dist/core/memory-engine/scan.js.map +1 -0
- package/dist/core/memory-engine/scope-contract.d.ts +104 -0
- package/dist/core/memory-engine/scope-contract.d.ts.map +1 -0
- package/dist/core/memory-engine/scope-contract.js +288 -0
- package/dist/core/memory-engine/scope-contract.js.map +1 -0
- package/dist/core/memory-engine/sync-client.d.ts +100 -0
- package/dist/core/memory-engine/sync-client.d.ts.map +1 -0
- package/dist/core/memory-engine/sync-client.js +328 -0
- package/dist/core/memory-engine/sync-client.js.map +1 -0
- package/dist/core/memory-engine/sync.d.ts +97 -0
- package/dist/core/memory-engine/sync.d.ts.map +1 -0
- package/dist/core/memory-engine/sync.js +91 -0
- package/dist/core/memory-engine/sync.js.map +1 -0
- package/dist/core/memory-engine/types.d.ts +279 -0
- package/dist/core/memory-engine/types.d.ts.map +1 -0
- package/dist/core/memory-engine/types.js +9 -0
- package/dist/core/memory-engine/types.js.map +1 -0
- package/dist/core/memory-recall.d.ts +261 -0
- package/dist/core/memory-recall.d.ts.map +1 -0
- package/dist/core/memory-recall.js +600 -0
- package/dist/core/memory-recall.js.map +1 -0
- package/dist/core/memory-vector.d.ts +24 -0
- package/dist/core/memory-vector.d.ts.map +1 -0
- package/dist/core/memory-vector.js +51 -0
- package/dist/core/memory-vector.js.map +1 -0
- package/dist/core/memory.d.ts +502 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +881 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/message-utils.d.ts +7 -0
- package/dist/core/message-utils.d.ts.map +1 -0
- package/dist/core/message-utils.js +10 -0
- package/dist/core/message-utils.js.map +1 -0
- package/dist/core/oracle-isolation.d.ts +85 -0
- package/dist/core/oracle-isolation.d.ts.map +1 -0
- package/dist/core/oracle-isolation.js +121 -0
- package/dist/core/oracle-isolation.js.map +1 -0
- package/dist/core/permission-rules.d.ts +102 -0
- package/dist/core/permission-rules.d.ts.map +1 -0
- package/dist/core/permission-rules.js +357 -0
- package/dist/core/permission-rules.js.map +1 -0
- package/dist/core/present-plan-tool.d.ts +28 -0
- package/dist/core/present-plan-tool.d.ts.map +1 -0
- package/dist/core/present-plan-tool.js +119 -0
- package/dist/core/present-plan-tool.js.map +1 -0
- package/dist/core/pricing.d.ts +48 -0
- package/dist/core/pricing.d.ts.map +1 -0
- package/dist/core/pricing.js +46 -0
- package/dist/core/pricing.js.map +1 -0
- package/dist/core/property-harness.d.ts +126 -0
- package/dist/core/property-harness.d.ts.map +1 -0
- package/dist/core/property-harness.js +192 -0
- package/dist/core/property-harness.js.map +1 -0
- package/dist/core/push-queue.d.ts +10 -0
- package/dist/core/push-queue.d.ts.map +1 -0
- package/dist/core/push-queue.js +42 -0
- package/dist/core/push-queue.js.map +1 -0
- package/dist/core/remote-env.d.ts +432 -0
- package/dist/core/remote-env.d.ts.map +1 -0
- package/dist/core/remote-env.js +77 -0
- package/dist/core/remote-env.js.map +1 -0
- package/dist/core/roles.d.ts +74 -0
- package/dist/core/roles.d.ts.map +1 -0
- package/dist/core/roles.js +272 -0
- package/dist/core/roles.js.map +1 -0
- package/dist/core/runner/active-skill-scope.d.ts +64 -0
- package/dist/core/runner/active-skill-scope.d.ts.map +1 -0
- package/dist/core/runner/active-skill-scope.js +197 -0
- package/dist/core/runner/active-skill-scope.js.map +1 -0
- package/dist/core/runner/assemble-result.d.ts +191 -0
- package/dist/core/runner/assemble-result.d.ts.map +1 -0
- package/dist/core/runner/assemble-result.js +250 -0
- package/dist/core/runner/assemble-result.js.map +1 -0
- package/dist/core/runner/call-cap.d.ts +130 -0
- package/dist/core/runner/call-cap.d.ts.map +1 -0
- package/dist/core/runner/call-cap.js +151 -0
- package/dist/core/runner/call-cap.js.map +1 -0
- package/dist/core/runner/grounding-signal.d.ts +12 -0
- package/dist/core/runner/grounding-signal.d.ts.map +1 -0
- package/dist/core/runner/grounding-signal.js +94 -0
- package/dist/core/runner/grounding-signal.js.map +1 -0
- package/dist/core/runner/image.d.ts +23 -0
- package/dist/core/runner/image.d.ts.map +1 -0
- package/dist/core/runner/image.js +151 -0
- package/dist/core/runner/image.js.map +1 -0
- package/dist/core/runner/memory-consolidation.d.ts +112 -0
- package/dist/core/runner/memory-consolidation.d.ts.map +1 -0
- package/dist/core/runner/memory-consolidation.js +372 -0
- package/dist/core/runner/memory-consolidation.js.map +1 -0
- package/dist/core/runner/prepare-task.d.ts +583 -0
- package/dist/core/runner/prepare-task.d.ts.map +1 -0
- package/dist/core/runner/prepare-task.js +3612 -0
- package/dist/core/runner/prepare-task.js.map +1 -0
- package/dist/core/runner/prompt-suggestions.d.ts +33 -0
- package/dist/core/runner/prompt-suggestions.d.ts.map +1 -0
- package/dist/core/runner/prompt-suggestions.js +116 -0
- package/dist/core/runner/prompt-suggestions.js.map +1 -0
- package/dist/core/runner/runtask.d.ts +274 -0
- package/dist/core/runner/runtask.d.ts.map +1 -0
- package/dist/core/runner/runtask.js +4606 -0
- package/dist/core/runner/runtask.js.map +1 -0
- package/dist/core/runner/session-rule-policy.d.ts +28 -0
- package/dist/core/runner/session-rule-policy.d.ts.map +1 -0
- package/dist/core/runner/session-rule-policy.js +110 -0
- package/dist/core/runner/session-rule-policy.js.map +1 -0
- package/dist/core/runner/strict-output-schema.d.ts +36 -0
- package/dist/core/runner/strict-output-schema.d.ts.map +1 -0
- package/dist/core/runner/strict-output-schema.js +365 -0
- package/dist/core/runner/strict-output-schema.js.map +1 -0
- package/dist/core/runner/synthetic-tools.d.ts +72 -0
- package/dist/core/runner/synthetic-tools.d.ts.map +1 -0
- package/dist/core/runner/synthetic-tools.js +203 -0
- package/dist/core/runner/synthetic-tools.js.map +1 -0
- package/dist/core/runner/tool-disclosure.d.ts +117 -0
- package/dist/core/runner/tool-disclosure.d.ts.map +1 -0
- package/dist/core/runner/tool-disclosure.js +0 -0
- package/dist/core/runner/tool-disclosure.js.map +1 -0
- package/dist/core/runner/turn-attachments.d.ts +381 -0
- package/dist/core/runner/turn-attachments.d.ts.map +1 -0
- package/dist/core/runner/turn-attachments.js +596 -0
- package/dist/core/runner/turn-attachments.js.map +1 -0
- package/dist/core/runner/usage-accounting.d.ts +35 -0
- package/dist/core/runner/usage-accounting.d.ts.map +1 -0
- package/dist/core/runner/usage-accounting.js +45 -0
- package/dist/core/runner/usage-accounting.js.map +1 -0
- package/dist/core/runtime.d.ts +9 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js +17 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/safety-axis-vocab.d.ts +33 -0
- package/dist/core/safety-axis-vocab.d.ts.map +1 -0
- package/dist/core/safety-axis-vocab.js +35 -0
- package/dist/core/safety-axis-vocab.js.map +1 -0
- package/dist/core/safety-merge-corpus.d.ts +48 -0
- package/dist/core/safety-merge-corpus.d.ts.map +1 -0
- package/dist/core/safety-merge-corpus.js +203 -0
- package/dist/core/safety-merge-corpus.js.map +1 -0
- package/dist/core/scheduler.d.ts +126 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +54 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/secret-env.d.ts +23 -0
- package/dist/core/secret-env.d.ts.map +1 -0
- package/dist/core/secret-env.js +35 -0
- package/dist/core/secret-env.js.map +1 -0
- package/dist/core/select-model.d.ts +26 -0
- package/dist/core/select-model.d.ts.map +1 -0
- package/dist/core/select-model.js +58 -0
- package/dist/core/select-model.js.map +1 -0
- package/dist/core/sensitive-path-policy.d.ts +24 -0
- package/dist/core/sensitive-path-policy.d.ts.map +1 -0
- package/dist/core/sensitive-path-policy.js +96 -0
- package/dist/core/sensitive-path-policy.js.map +1 -0
- package/dist/core/session-policy-store.d.ts +102 -0
- package/dist/core/session-policy-store.d.ts.map +1 -0
- package/dist/core/session-policy-store.js +177 -0
- package/dist/core/session-policy-store.js.map +1 -0
- package/dist/core/session-reconcile.d.ts +63 -0
- package/dist/core/session-reconcile.d.ts.map +1 -0
- package/dist/core/session-reconcile.js +71 -0
- package/dist/core/session-reconcile.js.map +1 -0
- package/dist/core/session-store.d.ts +99 -0
- package/dist/core/session-store.d.ts.map +1 -0
- package/dist/core/session-store.js +298 -0
- package/dist/core/session-store.js.map +1 -0
- package/dist/core/session.d.ts +144 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +56 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/spec-contract.d.ts +147 -0
- package/dist/core/spec-contract.d.ts.map +1 -0
- package/dist/core/spec-contract.js +340 -0
- package/dist/core/spec-contract.js.map +1 -0
- package/dist/core/strategy-store.d.ts +50 -0
- package/dist/core/strategy-store.d.ts.map +1 -0
- package/dist/core/strategy-store.js +100 -0
- package/dist/core/strategy-store.js.map +1 -0
- package/dist/core/stub-env.d.ts +35 -0
- package/dist/core/stub-env.d.ts.map +1 -0
- package/dist/core/stub-env.js +69 -0
- package/dist/core/stub-env.js.map +1 -0
- package/dist/core/task-notification.d.ts +115 -0
- package/dist/core/task-notification.d.ts.map +1 -0
- package/dist/core/task-notification.js +247 -0
- package/dist/core/task-notification.js.map +1 -0
- package/dist/core/task-outcome.d.ts +80 -0
- package/dist/core/task-outcome.d.ts.map +1 -0
- package/dist/core/task-outcome.js +40 -0
- package/dist/core/task-outcome.js.map +1 -0
- package/dist/core/task-registry.d.ts +349 -0
- package/dist/core/task-registry.d.ts.map +1 -0
- package/dist/core/task-registry.js +1751 -0
- package/dist/core/task-registry.js.map +1 -0
- package/dist/core/tighten-task-spec.d.ts +27 -0
- package/dist/core/tighten-task-spec.d.ts.map +1 -0
- package/dist/core/tighten-task-spec.js +95 -0
- package/dist/core/tighten-task-spec.js.map +1 -0
- package/dist/core/tool-detach.d.ts +31 -0
- package/dist/core/tool-detach.d.ts.map +1 -0
- package/dist/core/tool-detach.js +62 -0
- package/dist/core/tool-detach.js.map +1 -0
- package/dist/core/tool-errors.d.ts +72 -0
- package/dist/core/tool-errors.d.ts.map +1 -0
- package/dist/core/tool-errors.js +194 -0
- package/dist/core/tool-errors.js.map +1 -0
- package/dist/core/tool-name-aliases.d.ts +5 -0
- package/dist/core/tool-name-aliases.d.ts.map +1 -0
- package/dist/core/tool-name-aliases.js +130 -0
- package/dist/core/tool-name-aliases.js.map +1 -0
- package/dist/core/tool-policy.d.ts +295 -0
- package/dist/core/tool-policy.d.ts.map +1 -0
- package/dist/core/tool-policy.js +567 -0
- package/dist/core/tool-policy.js.map +1 -0
- package/dist/core/tool-result-budget.d.ts +44 -0
- package/dist/core/tool-result-budget.d.ts.map +1 -0
- package/dist/core/tool-result-budget.js +140 -0
- package/dist/core/tool-result-budget.js.map +1 -0
- package/dist/core/tool-result-store.d.ts +136 -0
- package/dist/core/tool-result-store.d.ts.map +1 -0
- package/dist/core/tool-result-store.js +219 -0
- package/dist/core/tool-result-store.js.map +1 -0
- package/dist/core/tools.d.ts +14 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +98 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/core/trace.d.ts +340 -0
- package/dist/core/trace.d.ts.map +1 -0
- package/dist/core/trace.js +12 -0
- package/dist/core/trace.js.map +1 -0
- package/dist/core/types.d.ts +2828 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/untrusted-egress.d.ts +32 -0
- package/dist/core/untrusted-egress.d.ts.map +1 -0
- package/dist/core/untrusted-egress.js +49 -0
- package/dist/core/untrusted-egress.js.map +1 -0
- package/dist/core/untrusted-text.d.ts +64 -0
- package/dist/core/untrusted-text.d.ts.map +1 -0
- package/dist/core/untrusted-text.js +119 -0
- package/dist/core/untrusted-text.js.map +1 -0
- package/dist/core/warm-resume.d.ts +23 -0
- package/dist/core/warm-resume.d.ts.map +1 -0
- package/dist/core/warm-resume.js +28 -0
- package/dist/core/warm-resume.js.map +1 -0
- package/dist/core/with-retry.d.ts +43 -0
- package/dist/core/with-retry.d.ts.map +1 -0
- package/dist/core/with-retry.js +59 -0
- package/dist/core/with-retry.js.map +1 -0
- package/dist/core/workflow-journal-store.d.ts +44 -0
- package/dist/core/workflow-journal-store.d.ts.map +1 -0
- package/dist/core/workflow-journal-store.js +47 -0
- package/dist/core/workflow-journal-store.js.map +1 -0
- package/dist/core/workflow-run-store-contract.d.ts +31 -0
- package/dist/core/workflow-run-store-contract.d.ts.map +1 -0
- package/dist/core/workflow-run-store-contract.js +191 -0
- package/dist/core/workflow-run-store-contract.js.map +1 -0
- package/dist/core/workflow-run-store.d.ts +149 -0
- package/dist/core/workflow-run-store.d.ts.map +1 -0
- package/dist/core/workflow-run-store.js +110 -0
- package/dist/core/workflow-run-store.js.map +1 -0
- package/dist/engine/compaction/compaction.d.ts +139 -0
- package/dist/engine/compaction/compaction.d.ts.map +1 -0
- package/dist/engine/compaction/compaction.js +1030 -0
- package/dist/engine/compaction/compaction.js.map +1 -0
- package/dist/engine/compaction/utils.d.ts +45 -0
- package/dist/engine/compaction/utils.d.ts.map +1 -0
- package/dist/engine/compaction/utils.js +203 -0
- package/dist/engine/compaction/utils.js.map +1 -0
- package/dist/engine/execution-env/kill-tree.d.ts +20 -0
- package/dist/engine/execution-env/kill-tree.d.ts.map +1 -0
- package/dist/engine/execution-env/kill-tree.js +183 -0
- package/dist/engine/execution-env/kill-tree.js.map +1 -0
- package/dist/engine/execution-env/node-execution-env.d.ts +133 -0
- package/dist/engine/execution-env/node-execution-env.d.ts.map +1 -0
- package/dist/engine/execution-env/node-execution-env.js +1031 -0
- package/dist/engine/execution-env/node-execution-env.js.map +1 -0
- package/dist/engine/harness/agent-harness.d.ts +174 -0
- package/dist/engine/harness/agent-harness.d.ts.map +1 -0
- package/dist/engine/harness/agent-harness.js +1053 -0
- package/dist/engine/harness/agent-harness.js.map +1 -0
- package/dist/engine/harness/messages.d.ts +17 -0
- package/dist/engine/harness/messages.d.ts.map +1 -0
- package/dist/engine/harness/messages.js +122 -0
- package/dist/engine/harness/messages.js.map +1 -0
- package/dist/engine/harness/types.d.ts +713 -0
- package/dist/engine/harness/types.d.ts.map +1 -0
- package/dist/engine/harness/types.js +100 -0
- package/dist/engine/harness/types.js.map +1 -0
- package/dist/engine/llm/diagnostics.d.ts +23 -0
- package/dist/engine/llm/diagnostics.d.ts.map +1 -0
- package/dist/engine/llm/diagnostics.js +32 -0
- package/dist/engine/llm/diagnostics.js.map +1 -0
- package/dist/engine/llm/event-stream.d.ts +25 -0
- package/dist/engine/llm/event-stream.d.ts.map +1 -0
- package/dist/engine/llm/event-stream.js +103 -0
- package/dist/engine/llm/event-stream.js.map +1 -0
- package/dist/engine/llm/index.d.ts +12 -0
- package/dist/engine/llm/index.d.ts.map +1 -0
- package/dist/engine/llm/index.js +12 -0
- package/dist/engine/llm/index.js.map +1 -0
- package/dist/engine/llm/types.d.ts +753 -0
- package/dist/engine/llm/types.d.ts.map +1 -0
- package/dist/engine/llm/types.js +2 -0
- package/dist/engine/llm/types.js.map +1 -0
- package/dist/engine/llm/validation.d.ts +8 -0
- package/dist/engine/llm/validation.d.ts.map +1 -0
- package/dist/engine/llm/validation.js +318 -0
- package/dist/engine/llm/validation.js.map +1 -0
- package/dist/engine/loop/agent-loop.d.ts +74 -0
- package/dist/engine/loop/agent-loop.d.ts.map +1 -0
- package/dist/engine/loop/agent-loop.js +1490 -0
- package/dist/engine/loop/agent-loop.js.map +1 -0
- package/dist/engine/loop/runtime-deps.d.ts +17 -0
- package/dist/engine/loop/runtime-deps.d.ts.map +1 -0
- package/dist/engine/loop/runtime-deps.js +21 -0
- package/dist/engine/loop/runtime-deps.js.map +1 -0
- package/dist/engine/loop/types.d.ts +609 -0
- package/dist/engine/loop/types.d.ts.map +1 -0
- package/dist/engine/loop/types.js +2 -0
- package/dist/engine/loop/types.js.map +1 -0
- package/dist/engine/lsp/frame-decoder.d.ts +16 -0
- package/dist/engine/lsp/frame-decoder.d.ts.map +1 -0
- package/dist/engine/lsp/frame-decoder.js +53 -0
- package/dist/engine/lsp/frame-decoder.js.map +1 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +105 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts.map +1 -0
- package/dist/engine/lsp/node-lsp-manager.js +343 -0
- package/dist/engine/lsp/node-lsp-manager.js.map +1 -0
- package/dist/engine/lsp/stdio-lsp-transport.d.ts +37 -0
- package/dist/engine/lsp/stdio-lsp-transport.d.ts.map +1 -0
- package/dist/engine/lsp/stdio-lsp-transport.js +185 -0
- package/dist/engine/lsp/stdio-lsp-transport.js.map +1 -0
- package/dist/engine/session/import-validate.d.ts +44 -0
- package/dist/engine/session/import-validate.d.ts.map +1 -0
- package/dist/engine/session/import-validate.js +92 -0
- package/dist/engine/session/import-validate.js.map +1 -0
- package/dist/engine/session/memory-repo.d.ts +25 -0
- package/dist/engine/session/memory-repo.d.ts.map +1 -0
- package/dist/engine/session/memory-repo.js +59 -0
- package/dist/engine/session/memory-repo.js.map +1 -0
- package/dist/engine/session/memory-storage.d.ts +14 -0
- package/dist/engine/session/memory-storage.d.ts.map +1 -0
- package/dist/engine/session/memory-storage.js +17 -0
- package/dist/engine/session/memory-storage.js.map +1 -0
- package/dist/engine/session/repo-utils.d.ts +11 -0
- package/dist/engine/session/repo-utils.d.ts.map +1 -0
- package/dist/engine/session/repo-utils.js +40 -0
- package/dist/engine/session/repo-utils.js.map +1 -0
- package/dist/engine/session/session.d.ts +34 -0
- package/dist/engine/session/session.d.ts.map +1 -0
- package/dist/engine/session/session.js +227 -0
- package/dist/engine/session/session.js.map +1 -0
- package/dist/engine/session/storage-base.d.ts +38 -0
- package/dist/engine/session/storage-base.d.ts.map +1 -0
- package/dist/engine/session/storage-base.js +157 -0
- package/dist/engine/session/storage-base.js.map +1 -0
- package/dist/engine/session/timestamps.d.ts +3 -0
- package/dist/engine/session/timestamps.d.ts.map +1 -0
- package/dist/engine/session/timestamps.js +15 -0
- package/dist/engine/session/timestamps.js.map +1 -0
- package/dist/engine/session/uuid.d.ts +2 -0
- package/dist/engine/session/uuid.d.ts.map +1 -0
- package/dist/engine/session/uuid.js +50 -0
- package/dist/engine/session/uuid.js.map +1 -0
- package/dist/index.d.ts +160 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +374 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/harness.d.ts +26 -0
- package/dist/internal/harness.d.ts.map +1 -0
- package/dist/internal/harness.js +24 -0
- package/dist/internal/harness.js.map +1 -0
- package/dist/internal/llm.d.ts +9 -0
- package/dist/internal/llm.d.ts.map +1 -0
- package/dist/internal/llm.js +8 -0
- package/dist/internal/llm.js.map +1 -0
- package/dist/orchestration/builtin-workflows.d.ts +44 -0
- package/dist/orchestration/builtin-workflows.d.ts.map +1 -0
- package/dist/orchestration/builtin-workflows.js +165 -0
- package/dist/orchestration/builtin-workflows.js.map +1 -0
- package/dist/orchestration/dev-vm-script-runner.d.ts +24 -0
- package/dist/orchestration/dev-vm-script-runner.d.ts.map +1 -0
- package/dist/orchestration/dev-vm-script-runner.js +106 -0
- package/dist/orchestration/dev-vm-script-runner.js.map +1 -0
- package/dist/orchestration/goal.d.ts +97 -0
- package/dist/orchestration/goal.d.ts.map +1 -0
- package/dist/orchestration/goal.js +248 -0
- package/dist/orchestration/goal.js.map +1 -0
- package/dist/orchestration/run-spec.d.ts +63 -0
- package/dist/orchestration/run-spec.d.ts.map +1 -0
- package/dist/orchestration/run-spec.js +274 -0
- package/dist/orchestration/run-spec.js.map +1 -0
- package/dist/orchestration/run-workflow-tool.d.ts +187 -0
- package/dist/orchestration/run-workflow-tool.d.ts.map +1 -0
- package/dist/orchestration/run-workflow-tool.js +612 -0
- package/dist/orchestration/run-workflow-tool.js.map +1 -0
- package/dist/orchestration/workflow-governance.d.ts +70 -0
- package/dist/orchestration/workflow-governance.d.ts.map +1 -0
- package/dist/orchestration/workflow-governance.js +176 -0
- package/dist/orchestration/workflow-governance.js.map +1 -0
- package/dist/orchestration/workflow-meta.d.ts +41 -0
- package/dist/orchestration/workflow-meta.d.ts.map +1 -0
- package/dist/orchestration/workflow-meta.js +426 -0
- package/dist/orchestration/workflow-meta.js.map +1 -0
- package/dist/orchestration/workflow-observe.d.ts +77 -0
- package/dist/orchestration/workflow-observe.d.ts.map +1 -0
- package/dist/orchestration/workflow-observe.js +177 -0
- package/dist/orchestration/workflow-observe.js.map +1 -0
- package/dist/orchestration/workflow-primitives.d.ts +31 -0
- package/dist/orchestration/workflow-primitives.d.ts.map +1 -0
- package/dist/orchestration/workflow-primitives.js +104 -0
- package/dist/orchestration/workflow-primitives.js.map +1 -0
- package/dist/orchestration/workflow-sandbox-conformance.d.ts +34 -0
- package/dist/orchestration/workflow-sandbox-conformance.d.ts.map +1 -0
- package/dist/orchestration/workflow-sandbox-conformance.js +301 -0
- package/dist/orchestration/workflow-sandbox-conformance.js.map +1 -0
- package/dist/orchestration/workflow-script-runner.d.ts +127 -0
- package/dist/orchestration/workflow-script-runner.d.ts.map +1 -0
- package/dist/orchestration/workflow-script-runner.js +48 -0
- package/dist/orchestration/workflow-script-runner.js.map +1 -0
- package/dist/orchestration/workflow-script-store.d.ts +99 -0
- package/dist/orchestration/workflow-script-store.d.ts.map +1 -0
- package/dist/orchestration/workflow-script-store.js +133 -0
- package/dist/orchestration/workflow-script-store.js.map +1 -0
- package/dist/orchestration/workflow-size-guideline.d.ts +50 -0
- package/dist/orchestration/workflow-size-guideline.d.ts.map +1 -0
- package/dist/orchestration/workflow-size-guideline.js +78 -0
- package/dist/orchestration/workflow-size-guideline.js.map +1 -0
- package/dist/orchestration/workflow.d.ts +624 -0
- package/dist/orchestration/workflow.d.ts.map +1 -0
- package/dist/orchestration/workflow.js +1596 -0
- package/dist/orchestration/workflow.js.map +1 -0
- package/dist/prompts/default.d.ts +474 -0
- package/dist/prompts/default.d.ts.map +1 -0
- package/dist/prompts/default.js +676 -0
- package/dist/prompts/default.js.map +1 -0
- package/dist/prompts/supervisor.d.ts +60 -0
- package/dist/prompts/supervisor.d.ts.map +1 -0
- package/dist/prompts/supervisor.js +162 -0
- package/dist/prompts/supervisor.js.map +1 -0
- package/dist/scenarios/env.d.ts +41 -0
- package/dist/scenarios/env.d.ts.map +1 -0
- package/dist/scenarios/env.js +65 -0
- package/dist/scenarios/env.js.map +1 -0
- package/dist/scenarios/full-body.d.ts +47 -0
- package/dist/scenarios/full-body.d.ts.map +1 -0
- package/dist/scenarios/full-body.js +36 -0
- package/dist/scenarios/full-body.js.map +1 -0
- package/dist/scenarios/scenario-registry.d.ts +107 -0
- package/dist/scenarios/scenario-registry.d.ts.map +1 -0
- package/dist/scenarios/scenario-registry.js +192 -0
- package/dist/scenarios/scenario-registry.js.map +1 -0
- package/dist/scenarios/teacher-quickstart.d.ts +41 -0
- package/dist/scenarios/teacher-quickstart.d.ts.map +1 -0
- package/dist/scenarios/teacher-quickstart.js +32 -0
- package/dist/scenarios/teacher-quickstart.js.map +1 -0
- package/dist/server/http.d.ts +36 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +144 -0
- package/dist/server/http.js.map +1 -0
- package/dist/stores/file/checkpoint-store.d.ts +62 -0
- package/dist/stores/file/checkpoint-store.d.ts.map +1 -0
- package/dist/stores/file/checkpoint-store.js +250 -0
- package/dist/stores/file/checkpoint-store.js.map +1 -0
- package/dist/stores/file/file-snapshot-store.d.ts +43 -0
- package/dist/stores/file/file-snapshot-store.d.ts.map +1 -0
- package/dist/stores/file/file-snapshot-store.js +374 -0
- package/dist/stores/file/file-snapshot-store.js.map +1 -0
- package/dist/stores/file/fs-atomic.d.ts +95 -0
- package/dist/stores/file/fs-atomic.d.ts.map +1 -0
- package/dist/stores/file/fs-atomic.js +415 -0
- package/dist/stores/file/fs-atomic.js.map +1 -0
- package/dist/stores/file/index.d.ts +98 -0
- package/dist/stores/file/index.d.ts.map +1 -0
- package/dist/stores/file/index.js +109 -0
- package/dist/stores/file/index.js.map +1 -0
- package/dist/stores/file/memory-store.d.ts +95 -0
- package/dist/stores/file/memory-store.d.ts.map +1 -0
- package/dist/stores/file/memory-store.js +393 -0
- package/dist/stores/file/memory-store.js.map +1 -0
- package/dist/stores/file/session-policy-store.d.ts +24 -0
- package/dist/stores/file/session-policy-store.d.ts.map +1 -0
- package/dist/stores/file/session-policy-store.js +123 -0
- package/dist/stores/file/session-policy-store.js.map +1 -0
- package/dist/stores/file/session-store.d.ts +34 -0
- package/dist/stores/file/session-store.d.ts.map +1 -0
- package/dist/stores/file/session-store.js +175 -0
- package/dist/stores/file/session-store.js.map +1 -0
- package/dist/stores/file/tool-result-store.d.ts +23 -0
- package/dist/stores/file/tool-result-store.d.ts.map +1 -0
- package/dist/stores/file/tool-result-store.js +61 -0
- package/dist/stores/file/tool-result-store.js.map +1 -0
- package/dist/stores/file/workflow-journal-store.d.ts +36 -0
- package/dist/stores/file/workflow-journal-store.d.ts.map +1 -0
- package/dist/stores/file/workflow-journal-store.js +157 -0
- package/dist/stores/file/workflow-journal-store.js.map +1 -0
- package/dist/stores/file/workflow-run-store.d.ts +58 -0
- package/dist/stores/file/workflow-run-store.d.ts.map +1 -0
- package/dist/stores/file/workflow-run-store.js +178 -0
- package/dist/stores/file/workflow-run-store.js.map +1 -0
- package/dist/stores/pg.d.ts +210 -0
- package/dist/stores/pg.d.ts.map +1 -0
- package/dist/stores/pg.js +652 -0
- package/dist/stores/pg.js.map +1 -0
- package/dist/tools/fs/encoding.d.ts +51 -0
- package/dist/tools/fs/encoding.d.ts.map +1 -0
- package/dist/tools/fs/encoding.js +74 -0
- package/dist/tools/fs/encoding.js.map +1 -0
- package/dist/tools/fs/gh-rate-limit.d.ts +19 -0
- package/dist/tools/fs/gh-rate-limit.d.ts.map +1 -0
- package/dist/tools/fs/gh-rate-limit.js +35 -0
- package/dist/tools/fs/gh-rate-limit.js.map +1 -0
- package/dist/tools/fs/index.d.ts +246 -0
- package/dist/tools/fs/index.d.ts.map +1 -0
- package/dist/tools/fs/index.js +2130 -0
- package/dist/tools/fs/index.js.map +1 -0
- package/dist/tools/fs/pdf.d.ts +106 -0
- package/dist/tools/fs/pdf.d.ts.map +1 -0
- package/dist/tools/fs/pdf.js +178 -0
- package/dist/tools/fs/pdf.js.map +1 -0
- package/dist/tools/fs/repo-map.d.ts +15 -0
- package/dist/tools/fs/repo-map.d.ts.map +1 -0
- package/dist/tools/fs/repo-map.js +251 -0
- package/dist/tools/fs/repo-map.js.map +1 -0
- package/dist/tools/fs/safety.d.ts +168 -0
- package/dist/tools/fs/safety.d.ts.map +1 -0
- package/dist/tools/fs/safety.js +479 -0
- package/dist/tools/fs/safety.js.map +1 -0
- package/dist/tools/fs/search.d.ts +118 -0
- package/dist/tools/fs/search.d.ts.map +1 -0
- package/dist/tools/fs/search.js +650 -0
- package/dist/tools/fs/search.js.map +1 -0
- package/dist/tools/gitea-issue.d.ts +39 -0
- package/dist/tools/gitea-issue.d.ts.map +1 -0
- package/dist/tools/gitea-issue.js +91 -0
- package/dist/tools/gitea-issue.js.map +1 -0
- package/dist/tools/monitor.d.ts +64 -0
- package/dist/tools/monitor.d.ts.map +1 -0
- package/dist/tools/monitor.js +135 -0
- package/dist/tools/monitor.js.map +1 -0
- package/dist/tools/scheduler-tools.d.ts +48 -0
- package/dist/tools/scheduler-tools.d.ts.map +1 -0
- package/dist/tools/scheduler-tools.js +449 -0
- package/dist/tools/scheduler-tools.js.map +1 -0
- package/dist/tools/sql-adapters.d.ts +32 -0
- package/dist/tools/sql-adapters.d.ts.map +1 -0
- package/dist/tools/sql-adapters.js +31 -0
- package/dist/tools/sql-adapters.js.map +1 -0
- package/dist/tools/sql.d.ts +36 -0
- package/dist/tools/sql.d.ts.map +1 -0
- package/dist/tools/sql.js +131 -0
- package/dist/tools/sql.js.map +1 -0
- package/dist/tools/task-list.d.ts +26 -0
- package/dist/tools/task-list.d.ts.map +1 -0
- package/dist/tools/task-list.js +352 -0
- package/dist/tools/task-list.js.map +1 -0
- package/dist/tools/todo.d.ts +11 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +126 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/web.d.ts +59 -0
- package/dist/tools/web.d.ts.map +1 -0
- package/dist/tools/web.js +607 -0
- package/dist/tools/web.js.map +1 -0
- package/dist/tools/worktree.d.ts +88 -0
- package/dist/tools/worktree.d.ts.map +1 -0
- package/dist/tools/worktree.js +434 -0
- package/dist/tools/worktree.js.map +1 -0
- package/docs/A1-ATTRIBUTION-ROUND1-2026-07-09.md +181 -0
- package/docs/AB-ORACLE-GATE-VERDICT-2026-07-10.md +100 -0
- package/docs/ANCHOR-GAP-INVENTORY-2026-07-09.md +143 -0
- package/docs/ARCHITECTURE.md +125 -0
- package/docs/BUGHUNT-2026-07-05-NIGHT.md +98 -0
- package/docs/BUILD.md +63 -0
- package/docs/CANCEL-ASYNC-ATTRIBUTION-2026-07-09.md +98 -0
- package/docs/CC-198-VS-201-DRIFT-2026-07-09.md +70 -0
- package/docs/CC-BASELINE-FAKE-ZERO-AUDIT-2026-07-09.md +51 -0
- package/docs/CC-DRIFT-198-206-AGENT-TYPES-2026-07-10.md +82 -0
- package/docs/CC-DRIFT-198-206-CHANGELOG-2026-07-10.md +82 -0
- package/docs/CC-DRIFT-198-206-REMINDERS-2026-07-10.md +96 -0
- package/docs/CC-DRIFT-198-206-ROADMAP-2026-07-10.md +110 -0
- package/docs/CC-DRIFT-198-206-TOOL-INVENTORY-2026-07-10.md +53 -0
- package/docs/CC-DRIFT-198-206-USAGE-CONSTANTS-2026-07-10.md +64 -0
- package/docs/CC-DRIFT-198-206-WORKFLOW-2026-07-10.md +83 -0
- package/docs/CC-PARITY-CHECKLIST.md +220 -0
- package/docs/CC-PARITY-DEEP-SWEEP-2026-07-07.md +149 -0
- package/docs/CC-SUBAGENT-PROMPT-STUDY-2026-07-09.md +219 -0
- package/docs/CC-TASK-REMINDER-CADENCE-STUDY-2026-07-09.md +396 -0
- package/docs/CC-TOOL-PARITY-SWEEP-2026-07.md +56 -0
- package/docs/CC-TOOL-PROMPT-DEEP-DIFF-2026-07-08.md +274 -0
- package/docs/CC-TOOLSURFACE-DEEP-DIVE-2026-07-07.md +197 -0
- package/docs/CC206-OBSERVER-ANCHORS-2026-07-11.md +463 -0
- package/docs/CC207-CORE-SWEEP-BACKLOG-2026-07-12.md +155 -0
- package/docs/CENTER-CONTROL-PLANE-SEAM.md +86 -0
- package/docs/CLEANUP-CONTRACT-ANCHOR-2026-07-09.md +83 -0
- package/docs/COLD-START-RSI-2026-07-09.md +72 -0
- package/docs/COMPACTION-LIVE-AUDIT-2026-07-09.md +114 -0
- package/docs/CONTEXT-lifecycle-extension-points-and-stop-attribution.md +71 -0
- package/docs/COREWARS-POLYGLOT-TRIAGE-2026-07-09.md +85 -0
- package/docs/DEADTARGET-OVERFULL-HBOX-2026-07-10.md +92 -0
- package/docs/DEADTARGET-PATH-TRACING-REVERSE-2026-07-10.md +87 -0
- package/docs/DEADTARGET-WINNING-AVG-COREWARS-2026-07-10.md +96 -0
- package/docs/DEEPSEEK-API-LIMITS-PROBE-2026-07-09.md +118 -0
- package/docs/DESIGN-140-MOCK-VERIFY-2026-07-11.md +79 -0
- package/docs/DESIGN-140-VERIFICATION-2026-07-11.md +43 -0
- package/docs/DESIGN-DRAFT-workflow-collab-2026-07-11.md +56 -0
- package/docs/DESIGN-ORACLE-GROUNDING-GATE-2026-07-10.md +167 -0
- package/docs/DESIGN-TFRAG-RECONCILE-SCAFFOLD-2026-07-09.md +102 -0
- package/docs/EXP-PA2-PE-DESIGN-2026-07-11.md +220 -0
- package/docs/EXT-DOGFOOD-2026-07-12.md +50 -0
- package/docs/FINAL-VERIFY-SURFACE-AUDIT-2026-07-09.md +44 -0
- package/docs/FRAG-RECON-INVESTIGATION-2026-07-09.md +183 -0
- package/docs/HANDOFF.md +121 -0
- package/docs/KNOWN-ISSUES.md +96 -0
- package/docs/LEGW-WINDOW-TAX-2026-07-10.md +82 -0
- package/docs/LIVE-PROBE-BATCH-2026-07-11.md +207 -0
- package/docs/M2-CERT-ATTRIBUTION-2026-07-10.md +61 -0
- package/docs/M25-LEG-VARIANCE-ATTRIBUTION-2026-07-10.md +81 -0
- package/docs/MAILMAN-TIMEOUT-ATTRIBUTION-2026-07-10.md +88 -0
- package/docs/MEMORY-BACKEND-DIALECT-NOTES.md +69 -0
- package/docs/MTEB-ESCAPE-HATCH-ATTRIBUTION-2026-07-09.md +57 -0
- package/docs/MTEB-LEADERBOARD-ATTRIBUTION-2026-07-10.md +134 -0
- package/docs/ORACLE-GATE-NEGATIVE-SAMPLE-2026-07-11.md +28 -0
- package/docs/PARITY-CONTEXT-TRANSACTIONS-2026-07-10.md +67 -0
- package/docs/PARITY-PROGRESS-MATRIX-2026-07-10.md +37 -0
- package/docs/PARITY-SPOT-AGENT-TYPES-2026-07-10.md +70 -0
- package/docs/PARITY-SPOT-REMINDERS-2026-07-10.md +144 -0
- package/docs/PARITY-SPOT-TOOL-INVENTORY-2026-07-10.md +61 -0
- package/docs/PARITY-SPOT-USAGE-CONSTANTS-2026-07-10.md +95 -0
- package/docs/PARITY-SPOT-WORKFLOW-2026-07-10.md +93 -0
- package/docs/PASSWORD-RECOVERY-PANEL-VERDICT-2026-07-10.md +62 -0
- package/docs/R8-R9-FINALIZE-COORDINATION-2026-07-09.md +124 -0
- package/docs/REPL-CODE-MODE-EVALUATION-2026-07-10.md +187 -0
- package/docs/REPORT-1249-TARGETED.md +48 -0
- package/docs/RESEARCH-3P-MEMORY-SWAP-2026-07-12.md +273 -0
- package/docs/ROADMAP.md +111 -0
- package/docs/RSI-CLOUD-DEPLOY-2026-07-06.md +289 -0
- package/docs/RSI-PROCESS-AI-COLDSTART-2026-07-11.md +68 -0
- package/docs/S18-THOROUGHNESS-AUDIT-2026-07-09.md +113 -0
- package/docs/SERVICE-INTEGRATION-GUIDE.md +298 -0
- package/docs/SUBAGENT-STREAM-RESILIENCE-PARITY-2026-07-10.md +118 -0
- package/docs/SWEBENCH-PRO-RECON-2026-07-11.md +31 -0
- package/docs/TB-EFFICIENCY-TELEMETRY-2026-07-08.md +114 -0
- package/docs/TB-FAILURE-AUTOPSY-2026-07-05-RERUN.md +67 -0
- package/docs/TB-FAIRNESS-AUDIT-2026-07-08.md +141 -0
- package/docs/TB-FULL-1257-2026-07-08.md +77 -0
- package/docs/TB-LEG-GAP-ATTRIBUTION-1261-1263-2026-07-11.md +154 -0
- package/docs/TB-REGRESSION-DAEMON-KILL-2026-07-08.md +58 -0
- package/docs/TB-RSI-CROSSCHECK-2026-07-06.md +68 -0
- package/docs/TB-RSI-LEDGER.md +30 -0
- package/docs/TB-STABLE-SET-2026-07-08.md +127 -0
- package/docs/TB21-RECON-2026-07-11.md +28 -0
- package/docs/TEST-DESIGN-BATCH-1-2-3.md +97 -0
- package/docs/THIRD-PARTY-INTEGRATION.md +45 -0
- package/docs/TOKEN-ESTIMATE-CALIBRATION-LIVE-2026-07-09.md +102 -0
- package/docs/audit-2026-06-10-/347/254/254/344/272/214/350/275/256-/347/251/272/347/231/275/345/214/272/344/270/216/345/277/230/346/216/245/347/272/277.md +147 -0
- package/docs/audit-2026-06-10-/350/256/241/347/256/227bug/346/211/253/346/217/217.md +163 -0
- package/docs/audit-2026-06-11-/344/277/256/345/244/215/345/244/215/345/256/241/344/270/216/345/233/236/345/275/222/344/270/223/346/211/253.md +95 -0
- package/docs/audit-2026-06-12-design71-P1/346/275/234/344/274/217/351/235/242/350/243/201/345/206/263/344/270/216/345/220/236/351/224/231/345/256/241/350/256/241.md +45 -0
- package/docs/audit-2026-06-12-/345/205/254/345/274/200/346/227/213/351/222/256/346/264/273/346/200/247/344/270/216vendored/346/255/273/350/267/257.md +63 -0
- package/docs/audit-2026-06-15/ADDENDUM-second-pass.md +88 -0
- package/docs/audit-2026-06-15/ARCHITECTURE-AND-ROADMAP.md +187 -0
- package/docs/audit-2026-06-15/DOC-CORRECTIONS.md +105 -0
- package/docs/audit-2026-06-15/INDEX.md +49 -0
- package/docs/audit-2026-06-15/ORCHESTRATION-STATUS.md +98 -0
- package/docs/audit-2026-06-15/PRODUCTION-ISSUES.md +189 -0
- package/docs/audit-2026-06-15/REFERENCES-literature.md +139 -0
- package/docs/audit-2026-06-15/VENDOR-REFACTOR-PLAN.md +96 -0
- package/docs/cc-probe-198/README.md +72 -0
- package/docs/cc-probe-198/STABILITY-AUDIT.md +118 -0
- package/docs/cc-probe-198/live-schema-monitor-worktree-2026-07-09.json +56 -0
- package/docs/cc-probe-198/mount-variants.json +536 -0
- package/docs/cc-probe-198/plan-mode-run.json +1 -0
- package/docs/cc-probe-198/probe-bash-bg.json +224 -0
- package/docs/cc-probe-198/probe-edit-mismatch.json +120 -0
- package/docs/cc-probe-198/probe-read-missing.json +62 -0
- package/docs/cc-probe-198/probe-search-empty.json +127 -0
- package/docs/cc-probe-198/probe-task-family.json +227 -0
- package/docs/cc-probe-198/probes.status +6 -0
- package/docs/cc-probe-198/raw-capture-interactive.json +948 -0
- package/docs/cc-probe-198/raw-capture-print.json +787 -0
- package/docs/cc-probe-198/raw-capture2-interactive.json +948 -0
- package/docs/cc-probe-198/raw-capture2-print.json +787 -0
- package/docs/cc-probe-198/system-prompt.txt +135 -0
- package/docs/cc-probe-198/tools-array.json +962 -0
- package/docs/durability-boundary.md +63 -0
- package/docs/fix-2026-06-10-/350/256/241/347/256/227bug/344/277/256/345/244/215-search/346/211/271.md +75 -0
- package/docs/fix-2026-06-11-/347/254/254/344/272/214/350/275/256-/344/277/256/345/244/215-search/346/211/271.md +62 -0
- package/docs/parity-sweep/REPORT-DYNAMIC.md +97 -0
- package/docs/parity-sweep/REPORT-STATIC-GGB.md +127 -0
- package/docs/parity-sweep/REPORT-STATIC-RWE.md +133 -0
- package/docs/vendor-history.md +385 -0
- package/docs/vendored-upstream-diff-2026-07.md +83 -0
- package/package.json +70 -0
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
// design/138 S1 — FileMemoryEngineBackend: the TOC 权威盘. The memory DIRECTORY ITSELF is the storage
|
|
2
|
+
// (直通零拷贝): each entry is one `<slug>.md` file with CC frontmatter + a hidden immutable `id:`.
|
|
3
|
+
// The engine's session projection and this backend's storage share ONE layout (layout.ts), so
|
|
4
|
+
// materialize on this backend writes nothing (files are already exactly where the projection wants
|
|
5
|
+
// them) and applyPatches is the sole write path (add/update/delete + per-id CAS on the content rev).
|
|
6
|
+
//
|
|
7
|
+
// 双轨评审 (B1/B2/B3/H4): zero-copy alone cannot carry the safety invariants, so this backend runs a
|
|
8
|
+
// CONTROL PLANE (layout.deriveControlPlaneDir — model-invisible, outside the memory dir):
|
|
9
|
+
// - `revs.json` — the committed-rev ledger (B3: atomic writes, corrupt ⇒ fail-closed, never a silent
|
|
10
|
+
// empty-ledger downgrade);
|
|
11
|
+
// - `scopes.json` — the scope registry (B3, via layout.ts);
|
|
12
|
+
// - `shadow/<id>.md` — the committed content copy per entry (B1: 「缺失≠删除」has an actual recovery
|
|
13
|
+
// source; written at the applyPatches commit point + backfilled on read-side sync);
|
|
14
|
+
// - `quarantine/` — inbound-gate-rejected files moved OUT of the model-visible plane (B2/L4);
|
|
15
|
+
// - `journal.json` + same-dir `.stage-*` files — the applyPatches transaction (H4: staged writes,
|
|
16
|
+
// fsync'd journal, atomic renames; a crash is rolled forward/back on the next construction).
|
|
17
|
+
import { lstatSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync, openSync, writeSync, fsyncSync, closeSync } from "node:fs";
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
19
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
20
|
+
import { jaccardDistance, termSet } from "../memory-vector.js";
|
|
21
|
+
import { MAX_MEMORY_BYTES } from "../memory.js";
|
|
22
|
+
import { inlineUntrusted } from "../untrusted-text.js";
|
|
23
|
+
import { computeEntryRev, entryFromFile, parseEntryFile, serializeEntryFile } from "./frontmatter.js";
|
|
24
|
+
import { ControlPlaneCorruptError, CURSORS_FILE, atomicWriteFileSync, claimRootScope, deriveControlPlaneDir, ensureDirExists, enqueueMemoryAnnouncement, registerScope, registeredScopes, resolveMemoryEngineRoot, scopeDirName, } from "./layout.js";
|
|
25
|
+
import { scanMemoryFileName, scanMemoryWrite } from "./scan.js";
|
|
26
|
+
/** Files/dirs the entry scan never treats as entries: the derived index, dotfiles (`.hydrate`,
|
|
27
|
+
* transaction staging files), and anything not `.md`. */
|
|
28
|
+
export const MEMORY_INDEX_FILENAME = "MEMORY.md";
|
|
29
|
+
/** Default nesting depth cap under a scope dir (CC memory is flat; a small allowance for topic dirs). */
|
|
30
|
+
export const DEFAULT_MAX_ENTRY_DEPTH = 3;
|
|
31
|
+
/**
|
|
32
|
+
* Enumerate a scope dir's entry files (depth-capped, symlinks skipped, dotfiles/index/non-`.md`
|
|
33
|
+
* ignored, `exclude` dirs — sibling scope homes under the root — skipped). Shared by the backend
|
|
34
|
+
* and the engine's harvest scan so the two can never disagree on what counts as an entry file.
|
|
35
|
+
*/
|
|
36
|
+
export function scanEntryFiles(dir, opts = {}) {
|
|
37
|
+
const maxDepth = opts.maxDepth ?? DEFAULT_MAX_ENTRY_DEPTH;
|
|
38
|
+
const out = [];
|
|
39
|
+
const walk = (d, depth) => {
|
|
40
|
+
let names;
|
|
41
|
+
try {
|
|
42
|
+
names = readdirSync(d);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return; // unreadable/missing dir ⇒ no entries (fail-open on reads)
|
|
46
|
+
}
|
|
47
|
+
for (const name of names.sort()) {
|
|
48
|
+
if (name.startsWith(".") || name === MEMORY_INDEX_FILENAME) {
|
|
49
|
+
if (name.startsWith("."))
|
|
50
|
+
opts.onSkip?.(join(d, name), "dotfile");
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const p = join(d, name);
|
|
54
|
+
let st;
|
|
55
|
+
try {
|
|
56
|
+
st = lstatSync(p);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (st.isSymbolicLink()) {
|
|
62
|
+
opts.onSkip?.(p, "symlink"); // containment gate: symlinks are never entries
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (st.isDirectory()) {
|
|
66
|
+
if (depth === 0 && opts.exclude?.has(name))
|
|
67
|
+
continue; // a sibling scope's home under the root
|
|
68
|
+
if (depth + 1 <= maxDepth)
|
|
69
|
+
walk(p, depth + 1);
|
|
70
|
+
else
|
|
71
|
+
opts.onSkip?.(p, "depth");
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (!st.isFile())
|
|
75
|
+
continue;
|
|
76
|
+
if (!name.endsWith(".md")) {
|
|
77
|
+
opts.onSkip?.(p, "nonmd");
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
out.push({ path: p, slug: relative(dir, p).replace(/\.md$/, "") });
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
walk(dir, 0);
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
const LEDGER_FILE = "revs.json";
|
|
87
|
+
const JOURNAL_FILE = "journal.json";
|
|
88
|
+
/** codex B5 — cross-process txn mutex: a lock older than this is a crashed holder (stolen; the
|
|
89
|
+
* journal recovery inside the lock makes the steal safe). */
|
|
90
|
+
const TXN_LOCK_STALE_MS = 30_000;
|
|
91
|
+
/** How long a writer waits for the mutex before failing loud (harvest is a boundary side-effect —
|
|
92
|
+
* a wedged sibling must surface, not hang the task teardown). */
|
|
93
|
+
const TXN_LOCK_WAIT_MS = 15_000;
|
|
94
|
+
/** 对抗复审 L3 — steal grace: a waiter that OBSERVES a lock extends its deadline to that lock's
|
|
95
|
+
* stale line plus this ε, so a holder that crashed inside the fixed-WAIT window ([T, T+WAIT) with
|
|
96
|
+
* WAIT < STALE) is still reachable by one steal attempt instead of every waiter timing out. */
|
|
97
|
+
const TXN_LOCK_STEAL_GRACE_MS = 250;
|
|
98
|
+
const SHADOW_DIR = "shadow";
|
|
99
|
+
const QUARANTINE_DIR = "quarantine";
|
|
100
|
+
/**
|
|
101
|
+
* ⚠️ DEPLOYMENT BOUNDARY (N0 定谳,channel 给service-AI.md [412],2026-07-09):this backend — and the
|
|
102
|
+
* file memory engine's materialize/harvest — operates on the WORKER-HOST fs plane (node:fs), matching
|
|
103
|
+
* CC's `~/.claude` host-plane memory (the only behavior anchor). It is NOT ExecutionEnv-aware: when a
|
|
104
|
+
* deployment routes the model's file tools to a REMOTE sandbox (e2b/k8s/ssh/adb/local-docker), the two
|
|
105
|
+
* planes do not intersect — the model cannot see the memory dir and harvest cannot see sandbox writes.
|
|
106
|
+
* Remote-hands deployments MUST gate the engine off for non-host lanes (reference: service
|
|
107
|
+
* `memoryEngineBackendFor` lane gate, fail-closed + `MEMORY_ENGINE_REMOTE_LANE=allow` override for
|
|
108
|
+
* lanes that genuinely share the worker fs, e.g. ssh+NFS). A future "remote-memory-materialize" design
|
|
109
|
+
* (ExecutionEnv-seam placement/harvest with sandbox-lifecycle contracts) is demand-triggered — do not
|
|
110
|
+
* bolt it on here.
|
|
111
|
+
*/
|
|
112
|
+
export class FileMemoryEngineBackend {
|
|
113
|
+
/** The repo-level memory dir this backend is the authority for (engine reads it for zero-copy). */
|
|
114
|
+
directoryRoot;
|
|
115
|
+
/** B3 — the engine control plane home (ledger/scopes/shadow/quarantine/journal). Model-invisible:
|
|
116
|
+
* NEVER under {@link directoryRoot}, always on the config-root side even for an in-repo memory dir.
|
|
117
|
+
* The engine picks this up (like `directoryRoot`) so both sides share ONE control plane. */
|
|
118
|
+
controlPlaneRoot;
|
|
119
|
+
/** Injected clock (opus 1.258 LOW: match the engine's `this.now` determinism discipline). */
|
|
120
|
+
now;
|
|
121
|
+
/**
|
|
122
|
+
* The COMMITTED-rev ledger (`revs.json`, id → rev). Zero-copy makes it load-bearing for CAS: the
|
|
123
|
+
* entry files are the SAME files the session edits, so "read the current rev from the file" would
|
|
124
|
+
* make every legitimate update self-conflict (the file already holds the new content). The ledger
|
|
125
|
+
* records the rev as of the last COMMIT (applyPatches) — a CAS compares against IT, so an in-session
|
|
126
|
+
* edit passes (baseRev == ledger) while a concurrently-committed change conflicts (ledger advanced).
|
|
127
|
+
* Read-side (`listHeaders`/`getByIds`/`search`) SYNCS the ledger to disk THROUGH the inbound gate
|
|
128
|
+
* (B2 — out-of-session edits, e.g. a git pull into an in-repo memory dir, are secret/cap-scanned;
|
|
129
|
+
* rejects are quarantined + shadow-restored, never adopted); the applyPatches lookup does NOT sync
|
|
130
|
+
* (that would erase the very baseline CAS needs). B3: corrupt ⇒ {@link ControlPlaneCorruptError}
|
|
131
|
+
* (fail-closed), never a silent empty-ledger downgrade.
|
|
132
|
+
*/
|
|
133
|
+
ledger;
|
|
134
|
+
/** B2 — inbound-gate findings accumulated by read-side syncs; the engine drains them into
|
|
135
|
+
* `HarvestReport.inboundFindings` at harvest. */
|
|
136
|
+
inboundFindings = [];
|
|
137
|
+
/** ⚠️ [508] service 逮的分家坑:不显式传 `controlDir` 时,控制平面按无参 `resolveMemoryEngineRoot()`
|
|
138
|
+
* 派生(env/默认 config 根)——若你的记忆目录带自定义根,控制面会与记忆目录分家。自建 backend 的
|
|
139
|
+
* consumer 应显式钉 `controlDir`(engine 同参)。`now` = 注入时钟(determinism,engine 同款)。 */
|
|
140
|
+
constructor(dir, opts = {}) {
|
|
141
|
+
this.now = opts.now ?? Date.now;
|
|
142
|
+
this.directoryRoot = dir;
|
|
143
|
+
this.controlPlaneRoot = opts.controlDir ?? deriveControlPlaneDir(resolveMemoryEngineRoot(), dir);
|
|
144
|
+
ensureDirExists(dir);
|
|
145
|
+
ensureDirExists(this.controlPlaneRoot);
|
|
146
|
+
this.recoverJournal(); // H4: roll an interrupted transaction forward before anything reads state
|
|
147
|
+
}
|
|
148
|
+
/** B3 fail-closed preflight (engine harvest duck-types this): force-reload every load-bearing
|
|
149
|
+
* sidecar from disk; throws {@link ControlPlaneCorruptError} when one is corrupt. Also completes
|
|
150
|
+
* any interrupted transaction (H4 recovery). */
|
|
151
|
+
checkControlPlane() {
|
|
152
|
+
this.recoverJournal();
|
|
153
|
+
this.ledger = undefined;
|
|
154
|
+
this.loadLedger();
|
|
155
|
+
registeredScopes(this.controlPlaneRoot); // throws on a corrupt scopes.json
|
|
156
|
+
}
|
|
157
|
+
/** B2 — drain the accumulated inbound-gate findings (engine harvest reporting). */
|
|
158
|
+
drainInboundFindings() {
|
|
159
|
+
const out = this.inboundFindings;
|
|
160
|
+
this.inboundFindings = [];
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/** B1 — read an entry's COMMITTED content copy from the control-plane shadow (undefined = none).
|
|
164
|
+
* The engine's missing-file recovery reads this (zero-copy: a deleted file is gone from the
|
|
165
|
+
* directory scan, so the shadow is the only committed copy left). */
|
|
166
|
+
readCommittedShadow(id) {
|
|
167
|
+
return readSafe(this.shadowPath(id));
|
|
168
|
+
}
|
|
169
|
+
shadowPath(id) {
|
|
170
|
+
return join(this.controlPlaneRoot, SHADOW_DIR, `${id}.md`);
|
|
171
|
+
}
|
|
172
|
+
/** B2/L4 + C-F9 (S2-0) — capture a gate-rejected file into control-plane quarantine FROM THE
|
|
173
|
+
* ALREADY-READ CONTENT (never re-reading the path — TOCTOU: the disk bytes may have been swapped
|
|
174
|
+
* since the gate scanned them), then remove the suspect from the model-visible plane (delete →
|
|
175
|
+
* clear in place). `detail` is set on ANY deviation from the clean path; callers escalate it into
|
|
176
|
+
* {@link inboundFindings} (report-visible) — never a silent best-effort downgrade. */
|
|
177
|
+
quarantineFile(path, content) {
|
|
178
|
+
const dest = join(this.controlPlaneRoot, QUARANTINE_DIR, `${Date.now()}-${basename(path)}`);
|
|
179
|
+
let captured;
|
|
180
|
+
let detail;
|
|
181
|
+
try {
|
|
182
|
+
ensureDirExists(dirname(dest));
|
|
183
|
+
writeFileSync(dest, content, "utf8");
|
|
184
|
+
captured = dest;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
detail = `quarantine copy failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
188
|
+
}
|
|
189
|
+
let removed = false;
|
|
190
|
+
try {
|
|
191
|
+
rmSync(path, { force: true });
|
|
192
|
+
removed = true;
|
|
193
|
+
}
|
|
194
|
+
catch (rmErr) {
|
|
195
|
+
try {
|
|
196
|
+
// Second rung: overwrite in place with a TOMBSTONE, not an empty string (opus review 1.257.2,
|
|
197
|
+
// mirrors the engine-side fix): in zero-copy the engine's next harvest scans this same dir —
|
|
198
|
+
// an empty husk would be minted into an empty entry; a `deleted: true` tombstone is skipped.
|
|
199
|
+
writeFileSync(path, "---\ndeleted: true\n---\n", "utf8");
|
|
200
|
+
removed = true;
|
|
201
|
+
detail = `${detail !== undefined ? `${detail}; ` : ""}delete failed (${rmErr instanceof Error ? rmErr.message : String(rmErr)}) — tombstoned in place`;
|
|
202
|
+
}
|
|
203
|
+
catch (clearErr) {
|
|
204
|
+
detail = `${detail !== undefined ? `${detail}; ` : ""}suspect file could not be deleted or cleared: ${clearErr instanceof Error ? clearErr.message : String(clearErr)}`;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { ...(captured !== undefined ? { dest: captured } : {}), removed, ...(detail !== undefined ? { detail } : {}) };
|
|
208
|
+
}
|
|
209
|
+
loadLedger() {
|
|
210
|
+
if (this.ledger)
|
|
211
|
+
return this.ledger;
|
|
212
|
+
const path = join(this.controlPlaneRoot, LEDGER_FILE);
|
|
213
|
+
let raw;
|
|
214
|
+
try {
|
|
215
|
+
raw = readFileSync(path, "utf8");
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
raw = undefined; // absent ⇒ first run (empty ledger is the true state, not a downgrade)
|
|
219
|
+
}
|
|
220
|
+
if (raw === undefined) {
|
|
221
|
+
this.ledger = {};
|
|
222
|
+
return this.ledger;
|
|
223
|
+
}
|
|
224
|
+
let parsed;
|
|
225
|
+
try {
|
|
226
|
+
parsed = JSON.parse(raw);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
throw new ControlPlaneCorruptError(`committed-rev ledger is unparseable: ${path}`);
|
|
230
|
+
}
|
|
231
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
232
|
+
throw new ControlPlaneCorruptError(`committed-rev ledger has the wrong shape: ${path}`);
|
|
233
|
+
}
|
|
234
|
+
for (const [k, v] of Object.entries(parsed)) {
|
|
235
|
+
if (typeof v !== "string")
|
|
236
|
+
throw new ControlPlaneCorruptError(`committed-rev ledger entry ${JSON.stringify(k)} is not a string: ${path}`);
|
|
237
|
+
}
|
|
238
|
+
this.ledger = parsed;
|
|
239
|
+
return this.ledger;
|
|
240
|
+
}
|
|
241
|
+
/** B3: atomic + fail-closed — a ledger that cannot be persisted throws (the commit is incomplete
|
|
242
|
+
* and the caller must know), never a silent swallow. */
|
|
243
|
+
saveLedger() {
|
|
244
|
+
if (!this.ledger)
|
|
245
|
+
return;
|
|
246
|
+
atomicWriteFileSync(join(this.controlPlaneRoot, LEDGER_FILE), `${JSON.stringify(this.ledger, null, 2)}\n`);
|
|
247
|
+
}
|
|
248
|
+
// ==========================================================================
|
|
249
|
+
// H4 — transaction journal (redo log) + crash recovery
|
|
250
|
+
// ==========================================================================
|
|
251
|
+
recoverJournal() {
|
|
252
|
+
const jp = join(this.controlPlaneRoot, JOURNAL_FILE);
|
|
253
|
+
const raw = readSafe(jp);
|
|
254
|
+
if (raw !== undefined) {
|
|
255
|
+
let journal;
|
|
256
|
+
try {
|
|
257
|
+
const parsed = JSON.parse(raw);
|
|
258
|
+
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.ops) || typeof parsed.ledger !== "object") {
|
|
259
|
+
throw new Error("wrong shape");
|
|
260
|
+
}
|
|
261
|
+
journal = parsed;
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// The journal is atomically renamed into place, so a torn journal should be impossible; if it
|
|
265
|
+
// happens anyway the transaction's effects are unknowable — fail closed for a human decision.
|
|
266
|
+
throw new ControlPlaneCorruptError(`transaction journal is unparseable: ${jp}`);
|
|
267
|
+
}
|
|
268
|
+
// REDO (idempotent — the journal carries full content): finish every op, restore the ledger
|
|
269
|
+
// snapshot, then drop the journal.
|
|
270
|
+
for (const op of journal.ops) {
|
|
271
|
+
try {
|
|
272
|
+
if (op.kind === "write" && op.content !== undefined) {
|
|
273
|
+
atomicWriteFileSync(op.target, op.content);
|
|
274
|
+
if (op.staged)
|
|
275
|
+
rmSync(op.staged, { force: true });
|
|
276
|
+
}
|
|
277
|
+
else if (op.kind === "delete") {
|
|
278
|
+
rmSync(op.target, { force: true });
|
|
279
|
+
}
|
|
280
|
+
else if (op.kind === "shadow-write" && op.content !== undefined) {
|
|
281
|
+
atomicWriteFileSync(this.shadowPath(op.target), op.content);
|
|
282
|
+
}
|
|
283
|
+
else if (op.kind === "shadow-delete") {
|
|
284
|
+
rmSync(this.shadowPath(op.target), { force: true });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch {
|
|
288
|
+
/* per-op best effort; the ledger snapshot below is the commit marker */
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.ledger = { ...journal.ledger };
|
|
292
|
+
this.saveLedger();
|
|
293
|
+
rmSync(jp, { force: true });
|
|
294
|
+
}
|
|
295
|
+
this.sweepStagedFiles();
|
|
296
|
+
}
|
|
297
|
+
/** Remove orphaned `.stage-*` files (a crash BEFORE the journal rename = clean rollback: nothing
|
|
298
|
+
* was committed, the staged tmps are litter). Dotfiles are invisible to entry scans regardless. */
|
|
299
|
+
sweepStagedFiles() {
|
|
300
|
+
const walk = (d, depth) => {
|
|
301
|
+
let names;
|
|
302
|
+
try {
|
|
303
|
+
names = readdirSync(d);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
for (const name of names) {
|
|
309
|
+
const p = join(d, name);
|
|
310
|
+
if (name.startsWith(".stage-")) {
|
|
311
|
+
rmSync(p, { force: true });
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (depth < DEFAULT_MAX_ENTRY_DEPTH + 1) {
|
|
315
|
+
try {
|
|
316
|
+
if (lstatSync(p).isDirectory())
|
|
317
|
+
walk(p, depth + 1);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
/* ignore */
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
walk(this.directoryRoot, 0);
|
|
326
|
+
}
|
|
327
|
+
/** The names of sibling scope subdirs to exclude when scanning the ROOT scope's own nested content. */
|
|
328
|
+
excludedSubdirNames(forScope) {
|
|
329
|
+
const reg = registeredScopes(this.controlPlaneRoot);
|
|
330
|
+
const names = new Set();
|
|
331
|
+
for (const [scope, dirName] of Object.entries(reg)) {
|
|
332
|
+
if (scope !== forScope && dirName !== "")
|
|
333
|
+
names.add(dirName);
|
|
334
|
+
}
|
|
335
|
+
return names;
|
|
336
|
+
}
|
|
337
|
+
scopeDir(scope) {
|
|
338
|
+
return registerScope(this.directoryRoot, this.controlPlaneRoot, scope);
|
|
339
|
+
}
|
|
340
|
+
/** B2 inbound gate for content that did NOT come through applyPatches (git pull / hand edits /
|
|
341
|
+
* a hand-seeded file): secret + cap + structure. Returns the rejection, or undefined (clean). */
|
|
342
|
+
inboundGate(relPath, text) {
|
|
343
|
+
// S2-B 判决四 (入库面): the file-NAME charset whitelist guards the inbound channel too — a
|
|
344
|
+
// git-pull-borne `foo</system-reminder>bar.md` must never be adopted (its PATH is an injection
|
|
345
|
+
// payload wherever it is echoed). Shared rule (scan.ts) with the harvest/beforeWrite mounts.
|
|
346
|
+
const nameFinding = scanMemoryFileName(relPath);
|
|
347
|
+
if (nameFinding !== undefined)
|
|
348
|
+
return { path: relPath, code: "filename", reason: `inbound memory change blocked: ${nameFinding.reason} (quarantined)` };
|
|
349
|
+
// codex 1.258 review (MED): the FULL shared rule set — scanMemoryWrite = secret + injection +
|
|
350
|
+
// (with maxBytes) too_large — so an inbound git-pull change carrying a framing break-out tag is
|
|
351
|
+
// quarantined exactly like the same content would be write-rejected / harvest-rejected. One rule
|
|
352
|
+
// set, three mounts (beforeWrite / harvest / inbound), zero drift.
|
|
353
|
+
const findings = scanMemoryWrite(text, { maxBytes: MAX_MEMORY_BYTES });
|
|
354
|
+
const first = findings[0];
|
|
355
|
+
if (first !== undefined) {
|
|
356
|
+
return { path: relPath, code: first.code, reason: `inbound memory change blocked: ${first.reason} (quarantined)` };
|
|
357
|
+
}
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
/** Read every COMMITTED entry of `scope` — a file must carry a valid `id:` to count. An id-less
|
|
361
|
+
* file is UNCOMMITTED session material: it becomes an entry only through the engine's harvest
|
|
362
|
+
* gates (which mint the id on commit). Reading it as an entry here would let gate-rejected files
|
|
363
|
+
* (secret / cap / quarantine) leak into the authoritative set through the zero-copy disk scan.
|
|
364
|
+
* `sync` (read-side callers) adopts a committed file's CURRENT disk rev into the committed-rev
|
|
365
|
+
* ledger ONLY through the inbound gate (B2: out-of-session edits, e.g. git-pull, are scanned;
|
|
366
|
+
* a reject is moved to control-plane quarantine and the committed shadow content is restored to
|
|
367
|
+
* disk). The applyPatches lookup passes false (the ledger must keep the baseline for CAS). */
|
|
368
|
+
readScope(scope, sync = true) {
|
|
369
|
+
const dir = this.scopeDir(scope);
|
|
370
|
+
const isRoot = dir === this.directoryRoot;
|
|
371
|
+
const files = scanEntryFiles(dir, { exclude: isRoot ? this.excludedSubdirNames(scope) : undefined });
|
|
372
|
+
const entries = [];
|
|
373
|
+
const ledger = sync ? this.loadLedger() : undefined;
|
|
374
|
+
let ledgerChanged = false;
|
|
375
|
+
// S2-B event class ② — KNOWN entries whose disk rev ≠ ledger (a git pull / hand edit adopted
|
|
376
|
+
// through the inbound gate). Announced below so the session that first SEES the change gets a
|
|
377
|
+
// session-first notice (materialize runs before inject). Hand-seeded never-committed files are
|
|
378
|
+
// NOT announced (no ledger baseline ⇒ not a "change"; first-run seeding would be pure noise).
|
|
379
|
+
const adoptedExternal = [];
|
|
380
|
+
for (const f of files) {
|
|
381
|
+
let text;
|
|
382
|
+
try {
|
|
383
|
+
text = readFileSync(f.path, "utf8");
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
const parsed = parseEntryFile(text);
|
|
389
|
+
if (parsed.id === undefined)
|
|
390
|
+
continue; // uncommitted (id-less) — only harvest can admit it
|
|
391
|
+
let entry = entryFromFile(text, parsed.id, f.slug, scope);
|
|
392
|
+
if (ledger) {
|
|
393
|
+
const committed = ledger[entry.id];
|
|
394
|
+
if (committed !== entry.rev) {
|
|
395
|
+
// Non-committed content on disk (external channel, or a hand-seeded file the ledger never
|
|
396
|
+
// saw): it must pass the inbound gate to be adopted as the new committed baseline (B2).
|
|
397
|
+
const finding = this.inboundGate(relative(this.directoryRoot, f.path), text);
|
|
398
|
+
if (finding) {
|
|
399
|
+
this.inboundFindings.push(finding);
|
|
400
|
+
// C-F9 (S2-0): quarantine from the already-read `text` (no path re-read — TOCTOU).
|
|
401
|
+
const q = this.quarantineFile(f.path, text);
|
|
402
|
+
const shadowText = committed !== undefined ? this.readCommittedShadow(entry.id) : undefined;
|
|
403
|
+
let restoredShadow = false;
|
|
404
|
+
if (shadowText !== undefined) {
|
|
405
|
+
// Restore the last committed content — the entry survives, the poison does not. This is
|
|
406
|
+
// also the third containment rung when delete/clear failed (overwrite with committed).
|
|
407
|
+
try {
|
|
408
|
+
atomicWriteFileSync(f.path, shadowText);
|
|
409
|
+
restoredShadow = true;
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
/* restore is best-effort; the entry below still serves the committed content */
|
|
413
|
+
}
|
|
414
|
+
entry = entryFromFile(shadowText, entry.id, f.slug, scope);
|
|
415
|
+
}
|
|
416
|
+
// C-F9 escalation: any quarantine deviation is REPORT-VISIBLE (drained into
|
|
417
|
+
// HarvestReport.inboundFindings at harvest), never debug-only.
|
|
418
|
+
if (q.detail !== undefined || (!q.removed && !restoredShadow)) {
|
|
419
|
+
const contained = q.removed || restoredShadow;
|
|
420
|
+
this.inboundFindings.push({
|
|
421
|
+
path: finding.path,
|
|
422
|
+
code: "quarantine_failed",
|
|
423
|
+
reason: `quarantine escalation: ${q.detail ?? "suspect copy not captured"}${contained ? "" : " — rejected content may still be on the model-visible plane"}`,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
if (shadowText === undefined) {
|
|
427
|
+
// Never committed (or shadow-less legacy): nothing to restore — the id leaves the set.
|
|
428
|
+
if (committed !== undefined) {
|
|
429
|
+
delete ledger[entry.id];
|
|
430
|
+
ledgerChanged = true;
|
|
431
|
+
}
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
if (committed !== undefined)
|
|
437
|
+
adoptedExternal.push(relative(this.directoryRoot, f.path));
|
|
438
|
+
ledger[entry.id] = entry.rev; // gate-passed external edit adopted as the committed baseline
|
|
439
|
+
try {
|
|
440
|
+
atomicWriteFileSync(this.shadowPath(entry.id), text);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
/* shadow backfill is best-effort */
|
|
444
|
+
}
|
|
445
|
+
ledgerChanged = true;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
else if (this.readCommittedShadow(entry.id) === undefined) {
|
|
449
|
+
// Shadow backfill for entries committed before the shadow existed.
|
|
450
|
+
try {
|
|
451
|
+
atomicWriteFileSync(this.shadowPath(entry.id), text);
|
|
452
|
+
}
|
|
453
|
+
catch {
|
|
454
|
+
/* best-effort */
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
entries.push(entry);
|
|
459
|
+
}
|
|
460
|
+
if (ledgerChanged)
|
|
461
|
+
this.saveLedger();
|
|
462
|
+
if (adoptedExternal.length > 0) {
|
|
463
|
+
// Journaled + locked queue (O-F6/C-F5) — fail-open: an unwritable queue never fails a read.
|
|
464
|
+
try {
|
|
465
|
+
enqueueMemoryAnnouncement(this.controlPlaneRoot, {
|
|
466
|
+
kind: "external",
|
|
467
|
+
at: this.now(),
|
|
468
|
+
items: adoptedExternal
|
|
469
|
+
.slice(0, 12)
|
|
470
|
+
.map((rel) => `out-of-session memory change adopted: ${JSON.stringify(inlineUntrusted(rel))} — re-read it before relying on prior knowledge of it`)
|
|
471
|
+
.concat(adoptedExternal.length > 12 ? [`…and ${adoptedExternal.length - 12} more adopted change(s)`] : []),
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
/* fail-open */
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return entries;
|
|
479
|
+
}
|
|
480
|
+
async listHeaders(scopes) {
|
|
481
|
+
const out = [];
|
|
482
|
+
for (const scope of scopes) {
|
|
483
|
+
const dir = this.scopeDir(scope);
|
|
484
|
+
for (const e of this.readScope(scope)) {
|
|
485
|
+
out.push(headerOf(e, join(dir, `${e.slug}.md`)));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return out;
|
|
489
|
+
}
|
|
490
|
+
async getByIds(ids) {
|
|
491
|
+
const want = new Set(ids);
|
|
492
|
+
const out = [];
|
|
493
|
+
for (const scope of Object.keys(registeredScopes(this.controlPlaneRoot))) {
|
|
494
|
+
for (const e of this.readScope(scope)) {
|
|
495
|
+
if (want.has(e.id))
|
|
496
|
+
out.push(e);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return out;
|
|
500
|
+
}
|
|
501
|
+
/** Lexical floor (design/138 §2.1): `1 - Jaccard` distance over name+description+body, ascending. */
|
|
502
|
+
async search(query, scopes, opts) {
|
|
503
|
+
const limit = opts?.limit ?? 20;
|
|
504
|
+
const q = termSet(query);
|
|
505
|
+
if (q.size === 0)
|
|
506
|
+
return [];
|
|
507
|
+
const scored = [];
|
|
508
|
+
for (const scope of scopes) {
|
|
509
|
+
const dir = this.scopeDir(scope);
|
|
510
|
+
for (const e of this.readScope(scope)) {
|
|
511
|
+
const haystack = `${e.frontmatter.name ?? e.slug} ${e.frontmatter.description ?? ""} ${e.body}`;
|
|
512
|
+
const d = jaccardDistance(q, haystack);
|
|
513
|
+
if (d === null)
|
|
514
|
+
continue;
|
|
515
|
+
scored.push({ ...headerOf(e, join(dir, `${e.slug}.md`)), score: d });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
// S3-core (opus 审 C4): deterministic id tie-break — tied jaccard scores must not order by
|
|
519
|
+
// directory-listing accident (the Pg backend mirrors this; the cross-backend equivalence
|
|
520
|
+
// assertion compares ordered projections).
|
|
521
|
+
scored.sort((a, b) => a.score - b.score || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
522
|
+
return scored.slice(0, limit);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* H4 — the entry transaction, staged and journaled:
|
|
526
|
+
* 1. RELOAD the ledger from disk (验收 M2: a concurrently-committed transaction from another
|
|
527
|
+
* process becomes a CAS conflict here, never a blind write over it) + finish any interrupted
|
|
528
|
+
* transaction (redo journal).
|
|
529
|
+
* 2. PLAN every patch against current state (CAS/conflicts decided now; no disk writes yet).
|
|
530
|
+
* 3. STAGE: write each new file content to a same-directory `.stage-*` tmp (fsync'd).
|
|
531
|
+
* 4. JOURNAL: atomically write the full redo log (ops with content + the post-txn ledger snapshot).
|
|
532
|
+
* ← the commit point: a crash after this rolls FORWARD (recovery redoes the journal); a crash
|
|
533
|
+
* before it rolls BACK (staged tmps are swept, nothing was committed).
|
|
534
|
+
* 5. EXECUTE: atomic renames / deletes / shadow updates.
|
|
535
|
+
* 6. Persist the ledger (atomic, fail-closed) and drop the journal.
|
|
536
|
+
*/
|
|
537
|
+
async applyPatches(patches) {
|
|
538
|
+
// codex 复审 B5 (design/142 S2b 连带): the reload→plan→journal→execute→ledger transaction was
|
|
539
|
+
// single-writer by assumption — two instances over the SAME root (dual-root personal mount:
|
|
540
|
+
// concurrent tasks of one principal; or plain multi-process TOC) could both pass CAS on the
|
|
541
|
+
// same stale ledger, overwrite each other's journal file and silently drop the loser's commit
|
|
542
|
+
// while BOTH report applied. A cross-process mutex serializes the whole transaction; a crashed
|
|
543
|
+
// holder's lock is stolen after a deadline — safe BECAUSE recovery replays/sweeps the journal
|
|
544
|
+
// inside the lock before planning.
|
|
545
|
+
const lock = await this.acquireTxnLock();
|
|
546
|
+
try {
|
|
547
|
+
return await this.applyPatchesLocked(patches, lock.token);
|
|
548
|
+
}
|
|
549
|
+
finally {
|
|
550
|
+
lock.release();
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
txnLockDir() {
|
|
554
|
+
return join(this.controlPlaneRoot, "txn.lock");
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* 对抗复审 L1/L2/L3 — the mkdir mutex, hardened (same shape as layout.ts' acquireSidecarLock, but
|
|
558
|
+
* fail-closed timings and an async wait):
|
|
559
|
+
* - L2: every acquisition writes an OWNER TOKEN (`<lock>/owner`, crypto-random — never a
|
|
560
|
+
* timestamp) immediately after mkdir. Release only removes the lock while the token is still
|
|
561
|
+
* ours; {@link assertTxnLockOwnership} re-verifies it at the commit point.
|
|
562
|
+
* - L1: the stale steal is SINGLE-WINNER — atomic rename of the stale lock dir to a unique
|
|
563
|
+
* tombstone (exactly one racer's rename succeeds; losers ENOENT back into the wait loop), then
|
|
564
|
+
* the winner removes the tombstone and re-acquires through a NORMAL mkdir. Never a bare
|
|
565
|
+
* rmSync+mkdir (two same-window stealers would force-rm each other's FRESH lock = double hold).
|
|
566
|
+
* - L2 (steal side): only a lock that is BOTH past its stale line AND carries an owner token is
|
|
567
|
+
* stealable (a tokenless dir is a mid-acquisition, not a crashed holder).
|
|
568
|
+
* - L3: the wait deadline is `max(waitMs, observed lock's stale line + grace)` — a holder that
|
|
569
|
+
* crashed with `remaining stale > waitMs` no longer strands every waiter in an all-throw window.
|
|
570
|
+
*/
|
|
571
|
+
async acquireTxnLock(timings = {}) {
|
|
572
|
+
const staleMs = timings.staleMs ?? TXN_LOCK_STALE_MS;
|
|
573
|
+
const waitMs = timings.waitMs ?? TXN_LOCK_WAIT_MS;
|
|
574
|
+
const stealGraceMs = timings.stealGraceMs ?? TXN_LOCK_STEAL_GRACE_MS;
|
|
575
|
+
const lockDir = this.txnLockDir();
|
|
576
|
+
const ownerPath = join(lockDir, "owner");
|
|
577
|
+
mkdirSync(this.controlPlaneRoot, { recursive: true });
|
|
578
|
+
const start = Date.now();
|
|
579
|
+
let deadline = start + waitMs;
|
|
580
|
+
for (;;) {
|
|
581
|
+
let acquired = false;
|
|
582
|
+
try {
|
|
583
|
+
mkdirSync(lockDir); // NOT recursive: recursive:true reports success on an EXISTING dir
|
|
584
|
+
acquired = true;
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
if (err.code !== "EEXIST")
|
|
588
|
+
throw err;
|
|
589
|
+
}
|
|
590
|
+
if (acquired) {
|
|
591
|
+
// L2: the token names THIS acquisition. Written (fsync'd) before we return — a lock without
|
|
592
|
+
// it is never stolen, so failing the write must release the dir and surface (fail-closed).
|
|
593
|
+
const token = randomUUID();
|
|
594
|
+
try {
|
|
595
|
+
const fd = openSync(ownerPath, "w", 0o600);
|
|
596
|
+
try {
|
|
597
|
+
writeSync(fd, token);
|
|
598
|
+
fsyncSync(fd);
|
|
599
|
+
}
|
|
600
|
+
finally {
|
|
601
|
+
closeSync(fd);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
try {
|
|
606
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
/* best-effort — a tokenless leftover is unstealable but times waiters out loudly */
|
|
610
|
+
}
|
|
611
|
+
throw new Error(`memory txn lock owner token could not be written at ${ownerPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
612
|
+
}
|
|
613
|
+
return {
|
|
614
|
+
token,
|
|
615
|
+
release: () => {
|
|
616
|
+
try {
|
|
617
|
+
if (readFileSync(ownerPath, "utf8") !== token)
|
|
618
|
+
return; // stolen while we stalled — the lock is someone else's now
|
|
619
|
+
}
|
|
620
|
+
catch {
|
|
621
|
+
return; // lock already gone (stolen + tombstoned) — nothing of ours left to release
|
|
622
|
+
}
|
|
623
|
+
try {
|
|
624
|
+
rmSync(lockDir, { recursive: true, force: true });
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
/* release is best-effort — a leaked lock is stolen after the stale deadline */
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
// Lock exists — decide steal / wait / timeout.
|
|
633
|
+
let mtimeMs;
|
|
634
|
+
try {
|
|
635
|
+
mtimeMs = statSync(lockDir).mtimeMs;
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
continue; // raced with the holder's release — retry the mkdir immediately
|
|
639
|
+
}
|
|
640
|
+
const staleAt = mtimeMs + staleMs;
|
|
641
|
+
deadline = Math.max(deadline, staleAt + stealGraceMs); // L3: reach the stale line + one steal attempt
|
|
642
|
+
if (Date.now() > staleAt) {
|
|
643
|
+
let tokenPresent = false;
|
|
644
|
+
try {
|
|
645
|
+
statSync(ownerPath);
|
|
646
|
+
tokenPresent = true;
|
|
647
|
+
}
|
|
648
|
+
catch {
|
|
649
|
+
/* tokenless = mid-acquisition (or already renamed away) — not stealable */
|
|
650
|
+
}
|
|
651
|
+
if (tokenPresent) {
|
|
652
|
+
// L1 single-winner steal (see doc above).
|
|
653
|
+
const tomb = join(this.controlPlaneRoot, `txn.lock.stale-${randomUUID()}`);
|
|
654
|
+
try {
|
|
655
|
+
renameSync(lockDir, tomb);
|
|
656
|
+
}
|
|
657
|
+
catch {
|
|
658
|
+
continue; // another waiter stole it (or the holder released) — back to the wait loop
|
|
659
|
+
}
|
|
660
|
+
rmSync(tomb, { recursive: true, force: true });
|
|
661
|
+
continue; // stolen: re-acquire through a NORMAL mkdir (journal recovery inside the lock covers the crashed txn)
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
if (Date.now() > deadline) {
|
|
665
|
+
throw new Error(`memory txn lock timeout (${waitMs}ms, extended to the lock's stale line) at ${lockDir} — another writer is wedged?`);
|
|
666
|
+
}
|
|
667
|
+
await new Promise((r) => setTimeout(r, 20 + Math.floor(Math.random() * 40)));
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/** 对抗复审 L2 — 提交点归属复验: called immediately before the JOURNAL write (the persistent commit
|
|
671
|
+
* point). A holder that stalled past the stale deadline (slow disk / GC pause / long txn) and was
|
|
672
|
+
* stolen from must ABORT — its staged tmps carry no committed state and the stealer's journal
|
|
673
|
+
* recovery is now authoritative; committing anyway would overwrite the stealer's transaction. */
|
|
674
|
+
assertTxnLockOwnership(token) {
|
|
675
|
+
let held;
|
|
676
|
+
try {
|
|
677
|
+
held = readFileSync(join(this.txnLockDir(), "owner"), "utf8");
|
|
678
|
+
}
|
|
679
|
+
catch {
|
|
680
|
+
held = undefined; // lock dir gone = stolen (we ALWAYS write a token on acquire)
|
|
681
|
+
}
|
|
682
|
+
if (held !== token) {
|
|
683
|
+
throw new ControlPlaneCorruptError("txn lock ownership lost before commit (holder stalled past the stale deadline and was stolen from?) — transaction aborted, nothing was committed");
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
async applyPatchesLocked(patches, lockToken) {
|
|
687
|
+
this.ledger = undefined; // M2: reload from disk — cross-process commits must be visible to CAS
|
|
688
|
+
this.recoverJournal();
|
|
689
|
+
const ledger = { ...this.loadLedger() };
|
|
690
|
+
const report = { applied: [], conflicts: [] };
|
|
691
|
+
const ops = [];
|
|
692
|
+
const plannedTargets = new Set();
|
|
693
|
+
// codex review (1.257.2): at most ONE non-delete op per id per batch. A rename legitimately pairs
|
|
694
|
+
// delete(X)+update(X); but two adds/updates for the same id (a COPY that kept its frontmatter id)
|
|
695
|
+
// would leave the caller's projection↔applied binding ambiguous — refuse the later one as a
|
|
696
|
+
// conflict so the committed-restore path handles its file instead of promoting unsanctioned content.
|
|
697
|
+
const nonDeleteIds = new Set();
|
|
698
|
+
for (const patch of patches) {
|
|
699
|
+
try {
|
|
700
|
+
if (patch.op !== "delete") {
|
|
701
|
+
// S3-core (codex 审): a patch whose entry carries a DIFFERENT id than the patch addresses is
|
|
702
|
+
// malformed — refused up front, byte-uniform with the Pg backend (which would otherwise key
|
|
703
|
+
// its SELECT on patch.id but its write on entry.id).
|
|
704
|
+
if (patch.entry !== undefined && patch.entry.id !== patch.id) {
|
|
705
|
+
report.conflicts.push({ op: patch.op, id: patch.id, reason: `patch id ${JSON.stringify(patch.id)} != entry id ${JSON.stringify(patch.entry.id)} (malformed patch refused)` });
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
if (nonDeleteIds.has(patch.id)) {
|
|
709
|
+
report.conflicts.push({ op: patch.op, id: patch.id, reason: "duplicate id in batch: another add/update for this id is already planned (copied file keeping its frontmatter id?)" });
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
nonDeleteIds.add(patch.id);
|
|
713
|
+
}
|
|
714
|
+
this.planOne(patch, report, ops, ledger, plannedTargets);
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
report.conflicts.push({ op: patch.op, id: patch.id, reason: `io error: ${err instanceof Error ? err.message : String(err)}` });
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
if (ops.length === 0) {
|
|
721
|
+
// Nothing to write — still persist the (unchanged) ledger view? No: no-op transactions must not
|
|
722
|
+
// touch the sidecars at all.
|
|
723
|
+
return report;
|
|
724
|
+
}
|
|
725
|
+
// STAGE: durable tmp files next to their targets (same-dir rename atomicity).
|
|
726
|
+
const txn = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
727
|
+
let n = 0;
|
|
728
|
+
for (const op of ops) {
|
|
729
|
+
if (op.kind !== "write" || op.content === undefined)
|
|
730
|
+
continue;
|
|
731
|
+
const staged = join(dirname(op.target), `.stage-${txn}-${n++}`);
|
|
732
|
+
mkdirSync(dirname(op.target), { recursive: true });
|
|
733
|
+
const fd = openSync(staged, "w", 0o600);
|
|
734
|
+
try {
|
|
735
|
+
writeSync(fd, op.content);
|
|
736
|
+
fsyncSync(fd);
|
|
737
|
+
}
|
|
738
|
+
finally {
|
|
739
|
+
closeSync(fd);
|
|
740
|
+
}
|
|
741
|
+
op.staged = staged;
|
|
742
|
+
}
|
|
743
|
+
// JOURNAL (the commit marker) — atomic rename means it either exists complete or not at all.
|
|
744
|
+
// L2: 归属复验 first — never write the commit marker after the lock was stolen from us.
|
|
745
|
+
this.assertTxnLockOwnership(lockToken);
|
|
746
|
+
const journal = { txn, ops, ledger };
|
|
747
|
+
atomicWriteFileSync(join(this.controlPlaneRoot, JOURNAL_FILE), JSON.stringify(journal));
|
|
748
|
+
// EXECUTE.
|
|
749
|
+
for (const op of ops) {
|
|
750
|
+
if (op.kind === "write" && op.staged) {
|
|
751
|
+
renameSync(op.staged, op.target);
|
|
752
|
+
}
|
|
753
|
+
else if (op.kind === "delete") {
|
|
754
|
+
rmSync(op.target, { force: true });
|
|
755
|
+
}
|
|
756
|
+
else if (op.kind === "shadow-write" && op.content !== undefined) {
|
|
757
|
+
atomicWriteFileSync(this.shadowPath(op.target), op.content);
|
|
758
|
+
}
|
|
759
|
+
else if (op.kind === "shadow-delete") {
|
|
760
|
+
rmSync(this.shadowPath(op.target), { force: true });
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
// COMMIT the ledger (atomic; throws = fail-closed, the journal stays for redo) then drop the journal.
|
|
764
|
+
this.ledger = ledger;
|
|
765
|
+
this.saveLedger();
|
|
766
|
+
rmSync(join(this.controlPlaneRoot, JOURNAL_FILE), { force: true });
|
|
767
|
+
return report;
|
|
768
|
+
}
|
|
769
|
+
/** Plan one patch: decide CAS/conflicts against CURRENT state, emit journal ops (no entry-file
|
|
770
|
+
* writes here — staging/execution happen in {@link applyPatches}). */
|
|
771
|
+
planOne(patch, report, ops, ledger, plannedTargets) {
|
|
772
|
+
if (patch.op === "add") {
|
|
773
|
+
const entry = patch.entry;
|
|
774
|
+
if (!entry) {
|
|
775
|
+
report.conflicts.push({ op: "add", id: patch.id, reason: "add patch without an entry" });
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
// E-02 add-if-absent guard (design/142 S2.5): a `guard: "absent"` add must NEVER blind-overwrite
|
|
779
|
+
// an existing id. If the id already exists, compare revs — same rev = idempotent apply (fall
|
|
780
|
+
// through to the normal add path, which zero-copy re-writes the same content), DIFFERENT rev =
|
|
781
|
+
// a reported conflict carrying the current rev, never a write. A plain (unguarded) add keeps the
|
|
782
|
+
// idempotent-overwrite semantics (contract clause unchanged) — this branch only runs when armed.
|
|
783
|
+
if (patch.guard === "absent") {
|
|
784
|
+
const existing = this.locateById(patch.id);
|
|
785
|
+
if (existing) {
|
|
786
|
+
const currentRev = ledger[patch.id] ?? existing.entry.rev;
|
|
787
|
+
if (currentRev !== computeEntryRev(entry)) {
|
|
788
|
+
report.conflicts.push({ op: "add", id: patch.id, reason: "add_guard_absent_conflict (id already exists at a different rev; add-if-absent refuses to overwrite)", currentRev });
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
// 三轮复查 (2026-07-12): same rev alone is NOT the idempotence proof — computeEntryRev hashes
|
|
792
|
+
// (id, frontmatter, body) but neither slug nor scope, so an existing copy at a DIFFERENT
|
|
793
|
+
// projection (renamed slug, or another scope after a central cross-scope move) would make the
|
|
794
|
+
// "no-op re-write" below mint a SECOND file for the same id (duplicate projection: getByIds
|
|
795
|
+
// then returns the id twice — the id-as-unit-of-truth invariant breaks). Idempotent ⇔ same
|
|
796
|
+
// rev AND same (scope, slug); a projection mismatch is a REPORTED conflict, never a write.
|
|
797
|
+
if (existing.entry.scope !== entry.scope || existing.entry.slug !== entry.slug) {
|
|
798
|
+
report.conflicts.push({
|
|
799
|
+
op: "add",
|
|
800
|
+
id: patch.id,
|
|
801
|
+
reason: `add_guard_absent_conflict (id already exists at the same rev but a different projection ${JSON.stringify(`${existing.entry.scope}/${existing.entry.slug}`)}; add-if-absent refuses to duplicate)`,
|
|
802
|
+
currentRev,
|
|
803
|
+
});
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
// same rev AND same projection ⇒ idempotent; fall through to the normal add (a zero-copy no-op re-write).
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
// First-ever write claims the root for its scope (the engine claims for writeScope at
|
|
810
|
+
// materialize; this is the standalone-usage counterpart — first-writer-wins, durable).
|
|
811
|
+
claimRootScope(this.controlPlaneRoot, entry.scope);
|
|
812
|
+
const dir = this.scopeDir(entry.scope);
|
|
813
|
+
let slug = entry.slug;
|
|
814
|
+
let target = join(dir, `${slug}.md`);
|
|
815
|
+
// Slug collision with a DIFFERENT entry (same slug, other id) → deterministic suffix. In-batch
|
|
816
|
+
// planned targets count as taken too (two adds of one slug in one transaction).
|
|
817
|
+
for (let n = 2;; n++) {
|
|
818
|
+
const existing = plannedTargets.has(target) ? "" : readSafe(target);
|
|
819
|
+
if (existing === undefined)
|
|
820
|
+
break;
|
|
821
|
+
if (existing !== "") {
|
|
822
|
+
const parsed = parseEntryFile(existing);
|
|
823
|
+
if (parsed.id === undefined || parsed.id === entry.id)
|
|
824
|
+
break; // same entry (zero-copy re-write) or claimable
|
|
825
|
+
}
|
|
826
|
+
slug = `${entry.slug}-${n}`;
|
|
827
|
+
target = join(dir, `${slug}.md`);
|
|
828
|
+
}
|
|
829
|
+
const content = serializeEntryFile(entry);
|
|
830
|
+
plannedTargets.add(target);
|
|
831
|
+
ops.push({ kind: "write", target, content });
|
|
832
|
+
ops.push({ kind: "shadow-write", target: entry.id, content });
|
|
833
|
+
ledger[entry.id] = computeEntryRev(entry);
|
|
834
|
+
report.applied.push({ op: "add", id: entry.id, slug });
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
// update/delete address an EXISTING entry by immutable id.
|
|
838
|
+
const found = this.locateById(patch.id, patch.op === "update" ? patch.entry?.scope : undefined);
|
|
839
|
+
if (!found) {
|
|
840
|
+
report.conflicts.push({ op: patch.op, id: patch.id, reason: "unknown id (entry not found in backend)" });
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
// CAS against the COMMITTED-rev ledger (see its docs) — the on-disk rev is the fallback only when
|
|
844
|
+
// the ledger has no record (a hand-seeded file never committed through this backend).
|
|
845
|
+
const currentRev = ledger[patch.id] ?? found.entry.rev;
|
|
846
|
+
if (patch.baseRev !== undefined && patch.baseRev !== currentRev) {
|
|
847
|
+
// Per-id CAS (§2.4 并发): NEVER blind-write over a concurrent change — report; the next task
|
|
848
|
+
// re-materializes the fresh state. B2: the conflicted DISK content is not left to be adopted as
|
|
849
|
+
// a new baseline by the next read-side sync — restore the committed shadow (the CAS winner).
|
|
850
|
+
report.conflicts.push({ op: patch.op, id: patch.id, reason: "rev mismatch (concurrent change)", baseRev: patch.baseRev, currentRev });
|
|
851
|
+
const shadowText = this.readCommittedShadow(patch.id);
|
|
852
|
+
if (shadowText !== undefined && shadowText !== serializeEntryFile(found.entry)) {
|
|
853
|
+
ops.push({ kind: "write", target: found.path, content: shadowText });
|
|
854
|
+
}
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
if (patch.op === "delete") {
|
|
858
|
+
ops.push({ kind: "delete", target: found.path });
|
|
859
|
+
ops.push({ kind: "shadow-delete", target: patch.id });
|
|
860
|
+
delete ledger[patch.id];
|
|
861
|
+
report.applied.push({ op: "delete", id: patch.id, slug: found.entry.slug });
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const entry = patch.entry;
|
|
865
|
+
if (!entry) {
|
|
866
|
+
report.conflicts.push({ op: "update", id: patch.id, reason: "update patch without an entry" });
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const dir = this.scopeDir(entry.scope);
|
|
870
|
+
const target = join(dir, `${entry.slug}.md`);
|
|
871
|
+
const content = serializeEntryFile(entry);
|
|
872
|
+
if (target !== found.path)
|
|
873
|
+
ops.push({ kind: "delete", target: found.path }); // slug rename: old projection removed
|
|
874
|
+
plannedTargets.add(target);
|
|
875
|
+
ops.push({ kind: "write", target, content });
|
|
876
|
+
ops.push({ kind: "shadow-write", target: entry.id, content });
|
|
877
|
+
ledger[entry.id] = computeEntryRev(entry);
|
|
878
|
+
report.applied.push({ op: "update", id: entry.id, slug: entry.slug });
|
|
879
|
+
}
|
|
880
|
+
locateById(id, preferScope) {
|
|
881
|
+
const scopes = Object.keys(registeredScopes(this.controlPlaneRoot));
|
|
882
|
+
const ordered = preferScope !== undefined ? [preferScope, ...scopes.filter((s) => s !== preferScope)] : scopes;
|
|
883
|
+
for (const scope of ordered) {
|
|
884
|
+
const dir = this.scopeDir(scope);
|
|
885
|
+
// sync=false: the applyPatches lookup must NOT adopt in-session disk edits into the ledger —
|
|
886
|
+
// that would erase the committed baseline the CAS above compares against.
|
|
887
|
+
for (const e of this.readScope(scope, false)) {
|
|
888
|
+
if (e.id === id)
|
|
889
|
+
return { entry: e, path: join(dir, `${e.slug}.md`) };
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
return undefined;
|
|
893
|
+
}
|
|
894
|
+
// design/84 Seam B cursor pair — durable control-plane `cursors.json` (S2 rewires consolidation).
|
|
895
|
+
async getConsolidationCursor(scope) {
|
|
896
|
+
const cursors = this.readCursors();
|
|
897
|
+
return cursors[scope];
|
|
898
|
+
}
|
|
899
|
+
async setConsolidationCursor(scope, cursor) {
|
|
900
|
+
const cursors = this.readCursors();
|
|
901
|
+
cursors[scope] = cursor;
|
|
902
|
+
atomicWriteFileSync(join(this.controlPlaneRoot, CURSORS_FILE), `${JSON.stringify(cursors, null, 2)}\n`);
|
|
903
|
+
}
|
|
904
|
+
readCursors() {
|
|
905
|
+
try {
|
|
906
|
+
const parsed = JSON.parse(readFileSync(join(this.controlPlaneRoot, CURSORS_FILE), "utf8"));
|
|
907
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
908
|
+
return Object.fromEntries(Object.entries(parsed).filter(([, v]) => typeof v === "string"));
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
catch {
|
|
912
|
+
/* absent/corrupt ⇒ no cursors (a periodic pass then sweeps from the start — safe: cursors are
|
|
913
|
+
an optimization, not a CAS baseline, so this one sidecar stays fail-open by design) */
|
|
914
|
+
}
|
|
915
|
+
return {};
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
function headerOf(e, path) {
|
|
919
|
+
let mtimeMs = 0;
|
|
920
|
+
try {
|
|
921
|
+
mtimeMs = statSync(path).mtimeMs;
|
|
922
|
+
}
|
|
923
|
+
catch {
|
|
924
|
+
/* header stays age-less (rendered as oldest) */
|
|
925
|
+
}
|
|
926
|
+
return {
|
|
927
|
+
id: e.id,
|
|
928
|
+
slug: e.slug,
|
|
929
|
+
scope: e.scope,
|
|
930
|
+
...(e.frontmatter.name !== undefined ? { name: e.frontmatter.name } : {}),
|
|
931
|
+
...(e.frontmatter.description !== undefined ? { description: e.frontmatter.description } : {}),
|
|
932
|
+
...(e.frontmatter.type !== undefined ? { type: e.frontmatter.type } : {}),
|
|
933
|
+
mtimeMs,
|
|
934
|
+
rev: e.rev,
|
|
935
|
+
sizeBytes: Buffer.byteLength(serializeEntryFile(e), "utf8"),
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
function readSafe(path) {
|
|
939
|
+
try {
|
|
940
|
+
return readFileSync(path, "utf8");
|
|
941
|
+
}
|
|
942
|
+
catch {
|
|
943
|
+
return undefined;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
// Re-export for engine use (single scan definition — see scanEntryFiles docs).
|
|
947
|
+
export { scopeDirName };
|
|
948
|
+
//# sourceMappingURL=file-backend.js.map
|