@bastani/atomic 0.9.21-alpha.1 → 0.9.21
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 +56 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +22 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +292 -60
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +23 -0
- package/dist/builtin/workflows/builtin/adversarial-verification.js +3 -3
- package/dist/builtin/workflows/builtin/{chunk-cw86srkf.js → chunk-632fxeb8.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-w18kbz63.js → chunk-94f8zfz1.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-kspvwc24.js → chunk-9cm2ckq2.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-jaj27rqc.js → chunk-a1ar035d.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-wh19f5ee.js → chunk-d3xhj946.js} +5 -4
- package/dist/builtin/workflows/builtin/{chunk-crw7q5g1.js → chunk-gyjck9z8.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-maqv731g.js → chunk-hj8mh07f.js} +10 -6
- package/dist/builtin/workflows/builtin/{chunk-0nrgfbag.js → chunk-kb7s3gx2.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-73c5tayt.js → chunk-kgn5wz1c.js} +19 -1
- package/dist/builtin/workflows/builtin/{chunk-2hak3b7g.js → chunk-nkj4qhj6.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-bzdvx2xr.js → chunk-r97ndfvt.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-vkmpdat4.js → chunk-wf876n16.js} +1 -1
- package/dist/builtin/workflows/builtin/classify-and-act.js +3 -3
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +3 -3
- package/dist/builtin/workflows/builtin/generate-and-filter.js +3 -3
- package/dist/builtin/workflows/builtin/goal.js +4 -4
- package/dist/builtin/workflows/builtin/index.js +12 -12
- package/dist/builtin/workflows/builtin/loop-until-done.js +3 -3
- package/dist/builtin/workflows/builtin/open-claude-design.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +4 -4
- package/dist/builtin/workflows/builtin/steering-context.js +1 -1
- package/dist/builtin/workflows/builtin/tournament.js +3 -3
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +40 -11
- package/dist/builtin/workflows/src/index.js +9 -3
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +6 -1
- package/dist/cli/auth-command.js +5 -0
- package/dist/cli/auth-command.js.map +1 -1
- package/dist/cli/credential-print.js +2 -0
- package/dist/cli/credential-print.js.map +1 -1
- package/dist/cli/experimental/command.js +5 -2
- package/dist/cli/experimental/command.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.js +4 -4
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +9 -4
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +4 -4
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts +4 -4
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +38 -15
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +14 -9
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +4 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +140 -95
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage-backends.js +2 -3
- package/dist/core/auth-storage-backends.js.map +1 -1
- package/dist/core/auth-storage.js +4 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-resource-loader.js +9 -0
- package/dist/core/builtin-resource-loader.js.map +1 -1
- package/dist/core/cache-warmer.js +8 -1
- package/dist/core/cache-warmer.js.map +1 -1
- package/dist/core/compaction/range-planner.js +6 -0
- package/dist/core/compaction/range-planner.js.map +1 -1
- package/dist/core/execution-model-router.d.ts +13 -3
- package/dist/core/execution-model-router.d.ts.map +1 -1
- package/dist/core/execution-model-router.js +227 -131
- package/dist/core/execution-model-router.js.map +1 -1
- package/dist/core/export-html/template-js/entries-navigation.js +16 -6
- package/dist/core/export-html/template-js/initialization.js +34 -11
- package/dist/core/export-html/template.css +10 -0
- package/dist/core/export-html/template.js +50 -17
- package/dist/core/extensions/context-types.d.ts +2 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/host-input.js +8 -4
- package/dist/core/extensions/host-input.js.map +1 -1
- package/dist/core/extensions/reactive-widget.js +1 -0
- package/dist/core/extensions/reactive-widget.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +1 -0
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +4 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +48 -30
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +1 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/extensions/workflow-activity-hub.js +9 -7
- package/dist/core/extensions/workflow-activity-hub.js.map +1 -1
- package/dist/core/footer-data-provider.js +24 -23
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/keybindings.js +1 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/mandatory-resource-loader.js +4 -1
- package/dist/core/mandatory-resource-loader.js.map +1 -1
- package/dist/core/model-config.js +2 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.js +1 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver-defaults.js +1 -1
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/{model-routing-task.d.ts → model-routing-bytes.d.ts} +1 -4
- package/dist/core/model-routing-bytes.d.ts.map +1 -0
- package/dist/core/model-routing-bytes.js +33 -0
- package/dist/core/model-routing-bytes.js.map +1 -0
- package/dist/core/model-routing-candidates.d.ts +42 -0
- package/dist/core/model-routing-candidates.d.ts.map +1 -0
- package/dist/core/model-routing-candidates.js +309 -0
- package/dist/core/model-routing-candidates.js.map +1 -0
- package/dist/core/model-routing-constraints.d.ts +4 -0
- package/dist/core/model-routing-constraints.d.ts.map +1 -1
- package/dist/core/model-routing-constraints.js +13 -1
- package/dist/core/model-routing-constraints.js.map +1 -1
- package/dist/core/model-routing-debug.d.ts +9 -0
- package/dist/core/model-routing-debug.d.ts.map +1 -0
- package/dist/core/model-routing-debug.js +14 -0
- package/dist/core/model-routing-debug.js.map +1 -0
- package/dist/core/model-routing-evals.d.ts +50 -0
- package/dist/core/model-routing-evals.d.ts.map +1 -0
- package/dist/core/model-routing-evals.js +190 -0
- package/dist/core/model-routing-evals.js.map +1 -0
- package/dist/core/model-routing-needs.d.ts +75 -0
- package/dist/core/model-routing-needs.d.ts.map +1 -0
- package/dist/core/model-routing-needs.js +176 -0
- package/dist/core/model-routing-needs.js.map +1 -0
- package/dist/core/model-runtime-streaming.js +3 -0
- package/dist/core/model-runtime-streaming.js.map +1 -1
- package/dist/core/model-runtime.js +26 -14
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.js +2 -3
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/output-guard.js +1 -0
- package/dist/core/output-guard.js.map +1 -1
- package/dist/core/package-manager-paths.d.ts +2 -1
- package/dist/core/package-manager-paths.d.ts.map +1 -1
- package/dist/core/package-manager-paths.js +4 -3
- package/dist/core/package-manager-paths.js.map +1 -1
- package/dist/core/package-manager.js +1 -0
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader-assets.d.ts.map +1 -1
- package/dist/core/resource-loader-assets.js +9 -7
- package/dist/core/resource-loader-assets.js.map +1 -1
- package/dist/core/resource-loader-core.js +49 -0
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/runtime-credentials.js +2 -1
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/session-cwd.js +1 -0
- package/dist/core/session-cwd.js.map +1 -1
- package/dist/core/session-manager-archive.d.ts.map +1 -1
- package/dist/core/session-manager-archive.js +4 -2
- package/dist/core/session-manager-archive.js.map +1 -1
- package/dist/core/session-manager-core.js +11 -7
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +10 -4
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +12 -6
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +2 -1
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +21 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-core.js +13 -7
- package/dist/core/settings-manager-core.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-storage.js +6 -0
- package/dist/core/settings-storage.js.map +1 -1
- package/dist/core/settings-types.d.ts +8 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/structured-output/index.d.ts.map +1 -1
- package/dist/core/structured-output/index.js +4 -1
- package/dist/core/structured-output/index.js.map +1 -1
- package/dist/core/structured-output/invalid-output.js +1 -0
- package/dist/core/structured-output/invalid-output.js.map +1 -1
- package/dist/core/tasks/agent-adapter.js +5 -3
- package/dist/core/tasks/agent-adapter.js.map +1 -1
- package/dist/core/tasks/child-command-owner.js +3 -7
- package/dist/core/tasks/child-command-owner.js.map +1 -1
- package/dist/core/tasks/completion.js +5 -1
- package/dist/core/tasks/completion.js.map +1 -1
- package/dist/core/tasks/owner-store.js +12 -8
- package/dist/core/tasks/owner-store.js.map +1 -1
- package/dist/core/tasks/supervisor.js +14 -35
- package/dist/core/tasks/supervisor.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.js +13 -4
- package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js +11 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/option-list-view.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/option-list-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js +5 -0
- package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +2 -0
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js +13 -8
- package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/tab-bar.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/tab-bar.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +30 -24
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.js +5 -0
- package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/props-adapter.js +8 -0
- package/dist/core/tools/ask-user-question/view/props-adapter.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/tab-content-strategy.js +4 -4
- package/dist/core/tools/ask-user-question/view/tab-content-strategy.js.map +1 -1
- package/dist/core/tools/bash.js +5 -8
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-batch.js +4 -0
- package/dist/core/tools/edit-batch.js.map +1 -1
- package/dist/core/tools/edit.js +2 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-coordinator.js +9 -0
- package/dist/core/tools/file-mutation-coordinator.js.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/hashline-engine/fs.js +1 -1
- package/dist/core/tools/hashline-engine/fs.js.map +1 -1
- package/dist/core/tools/hashline-engine/input.js +4 -0
- package/dist/core/tools/hashline-engine/input.js.map +1 -1
- package/dist/core/tools/hashline-engine/mismatch.js +6 -0
- package/dist/core/tools/hashline-engine/mismatch.js.map +1 -1
- package/dist/core/tools/hashline-engine/patcher.js +13 -0
- package/dist/core/tools/hashline-engine/patcher.js.map +1 -1
- package/dist/core/tools/hashline-engine/recovery.js +1 -0
- package/dist/core/tools/hashline-engine/recovery.js.map +1 -1
- package/dist/core/tools/output-accumulator.js +20 -13
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/persisted-output-file.js +9 -3
- package/dist/core/tools/persisted-output-file.js.map +1 -1
- package/dist/core/tools/resource-selectors.js +1 -0
- package/dist/core/tools/resource-selectors.js.map +1 -1
- package/dist/core/tools/write.js +1 -0
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.js +1 -0
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/workflow-stage-admission.js +17 -10
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/extensions/llama/client.js +2 -0
- package/dist/extensions/llama/client.js.map +1 -1
- package/dist/extensions/llama/huggingface-ui.js +17 -9
- package/dist/extensions/llama/huggingface-ui.js.map +1 -1
- package/dist/extensions/llama/huggingface.js +2 -0
- package/dist/extensions/llama/huggingface.js.map +1 -1
- package/dist/extensions/llama/ui.js +11 -3
- package/dist/extensions/llama/ui.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/armin.js +10 -6
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +10 -2
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/atomic-working-status.js +10 -2
- package/dist/modes/interactive/components/atomic-working-status.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +9 -4
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +3 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +4 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +2 -1
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +63 -31
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +8 -1
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.js +24 -14
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.js +2 -1
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector-list.js +15 -6
- package/dist/modes/interactive/components/config-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +7 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.js +2 -0
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +21 -1
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +4 -1
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +9 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +8 -6
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +1 -0
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +7 -1
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +8 -2
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/extension-selector.js +9 -1
- package/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +4 -2
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.js +5 -2
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/host-input-form.js +13 -2
- package/dist/modes/interactive/components/host-input-form.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +9 -3
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +24 -12
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +12 -3
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/reserved-bottom-overlay.js +11 -2
- package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +13 -8
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/scroll-widget.js +4 -0
- package/dist/modes/interactive/components/scroll-widget.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-header.js +11 -7
- package/dist/modes/interactive/components/session-selector-header.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js +25 -12
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +23 -15
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-submenus.js +19 -1
- package/dist/modes/interactive/components/settings-selector-submenus.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +1 -0
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +4 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/startup-identity.js +8 -3
- package/dist/modes/interactive/components/startup-identity.js.map +1 -1
- package/dist/modes/interactive/components/task-completion-message.js +2 -0
- package/dist/modes/interactive/components/task-completion-message.js.map +1 -1
- package/dist/modes/interactive/components/task-detail.js +2 -0
- package/dist/modes/interactive/components/task-detail.js.map +1 -1
- package/dist/modes/interactive/components/task-inspector.js +22 -12
- package/dist/modes/interactive/components/task-inspector.js.map +1 -1
- package/dist/modes/interactive/components/task-list.js +2 -0
- package/dist/modes/interactive/components/task-list.js.map +1 -1
- package/dist/modes/interactive/components/task-live-transcript.js +8 -3
- package/dist/modes/interactive/components/task-live-transcript.js.map +1 -1
- package/dist/modes/interactive/components/task-navigation.js +5 -2
- package/dist/modes/interactive/components/task-navigation.js.map +1 -1
- package/dist/modes/interactive/components/task-row.js +2 -0
- package/dist/modes/interactive/components/task-row.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +2 -0
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +7 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +25 -10
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/transcript-follow-indicator.js +1 -0
- package/dist/modes/interactive/components/transcript-follow-indicator.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-component.js +7 -3
- package/dist/modes/interactive/components/tree-selector-component.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-help.js +1 -0
- package/dist/modes/interactive/components/tree-selector-help.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-label-input.js +6 -2
- package/dist/modes/interactive/components/tree-selector-label-input.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-list.js +4 -0
- package/dist/modes/interactive/components/tree-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/trust-selector.js +6 -0
- package/dist/modes/interactive/components/trust-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +6 -3
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.js +5 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/working-status.js +1 -0
- package/dist/modes/interactive/components/working-status.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +2 -0
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js +1 -0
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +162 -120
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.js +3 -0
- package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +0 -6
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-disclosure.js +0 -4
- package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-rendering.js +0 -12
- package/dist/modes/interactive/interactive-resource-rendering.js.map +1 -1
- package/dist/modes/interactive/interactive-startup-chat-container.js +1 -4
- package/dist/modes/interactive/interactive-startup-chat-container.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.js +1 -3
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -1
- package/dist/modes/interactive/theme/color-utils.d.ts +5 -0
- package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
- package/dist/modes/interactive/theme/color-utils.js +11 -0
- package/dist/modes/interactive/theme/color-utils.js.map +1 -1
- package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/global-theme.js +4 -3
- package/dist/modes/interactive/theme/global-theme.js.map +1 -1
- package/dist/modes/interactive/theme/theme-class.js +7 -0
- package/dist/modes/interactive/theme/theme-class.js.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +9 -2
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive-engine/activity-watchdog.js +8 -3
- package/dist/modes/interactive-engine/activity-watchdog.js.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.js +12 -8
- package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
- package/dist/modes/interactive-engine/engine-dialog-host.js +7 -3
- package/dist/modes/interactive-engine/engine-dialog-host.js.map +1 -1
- package/dist/modes/interactive-engine/engine-health.js +23 -13
- package/dist/modes/interactive-engine/engine-health.js.map +1 -1
- package/dist/modes/interactive-engine/engine-input-form.js +3 -2
- package/dist/modes/interactive-engine/engine-input-form.js.map +1 -1
- package/dist/modes/interactive-engine/engine-monitor.js +13 -1
- package/dist/modes/interactive-engine/engine-monitor.js.map +1 -1
- package/dist/modes/interactive-engine/engine-project-trust.js +2 -1
- package/dist/modes/interactive-engine/engine-project-trust.js.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +7 -4
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/engine-session-picker.js +3 -2
- package/dist/modes/interactive-engine/engine-session-picker.js.map +1 -1
- package/dist/modes/interactive-engine/input-form-host.js +5 -1
- package/dist/modes/interactive-engine/input-form-host.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +37 -23
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-command-catalog.js +4 -3
- package/dist/modes/interactive-engine/remote-command-catalog.js.map +1 -1
- package/dist/modes/interactive-engine/remote-component.js +24 -12
- package/dist/modes/interactive-engine/remote-component.js.map +1 -1
- package/dist/modes/interactive-engine/remote-frame-clamp.js +3 -3
- package/dist/modes/interactive-engine/remote-frame-clamp.js.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js +5 -4
- package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
- package/dist/modes/interactive-engine/remote-queue-pause.js +3 -1
- package/dist/modes/interactive-engine/remote-queue-pause.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +24 -13
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/interactive-engine/resource-readiness-error.js +1 -0
- package/dist/modes/interactive-engine/resource-readiness-error.js.map +1 -1
- package/dist/modes/interactive-engine/session-picker-host.js +5 -1
- package/dist/modes/interactive-engine/session-picker-host.js.map +1 -1
- package/dist/modes/interactive-engine/terminal-mode-controller.js +2 -1
- package/dist/modes/interactive-engine/terminal-mode-controller.js.map +1 -1
- package/dist/modes/rpc/queued-writer.js +13 -4
- package/dist/modes/rpc/queued-writer.js.map +1 -1
- package/dist/modes/rpc/rpc-bash-request-owners.js +2 -1
- package/dist/modes/rpc/rpc-bash-request-owners.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +8 -4
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +10 -3
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +35 -22
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +6 -6
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-event-buffer.js +3 -1
- package/dist/modes/rpc/rpc-event-buffer.js.map +1 -1
- package/dist/modes/rpc/rpc-generation-buffer.js +1 -3
- package/dist/modes/rpc/rpc-generation-buffer.js.map +1 -1
- package/dist/modes/rpc/rpc-keybindings-reload.js +4 -1
- package/dist/modes/rpc/rpc-keybindings-reload.js.map +1 -1
- package/dist/modes/rpc/rpc-output-buffer.js +3 -4
- package/dist/modes/rpc/rpc-output-buffer.js.map +1 -1
- package/dist/modes/rpc/rpc-pending-requests.js +1 -3
- package/dist/modes/rpc/rpc-pending-requests.js.map +1 -1
- package/dist/modes/rpc/rpc-provider-auth.js +3 -1
- package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
- package/dist/modes/rpc/rpc-resource-readiness.js +4 -5
- package/dist/modes/rpc/rpc-resource-readiness.js.map +1 -1
- package/dist/modes/rpc/rpc-session-binding.js +15 -0
- package/dist/modes/rpc/rpc-session-binding.js.map +1 -1
- package/dist/modes/rpc/rpc-terminal-drain.js +3 -0
- package/dist/modes/rpc/rpc-terminal-drain.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +10 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/models/evals.md +883 -39
- package/docs/models/model-selection.md +7 -8
- package/docs/rpc/examples.md +1 -1
- package/docs/rpc/protocol.md +9 -3
- package/docs/sdk/structured-decisions.md +1 -1
- package/docs/sdk.md +3 -3
- package/docs/settings.md +24 -3
- package/docs/subagents/reference.md +22 -4
- package/docs/subagents.md +2 -0
- package/docs/usage.md +3 -3
- package/docs/workflows/api-reference.md +1 -1
- package/docs/workflows/authoring.md +1 -7
- package/docs/workflows/builtins.md +1 -1
- package/docs/workflows/reliable-design.md +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +5 -5
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/rpc-client.ts +1 -1
- package/examples/rpc-extension-ui.ts +1 -1
- package/npm-shrinkwrap.json +70 -33
- package/package.json +6 -7
- package/dist/core/model-routing-task.d.ts.map +0 -1
- package/dist/core/model-routing-task.js +0 -120
- package/dist/core/model-routing-task.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/input.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iLAAiL;AACjL;;;;;;;;GAQG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EACN,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,cAAc,GACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,yDAAyD;AACzD,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;AAElC,SAAS,mBAAmB,CAAC,QAAgB;IAC5C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrF,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,yBAAyB,GAC9B,iGAAiG,CAAC;AAEnG,SAAS,wBAAwB,CAAC,QAAgB;IACjD,OAAO,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;AACxD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,sBAAsB,CAAC,IAAY,EAAE,GAAY;IACzD,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IACpF,MAAM,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,qEAAqE;IACrE,wEAAwE;IACxE,kEAAkE;IAClE,2CAA2C;IAC3C,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,iBAAiB,mBAAmB,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtF,IAAI,QAAgB,CAAC;IACrB,IAAI,QAA4B,CAAC;IACjC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzC,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IACtC,CAAC;SAAM,CAAC;QACP,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,sEAAsE;IACtE,8DAA8D;IAC9D,sEAAsE;IACtE,mEAAmE;IACnE,mEAAmE;IACnE,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACnF,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe,EAAE,GAAY;IAC3D,MAAM,QAAQ,GAAG,wBAAwB,CAAC,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC/E,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1E,MAAM,WAAW,GAAG,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;IAClG,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AACjD,CAAC;AAQD;;;;;GAKG;AACH,SAAS,uBAAuB,CAAC,IAAY,EAAE,GAAY;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,oEAAoE;QACpE,sEAAsE;QACtE,gDAAgD;QAChD,MAAM,SAAS,GAAG,sBAAsB,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QACvD,IAAI,SAAS,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACzC,MAAM,IAAI,KAAK,CACd,wBAAwB,cAAc,OAAO,cAAc,OAAO,cAAc,OAAO,gBAAgB,MAAM,cAAc,WAAW,mBAAmB,8BAA8B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CACjN,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC1D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,iBAAiB,cAAc,GAAG,cAAc,kCAAkC,CAAC,CAAC;IACrG,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,KAAK,SAAS;QAClC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1D,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACnC,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa;IAC5C,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACrE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YACpF,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,SAAS;QACV,CAAC;QACD,MAAM;IACP,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sCAAsC,CAAC,KAAa;IACnE,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IACvC,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa,EAAE,OAAqB;IACnE,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACrE,MAAM,iBAAiB,GAAG,QAAQ;SAChC,KAAK,CAAC,OAAO,CAAC;SACd,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,uBAAuB,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC;IAC5E,IAAI,iBAAiB;QAAE,OAAO,KAAK,CAAC;IAEpC,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,sCAAsC,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClF,MAAM,YAAY,GAAG,qBAAqB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACtE,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAO,GAAG,cAAc,GAAG,YAAY,GAAG,cAAc,KAAK,KAAK,EAAE,CAAC;AACtE,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAa,EAAE,OAAO,GAAiB,EAAE;IAClE,MAAM,QAAQ,GAAG,sBAAsB,CAAC,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEjC,IAAI,uBAAuB,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;QAC9D,oEAAoE;QACpE,kCAAkC;QAClC,MAAM,YAAY,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QACzC,IAAI,wCAAwC,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CACd,yEAAyE;gBACxE,8BAA8B,cAAc,OAAO,gBAAgB,OAAO,cAAc,qDAAqD,CAC9I,CAAC;QACH,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QACxD,MAAM,IAAI,KAAK,CACd,0BAA0B,cAAc,OAAO,gBAAgB,OAAO,cAAc,0DAA0D,OAAO,IAAI;YACxJ,aAAa,cAAc,aAAa,gBAAgB,GAAG,qBAAqB,CAAC,CAAC,CAAC,GAAG,cAAc,kBAAkB,CACvH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAiB,EAAE,CAAC;IAClC,IAAI,OAA+B,CAAC;IACpC,IAAI,YAAY,GAAa,EAAE,CAAC;IAEhC,MAAM,KAAK,GAAG,GAAG,EAAE;QAClB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnE,IAAI,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzE,YAAY,GAAG,EAAE,CAAC;IACnB,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YAAE,MAAM;QACnE,IAAI,KAAK,CAAC,IAAI,KAAK,gBAAgB;YAAE,SAAS;QAE9C,uEAAuE;QACvE,oEAAoE;QACpE,kEAAkE;QAClE,YAAY;QACZ,IAAI,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1D,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACrB,KAAK,EAAE,CAAC;gBACR,OAAO,GAAG,MAAM,CAAC;gBACjB,YAAY,GAAG,EAAE,CAAC;gBAClB,SAAS;YACV,CAAC;QACF,CAAC;QACD,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IAIxB,OAAO,CAAoD;IAE3D,YAAY,GAAe;QAC1B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,KAAK;QACJ,IAAI,CAAC,OAAO,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAED,qCAAqC;IACrC,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED,uDAAuD;IACvD,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,IAAI,mBAAmB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YAC/B,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YACxC,uEAAuE;YACvE,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;gBAAE,OAAO,IAAI,CAAC;YACvC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC;QACpF,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,+EAA+E;IAC/E,kBAAkB;QACjB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC5B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5B,SAAS;YACV,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBAC5B,SAAS;YACV,CAAC;YACD,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACjF,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,CAAC;QACF,CAAC;QACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAY,EAAE,aAA6B;QAClD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzC,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE;YACzE,YAAY,EAAE,OAAO;YACrB,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;SACrD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,oEAAoE;QACpE,cAAc;QACd,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC;YACvB,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE;YACjC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC;IACrE,CAAC;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAY,EAAE,aAA6B;QACzD,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,eAAe,GAAa,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,EAAE;YACzE,YAAY,EAAE,MAAM;YACpB,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;SACrD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,EAAE,GAAG,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7E,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC;YACvB,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE;YACjC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC;IACrE,CAAC;CACD;AAED;;;;;;GAMG;AACH,MAAM,OAAO,KAAK;IAGjB,YAAoB,QAAwB;QAC3C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,CAAC,KAAa,EAAE,OAAO,GAAiB,EAAE;QACrD,MAAM,GAAG,GAAG,qBAAqB,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;QACpE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,KAAa,EAAE,OAAO,GAAiB,EAAE;QAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QACzE,OAAO,KAAK,CAAC;IACd,CAAC;CACD;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,QAAsB;IACpD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkD,CAAC;IACzE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,QAAQ,EAAE,CAAC;YACd,IACC,QAAQ,CAAC,QAAQ,KAAK,SAAS;gBAC/B,OAAO,CAAC,QAAQ,KAAK,SAAS;gBAC9B,QAAQ,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,EACrC,CAAC;gBACF,MAAM,IAAI,KAAK,CACd,0CAA0C,OAAO,CAAC,IAAI,MAAM,QAAQ,CAAC,QAAQ,SAAS,OAAO,CAAC,QAAQ,uDAAuD,CAC7J,CAAC;YACH,CAAC;YACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS;gBAAE,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YAC5G,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAClC,SAAS;QACV,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE;YACxB,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,KAAK,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SACrB,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,IAAI,EAAE,WAAW;QACjB,GAAG,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;KAC5B,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Top-level patch parser. Splits an authored hashline input into a list of\n * {@link PatchSection}s, each rooted at a `[PATH#HASH]` header, then exposes\n * a {@link Patch} class that gives lazy access to the parsed edits per\n * section.\n *\n * The splitter is purely lexical — it doesn't know whether a section's path\n * actually exists. That's the patcher's job.\n */\nimport * as path from \"node:path\";\nimport { applyEdits } from \"./apply.js\";\nimport { resolveBlockEdits } from \"./block.js\";\nimport {\n\tHL_FILE_HASH_EXAMPLES,\n\tHL_FILE_HASH_LENGTH,\n\tHL_FILE_HASH_SEP,\n\tHL_FILE_PREFIX,\n\tHL_FILE_SUFFIX,\n} from \"./format.js\";\nimport { parsePatch, parsePatchStreaming } from \"./parser.js\";\nimport { Tokenizer } from \"./tokenizer.js\";\nimport type { ApplyResult, BlockResolver, Edit, SplitOptions } from \"./types.js\";\n\n// Pure classification — single shared tokenizer is safe.\nconst TOKENIZER = new Tokenizer();\n\nfunction unquoteHashlinePath(pathText: string): string {\n\tif (pathText.length < 2) return pathText;\n\tconst first = pathText[0];\n\tconst last = pathText[pathText.length - 1];\n\tif ((first === '\"' || first === \"'\") && first === last) return pathText.slice(1, -1);\n\treturn pathText;\n}\n\n/**\n * Strip apply_patch-style noise that models reflexively prepend to the\n * path. Examples observed in benchmark traces:\n *\n * `Update File:foo.ts`, `Update:foo.ts`, `UpdateFile:foo.ts`,\n * `Update/File:foo.ts`, `Update-file:foo.ts`, `Update(File):foo.ts`,\n * `Update<File:foo.ts`, `Add File:foo.ts`, `Delete File:foo.ts`,\n * `Move to:foo.ts`, `***foo.ts`, `***Update File:foo.ts`.\n *\n * We strip a leading `***` (the model duplicating the header sigil) and a\n * leading `(Update|Add|Delete|Move)[<separator>]*(File|to)?[<separator>]*:`\n * keyword block, case-insensitive. The remaining text is the real path.\n */\nconst APPLY_PATCH_PATH_NOISE_RE =\n\t/^\\*{0,3}\\s*(?:(?:update|add|delete|move)[^A-Za-z0-9]*(?:file|to)?[^A-Za-z0-9]*:)?\\s*\\*{0,3}\\s*/i;\n\nfunction stripApplyPatchPathNoise(pathText: string): string {\n\treturn pathText.replace(APPLY_PATCH_PATH_NOISE_RE, \"\");\n}\n\n/**\n * Best-effort recovery for bracketed header lines the strict tokenizer\n * rejects. Strips apply_patch keyword noise (`Update File:`, `Update:`,\n * etc.) and an extra leading `***` (some models emit a hybrid\n * `[***foo.ts#HASH]` shape), then expects `PATH(#HASH)?`.\n * Returns `null` when no clean path can be salvaged.\n */\nfunction tryParseRecoveryHeader(line: string, cwd?: string): RawSection | null {\n\tif (!line.startsWith(HL_FILE_PREFIX) || !line.endsWith(HL_FILE_SUFFIX)) return null;\n\tconst body = stripApplyPatchPathNoise(line.slice(HL_FILE_PREFIX.length, line.length - HL_FILE_SUFFIX.length).trim());\n\tif (body.length === 0) return null;\n\n\t// Trailing `#XXXX` is the tag; everything before it is the path. The\n\t// path may contain whitespace (Windows OneDrive folders, Program Files,\n\t// etc.), so we anchor the tag at end-of-body rather than scanning\n\t// forward and stopping at the first space.\n\tconst trailing = new RegExp(`#([0-9A-Fa-f]{${HL_FILE_HASH_LENGTH}})\\\\s*$`).exec(body);\n\tlet pathText: string;\n\tlet fileHash: string | undefined;\n\tif (trailing !== null) {\n\t\tpathText = body.slice(0, trailing.index);\n\t\tfileHash = trailing[1].toUpperCase();\n\t} else {\n\t\tpathText = body.replace(/\\s+$/, \"\");\n\t}\n\n\t// Same rule as the strict tokenizer: the hashline header grammar uses\n\t// `#` as the path/tag separator and does not allow `#` inside\n\t// filenames. Anything `#` left in the path body — short tags, non-hex\n\t// tags, over-long tags, stale-tag copy-paste, line-suffixed tags —\n\t// means the header is malformed, not a path with an embedded hash.\n\tif (pathText.includes(\"#\")) return null;\n\n\tconst path = normalizeHashlinePath(pathText, cwd);\n\tif (path.length === 0) return null;\n\treturn fileHash !== undefined ? { path, fileHash, diff: \"\" } : { path, diff: \"\" };\n}\n\nfunction normalizeHashlinePath(rawPath: string, cwd?: string): string {\n\tconst unquoted = stripApplyPatchPathNoise(unquoteHashlinePath(rawPath.trim()));\n\tif (!cwd || !path.isAbsolute(unquoted)) return unquoted;\n\tconst relative = path.relative(path.resolve(cwd), path.resolve(unquoted));\n\tconst isWithinCwd = relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n\treturn isWithinCwd ? relative || \".\" : unquoted;\n}\n\ninterface RawSection {\n\tpath: string;\n\tfileHash?: string;\n\tdiff: string;\n}\n\n/**\n * Parse a `[PATH]` or `[PATH#hash]` header line. Returns `null` for lines that do\n * not start with `[`. Throws the strict \"Input header must be …\" error\n * when a bracketed line fails the strict shape (so malformed paths\n * surface immediately instead of being silently re-classified as payload).\n */\nfunction parseHashlineHeaderLine(line: string, cwd?: string): RawSection | null {\n\tconst trimmed = line.trimEnd();\n\tif (!trimmed.startsWith(HL_FILE_PREFIX)) return null;\n\n\tconst token = TOKENIZER.tokenize(trimmed);\n\tif (token.kind !== \"header\") {\n\t\t// Recovery: try to extract a path from the raw line after stripping\n\t\t// apply_patch noise. This handles `[*** Update File:foo.ts#CB5A]` and\n\t\t// the half-dozen variants models actually emit.\n\t\tconst recovered = tryParseRecoveryHeader(trimmed, cwd);\n\t\tif (recovered !== null) return recovered;\n\t\tthrow new Error(\n\t\t\t`Input header must be ${HL_FILE_PREFIX}PATH${HL_FILE_SUFFIX} or ${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}TAG${HL_FILE_SUFFIX} with a ${HL_FILE_HASH_LENGTH}-hex content-hash tag; got ${JSON.stringify(trimmed)}.`,\n\t\t);\n\t}\n\n\tconst parsedPath = normalizeHashlinePath(token.path, cwd);\n\tif (parsedPath.length === 0) {\n\t\tthrow new Error(`Input header \"${HL_FILE_PREFIX}${HL_FILE_SUFFIX}\" is empty; provide a file path.`);\n\t}\n\treturn token.fileHash !== undefined\n\t\t? { path: parsedPath, fileHash: token.fileHash, diff: \"\" }\n\t\t: { path: parsedPath, diff: \"\" };\n}\n\nfunction stripLeadingBlankLines(input: string): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst lines = stripped.split(\"\\n\");\n\twhile (lines.length > 0) {\n\t\tconst head = lines[0].replace(/\\r$/, \"\");\n\t\tif (head.trim().length === 0 || TOKENIZER.tokenize(head).kind === \"envelope-begin\") {\n\t\t\tlines.shift();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Returns true when the input contains at least one line that the tokenizer\n * recognizes as a hashline op. Used by streaming previews to decide whether\n * the partial input is worth treating as a hashline patch yet.\n */\nexport function containsRecognizableHashlineOperations(input: string): boolean {\n\tfor (const line of input.split(/\\r?\\n/)) {\n\t\tif (TOKENIZER.isOp(line)) return true;\n\t}\n\treturn false;\n}\n\nfunction normalizeFallbackInput(input: string, options: SplitOptions): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst hasExplicitHeader = stripped\n\t\t.split(/\\r?\\n/)\n\t\t.some((rawLine) => parseHashlineHeaderLine(rawLine, options.cwd) !== null);\n\tif (hasExplicitHeader) return input;\n\n\tif (!options.path || !containsRecognizableHashlineOperations(input)) return input;\n\tconst fallbackPath = normalizeHashlinePath(options.path, options.cwd);\n\tif (fallbackPath.length === 0) return input;\n\treturn `${HL_FILE_PREFIX}${fallbackPath}${HL_FILE_SUFFIX}\\n${input}`;\n}\n\nfunction splitRawSections(input: string, options: SplitOptions = {}): RawSection[] {\n\tconst stripped = stripLeadingBlankLines(normalizeFallbackInput(input, options));\n\tconst lines = stripped.split(/\\r?\\n/);\n\tconst firstLine = lines[0] ?? \"\";\n\n\tif (parseHashlineHeaderLine(firstLine, options.cwd) === null) {\n\t\t// Catch unified-diff hunk-header contamination on the first line so\n\t\t// the model sees a focused error.\n\t\tconst firstTrimmed = firstLine.trimEnd();\n\t\tif (/^@@\\s+[-+]?\\d+,\\d+\\s+[-+]?\\d+,\\d+\\s+@@/.test(firstTrimmed)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"unified-diff hunk header (`@@ -N,M +N,M @@`) is not valid in hashline. \" +\n\t\t\t\t\t`File sections start with \\`${HL_FILE_PREFIX}path${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\\`; use \\`replace\\`, \\`delete\\`, or \\`insert\\` ops.`,\n\t\t\t);\n\t\t}\n\t\tconst preview = JSON.stringify(firstLine.slice(0, 120));\n\t\tthrow new Error(\n\t\t\t`input must begin with \"${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\" on the first non-blank line for anchored edits; got: ${preview}. ` +\n\t\t\t\t`Example: \"${HL_FILE_PREFIX}src/foo.ts${HL_FILE_HASH_SEP}${HL_FILE_HASH_EXAMPLES[0]}${HL_FILE_SUFFIX}\" then edit ops.`,\n\t\t);\n\t}\n\n\tconst sections: RawSection[] = [];\n\tlet current: RawSection | undefined;\n\tlet currentLines: string[] = [];\n\n\tconst flush = () => {\n\t\tif (!current) return;\n\t\tconst hasOps = currentLines.some((line) => line.trim().length > 0);\n\t\tif (hasOps) sections.push({ ...current, diff: currentLines.join(\"\\n\") });\n\t\tcurrentLines = [];\n\t};\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trimEnd();\n\t\tconst token = TOKENIZER.tokenize(line);\n\t\tif (token.kind === \"envelope-end\" || token.kind === \"abort\") break;\n\t\tif (token.kind === \"envelope-begin\") continue;\n\n\t\t// Route every bracket-prefixed line through parseHashlineHeaderLine so\n\t\t// malformed headers still raise the strict \"Input header must be …\"\n\t\t// diagnostic (the tokenizer alone would silently classify them as\n\t\t// payload).\n\t\tif (trimmed.startsWith(HL_FILE_PREFIX)) {\n\t\t\tconst header = parseHashlineHeaderLine(line, options.cwd);\n\t\t\tif (header !== null) {\n\t\t\t\tflush();\n\t\t\t\tcurrent = header;\n\t\t\t\tcurrentLines = [];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tcurrentLines.push(line);\n\t}\n\tflush();\n\treturn sections;\n}\n\n/**\n * Snapshot of one section in a parsed {@link Patch}: a target file plus the\n * lazily-parsed list of edits that should land on it. Constructed by\n * {@link Patch.parse}; consumers usually iterate `patch.sections` rather\n * than build these directly.\n */\nexport class PatchSection {\n\treadonly path: string;\n\treadonly fileHash: string | undefined;\n\treadonly diff: string;\n\t#parsed: { edits: Edit[]; warnings: string[] } | undefined;\n\n\tconstructor(raw: RawSection) {\n\t\tthis.path = raw.path;\n\t\tthis.fileHash = raw.fileHash;\n\t\tthis.diff = raw.diff;\n\t}\n\n\t/**\n\t * Parse this section's diff body. Cached: subsequent calls return the\n\t * same `{ edits, warnings }` object so callers can safely call this from\n\t * multiple paths (preflight, apply, diff-preview).\n\t */\n\tparse(): { edits: Edit[]; warnings: readonly string[] } {\n\t\tthis.#parsed ??= parsePatch(this.diff);\n\t\treturn this.#parsed;\n\t}\n\n\t/** Parsed edits for this section. */\n\tget edits(): readonly Edit[] {\n\t\treturn this.parse().edits;\n\t}\n\n\t/** Warnings emitted during parsing of this section. */\n\tget warnings(): readonly string[] {\n\t\treturn this.parse().warnings;\n\t}\n\n\t/**\n\t * True when at least one edit anchors to concrete file content. Pure\n\t * `insert head:` / `insert tail:` literal inserts do not count: those are\n\t * safe to apply to files that don't yet exist.\n\t */\n\tget hasAnchorScopedEdit(): boolean {\n\t\treturn this.edits.some((edit) => {\n\t\t\tif (edit.kind === \"delete\") return true;\n\t\t\t// A `replace block N:` edit is anchored to concrete content on line N.\n\t\t\tif (edit.kind === \"block\") return true;\n\t\t\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\";\n\t\t});\n\t}\n\n\t/** Anchor lines touched by this section, sorted ascending and deduplicated. */\n\tcollectAnchorLines(): readonly number[] {\n\t\tconst lines = new Set<number>();\n\t\tfor (const edit of this.edits) {\n\t\t\tif (edit.kind === \"delete\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.kind === \"block\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\") {\n\t\t\t\tlines.add(edit.cursor.anchor.line);\n\t\t\t}\n\t\t}\n\t\treturn [...lines].sort((a, b) => a - b);\n\t}\n\n\t/**\n\t * Apply this section's edits to `text` and return the post-edit result.\n\t * Pure: does no I/O, does not validate the section snapshot tag. The\n\t * {@link Patcher} owns tag validation and recovery; reach for this\n\t * method directly when you've already validated the file content and\n\t * just want the result.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block throws (this is the final, authoritative preview path).\n\t */\n\tapplyTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = this.parse();\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"throw\",\n\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\t// Preserve parse warnings so consumers don't need to call `parse()`\n\t\t// separately.\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n\n\t/**\n\t * Streaming-tolerant counterpart to {@link applyTo}. Uses\n\t * {@link parsePatchStreaming} so a trailing in-flight op (no payload yet,\n\t * or a per-token parse error mid-stream) does not throw or emit a phantom\n\t * empty-payload edit. Intended for incremental diff previews; the writer\n\t * path should always use {@link applyTo}.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block is silently dropped so a half-written file does not\n\t * throw mid-stream.\n\t */\n\tapplyPartialTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = parsePatchStreaming(this.diff);\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"drop\",\n\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n}\n\n/**\n * A parsed hashline patch — zero or more {@link PatchSection}s, each rooted\n * at a `[PATH#HASH]` header. Construct via {@link Patch.parse}.\n *\n * `Patch` is pure data: parsing is line-anchored and does not look at the\n * filesystem. To apply a patch, hand it to {@link Patcher.apply}.\n */\nexport class Patch {\n\treadonly sections: readonly PatchSection[];\n\n\tprivate constructor(sections: PatchSection[]) {\n\t\tthis.sections = sections;\n\t}\n\n\t/**\n\t * Parse `input` into a {@link Patch}. `options.cwd` resolves absolute\n\t * paths inside headers to cwd-relative form; `options.path` provides a\n\t * fallback when the input lacks a header but contains hashline ops\n\t * (useful for streaming previews).\n\t *\n\t * Consecutive sections targeting the same path are merged into a single\n\t * section with concatenated diff bodies. Anchors authored against the\n\t * same file snapshot must be applied as one batch; otherwise the first\n\t * sub-edit shifts line numbers out from under the second's anchors and\n\t * validation fails.\n\t */\n\tstatic parse(input: string, options: SplitOptions = {}): Patch {\n\t\tconst raw = mergeSamePathSections(splitRawSections(input, options));\n\t\treturn new Patch(raw.map((section) => new PatchSection(section)));\n\t}\n\n\t/**\n\t * Parse `input` and return only the first section. Throws if the input\n\t * has zero sections. Convenience for the single-section case where the\n\t * caller already knows the patch is one hunk.\n\t */\n\tstatic parseSingle(input: string, options: SplitOptions = {}): PatchSection {\n\t\tconst patch = Patch.parse(input, options);\n\t\tconst first = patch.sections[0];\n\t\tif (!first) throw new Error(\"Patch input did not produce any sections.\");\n\t\treturn first;\n\t}\n}\n\n/**\n * Collapse consecutive or interleaved sections targeting the same path into a\n * single section with concatenated diffs. Anchors authored against the same\n * file snapshot must be applied as one batch; otherwise the first sub-edit\n * shifts line numbers out from under the second's anchors and validation\n * fails. Path order is preserved by first occurrence.\n */\nfunction mergeSamePathSections(sections: RawSection[]): RawSection[] {\n\tconst byPath = new Map<string, { fileHash?: string; diffs: string[] }>();\n\tfor (const section of sections) {\n\t\tconst existing = byPath.get(section.path);\n\t\tif (existing) {\n\t\t\tif (\n\t\t\t\texisting.fileHash !== undefined &&\n\t\t\t\tsection.fileHash !== undefined &&\n\t\t\t\texisting.fileHash !== section.fileHash\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Conflicting hashline snapshot tags for ${section.path}: #${existing.fileHash} and #${section.fileHash}. Re-read the file and retry with one current header.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (existing.fileHash === undefined && section.fileHash !== undefined) existing.fileHash = section.fileHash;\n\t\t\texisting.diffs.push(section.diff);\n\t\t\tcontinue;\n\t\t}\n\t\tbyPath.set(section.path, {\n\t\t\t...(section.fileHash !== undefined ? { fileHash: section.fileHash } : {}),\n\t\t\tdiffs: [section.diff],\n\t\t});\n\t}\n\treturn Array.from(byPath, ([sectionPath, entry]) => ({\n\t\tpath: sectionPath,\n\t\t...(entry.fileHash !== undefined ? { fileHash: entry.fileHash } : {}),\n\t\tdiff: entry.diffs.join(\"\\n\"),\n\t}));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/input.ts"],"names":[],"mappings":"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","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Top-level patch parser. Splits an authored hashline input into a list of\n * {@link PatchSection}s, each rooted at a `[PATH#HASH]` header, then exposes\n * a {@link Patch} class that gives lazy access to the parsed edits per\n * section.\n *\n * The splitter is purely lexical — it doesn't know whether a section's path\n * actually exists. That's the patcher's job.\n */\nimport * as path from \"node:path\";\nimport { applyEdits } from \"./apply.js\";\nimport { resolveBlockEdits } from \"./block.js\";\nimport {\n\tHL_FILE_HASH_EXAMPLES,\n\tHL_FILE_HASH_LENGTH,\n\tHL_FILE_HASH_SEP,\n\tHL_FILE_PREFIX,\n\tHL_FILE_SUFFIX,\n} from \"./format.js\";\nimport { parsePatch, parsePatchStreaming } from \"./parser.js\";\nimport { Tokenizer } from \"./tokenizer.js\";\nimport type { ApplyResult, BlockResolver, Edit, SplitOptions } from \"./types.js\";\n\n// Pure classification — single shared tokenizer is safe.\nconst TOKENIZER = new Tokenizer();\n\nfunction unquoteHashlinePath(pathText: string): string {\n\tif (pathText.length < 2) return pathText;\n\tconst first = pathText[0];\n\tconst last = pathText[pathText.length - 1];\n\tif ((first === '\"' || first === \"'\") && first === last) return pathText.slice(1, -1);\n\treturn pathText;\n}\n\n/**\n * Strip apply_patch-style noise that models reflexively prepend to the\n * path. Examples observed in benchmark traces:\n *\n * `Update File:foo.ts`, `Update:foo.ts`, `UpdateFile:foo.ts`,\n * `Update/File:foo.ts`, `Update-file:foo.ts`, `Update(File):foo.ts`,\n * `Update<File:foo.ts`, `Add File:foo.ts`, `Delete File:foo.ts`,\n * `Move to:foo.ts`, `***foo.ts`, `***Update File:foo.ts`.\n *\n * We strip a leading `***` (the model duplicating the header sigil) and a\n * leading `(Update|Add|Delete|Move)[<separator>]*(File|to)?[<separator>]*:`\n * keyword block, case-insensitive. The remaining text is the real path.\n */\nconst APPLY_PATCH_PATH_NOISE_RE =\n\t/^\\*{0,3}\\s*(?:(?:update|add|delete|move)[^A-Za-z0-9]*(?:file|to)?[^A-Za-z0-9]*:)?\\s*\\*{0,3}\\s*/i;\n\nfunction stripApplyPatchPathNoise(pathText: string): string {\n\treturn pathText.replace(APPLY_PATCH_PATH_NOISE_RE, \"\");\n}\n\n/**\n * Best-effort recovery for bracketed header lines the strict tokenizer\n * rejects. Strips apply_patch keyword noise (`Update File:`, `Update:`,\n * etc.) and an extra leading `***` (some models emit a hybrid\n * `[***foo.ts#HASH]` shape), then expects `PATH(#HASH)?`.\n * Returns `null` when no clean path can be salvaged.\n */\nfunction tryParseRecoveryHeader(line: string, cwd?: string): RawSection | null {\n\tif (!line.startsWith(HL_FILE_PREFIX) || !line.endsWith(HL_FILE_SUFFIX)) return null;\n\tconst body = stripApplyPatchPathNoise(line.slice(HL_FILE_PREFIX.length, line.length - HL_FILE_SUFFIX.length).trim());\n\tif (body.length === 0) return null;\n\n\t// Trailing `#XXXX` is the tag; everything before it is the path. The\n\t// path may contain whitespace (Windows OneDrive folders, Program Files,\n\t// etc.), so we anchor the tag at end-of-body rather than scanning\n\t// forward and stopping at the first space.\n\tconst trailing = new RegExp(`#([0-9A-Fa-f]{${HL_FILE_HASH_LENGTH}})\\\\s*$`).exec(body);\n\tlet pathText: string;\n\tlet fileHash: string | undefined;\n\tif (trailing !== null) {\n\t\tpathText = body.slice(0, trailing.index);\n\t\tfileHash = trailing[1].toUpperCase();\n\t} else {\n\t\tpathText = body.replace(/\\s+$/, \"\");\n\t}\n\n\t// Same rule as the strict tokenizer: the hashline header grammar uses\n\t// `#` as the path/tag separator and does not allow `#` inside\n\t// filenames. Anything `#` left in the path body — short tags, non-hex\n\t// tags, over-long tags, stale-tag copy-paste, line-suffixed tags —\n\t// means the header is malformed, not a path with an embedded hash.\n\tif (pathText.includes(\"#\")) return null;\n\n\tconst path = normalizeHashlinePath(pathText, cwd);\n\tif (path.length === 0) return null;\n\treturn fileHash !== undefined ? { path, fileHash, diff: \"\" } : { path, diff: \"\" };\n}\n\nfunction normalizeHashlinePath(rawPath: string, cwd?: string): string {\n\tconst unquoted = stripApplyPatchPathNoise(unquoteHashlinePath(rawPath.trim()));\n\tif (!cwd || !path.isAbsolute(unquoted)) return unquoted;\n\tconst relative = path.relative(path.resolve(cwd), path.resolve(unquoted));\n\tconst isWithinCwd = relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n\treturn isWithinCwd ? relative || \".\" : unquoted;\n}\n\ninterface RawSection {\n\tpath: string;\n\tfileHash?: string;\n\tdiff: string;\n}\n\n/**\n * Parse a `[PATH]` or `[PATH#hash]` header line. Returns `null` for lines that do\n * not start with `[`. Throws the strict \"Input header must be …\" error\n * when a bracketed line fails the strict shape (so malformed paths\n * surface immediately instead of being silently re-classified as payload).\n */\nfunction parseHashlineHeaderLine(line: string, cwd?: string): RawSection | null {\n\tconst trimmed = line.trimEnd();\n\tif (!trimmed.startsWith(HL_FILE_PREFIX)) return null;\n\n\tconst token = TOKENIZER.tokenize(trimmed);\n\tif (token.kind !== \"header\") {\n\t\t// Recovery: try to extract a path from the raw line after stripping\n\t\t// apply_patch noise. This handles `[*** Update File:foo.ts#CB5A]` and\n\t\t// the half-dozen variants models actually emit.\n\t\tconst recovered = tryParseRecoveryHeader(trimmed, cwd);\n\t\tif (recovered !== null) return recovered;\n\t\tthrow new Error(\n\t\t\t`Input header must be ${HL_FILE_PREFIX}PATH${HL_FILE_SUFFIX} or ${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}TAG${HL_FILE_SUFFIX} with a ${HL_FILE_HASH_LENGTH}-hex content-hash tag; got ${JSON.stringify(trimmed)}.`,\n\t\t);\n\t}\n\n\tconst parsedPath = normalizeHashlinePath(token.path, cwd);\n\tif (parsedPath.length === 0) {\n\t\tthrow new Error(`Input header \"${HL_FILE_PREFIX}${HL_FILE_SUFFIX}\" is empty; provide a file path.`);\n\t}\n\treturn token.fileHash !== undefined\n\t\t? { path: parsedPath, fileHash: token.fileHash, diff: \"\" }\n\t\t: { path: parsedPath, diff: \"\" };\n}\n\nfunction stripLeadingBlankLines(input: string): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst lines = stripped.split(\"\\n\");\n\twhile (lines.length > 0) {\n\t\tconst head = lines[0].replace(/\\r$/, \"\");\n\t\tif (head.trim().length === 0 || TOKENIZER.tokenize(head).kind === \"envelope-begin\") {\n\t\t\tlines.shift();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Returns true when the input contains at least one line that the tokenizer\n * recognizes as a hashline op. Used by streaming previews to decide whether\n * the partial input is worth treating as a hashline patch yet.\n */\nexport function containsRecognizableHashlineOperations(input: string): boolean {\n\tfor (const line of input.split(/\\r?\\n/)) {\n\t\tif (TOKENIZER.isOp(line)) return true;\n\t}\n\treturn false;\n}\n\nfunction normalizeFallbackInput(input: string, options: SplitOptions): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst hasExplicitHeader = stripped\n\t\t.split(/\\r?\\n/)\n\t\t.some((rawLine) => parseHashlineHeaderLine(rawLine, options.cwd) !== null);\n\tif (hasExplicitHeader) return input;\n\n\tif (!options.path || !containsRecognizableHashlineOperations(input)) return input;\n\tconst fallbackPath = normalizeHashlinePath(options.path, options.cwd);\n\tif (fallbackPath.length === 0) return input;\n\treturn `${HL_FILE_PREFIX}${fallbackPath}${HL_FILE_SUFFIX}\\n${input}`;\n}\n\nfunction splitRawSections(input: string, options: SplitOptions = {}): RawSection[] {\n\tconst stripped = stripLeadingBlankLines(normalizeFallbackInput(input, options));\n\tconst lines = stripped.split(/\\r?\\n/);\n\tconst firstLine = lines[0] ?? \"\";\n\n\tif (parseHashlineHeaderLine(firstLine, options.cwd) === null) {\n\t\t// Catch unified-diff hunk-header contamination on the first line so\n\t\t// the model sees a focused error.\n\t\tconst firstTrimmed = firstLine.trimEnd();\n\t\tif (/^@@\\s+[-+]?\\d+,\\d+\\s+[-+]?\\d+,\\d+\\s+@@/.test(firstTrimmed)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"unified-diff hunk header (`@@ -N,M +N,M @@`) is not valid in hashline. \" +\n\t\t\t\t\t`File sections start with \\`${HL_FILE_PREFIX}path${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\\`; use \\`replace\\`, \\`delete\\`, or \\`insert\\` ops.`,\n\t\t\t);\n\t\t}\n\t\tconst preview = JSON.stringify(firstLine.slice(0, 120));\n\t\tthrow new Error(\n\t\t\t`input must begin with \"${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\" on the first non-blank line for anchored edits; got: ${preview}. ` +\n\t\t\t\t`Example: \"${HL_FILE_PREFIX}src/foo.ts${HL_FILE_HASH_SEP}${HL_FILE_HASH_EXAMPLES[0]}${HL_FILE_SUFFIX}\" then edit ops.`,\n\t\t);\n\t}\n\n\tconst sections: RawSection[] = [];\n\tlet current: RawSection | undefined;\n\tlet currentLines: string[] = [];\n\n\tconst flush = () => {\n\t\tif (!current) return;\n\t\tconst hasOps = currentLines.some((line) => line.trim().length > 0);\n\t\tif (hasOps) sections.push({ ...current, diff: currentLines.join(\"\\n\") });\n\t\tcurrentLines = [];\n\t};\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trimEnd();\n\t\tconst token = TOKENIZER.tokenize(line);\n\t\tif (token.kind === \"envelope-end\" || token.kind === \"abort\") break;\n\t\tif (token.kind === \"envelope-begin\") continue;\n\n\t\t// Route every bracket-prefixed line through parseHashlineHeaderLine so\n\t\t// malformed headers still raise the strict \"Input header must be …\"\n\t\t// diagnostic (the tokenizer alone would silently classify them as\n\t\t// payload).\n\t\tif (trimmed.startsWith(HL_FILE_PREFIX)) {\n\t\t\tconst header = parseHashlineHeaderLine(line, options.cwd);\n\t\t\tif (header !== null) {\n\t\t\t\tflush();\n\t\t\t\tcurrent = header;\n\t\t\t\tcurrentLines = [];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tcurrentLines.push(line);\n\t}\n\tflush();\n\treturn sections;\n}\n\n/**\n * Snapshot of one section in a parsed {@link Patch}: a target file plus the\n * lazily-parsed list of edits that should land on it. Constructed by\n * {@link Patch.parse}; consumers usually iterate `patch.sections` rather\n * than build these directly.\n */\nexport class PatchSection {\n\treadonly path: string;\n\treadonly fileHash: string | undefined;\n\treadonly diff: string;\n\t#parsed: { edits: Edit[]; warnings: string[] } | undefined;\n\n\tconstructor(raw: RawSection) {\n\t\tthis.path = raw.path;\n\t\tthis.fileHash = raw.fileHash;\n\t\tthis.diff = raw.diff;\n\t}\n\n\t/**\n\t * Parse this section's diff body. Cached: subsequent calls return the\n\t * same `{ edits, warnings }` object so callers can safely call this from\n\t * multiple paths (preflight, apply, diff-preview).\n\t */\n\tparse(): { edits: Edit[]; warnings: readonly string[] } {\n\t\tthis.#parsed ??= parsePatch(this.diff);\n\t\treturn this.#parsed;\n\t}\n\n\t/** Parsed edits for this section. */\n\tget edits(): readonly Edit[] {\n\t\treturn this.parse().edits;\n\t}\n\n\t/** Warnings emitted during parsing of this section. */\n\tget warnings(): readonly string[] {\n\t\treturn this.parse().warnings;\n\t}\n\n\t/**\n\t * True when at least one edit anchors to concrete file content. Pure\n\t * `insert head:` / `insert tail:` literal inserts do not count: those are\n\t * safe to apply to files that don't yet exist.\n\t */\n\tget hasAnchorScopedEdit(): boolean {\n\t\treturn this.edits.some((edit) => {\n\t\t\tif (edit.kind === \"delete\") return true;\n\t\t\t// A `replace block N:` edit is anchored to concrete content on line N.\n\t\t\tif (edit.kind === \"block\") return true;\n\t\t\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\";\n\t\t});\n\t}\n\n\t/** Anchor lines touched by this section, sorted ascending and deduplicated. */\n\tcollectAnchorLines(): readonly number[] {\n\t\tconst lines = new Set<number>();\n\t\tfor (const edit of this.edits) {\n\t\t\tif (edit.kind === \"delete\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.kind === \"block\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\") {\n\t\t\t\tlines.add(edit.cursor.anchor.line);\n\t\t\t}\n\t\t}\n\t\treturn [...lines].sort((a, b) => a - b);\n\t}\n\n\t/**\n\t * Apply this section's edits to `text` and return the post-edit result.\n\t * Pure: does no I/O, does not validate the section snapshot tag. The\n\t * {@link Patcher} owns tag validation and recovery; reach for this\n\t * method directly when you've already validated the file content and\n\t * just want the result.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block throws (this is the final, authoritative preview path).\n\t */\n\tapplyTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = this.parse();\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"throw\",\n\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\t// Preserve parse warnings so consumers don't need to call `parse()`\n\t\t// separately.\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n\n\t/**\n\t * Streaming-tolerant counterpart to {@link applyTo}. Uses\n\t * {@link parsePatchStreaming} so a trailing in-flight op (no payload yet,\n\t * or a per-token parse error mid-stream) does not throw or emit a phantom\n\t * empty-payload edit. Intended for incremental diff previews; the writer\n\t * path should always use {@link applyTo}.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block is silently dropped so a half-written file does not\n\t * throw mid-stream.\n\t */\n\tapplyPartialTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = parsePatchStreaming(this.diff);\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"drop\",\n\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n}\n\n/**\n * A parsed hashline patch — zero or more {@link PatchSection}s, each rooted\n * at a `[PATH#HASH]` header. Construct via {@link Patch.parse}.\n *\n * `Patch` is pure data: parsing is line-anchored and does not look at the\n * filesystem. To apply a patch, hand it to {@link Patcher.apply}.\n */\nexport class Patch {\n\treadonly sections: readonly PatchSection[];\n\n\tprivate constructor(sections: PatchSection[]) {\n\t\tthis.sections = sections;\n\t}\n\n\t/**\n\t * Parse `input` into a {@link Patch}. `options.cwd` resolves absolute\n\t * paths inside headers to cwd-relative form; `options.path` provides a\n\t * fallback when the input lacks a header but contains hashline ops\n\t * (useful for streaming previews).\n\t *\n\t * Consecutive sections targeting the same path are merged into a single\n\t * section with concatenated diff bodies. Anchors authored against the\n\t * same file snapshot must be applied as one batch; otherwise the first\n\t * sub-edit shifts line numbers out from under the second's anchors and\n\t * validation fails.\n\t */\n\tstatic parse(input: string, options: SplitOptions = {}): Patch {\n\t\tconst raw = mergeSamePathSections(splitRawSections(input, options));\n\t\treturn new Patch(raw.map((section) => new PatchSection(section)));\n\t}\n\n\t/**\n\t * Parse `input` and return only the first section. Throws if the input\n\t * has zero sections. Convenience for the single-section case where the\n\t * caller already knows the patch is one hunk.\n\t */\n\tstatic parseSingle(input: string, options: SplitOptions = {}): PatchSection {\n\t\tconst patch = Patch.parse(input, options);\n\t\tconst first = patch.sections[0];\n\t\tif (!first) throw new Error(\"Patch input did not produce any sections.\");\n\t\treturn first;\n\t}\n}\n\n/**\n * Collapse consecutive or interleaved sections targeting the same path into a\n * single section with concatenated diffs. Anchors authored against the same\n * file snapshot must be applied as one batch; otherwise the first sub-edit\n * shifts line numbers out from under the second's anchors and validation\n * fails. Path order is preserved by first occurrence.\n */\nfunction mergeSamePathSections(sections: RawSection[]): RawSection[] {\n\tconst byPath = new Map<string, { fileHash?: string; diffs: string[] }>();\n\tfor (const section of sections) {\n\t\tconst existing = byPath.get(section.path);\n\t\tif (existing) {\n\t\t\tif (\n\t\t\t\texisting.fileHash !== undefined &&\n\t\t\t\tsection.fileHash !== undefined &&\n\t\t\t\texisting.fileHash !== section.fileHash\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Conflicting hashline snapshot tags for ${section.path}: #${existing.fileHash} and #${section.fileHash}. Re-read the file and retry with one current header.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (existing.fileHash === undefined && section.fileHash !== undefined) existing.fileHash = section.fileHash;\n\t\t\texisting.diffs.push(section.diff);\n\t\t\tcontinue;\n\t\t}\n\t\tbyPath.set(section.path, {\n\t\t\t...(section.fileHash !== undefined ? { fileHash: section.fileHash } : {}),\n\t\t\tdiffs: [section.diff],\n\t\t});\n\t}\n\treturn Array.from(byPath, ([sectionPath, entry]) => ({\n\t\tpath: sectionPath,\n\t\t...(entry.fileHash !== undefined ? { fileHash: entry.fileHash } : {}),\n\t\tdiff: entry.diffs.join(\"\\n\"),\n\t}));\n}\n"]}
|
|
@@ -35,6 +35,12 @@ export function parseTag(ref) {
|
|
|
35
35
|
* diagnostic via {@link MismatchError.displayMessage}.
|
|
36
36
|
*/
|
|
37
37
|
export class MismatchError extends Error {
|
|
38
|
+
path;
|
|
39
|
+
expectedFileHash;
|
|
40
|
+
actualFileHash;
|
|
41
|
+
fileLines;
|
|
42
|
+
anchorLines;
|
|
43
|
+
hashRecognized;
|
|
38
44
|
constructor(details) {
|
|
39
45
|
super(MismatchError.formatMessage(details));
|
|
40
46
|
this.name = "MismatchError";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mismatch.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/mismatch.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iLAAiL;AACjL;;;;;;;GAOG;AACH,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,GAAG,kCAAkC,CAAC;AACvD,qFAAqF;AACrF,MAAM,UAAU,2BAA2B,CAAC,GAAY;IACvD,MAAM,QAAQ,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9E,OAAO,CACN,sFAAsF;QACtF,gBAAgB,cAAc,aAAa,gBAAgB,GAAG,qBAAqB,CAAC,CAAC,CAAC,GAAG,cAAc,mBAAmB,QAAQ,EAAE,CACpI,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,QAAQ,CAAC,GAAW;IACnC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oCAAoC,2BAA2B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,QAAQ,GAAG,IAAI,CAAC,CAAC;IACpF,OAAO,EAAE,IAAI,EAAE,CAAC;AACjB,CAAC;AAkBD;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"mismatch.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/mismatch.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iLAAiL;AACjL;;;;;;;GAOG;AACH,OAAO,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,GAAG,kCAAkC,CAAC;AACvD,qFAAqF;AACrF,MAAM,UAAU,2BAA2B,CAAC,GAAY;IACvD,MAAM,QAAQ,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;IAC9E,OAAO,CACN,sFAAsF;QACtF,gBAAgB,cAAc,aAAa,gBAAgB,GAAG,qBAAqB,CAAC,CAAC,CAAC,GAAG,cAAc,mBAAmB,QAAQ,EAAE,CACpI,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,QAAQ,CAAC,GAAW;IACnC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,oCAAoC,2BAA2B,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3C,IAAI,IAAI,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,QAAQ,GAAG,IAAI,CAAC,CAAC;IACpF,OAAO,EAAE,IAAI,EAAE,CAAC;AACjB,CAAC;AAkBD;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC9B,IAAI,CAAqB;IACzB,gBAAgB,CAAS;IACzB,cAAc,CAAS;IACvB,SAAS,CAAW;IACpB,WAAW,CAAoB;IAC/B,cAAc,CAAU;IAEjC,YAAY,OAAwB;QACnC,KAAK,CAAC,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACjD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;QAC7C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC;IACtD,CAAC;IAED,IAAI,cAAc;QACjB,OAAO,aAAa,CAAC,oBAAoB,CAAC;YACzC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;SACnC,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,eAAe,CAAC,OAAwB;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5D,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC;QACtD,IAAI,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO;gBACN,gBAAgB,QAAQ,UAAU,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,4BAA4B;gBACzG,8BAA8B,gBAAgB,GAAG,OAAO,CAAC,cAAc,sDAAsD,cAAc,OAAO,gBAAgB,MAAM,cAAc,0EAA0E;aAChQ,CAAC;QACH,CAAC;QACD,OAAO;YACN,gBAAgB,QAAQ,uCAAuC;YAC/D,uBAAuB,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,oCAAoC,gBAAgB,GAAG,OAAO,CAAC,cAAc,kEAAkE,cAAc,OAAO,gBAAgB,UAAU,cAAc,iHAAiH;SAC/X,CAAC;IACH,CAAC;IAED,MAAM,CAAC,oBAAoB,CAAC,OAAwB;QACnD,OAAO,aAAa,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,MAAM,CAAC,aAAa,CAAC,OAAwB;QAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;QACpF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CACD;AAED,0EAA0E;AAC1E,MAAM,UAAU,eAAe,CAAC,GAAqB,EAAE,SAAmB;IACzE,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,QAAQ,GAAG,CAAC,IAAI,6BAA6B,SAAS,CAAC,MAAM,SAAS,CAAC,CAAC;IACzF,CAAC;AACF,CAAC","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Error type raised when a section's snapshot tag does not match the live file\n * content and recovery is unavailable / has failed.\n *\n * Carries enough context to render a useful diagnostic: the anchored lines\n * plus a couple of lines of surrounding context. The {@link MismatchError}\n * formats this into a message at construction time.\n */\nimport { HL_FILE_HASH_EXAMPLES, HL_FILE_HASH_SEP, HL_FILE_PREFIX, HL_FILE_SUFFIX } from \"./format.js\";\nimport { formatAnchoredContext } from \"./messages.js\";\n\nconst LINE_REF_RE = /^\\s*[>+\\-*]*\\s*(\\d+)(?::.*)?\\s*$/;\n/** Format the required-shape diagnostic shown when a line reference is malformed. */\nexport function formatFullAnchorRequirement(raw?: string): string {\n\tconst received = raw === undefined ? \"\" : ` Received ${JSON.stringify(raw)}.`;\n\treturn (\n\t\t`a bare line number from read/search output plus the section header content-hash tag ` +\n\t\t`(for example ${HL_FILE_PREFIX}src/foo.ts${HL_FILE_HASH_SEP}${HL_FILE_HASH_EXAMPLES[0]}${HL_FILE_SUFFIX} and line \"160\")${received}`\n\t);\n}\n\n/** Parse a decorated bare line-number anchor like `42`, `*42:foo`, ` > 7`. */\nexport function parseTag(ref: string): { line: number } {\n\tconst match = ref.match(LINE_REF_RE);\n\tif (!match) {\n\t\tthrow new Error(`Invalid line reference. Expected ${formatFullAnchorRequirement(ref)}.`);\n\t}\n\tconst line = Number.parseInt(match[1], 10);\n\tif (line < 1) throw new Error(`Line number must be >= 1, got ${line} in \"${ref}\".`);\n\treturn { line };\n}\n\nexport interface MismatchDetails {\n\tpath?: string;\n\texpectedFileHash: string;\n\tactualFileHash: string;\n\tfileLines: string[];\n\tanchorLines?: readonly number[];\n\t/**\n\t * `true` when the section's expected hash resolved to a recorded snapshot\n\t * (file content drifted since that snapshot), `false` when no snapshot\n\t * was ever recorded for the hash (likely fabricated or carried over from\n\t * a prior session). Drives a more actionable rejection message; defaults\n\t * to `true` for backward compatibility with direct callers.\n\t */\n\thashRecognized?: boolean;\n}\n\n/**\n * Raised when a hashline section's snapshot tag doesn't match the live file's\n * content (and recovery, if configured, declined the merge). Carries the\n * file lines plus anchored lines so renderers can produce a richer\n * diagnostic via {@link MismatchError.displayMessage}.\n */\nexport class MismatchError extends Error {\n\treadonly path: string | undefined;\n\treadonly expectedFileHash: string;\n\treadonly actualFileHash: string;\n\treadonly fileLines: string[];\n\treadonly anchorLines: readonly number[];\n\treadonly hashRecognized: boolean;\n\n\tconstructor(details: MismatchDetails) {\n\t\tsuper(MismatchError.formatMessage(details));\n\t\tthis.name = \"MismatchError\";\n\t\tthis.path = details.path;\n\t\tthis.expectedFileHash = details.expectedFileHash;\n\t\tthis.actualFileHash = details.actualFileHash;\n\t\tthis.fileLines = details.fileLines;\n\t\tthis.anchorLines = details.anchorLines ?? [];\n\t\tthis.hashRecognized = details.hashRecognized ?? true;\n\t}\n\n\tget displayMessage(): string {\n\t\treturn MismatchError.formatDisplayMessage({\n\t\t\tpath: this.path,\n\t\t\texpectedFileHash: this.expectedFileHash,\n\t\t\tactualFileHash: this.actualFileHash,\n\t\t\tfileLines: this.fileLines,\n\t\t\tanchorLines: this.anchorLines,\n\t\t\thashRecognized: this.hashRecognized,\n\t\t});\n\t}\n\n\tstatic rejectionHeader(details: MismatchDetails): string[] {\n\t\tconst pathText = details.path ? ` for ${details.path}` : \"\";\n\t\tconst hashRecognized = details.hashRecognized ?? true;\n\t\tif (!hashRecognized) {\n\t\t\treturn [\n\t\t\t\t`Edit rejected${pathText}: hash ${HL_FILE_HASH_SEP}${details.expectedFileHash} is not from this session.`,\n\t\t\t\t`The current file hashes to ${HL_FILE_HASH_SEP}${details.actualFileHash}. Re-read the file with \\`read\\` to copy a current ${HL_FILE_PREFIX}path${HL_FILE_HASH_SEP}tag${HL_FILE_SUFFIX} header — never invent the tag and never reuse one from a prior session.`,\n\t\t\t];\n\t\t}\n\t\treturn [\n\t\t\t`Edit rejected${pathText}: file changed between read and edit.`,\n\t\t\t`Section is bound to ${HL_FILE_HASH_SEP}${details.expectedFileHash}, but the current file hashes to ${HL_FILE_HASH_SEP}${details.actualFileHash}. If a prior edit in this session modified this file, copy the ${HL_FILE_PREFIX}path${HL_FILE_HASH_SEP}newhash${HL_FILE_SUFFIX} header from that edit's response; otherwise re-read the file with \\`read\\` to refresh the tag before retrying.`,\n\t\t];\n\t}\n\n\tstatic formatDisplayMessage(details: MismatchDetails): string {\n\t\treturn MismatchError.formatMessage(details);\n\t}\n\n\tstatic formatMessage(details: MismatchDetails): string {\n\t\tconst lines = MismatchError.rejectionHeader(details);\n\t\tconst context = formatAnchoredContext(details.anchorLines ?? [], details.fileLines);\n\t\tif (context.length === 0) return lines.join(\"\\n\");\n\t\tlines.push(\"\", ...context);\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/** Throws when the line reference is out of bounds for the given file. */\nexport function validateLineRef(ref: { line: number }, fileLines: string[]): void {\n\tif (ref.line < 1 || ref.line > fileLines.length) {\n\t\tthrow new Error(`Line ${ref.line} does not exist (file has ${fileLines.length} lines)`);\n\t}\n}\n"]}
|
|
@@ -39,6 +39,15 @@ import { Recovery } from "./recovery.js";
|
|
|
39
39
|
* {@link Patcher.commit} just writes the {@link PreparedSection.applyResult}.
|
|
40
40
|
*/
|
|
41
41
|
export class PreparedSection {
|
|
42
|
+
section;
|
|
43
|
+
canonicalPath;
|
|
44
|
+
exists;
|
|
45
|
+
rawContent;
|
|
46
|
+
bom;
|
|
47
|
+
lineEnding;
|
|
48
|
+
normalized;
|
|
49
|
+
applyResult;
|
|
50
|
+
parseWarnings;
|
|
42
51
|
/** @internal */
|
|
43
52
|
constructor(section, canonicalPath, exists, rawContent, bom, lineEnding, normalized, applyResult, parseWarnings) {
|
|
44
53
|
this.section = section;
|
|
@@ -105,6 +114,10 @@ function assertUniqueCanonicalPaths(prepared) {
|
|
|
105
114
|
* Construct once per FS configuration; reuse across patches.
|
|
106
115
|
*/
|
|
107
116
|
export class Patcher {
|
|
117
|
+
fs;
|
|
118
|
+
snapshots;
|
|
119
|
+
recovery;
|
|
120
|
+
blockResolver;
|
|
108
121
|
constructor(options) {
|
|
109
122
|
if (!options.snapshots) {
|
|
110
123
|
throw new Error("Hashline Patcher requires a SnapshotStore; section tags are opaque store pointers.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patcher.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/patcher.ts"],"names":[],"mappings":"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","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * High-level patch orchestrator. Reads each section's target file via the\n * configured {@link Filesystem}, strips BOM and normalizes line endings,\n * validates the section snapshot tag (with {@link Recovery}), applies the\n * result back through the same {@link Filesystem}.\n *\n * Two layers:\n * - {@link Patcher.apply} — high-level, preflight-atomic. It validates and\n * applies every section in memory before any write hits disk, then commits\n * in order. It is not write-transactional: a mid-batch filesystem failure\n * can leave earlier sections already written, and the thrown error reports\n * which sections landed.\n * - {@link Patcher.prepare} / {@link Patcher.commit} — granular primitives\n * for callers that need per-section control (e.g. batched LSP flush,\n * custom interleaving). `prepare` performs all the read-side work,\n * validates the section snapshot tag (with recovery), and applies the\n * edits in memory. `commit` writes the prepared result and records a\n * fresh snapshot.\n *\n * Because `prepare` already runs the full apply, a multi-section batch fails\n * before any write when parsing, stale-tag validation, or in-memory apply fails.\n *\n * The patcher itself is stateless across calls; reuse one instance per\n * filesystem configuration.\n */\nimport { applyEdits } from \"./apply.js\";\nimport { hasBlockEdit, resolveBlockEdits } from \"./block.js\";\nimport { computeFileHash, formatHashlineHeader } from \"./format.js\";\nimport type { Filesystem, WriteResult } from \"./fs.js\";\nimport { isNotFound } from \"./fs.js\";\nimport type { Patch, PatchSection } from \"./input.js\";\nimport { HEADTAIL_DRIFT_WARNING, missingSnapshotTagMessage } from \"./messages.js\";\nimport { MismatchError } from \"./mismatch.js\";\nimport { detectLineEnding, type LineEnding, normalizeToLF, restoreLineEndings, stripBom } from \"./normalize.js\";\nimport { Recovery, type RecoveryResult } from \"./recovery.js\";\nimport type { SnapshotStore } from \"./snapshots.js\";\nimport type { ApplyResult, BlockResolution, BlockResolver, Edit } from \"./types.js\";\n\nexport interface PatcherOptions {\n\t/** Storage backend used for all reads and writes. */\n\tfs: Filesystem;\n\t/** Snapshot store that minted and resolves hashline section tags. Required. */\n\tsnapshots: SnapshotStore;\n\t/**\n\t * Resolves `replace block N:` anchors to concrete line spans via tree-sitter.\n\t * Optional: when omitted, any `replace block N:` edit throws on apply (the\n\t * host did not wire a resolver). Plain line-range ops never need it.\n\t */\n\tblockResolver?: BlockResolver;\n}\n\n/** Per-section result returned by {@link Patcher.apply} / {@link Patcher.commit}. */\nexport interface PatchSectionResult {\n\t/** Section path (as authored, after cwd-resolution at parse time). */\n\tpath: string;\n\t/** Filesystem-canonical key for this section (e.g. absolute path). */\n\tcanonicalPath: string;\n\t/** `\"noop\"` when the apply produced no change; otherwise `\"create\"` / `\"update\"`. */\n\top: \"create\" | \"update\" | \"noop\";\n\t/** Pre-edit text (LF-normalized, BOM-stripped). */\n\tbefore: string;\n\t/** Post-edit text (LF-normalized, BOM-stripped). For `\"noop\"` equals `before`. */\n\tafter: string;\n\t/** Same text as `after` but with the original BOM and line ending restored. */\n\tpersisted: string;\n\t/** Final text that the {@link Filesystem} actually wrote (may differ if the FS transformed it). */\n\twritten: string;\n\t/** 4-hex content-hash tag for `after`. Use to anchor follow-up edits. */\n\tfileHash: string;\n\t/** Hashline section header (`[path#tag]`) of the post-edit content. */\n\theader: string;\n\t/** 1-indexed first changed line in `after`, or `undefined` for noops. */\n\tfirstChangedLine?: number;\n\t/** Warnings collected by the parser, applier, and (optionally) recovery. */\n\twarnings: string[];\n\t/**\n\t * Resolved spans for any `replace block`/`delete block` ops, present when the\n\t * apply matched the tagged content. Undefined for patches with no block ops\n\t * (and for resolutions routed through drift recovery, where numbers shift).\n\t */\n\tblockResolutions?: BlockResolution[];\n}\n\nexport interface PatcherApplyResult {\n\tsections: PatchSectionResult[];\n}\n\n/**\n * Opaque token returned by {@link Patcher.prepare}. Carries the section, the\n * raw file content read off disk, and the in-memory apply result.\n * {@link Patcher.commit} just writes the {@link PreparedSection.applyResult}.\n */\nexport class PreparedSection {\n\treadonly section: PatchSection;\n\treadonly canonicalPath: string;\n\treadonly exists: boolean;\n\treadonly rawContent: string;\n\treadonly bom: string;\n\treadonly lineEnding: LineEnding;\n\treadonly normalized: string;\n\treadonly applyResult: ApplyResult;\n\treadonly parseWarnings: readonly string[];\n\t/** @internal */\n\tconstructor(\n\t\tsection: PatchSection,\n\t\tcanonicalPath: string,\n\t\texists: boolean,\n\t\trawContent: string,\n\t\tbom: string,\n\t\tlineEnding: LineEnding,\n\t\tnormalized: string,\n\t\tapplyResult: ApplyResult,\n\t\tparseWarnings: readonly string[],\n\t) {\n\t\tthis.section = section;\n\t\tthis.canonicalPath = canonicalPath;\n\t\tthis.exists = exists;\n\t\tthis.rawContent = rawContent;\n\t\tthis.bom = bom;\n\t\tthis.lineEnding = lineEnding;\n\t\tthis.normalized = normalized;\n\t\tthis.applyResult = applyResult;\n\t\tthis.parseWarnings = parseWarnings;\n\t}\n\n\t/** Convenience: returns true when the apply produced no change. */\n\tget isNoop(): boolean {\n\t\treturn this.applyResult.text === this.normalized;\n\t}\n}\n\nfunction hasAnchorScopedEdit(edits: readonly Edit[]): boolean {\n\treturn edits.some((edit) => {\n\t\tif (edit.kind === \"delete\") return true;\n\t\t// A `replace block N:` edit anchors to concrete content on line N.\n\t\tif (edit.kind === \"block\") return true;\n\t\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\";\n\t});\n}\n\nfunction assertSectionHashPresent(sectionPath: string, fileHash: string | undefined): void {\n\tif (fileHash !== undefined) return;\n\tthrow new Error(missingSnapshotTagMessage(sectionPath));\n}\n\nfunction recoveryToApplyResult(result: RecoveryResult): ApplyResult {\n\treturn {\n\t\ttext: result.text,\n\t\tfirstChangedLine: result.firstChangedLine,\n\t\twarnings: result.warnings,\n\t};\n}\nfunction mergeWarnings(...sources: ReadonlyArray<readonly string[] | undefined>): string[] {\n\tconst out: string[] = [];\n\tfor (const source of sources) {\n\t\tif (!source) continue;\n\t\tfor (const warning of source) out.push(warning);\n\t}\n\treturn out;\n}\n\nfunction assertUniqueCanonicalPaths(prepared: readonly PreparedSection[]): void {\n\tconst seen = new Map<string, string>();\n\tfor (const entry of prepared) {\n\t\tconst previous = seen.get(entry.canonicalPath);\n\t\tif (previous !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.`,\n\t\t\t);\n\t\t}\n\t\tseen.set(entry.canonicalPath, entry.section.path);\n\t}\n}\n\n/**\n * High-level patcher. Wires a {@link Filesystem} and a required\n * {@link SnapshotStore} together with the parsing + applying core.\n *\n * Construct once per FS configuration; reuse across patches.\n */\nexport class Patcher {\n\treadonly fs: Filesystem;\n\treadonly snapshots: SnapshotStore;\n\treadonly recovery: Recovery;\n\treadonly blockResolver: BlockResolver | undefined;\n\n\tconstructor(options: PatcherOptions) {\n\t\tif (!options.snapshots) {\n\t\t\tthrow new Error(\"Hashline Patcher requires a SnapshotStore; section tags are opaque store pointers.\");\n\t\t}\n\t\tthis.fs = options.fs;\n\t\tthis.snapshots = options.snapshots;\n\t\tthis.recovery = new Recovery(options.snapshots);\n\t\tthis.blockResolver = options.blockResolver;\n\t}\n\n\t/**\n\t * Apply every section in `patch`. `prepare` runs the full apply for each\n\t * section in memory before any write hits the filesystem, so a\n\t * multi-section batch fails before writing on parse/validation/apply errors.\n\t * Write commits are sequential rather than transactional; if a write fails,\n\t * earlier sections may already be on disk and are listed in the thrown error.\n\t * Returns one {@link PatchSectionResult} per section in the original patch order.\n\t */\n\tasync apply(patch: Patch): Promise<PatcherApplyResult> {\n\t\t// Single-section fast path.\n\t\tif (patch.sections.length === 1) {\n\t\t\tconst prepared = await this.prepare(patch.sections[0]);\n\t\t\treturn { sections: [await this.commit(prepared)] };\n\t\t}\n\n\t\t// Prepare every section first so any failure (stale hash, missing\n\t\t// file, parse error, in-memory no-op) surfaces before any write.\n\t\tconst prepared: PreparedSection[] = [];\n\t\tfor (const section of patch.sections) prepared.push(await this.prepare(section));\n\t\tassertUniqueCanonicalPaths(prepared);\n\t\tfor (const entry of prepared) {\n\t\t\tif (entry.isNoop) {\n\t\t\t\tthrow new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);\n\t\t\t}\n\t\t}\n\n\t\tconst results: PatchSectionResult[] = [];\n\t\tfor (let index = 0; index < prepared.length; index++) {\n\t\t\ttry {\n\t\t\t\tresults.push(await this.commit(prepared[index]));\n\t\t\t} catch (error) {\n\t\t\t\t// A mid-batch write failure leaves earlier sections on disk with no\n\t\t\t\t// rollback; report exactly which sections landed so the caller can\n\t\t\t\t// re-issue only the missing ones instead of double-applying.\n\t\t\t\tconst written = prepared.slice(0, index).map((entry) => entry.section.path);\n\t\t\t\tconst notWritten = prepared.slice(index + 1).map((entry) => entry.section.path);\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to write ${prepared[index].section.path}: ${message}` +\n\t\t\t\t\t\t(written.length > 0 ? ` Sections already written: ${written.join(\", \")}.` : \"\") +\n\t\t\t\t\t\t(notWritten.length > 0 ? ` Sections not written: ${notWritten.join(\", \")}.` : \"\"),\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn { sections: results };\n\t}\n\n\t/**\n\t * Run the preflight pass only: read, parse, validate, apply-in-memory.\n\t * No writes hit the filesystem. Use for CI checks and dry runs.\n\t */\n\tasync preflight(patch: Patch): Promise<void> {\n\t\tconst prepared: PreparedSection[] = [];\n\t\tfor (const section of patch.sections) prepared.push(await this.prepare(section));\n\t\tassertUniqueCanonicalPaths(prepared);\n\t\tfor (const entry of prepared) {\n\t\t\tif (entry.isNoop) {\n\t\t\t\tthrow new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Read a section's target file, parse the section, validate the snapshot\n\t * tag (with recovery), and apply the edits in memory. Returns a\n\t * {@link PreparedSection} which can be fed to {@link commit} to land\n\t * the result on the filesystem.\n\t *\n\t * Throws on parse error, missing-file-for-anchored-edit, or unrecovered\n\t * tag mismatch ({@link MismatchError}).\n\t */\n\tasync prepare(section: PatchSection): Promise<PreparedSection> {\n\t\tconst { edits, warnings: parseWarnings } = section.parse();\n\t\tassertSectionHashPresent(section.path, section.fileHash);\n\n\t\tconst canonicalPath = this.fs.canonicalPath(section.path);\n\t\tawait this.fs.preflightWrite(section.path);\n\t\tconst { exists, rawContent } = await this.#tryRead(section.path);\n\t\tif (!exists) {\n\t\t\tthrow new Error(`File not found: ${section.path}. Use the write tool to create new files.`);\n\t\t}\n\n\t\tconst { bom, text } = stripBom(rawContent);\n\t\tconst lineEnding = detectLineEnding(text);\n\t\tconst normalized = normalizeToLF(text);\n\n\t\tconst applyResult = this.#applyWithRecovery({\n\t\t\tsection,\n\t\t\tcanonicalPath,\n\t\t\texists,\n\t\t\tnormalized,\n\t\t\tedits,\n\t\t});\n\n\t\treturn new PreparedSection(\n\t\t\tsection,\n\t\t\tcanonicalPath,\n\t\t\texists,\n\t\t\trawContent,\n\t\t\tbom,\n\t\t\tlineEnding,\n\t\t\tnormalized,\n\t\t\tapplyResult,\n\t\t\tparseWarnings,\n\t\t);\n\t}\n\n\t/**\n\t * Commit a previously {@link prepare}d section to the filesystem.\n\t * Restores line endings and BOM, writes via the {@link Filesystem}, and\n\t * records a fresh snapshot in the {@link SnapshotStore} keyed by the\n\t * filesystem-canonical path.\n\t */\n\tasync commit(prepared: PreparedSection): Promise<PatchSectionResult> {\n\t\tconst { section, normalized, bom, lineEnding, parseWarnings, exists, applyResult, canonicalPath } = prepared;\n\t\tconst after = applyResult.text;\n\t\tconst warnings = mergeWarnings(parseWarnings, applyResult.warnings);\n\n\t\tif (after === normalized) {\n\t\t\tconst hash = this.#recordFullSnapshot(canonicalPath, normalized);\n\t\t\treturn {\n\t\t\t\tpath: section.path,\n\t\t\t\tcanonicalPath,\n\t\t\t\top: \"noop\",\n\t\t\t\tbefore: normalized,\n\t\t\t\tafter: normalized,\n\t\t\t\tpersisted: prepared.rawContent,\n\t\t\t\twritten: prepared.rawContent,\n\t\t\t\tfileHash: hash,\n\t\t\t\theader: formatHashlineHeader(section.path, hash),\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tconst persisted = bom + restoreLineEndings(after, lineEnding);\n\t\tconst write: WriteResult = await this.fs.writeText(section.path, persisted);\n\t\tconst fileHash = this.#recordFullSnapshot(canonicalPath, after);\n\t\tconst op = exists ? \"update\" : \"create\";\n\n\t\treturn {\n\t\t\tpath: section.path,\n\t\t\tcanonicalPath,\n\t\t\top,\n\t\t\tbefore: normalized,\n\t\t\tafter,\n\t\t\tpersisted,\n\t\t\twritten: write.text,\n\t\t\tfileHash,\n\t\t\theader: formatHashlineHeader(section.path, fileHash),\n\t\t\tfirstChangedLine: applyResult.firstChangedLine,\n\t\t\tblockResolutions: applyResult.blockResolutions,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync #tryRead(path: string): Promise<{ exists: boolean; rawContent: string }> {\n\t\ttry {\n\t\t\tconst content = await this.fs.readText(path);\n\t\t\treturn { exists: true, rawContent: content };\n\t\t} catch (error) {\n\t\t\tif (isNotFound(error)) return { exists: false, rawContent: \"\" };\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t#recordFullSnapshot(canonicalPath: string, normalized: string): string {\n\t\treturn this.snapshots.record(canonicalPath, normalized);\n\t}\n\t#mismatchError(\n\t\tsection: PatchSection,\n\t\tcanonicalPath: string,\n\t\tnormalized: string,\n\t\texpected: string,\n\t\thashRecognized: boolean,\n\t): MismatchError {\n\t\tconst actualFileHash = this.#recordFullSnapshot(canonicalPath, normalized);\n\t\treturn new MismatchError({\n\t\t\tpath: section.path,\n\t\t\texpectedFileHash: expected,\n\t\t\tactualFileHash,\n\t\t\tfileLines: normalized.split(\"\\n\"),\n\t\t\tanchorLines: section.collectAnchorLines(),\n\t\t\thashRecognized,\n\t\t});\n\t}\n\n\t#applyWithRecovery(args: {\n\t\tsection: PatchSection;\n\t\tcanonicalPath: string;\n\t\texists: boolean;\n\t\tnormalized: string;\n\t\tedits: readonly Edit[];\n\t}): ApplyResult {\n\t\tconst { section, canonicalPath, exists, normalized, edits } = args;\n\t\tconst expected = exists ? section.fileHash : undefined;\n\t\tconst expectedSnapshot = expected === undefined ? null : this.snapshots.byHash(canonicalPath, expected);\n\t\tconst liveHashMatches = expected !== undefined && computeFileHash(normalized) === expected;\n\t\tconst liveSnapshot =\n\t\t\texpected === undefined ? null : this.snapshots.byHashAndText(canonicalPath, expected, normalized);\n\t\tconst liveMatches = liveHashMatches && liveSnapshot !== null;\n\t\tif (liveHashMatches && !liveMatches) {\n\t\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected, expectedSnapshot !== null);\n\t\t}\n\n\t\t// Resolve `replace block N:` edits to concrete ranges before recovery\n\t\t// runs. Block anchors are expressed against the snapshot the section tag\n\t\t// names, so resolve against that exact text:\n\t\t// - live content matches the tag (or there is no tag) → resolve against\n\t\t// the live, normalized content;\n\t\t// - the file drifted → resolve against the tagged snapshot's text so the\n\t\t// resulting ranges flow through the 3-way-merge recovery below.\n\t\t// When a block edit needs the tagged snapshot but it is unavailable, the\n\t\t// range cannot be placed safely — reject with a MismatchError (re-read).\n\t\tconst blockResolutions: BlockResolution[] = [];\n\t\tconst resolveWarnings: string[] = [];\n\t\tlet resolved: readonly Edit[] = edits;\n\t\tif (hasBlockEdit(edits)) {\n\t\t\tconst baseText = expected === undefined || liveMatches ? normalized : expectedSnapshot?.text;\n\t\t\tif (baseText === undefined) {\n\t\t\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected ?? \"\", false);\n\t\t\t}\n\t\t\tresolved = resolveBlockEdits(edits, baseText, section.path, this.blockResolver, {\n\t\t\t\tonUnresolved: \"throw\",\n\t\t\t\tonResolved: (resolution) => blockResolutions.push(resolution),\n\t\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t\t});\n\t\t}\n\t\tconst withResolveWarnings = (result: ApplyResult): ApplyResult =>\n\t\t\tresolveWarnings.length === 0\n\t\t\t\t? result\n\t\t\t\t: { ...result, warnings: [...resolveWarnings, ...(result.warnings ?? [])] };\n\n\t\t// No tag, or the tag still names the live content: an edit anchored at any\n\t\t// line is safe to apply, and the resolved block spans line up with what\n\t\t// the caller read, so echo them back. (A drifted file falls through to\n\t\t// recovery below, where line numbers shift, so resolutions are dropped.)\n\t\tif (expected === undefined || liveMatches) {\n\t\t\tconst result = applyEdits(normalized, resolved);\n\t\t\treturn withResolveWarnings(blockResolutions.length > 0 ? { ...result, blockResolutions } : result);\n\t\t}\n\t\t// Head/tail-only inserts are position-stable: \"start\"/\"end\" cannot move\n\t\t// with content drift, so a stale tag is non-fatal. Apply onto the live\n\t\t// content and warn instead of hard-failing — unlike an anchored\n\t\t// mismatch, which cannot be safely relocated and must reject.\n\t\tif (!hasAnchorScopedEdit(resolved)) {\n\t\t\tconst result = applyEdits(normalized, resolved);\n\t\t\treturn withResolveWarnings({ ...result, warnings: [HEADTAIL_DRIFT_WARNING, ...(result.warnings ?? [])] });\n\t\t}\n\t\t// File drifted: try to replay the edit against the version the tag\n\t\t// names and 3-way-merge it onto the live content.\n\t\tconst recovered = this.recovery.tryRecover({\n\t\t\tpath: canonicalPath,\n\t\t\tcurrentText: normalized,\n\t\t\tfileHash: expected,\n\t\t\tedits: resolved,\n\t\t});\n\t\tif (recovered) return withResolveWarnings(recoveryToApplyResult(recovered));\n\t\tconst hashRecognized = expectedSnapshot !== null;\n\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected, hashRecognized);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"patcher.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/patcher.ts"],"names":[],"mappings":"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","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * High-level patch orchestrator. Reads each section's target file via the\n * configured {@link Filesystem}, strips BOM and normalizes line endings,\n * validates the section snapshot tag (with {@link Recovery}), applies the\n * result back through the same {@link Filesystem}.\n *\n * Two layers:\n * - {@link Patcher.apply} — high-level, preflight-atomic. It validates and\n * applies every section in memory before any write hits disk, then commits\n * in order. It is not write-transactional: a mid-batch filesystem failure\n * can leave earlier sections already written, and the thrown error reports\n * which sections landed.\n * - {@link Patcher.prepare} / {@link Patcher.commit} — granular primitives\n * for callers that need per-section control (e.g. batched LSP flush,\n * custom interleaving). `prepare` performs all the read-side work,\n * validates the section snapshot tag (with recovery), and applies the\n * edits in memory. `commit` writes the prepared result and records a\n * fresh snapshot.\n *\n * Because `prepare` already runs the full apply, a multi-section batch fails\n * before any write when parsing, stale-tag validation, or in-memory apply fails.\n *\n * The patcher itself is stateless across calls; reuse one instance per\n * filesystem configuration.\n */\nimport { applyEdits } from \"./apply.js\";\nimport { hasBlockEdit, resolveBlockEdits } from \"./block.js\";\nimport { computeFileHash, formatHashlineHeader } from \"./format.js\";\nimport type { Filesystem, WriteResult } from \"./fs.js\";\nimport { isNotFound } from \"./fs.js\";\nimport type { Patch, PatchSection } from \"./input.js\";\nimport { HEADTAIL_DRIFT_WARNING, missingSnapshotTagMessage } from \"./messages.js\";\nimport { MismatchError } from \"./mismatch.js\";\nimport { detectLineEnding, type LineEnding, normalizeToLF, restoreLineEndings, stripBom } from \"./normalize.js\";\nimport { Recovery, type RecoveryResult } from \"./recovery.js\";\nimport type { SnapshotStore } from \"./snapshots.js\";\nimport type { ApplyResult, BlockResolution, BlockResolver, Edit } from \"./types.js\";\n\nexport interface PatcherOptions {\n\t/** Storage backend used for all reads and writes. */\n\tfs: Filesystem;\n\t/** Snapshot store that minted and resolves hashline section tags. Required. */\n\tsnapshots: SnapshotStore;\n\t/**\n\t * Resolves `replace block N:` anchors to concrete line spans via tree-sitter.\n\t * Optional: when omitted, any `replace block N:` edit throws on apply (the\n\t * host did not wire a resolver). Plain line-range ops never need it.\n\t */\n\tblockResolver?: BlockResolver;\n}\n\n/** Per-section result returned by {@link Patcher.apply} / {@link Patcher.commit}. */\nexport interface PatchSectionResult {\n\t/** Section path (as authored, after cwd-resolution at parse time). */\n\tpath: string;\n\t/** Filesystem-canonical key for this section (e.g. absolute path). */\n\tcanonicalPath: string;\n\t/** `\"noop\"` when the apply produced no change; otherwise `\"create\"` / `\"update\"`. */\n\top: \"create\" | \"update\" | \"noop\";\n\t/** Pre-edit text (LF-normalized, BOM-stripped). */\n\tbefore: string;\n\t/** Post-edit text (LF-normalized, BOM-stripped). For `\"noop\"` equals `before`. */\n\tafter: string;\n\t/** Same text as `after` but with the original BOM and line ending restored. */\n\tpersisted: string;\n\t/** Final text that the {@link Filesystem} actually wrote (may differ if the FS transformed it). */\n\twritten: string;\n\t/** 4-hex content-hash tag for `after`. Use to anchor follow-up edits. */\n\tfileHash: string;\n\t/** Hashline section header (`[path#tag]`) of the post-edit content. */\n\theader: string;\n\t/** 1-indexed first changed line in `after`, or `undefined` for noops. */\n\tfirstChangedLine?: number;\n\t/** Warnings collected by the parser, applier, and (optionally) recovery. */\n\twarnings: string[];\n\t/**\n\t * Resolved spans for any `replace block`/`delete block` ops, present when the\n\t * apply matched the tagged content. Undefined for patches with no block ops\n\t * (and for resolutions routed through drift recovery, where numbers shift).\n\t */\n\tblockResolutions?: BlockResolution[];\n}\n\nexport interface PatcherApplyResult {\n\tsections: PatchSectionResult[];\n}\n\n/**\n * Opaque token returned by {@link Patcher.prepare}. Carries the section, the\n * raw file content read off disk, and the in-memory apply result.\n * {@link Patcher.commit} just writes the {@link PreparedSection.applyResult}.\n */\nexport class PreparedSection {\n\treadonly section: PatchSection;\n\treadonly canonicalPath: string;\n\treadonly exists: boolean;\n\treadonly rawContent: string;\n\treadonly bom: string;\n\treadonly lineEnding: LineEnding;\n\treadonly normalized: string;\n\treadonly applyResult: ApplyResult;\n\treadonly parseWarnings: readonly string[];\n\t/** @internal */\n\tconstructor(\n\t\tsection: PatchSection,\n\t\tcanonicalPath: string,\n\t\texists: boolean,\n\t\trawContent: string,\n\t\tbom: string,\n\t\tlineEnding: LineEnding,\n\t\tnormalized: string,\n\t\tapplyResult: ApplyResult,\n\t\tparseWarnings: readonly string[],\n\t) {\n\t\tthis.section = section;\n\t\tthis.canonicalPath = canonicalPath;\n\t\tthis.exists = exists;\n\t\tthis.rawContent = rawContent;\n\t\tthis.bom = bom;\n\t\tthis.lineEnding = lineEnding;\n\t\tthis.normalized = normalized;\n\t\tthis.applyResult = applyResult;\n\t\tthis.parseWarnings = parseWarnings;\n\t}\n\n\t/** Convenience: returns true when the apply produced no change. */\n\tget isNoop(): boolean {\n\t\treturn this.applyResult.text === this.normalized;\n\t}\n}\n\nfunction hasAnchorScopedEdit(edits: readonly Edit[]): boolean {\n\treturn edits.some((edit) => {\n\t\tif (edit.kind === \"delete\") return true;\n\t\t// A `replace block N:` edit anchors to concrete content on line N.\n\t\tif (edit.kind === \"block\") return true;\n\t\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\";\n\t});\n}\n\nfunction assertSectionHashPresent(sectionPath: string, fileHash: string | undefined): void {\n\tif (fileHash !== undefined) return;\n\tthrow new Error(missingSnapshotTagMessage(sectionPath));\n}\n\nfunction recoveryToApplyResult(result: RecoveryResult): ApplyResult {\n\treturn {\n\t\ttext: result.text,\n\t\tfirstChangedLine: result.firstChangedLine,\n\t\twarnings: result.warnings,\n\t};\n}\nfunction mergeWarnings(...sources: ReadonlyArray<readonly string[] | undefined>): string[] {\n\tconst out: string[] = [];\n\tfor (const source of sources) {\n\t\tif (!source) continue;\n\t\tfor (const warning of source) out.push(warning);\n\t}\n\treturn out;\n}\n\nfunction assertUniqueCanonicalPaths(prepared: readonly PreparedSection[]): void {\n\tconst seen = new Map<string, string>();\n\tfor (const entry of prepared) {\n\t\tconst previous = seen.get(entry.canonicalPath);\n\t\tif (previous !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.`,\n\t\t\t);\n\t\t}\n\t\tseen.set(entry.canonicalPath, entry.section.path);\n\t}\n}\n\n/**\n * High-level patcher. Wires a {@link Filesystem} and a required\n * {@link SnapshotStore} together with the parsing + applying core.\n *\n * Construct once per FS configuration; reuse across patches.\n */\nexport class Patcher {\n\treadonly fs: Filesystem;\n\treadonly snapshots: SnapshotStore;\n\treadonly recovery: Recovery;\n\treadonly blockResolver: BlockResolver | undefined;\n\n\tconstructor(options: PatcherOptions) {\n\t\tif (!options.snapshots) {\n\t\t\tthrow new Error(\"Hashline Patcher requires a SnapshotStore; section tags are opaque store pointers.\");\n\t\t}\n\t\tthis.fs = options.fs;\n\t\tthis.snapshots = options.snapshots;\n\t\tthis.recovery = new Recovery(options.snapshots);\n\t\tthis.blockResolver = options.blockResolver;\n\t}\n\n\t/**\n\t * Apply every section in `patch`. `prepare` runs the full apply for each\n\t * section in memory before any write hits the filesystem, so a\n\t * multi-section batch fails before writing on parse/validation/apply errors.\n\t * Write commits are sequential rather than transactional; if a write fails,\n\t * earlier sections may already be on disk and are listed in the thrown error.\n\t * Returns one {@link PatchSectionResult} per section in the original patch order.\n\t */\n\tasync apply(patch: Patch): Promise<PatcherApplyResult> {\n\t\t// Single-section fast path.\n\t\tif (patch.sections.length === 1) {\n\t\t\tconst prepared = await this.prepare(patch.sections[0]);\n\t\t\treturn { sections: [await this.commit(prepared)] };\n\t\t}\n\n\t\t// Prepare every section first so any failure (stale hash, missing\n\t\t// file, parse error, in-memory no-op) surfaces before any write.\n\t\tconst prepared: PreparedSection[] = [];\n\t\tfor (const section of patch.sections) prepared.push(await this.prepare(section));\n\t\tassertUniqueCanonicalPaths(prepared);\n\t\tfor (const entry of prepared) {\n\t\t\tif (entry.isNoop) {\n\t\t\t\tthrow new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);\n\t\t\t}\n\t\t}\n\n\t\tconst results: PatchSectionResult[] = [];\n\t\tfor (let index = 0; index < prepared.length; index++) {\n\t\t\ttry {\n\t\t\t\tresults.push(await this.commit(prepared[index]));\n\t\t\t} catch (error) {\n\t\t\t\t// A mid-batch write failure leaves earlier sections on disk with no\n\t\t\t\t// rollback; report exactly which sections landed so the caller can\n\t\t\t\t// re-issue only the missing ones instead of double-applying.\n\t\t\t\tconst written = prepared.slice(0, index).map((entry) => entry.section.path);\n\t\t\t\tconst notWritten = prepared.slice(index + 1).map((entry) => entry.section.path);\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to write ${prepared[index].section.path}: ${message}` +\n\t\t\t\t\t\t(written.length > 0 ? ` Sections already written: ${written.join(\", \")}.` : \"\") +\n\t\t\t\t\t\t(notWritten.length > 0 ? ` Sections not written: ${notWritten.join(\", \")}.` : \"\"),\n\t\t\t\t\t{ cause: error },\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn { sections: results };\n\t}\n\n\t/**\n\t * Run the preflight pass only: read, parse, validate, apply-in-memory.\n\t * No writes hit the filesystem. Use for CI checks and dry runs.\n\t */\n\tasync preflight(patch: Patch): Promise<void> {\n\t\tconst prepared: PreparedSection[] = [];\n\t\tfor (const section of patch.sections) prepared.push(await this.prepare(section));\n\t\tassertUniqueCanonicalPaths(prepared);\n\t\tfor (const entry of prepared) {\n\t\t\tif (entry.isNoop) {\n\t\t\t\tthrow new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Read a section's target file, parse the section, validate the snapshot\n\t * tag (with recovery), and apply the edits in memory. Returns a\n\t * {@link PreparedSection} which can be fed to {@link commit} to land\n\t * the result on the filesystem.\n\t *\n\t * Throws on parse error, missing-file-for-anchored-edit, or unrecovered\n\t * tag mismatch ({@link MismatchError}).\n\t */\n\tasync prepare(section: PatchSection): Promise<PreparedSection> {\n\t\tconst { edits, warnings: parseWarnings } = section.parse();\n\t\tassertSectionHashPresent(section.path, section.fileHash);\n\n\t\tconst canonicalPath = this.fs.canonicalPath(section.path);\n\t\tawait this.fs.preflightWrite(section.path);\n\t\tconst { exists, rawContent } = await this.#tryRead(section.path);\n\t\tif (!exists) {\n\t\t\tthrow new Error(`File not found: ${section.path}. Use the write tool to create new files.`);\n\t\t}\n\n\t\tconst { bom, text } = stripBom(rawContent);\n\t\tconst lineEnding = detectLineEnding(text);\n\t\tconst normalized = normalizeToLF(text);\n\n\t\tconst applyResult = this.#applyWithRecovery({\n\t\t\tsection,\n\t\t\tcanonicalPath,\n\t\t\texists,\n\t\t\tnormalized,\n\t\t\tedits,\n\t\t});\n\n\t\treturn new PreparedSection(\n\t\t\tsection,\n\t\t\tcanonicalPath,\n\t\t\texists,\n\t\t\trawContent,\n\t\t\tbom,\n\t\t\tlineEnding,\n\t\t\tnormalized,\n\t\t\tapplyResult,\n\t\t\tparseWarnings,\n\t\t);\n\t}\n\n\t/**\n\t * Commit a previously {@link prepare}d section to the filesystem.\n\t * Restores line endings and BOM, writes via the {@link Filesystem}, and\n\t * records a fresh snapshot in the {@link SnapshotStore} keyed by the\n\t * filesystem-canonical path.\n\t */\n\tasync commit(prepared: PreparedSection): Promise<PatchSectionResult> {\n\t\tconst { section, normalized, bom, lineEnding, parseWarnings, exists, applyResult, canonicalPath } = prepared;\n\t\tconst after = applyResult.text;\n\t\tconst warnings = mergeWarnings(parseWarnings, applyResult.warnings);\n\n\t\tif (after === normalized) {\n\t\t\tconst hash = this.#recordFullSnapshot(canonicalPath, normalized);\n\t\t\treturn {\n\t\t\t\tpath: section.path,\n\t\t\t\tcanonicalPath,\n\t\t\t\top: \"noop\",\n\t\t\t\tbefore: normalized,\n\t\t\t\tafter: normalized,\n\t\t\t\tpersisted: prepared.rawContent,\n\t\t\t\twritten: prepared.rawContent,\n\t\t\t\tfileHash: hash,\n\t\t\t\theader: formatHashlineHeader(section.path, hash),\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tconst persisted = bom + restoreLineEndings(after, lineEnding);\n\t\tconst write: WriteResult = await this.fs.writeText(section.path, persisted);\n\t\tconst fileHash = this.#recordFullSnapshot(canonicalPath, after);\n\t\tconst op = exists ? \"update\" : \"create\";\n\n\t\treturn {\n\t\t\tpath: section.path,\n\t\t\tcanonicalPath,\n\t\t\top,\n\t\t\tbefore: normalized,\n\t\t\tafter,\n\t\t\tpersisted,\n\t\t\twritten: write.text,\n\t\t\tfileHash,\n\t\t\theader: formatHashlineHeader(section.path, fileHash),\n\t\t\tfirstChangedLine: applyResult.firstChangedLine,\n\t\t\tblockResolutions: applyResult.blockResolutions,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync #tryRead(path: string): Promise<{ exists: boolean; rawContent: string }> {\n\t\ttry {\n\t\t\tconst content = await this.fs.readText(path);\n\t\t\treturn { exists: true, rawContent: content };\n\t\t} catch (error) {\n\t\t\tif (isNotFound(error)) return { exists: false, rawContent: \"\" };\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t#recordFullSnapshot(canonicalPath: string, normalized: string): string {\n\t\treturn this.snapshots.record(canonicalPath, normalized);\n\t}\n\t#mismatchError(\n\t\tsection: PatchSection,\n\t\tcanonicalPath: string,\n\t\tnormalized: string,\n\t\texpected: string,\n\t\thashRecognized: boolean,\n\t): MismatchError {\n\t\tconst actualFileHash = this.#recordFullSnapshot(canonicalPath, normalized);\n\t\treturn new MismatchError({\n\t\t\tpath: section.path,\n\t\t\texpectedFileHash: expected,\n\t\t\tactualFileHash,\n\t\t\tfileLines: normalized.split(\"\\n\"),\n\t\t\tanchorLines: section.collectAnchorLines(),\n\t\t\thashRecognized,\n\t\t});\n\t}\n\n\t#applyWithRecovery(args: {\n\t\tsection: PatchSection;\n\t\tcanonicalPath: string;\n\t\texists: boolean;\n\t\tnormalized: string;\n\t\tedits: readonly Edit[];\n\t}): ApplyResult {\n\t\tconst { section, canonicalPath, exists, normalized, edits } = args;\n\t\tconst expected = exists ? section.fileHash : undefined;\n\t\tconst expectedSnapshot = expected === undefined ? null : this.snapshots.byHash(canonicalPath, expected);\n\t\tconst liveHashMatches = expected !== undefined && computeFileHash(normalized) === expected;\n\t\tconst liveSnapshot =\n\t\t\texpected === undefined ? null : this.snapshots.byHashAndText(canonicalPath, expected, normalized);\n\t\tconst liveMatches = liveHashMatches && liveSnapshot !== null;\n\t\tif (liveHashMatches && !liveMatches) {\n\t\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected, expectedSnapshot !== null);\n\t\t}\n\n\t\t// Resolve `replace block N:` edits to concrete ranges before recovery\n\t\t// runs. Block anchors are expressed against the snapshot the section tag\n\t\t// names, so resolve against that exact text:\n\t\t// - live content matches the tag (or there is no tag) → resolve against\n\t\t// the live, normalized content;\n\t\t// - the file drifted → resolve against the tagged snapshot's text so the\n\t\t// resulting ranges flow through the 3-way-merge recovery below.\n\t\t// When a block edit needs the tagged snapshot but it is unavailable, the\n\t\t// range cannot be placed safely — reject with a MismatchError (re-read).\n\t\tconst blockResolutions: BlockResolution[] = [];\n\t\tconst resolveWarnings: string[] = [];\n\t\tlet resolved: readonly Edit[] = edits;\n\t\tif (hasBlockEdit(edits)) {\n\t\t\tconst baseText = expected === undefined || liveMatches ? normalized : expectedSnapshot?.text;\n\t\t\tif (baseText === undefined) {\n\t\t\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected ?? \"\", false);\n\t\t\t}\n\t\t\tresolved = resolveBlockEdits(edits, baseText, section.path, this.blockResolver, {\n\t\t\t\tonUnresolved: \"throw\",\n\t\t\t\tonResolved: (resolution) => blockResolutions.push(resolution),\n\t\t\t\tonWarning: (warning) => resolveWarnings.push(warning),\n\t\t\t});\n\t\t}\n\t\tconst withResolveWarnings = (result: ApplyResult): ApplyResult =>\n\t\t\tresolveWarnings.length === 0\n\t\t\t\t? result\n\t\t\t\t: { ...result, warnings: [...resolveWarnings, ...(result.warnings ?? [])] };\n\n\t\t// No tag, or the tag still names the live content: an edit anchored at any\n\t\t// line is safe to apply, and the resolved block spans line up with what\n\t\t// the caller read, so echo them back. (A drifted file falls through to\n\t\t// recovery below, where line numbers shift, so resolutions are dropped.)\n\t\tif (expected === undefined || liveMatches) {\n\t\t\tconst result = applyEdits(normalized, resolved);\n\t\t\treturn withResolveWarnings(blockResolutions.length > 0 ? { ...result, blockResolutions } : result);\n\t\t}\n\t\t// Head/tail-only inserts are position-stable: \"start\"/\"end\" cannot move\n\t\t// with content drift, so a stale tag is non-fatal. Apply onto the live\n\t\t// content and warn instead of hard-failing — unlike an anchored\n\t\t// mismatch, which cannot be safely relocated and must reject.\n\t\tif (!hasAnchorScopedEdit(resolved)) {\n\t\t\tconst result = applyEdits(normalized, resolved);\n\t\t\treturn withResolveWarnings({ ...result, warnings: [HEADTAIL_DRIFT_WARNING, ...(result.warnings ?? [])] });\n\t\t}\n\t\t// File drifted: try to replay the edit against the version the tag\n\t\t// names and 3-way-merge it onto the live content.\n\t\tconst recovered = this.recovery.tryRecover({\n\t\t\tpath: canonicalPath,\n\t\t\tcurrentText: normalized,\n\t\t\tfileHash: expected,\n\t\t\tedits: resolved,\n\t\t});\n\t\tif (recovered) return withResolveWarnings(recoveryToApplyResult(recovered));\n\t\tconst hashRecognized = expectedSnapshot !== null;\n\t\tthrow this.#mismatchError(section, canonicalPath, normalized, expected, hashRecognized);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/recovery.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,iLAAiL;AACjL;;;;;;;;;GASG;AACH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EACN,yBAAyB,EACzB,8BAA8B,EAC9B,+BAA+B,GAC/B,MAAM,eAAe,CAAC;AAIvB,wEAAwE;AACxE,uEAAuE;AACvE,oDAAoD;AACpD,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAkB/B,SAAS,oBAAoB,CAC5B,YAAoB,EACpB,WAAmB,EACnB,KAAsB,EACtB,eAAuB;IAEvB,IAAI,OAAoB,CAAC;IACzB,IAAI,CAAC;QACJ,OAAO,GAAG,UAAU,CAAC,YAAY,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;IACvG,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAEtE,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAC/F,MAAM,YAAY,GAAG,gBAAgB,KAAK,SAAS,CAAC;IACpD,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,eAAe,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/G,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,QAAQ,EAAE,CAAC;AACrD,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAsB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,KAAK,MAAM,MAAM,IAAI,cAAc,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,IAAU;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,4EAA4E;IAC5E,6DAA6D;IAC7D,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAChH,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,YAAoB,EAAE,WAAmB,EAAE,KAAsB;IAC7F,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC;QACrB,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QACtE,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAC3C,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,2BAA2B,CACnC,YAAoB,EACpB,WAAmB,EACnB,KAAsB;IAEtB,wEAAwE;IACxE,uEAAuE;IACvE,uEAAuE;IACvE,qCAAqC;IACrC,wEAAwE;IACxE,gEAAgE;IAChE,uEAAuE;IACvE,iEAAiE;IACjE,wEAAwE;IACxE,oEAAoE;IACpE,qEAAqE;IACrE,kEAAkE;IAClE,aAAa;IACb,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACpF,IAAI,CAAC,mBAAmB,CAAC,YAAY,EAAE,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,IAAI,OAAoB,CAAC;IACzB,IAAI,CAAC;QACJ,OAAO,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9C,OAAO;QACN,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;QAC1C,QAAQ,EAAE,CAAC,+BAA+B,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;KACxE,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,SAAS,oBAAoB,CAAC,CAAS,EAAE,CAAS;IACjD,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACnD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,cAAc,CAAC,IAAqB,EAAE,QAAkB;IAChE,OAAO,IAAI,KAAK,QAAQ,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,QAAQ;IAEpB,YAAY,KAAoB;QAC/B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;IACD;;;OAGG;IACH,UAAU,CAAC,IAAkB;QAC5B,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC3B,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC/D,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,8BAA8B,CAAC;QAC5F,MAAM,MAAM,GAAG,oBAAoB,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;QACxF,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QACnC,kEAAkE;QAClE,0DAA0D;QAC1D,+DAA+D;QAC/D,oEAAoE;QACpE,IAAI,CAAC,MAAM;YAAE,OAAO,2BAA2B,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;QACnF,OAAO,IAAI,CAAC;IACb,CAAC;CACD","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Recover from a stale section snapshot tag by replaying the would-be edit\n * against a cached pre-edit snapshot of the file and 3-way-merging the\n * result onto the current on-disk content.\n *\n * The patcher consults this when a section tag resolves to a snapshot that no\n * longer matches the live file content. The recovery class is stateless apart\n * from the {@link SnapshotStore} it queries; the snapshot store is the seam\n * lets you plug in your own caching strategy.\n */\nimport * as Diff from \"diff\";\nimport { applyEdits } from \"./apply.js\";\nimport {\n\tRECOVERY_EXTERNAL_WARNING,\n\tRECOVERY_SESSION_CHAIN_WARNING,\n\tRECOVERY_SESSION_REPLAY_WARNING,\n} from \"./messages.js\";\nimport type { Snapshot, SnapshotStore } from \"./snapshots.js\";\nimport type { Anchor, ApplyResult, Edit } from \"./types.js\";\n\n// Section tags are line-precise; never let Diff.applyPatch slide a hunk\n// onto a duplicate closer 100+ lines away. If snapshot replay does not\n// align exactly, refuse and let the caller re-read.\nconst RECOVERY_FUZZ_FACTOR = 0;\n\nexport interface RecoveryArgs {\n\tpath: string;\n\tcurrentText: string;\n\tfileHash: string;\n\tedits: readonly Edit[];\n}\n\nexport interface RecoveryResult {\n\t/** Post-recovery text. */\n\ttext: string;\n\t/** First changed line (1-indexed) relative to the live `currentText`, or `undefined`. */\n\tfirstChangedLine: number | undefined;\n\t/** Warnings collected during recovery, including the user-facing recovery banner. */\n\twarnings: string[];\n}\n\nfunction applyEditsToSnapshot(\n\tpreviousText: string,\n\tcurrentText: string,\n\tedits: readonly Edit[],\n\trecoveryWarning: string,\n): RecoveryResult | null {\n\tlet applied: ApplyResult;\n\ttry {\n\t\tapplied = applyEdits(previousText, [...edits]);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (applied.text === previousText) return null;\n\n\tconst patch = Diff.structuredPatch(\"file\", \"file\", previousText, applied.text, \"\", \"\", { context: 3 });\n\tconst merged = Diff.applyPatch(currentText, patch, { fuzzFactor: RECOVERY_FUZZ_FACTOR });\n\tif (typeof merged !== \"string\" || merged === currentText) return null;\n\n\tconst firstChangedLine = findFirstChangedLine(currentText, merged) ?? applied.firstChangedLine;\n\tconst hasNetChange = firstChangedLine !== undefined;\n\tconst warnings = hasNetChange ? [recoveryWarning, ...(applied.warnings ?? [])] : [...(applied.warnings ?? [])];\n\n\treturn { text: merged, firstChangedLine, warnings };\n}\n\nfunction collectAnchorLines(edits: readonly Edit[]): number[] {\n\tconst lines: number[] = [];\n\tfor (const edit of edits) {\n\t\tfor (const anchor of getEditAnchors(edit)) lines.push(anchor.line);\n\t}\n\treturn lines;\n}\n\nfunction getEditAnchors(edit: Edit): Anchor[] {\n\tif (edit.kind === \"delete\") return [edit.anchor];\n\t// Recovery only ever receives already-resolved edits (no `block`); this arm\n\t// exists for type-exhaustiveness over the full `Edit` union.\n\tif (edit.kind === \"block\") return [edit.anchor];\n\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\" ? [edit.cursor.anchor] : [];\n}\n\n/**\n * Returns true when every anchor line in `edits` has identical content in\n * `previousText` and `currentText`. The session-chain replay fast-path\n * requires this: if the prior in-session edit rewrote the line the model is\n * now re-targeting with a stale hash, replaying onto current would silently\n * overwrite the new content with whatever the model authored against the\n * old content — a corruption window, not a recovery.\n */\nfunction verifyAnchorContent(previousText: string, currentText: string, edits: readonly Edit[]): boolean {\n\tconst lines = collectAnchorLines(edits);\n\tif (lines.length === 0) return true;\n\tconst prev = previousText.split(\"\\n\");\n\tconst curr = currentText.split(\"\\n\");\n\tfor (const line of lines) {\n\t\tconst idx = line - 1;\n\t\tif (idx < 0 || idx >= prev.length || idx >= curr.length) return false;\n\t\tif (prev[idx] !== curr[idx]) return false;\n\t}\n\treturn true;\n}\n\nfunction replaySessionChainOnCurrent(\n\tpreviousText: string,\n\tcurrentText: string,\n\tedits: readonly Edit[],\n): RecoveryResult | null {\n\t// Two guards narrow the corruption window. Neither alone is sufficient,\n\t// and even together they don't fully prove correctness — replay is the\n\t// less-certain recovery mode and emits RECOVERY_SESSION_REPLAY_WARNING\n\t// so the caller can verify the diff.\n\t// - Equal line counts: every line number in `edits` still resolves to\n\t// SOME logical row (no net shift across the prior chain). A\n\t// coincidental insert+delete pair can still leave indices pointing\n\t// at different logical rows than the model anchored against.\n\t// - Anchor-content alignment: the row at each anchor's line index has\n\t// identical content in previous and current. Catches the common\n\t// case of a prior edit rewriting the targeted line; can still be\n\t// coincidentally satisfied by a duplicated row at the shifted\n\t// index.\n\tif (previousText.split(\"\\n\").length !== currentText.split(\"\\n\").length) return null;\n\tif (!verifyAnchorContent(previousText, currentText, edits)) return null;\n\tlet applied: ApplyResult;\n\ttry {\n\t\tapplied = applyEdits(currentText, [...edits]);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (applied.text === currentText) return null;\n\treturn {\n\t\ttext: applied.text,\n\t\tfirstChangedLine: applied.firstChangedLine,\n\t\twarnings: [RECOVERY_SESSION_REPLAY_WARNING, ...(applied.warnings ?? [])],\n\t};\n}\n\n/** First 1-indexed line at which `a` and `b` diverge, or `undefined` if equal. */\nfunction findFirstChangedLine(a: string, b: string): number | undefined {\n\tif (a === b) return undefined;\n\tconst aLines = a.split(\"\\n\");\n\tconst bLines = b.split(\"\\n\");\n\tconst max = Math.max(aLines.length, bLines.length);\n\tfor (let i = 0; i < max; i++) {\n\t\tif (aLines[i] !== bLines[i]) return i + 1;\n\t}\n\treturn undefined;\n}\n\nfunction isHeadSnapshot(head: Snapshot | null, snapshot: Snapshot): boolean {\n\treturn head === snapshot;\n}\n\n/**\n * Stateless recovery driver over a {@link SnapshotStore}. Construct once and\n * call {@link Recovery.tryRecover} per stale-tag incident. The default\n * implementation tries two strategies in order:\n *\n * 1. Apply the edits on the full-file version the tag names, then 3-way-merge\n * the resulting patch onto the live content (handles external writes).\n * 2. (Session chain) If that version wasn't the head, replay the edits onto\n * the live content directly when line counts match AND every edit's anchor\n * line content is unchanged between version and current — a prior in-session\n * edit advanced the tag and the model's anchors still name the same logical\n * rows. Emits a dedicated {@link RECOVERY_SESSION_REPLAY_WARNING} because\n * even with both guards a coincidental insert+delete pair on duplicate rows\n * can still land the edit on the wrong row; see {@link replaySessionChainOnCurrent}.\n */\nexport class Recovery {\n\treadonly store: SnapshotStore;\n\tconstructor(store: SnapshotStore) {\n\t\tthis.store = store;\n\t}\n\t/**\n\t * Attempt recovery. Returns `null` when no path forward is found — the\n\t * caller should then surface a {@link MismatchError}.\n\t */\n\ttryRecover(args: RecoveryArgs): RecoveryResult | null {\n\t\tconst { path, currentText, fileHash, edits } = args;\n\t\tconst snapshot = this.store.byHash(path, fileHash);\n\t\tif (!snapshot) return null;\n\t\tconst isHead = isHeadSnapshot(this.store.head(path), snapshot);\n\t\tconst recoveryWarning = isHead ? RECOVERY_EXTERNAL_WARNING : RECOVERY_SESSION_CHAIN_WARNING;\n\t\tconst merged = applyEditsToSnapshot(snapshot.text, currentText, edits, recoveryWarning);\n\t\tif (merged !== null) return merged;\n\t\t// Session-chain fallback: the 3-way merge on the version refused.\n\t\t// Replay onto current is gated by line-count equality AND\n\t\t// anchor-content alignment — see `replaySessionChainOnCurrent`\n\t\t// for why both guards together still don't fully prove correctness.\n\t\tif (!isHead) return replaySessionChainOnCurrent(snapshot.text, currentText, edits);\n\t\treturn null;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/recovery.ts"],"names":[],"mappings":"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","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Recover from a stale section snapshot tag by replaying the would-be edit\n * against a cached pre-edit snapshot of the file and 3-way-merging the\n * result onto the current on-disk content.\n *\n * The patcher consults this when a section tag resolves to a snapshot that no\n * longer matches the live file content. The recovery class is stateless apart\n * from the {@link SnapshotStore} it queries; the snapshot store is the seam\n * lets you plug in your own caching strategy.\n */\nimport * as Diff from \"diff\";\nimport { applyEdits } from \"./apply.js\";\nimport {\n\tRECOVERY_EXTERNAL_WARNING,\n\tRECOVERY_SESSION_CHAIN_WARNING,\n\tRECOVERY_SESSION_REPLAY_WARNING,\n} from \"./messages.js\";\nimport type { Snapshot, SnapshotStore } from \"./snapshots.js\";\nimport type { Anchor, ApplyResult, Edit } from \"./types.js\";\n\n// Section tags are line-precise; never let Diff.applyPatch slide a hunk\n// onto a duplicate closer 100+ lines away. If snapshot replay does not\n// align exactly, refuse and let the caller re-read.\nconst RECOVERY_FUZZ_FACTOR = 0;\n\nexport interface RecoveryArgs {\n\tpath: string;\n\tcurrentText: string;\n\tfileHash: string;\n\tedits: readonly Edit[];\n}\n\nexport interface RecoveryResult {\n\t/** Post-recovery text. */\n\ttext: string;\n\t/** First changed line (1-indexed) relative to the live `currentText`, or `undefined`. */\n\tfirstChangedLine: number | undefined;\n\t/** Warnings collected during recovery, including the user-facing recovery banner. */\n\twarnings: string[];\n}\n\nfunction applyEditsToSnapshot(\n\tpreviousText: string,\n\tcurrentText: string,\n\tedits: readonly Edit[],\n\trecoveryWarning: string,\n): RecoveryResult | null {\n\tlet applied: ApplyResult;\n\ttry {\n\t\tapplied = applyEdits(previousText, [...edits]);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (applied.text === previousText) return null;\n\n\tconst patch = Diff.structuredPatch(\"file\", \"file\", previousText, applied.text, \"\", \"\", { context: 3 });\n\tconst merged = Diff.applyPatch(currentText, patch, { fuzzFactor: RECOVERY_FUZZ_FACTOR });\n\tif (typeof merged !== \"string\" || merged === currentText) return null;\n\n\tconst firstChangedLine = findFirstChangedLine(currentText, merged) ?? applied.firstChangedLine;\n\tconst hasNetChange = firstChangedLine !== undefined;\n\tconst warnings = hasNetChange ? [recoveryWarning, ...(applied.warnings ?? [])] : [...(applied.warnings ?? [])];\n\n\treturn { text: merged, firstChangedLine, warnings };\n}\n\nfunction collectAnchorLines(edits: readonly Edit[]): number[] {\n\tconst lines: number[] = [];\n\tfor (const edit of edits) {\n\t\tfor (const anchor of getEditAnchors(edit)) lines.push(anchor.line);\n\t}\n\treturn lines;\n}\n\nfunction getEditAnchors(edit: Edit): Anchor[] {\n\tif (edit.kind === \"delete\") return [edit.anchor];\n\t// Recovery only ever receives already-resolved edits (no `block`); this arm\n\t// exists for type-exhaustiveness over the full `Edit` union.\n\tif (edit.kind === \"block\") return [edit.anchor];\n\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\" ? [edit.cursor.anchor] : [];\n}\n\n/**\n * Returns true when every anchor line in `edits` has identical content in\n * `previousText` and `currentText`. The session-chain replay fast-path\n * requires this: if the prior in-session edit rewrote the line the model is\n * now re-targeting with a stale hash, replaying onto current would silently\n * overwrite the new content with whatever the model authored against the\n * old content — a corruption window, not a recovery.\n */\nfunction verifyAnchorContent(previousText: string, currentText: string, edits: readonly Edit[]): boolean {\n\tconst lines = collectAnchorLines(edits);\n\tif (lines.length === 0) return true;\n\tconst prev = previousText.split(\"\\n\");\n\tconst curr = currentText.split(\"\\n\");\n\tfor (const line of lines) {\n\t\tconst idx = line - 1;\n\t\tif (idx < 0 || idx >= prev.length || idx >= curr.length) return false;\n\t\tif (prev[idx] !== curr[idx]) return false;\n\t}\n\treturn true;\n}\n\nfunction replaySessionChainOnCurrent(\n\tpreviousText: string,\n\tcurrentText: string,\n\tedits: readonly Edit[],\n): RecoveryResult | null {\n\t// Two guards narrow the corruption window. Neither alone is sufficient,\n\t// and even together they don't fully prove correctness — replay is the\n\t// less-certain recovery mode and emits RECOVERY_SESSION_REPLAY_WARNING\n\t// so the caller can verify the diff.\n\t// - Equal line counts: every line number in `edits` still resolves to\n\t// SOME logical row (no net shift across the prior chain). A\n\t// coincidental insert+delete pair can still leave indices pointing\n\t// at different logical rows than the model anchored against.\n\t// - Anchor-content alignment: the row at each anchor's line index has\n\t// identical content in previous and current. Catches the common\n\t// case of a prior edit rewriting the targeted line; can still be\n\t// coincidentally satisfied by a duplicated row at the shifted\n\t// index.\n\tif (previousText.split(\"\\n\").length !== currentText.split(\"\\n\").length) return null;\n\tif (!verifyAnchorContent(previousText, currentText, edits)) return null;\n\tlet applied: ApplyResult;\n\ttry {\n\t\tapplied = applyEdits(currentText, [...edits]);\n\t} catch {\n\t\treturn null;\n\t}\n\tif (applied.text === currentText) return null;\n\treturn {\n\t\ttext: applied.text,\n\t\tfirstChangedLine: applied.firstChangedLine,\n\t\twarnings: [RECOVERY_SESSION_REPLAY_WARNING, ...(applied.warnings ?? [])],\n\t};\n}\n\n/** First 1-indexed line at which `a` and `b` diverge, or `undefined` if equal. */\nfunction findFirstChangedLine(a: string, b: string): number | undefined {\n\tif (a === b) return undefined;\n\tconst aLines = a.split(\"\\n\");\n\tconst bLines = b.split(\"\\n\");\n\tconst max = Math.max(aLines.length, bLines.length);\n\tfor (let i = 0; i < max; i++) {\n\t\tif (aLines[i] !== bLines[i]) return i + 1;\n\t}\n\treturn undefined;\n}\n\nfunction isHeadSnapshot(head: Snapshot | null, snapshot: Snapshot): boolean {\n\treturn head === snapshot;\n}\n\n/**\n * Stateless recovery driver over a {@link SnapshotStore}. Construct once and\n * call {@link Recovery.tryRecover} per stale-tag incident. The default\n * implementation tries two strategies in order:\n *\n * 1. Apply the edits on the full-file version the tag names, then 3-way-merge\n * the resulting patch onto the live content (handles external writes).\n * 2. (Session chain) If that version wasn't the head, replay the edits onto\n * the live content directly when line counts match AND every edit's anchor\n * line content is unchanged between version and current — a prior in-session\n * edit advanced the tag and the model's anchors still name the same logical\n * rows. Emits a dedicated {@link RECOVERY_SESSION_REPLAY_WARNING} because\n * even with both guards a coincidental insert+delete pair on duplicate rows\n * can still land the edit on the wrong row; see {@link replaySessionChainOnCurrent}.\n */\nexport class Recovery {\n\treadonly store: SnapshotStore;\n\tconstructor(store: SnapshotStore) {\n\t\tthis.store = store;\n\t}\n\t/**\n\t * Attempt recovery. Returns `null` when no path forward is found — the\n\t * caller should then surface a {@link MismatchError}.\n\t */\n\ttryRecover(args: RecoveryArgs): RecoveryResult | null {\n\t\tconst { path, currentText, fileHash, edits } = args;\n\t\tconst snapshot = this.store.byHash(path, fileHash);\n\t\tif (!snapshot) return null;\n\t\tconst isHead = isHeadSnapshot(this.store.head(path), snapshot);\n\t\tconst recoveryWarning = isHead ? RECOVERY_EXTERNAL_WARNING : RECOVERY_SESSION_CHAIN_WARNING;\n\t\tconst merged = applyEditsToSnapshot(snapshot.text, currentText, edits, recoveryWarning);\n\t\tif (merged !== null) return merged;\n\t\t// Session-chain fallback: the 3-way merge on the version refused.\n\t\t// Replay onto current is gated by line-count equality AND\n\t\t// anchor-content alignment — see `replaySessionChainOnCurrent`\n\t\t// for why both guards together still don't fully prove correctness.\n\t\tif (!isHead) return replaySessionChainOnCurrent(snapshot.text, currentText, edits);\n\t\treturn null;\n\t}\n}\n"]}
|
|
@@ -19,20 +19,27 @@ function byteLength(text) {
|
|
|
19
19
|
* to be preserved.
|
|
20
20
|
*/
|
|
21
21
|
export class OutputAccumulator {
|
|
22
|
+
maxLines;
|
|
23
|
+
maxBytes;
|
|
24
|
+
maxRollingBytes;
|
|
25
|
+
tempFilePrefix;
|
|
26
|
+
tempDir;
|
|
27
|
+
decoder = new TextDecoder();
|
|
28
|
+
rawChunks = [];
|
|
29
|
+
tailText = "";
|
|
30
|
+
tailBytes = 0;
|
|
31
|
+
tailStartsAtLineBoundary = true;
|
|
32
|
+
totalRawBytes = 0;
|
|
33
|
+
totalDecodedBytes = 0;
|
|
34
|
+
completedLines = 0;
|
|
35
|
+
totalLines = 0;
|
|
36
|
+
currentLineBytes = 0;
|
|
37
|
+
hasOpenLine = false;
|
|
38
|
+
finished = false;
|
|
39
|
+
tempFilePath;
|
|
40
|
+
tempFile;
|
|
41
|
+
tempFileUnavailable = false;
|
|
22
42
|
constructor(options = {}) {
|
|
23
|
-
this.decoder = new TextDecoder();
|
|
24
|
-
this.rawChunks = [];
|
|
25
|
-
this.tailText = "";
|
|
26
|
-
this.tailBytes = 0;
|
|
27
|
-
this.tailStartsAtLineBoundary = true;
|
|
28
|
-
this.totalRawBytes = 0;
|
|
29
|
-
this.totalDecodedBytes = 0;
|
|
30
|
-
this.completedLines = 0;
|
|
31
|
-
this.totalLines = 0;
|
|
32
|
-
this.currentLineBytes = 0;
|
|
33
|
-
this.hasOpenLine = false;
|
|
34
|
-
this.finished = false;
|
|
35
|
-
this.tempFileUnavailable = false;
|
|
36
43
|
this.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
37
44
|
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
38
45
|
this.maxRollingBytes = Math.max(this.maxBytes * 2, 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAyB,YAAY,EAAE,MAAM,eAAe,CAAC;AAmB1G,SAAS,mBAAmB,CAAC,MAAc,EAAE,OAA2B;IACvE,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,GAAG,MAAM,IAAI,EAAE,MAAM,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC/B,OAAO,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,iBAAiB;IAwB7B,YAAY,OAAO,GAA6B,EAAE;QAlBjC,YAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAErC,cAAS,GAAa,EAAE,CAAC;QACzB,aAAQ,GAAG,EAAE,CAAC;QACd,cAAS,GAAG,CAAC,CAAC;QACd,6BAAwB,GAAG,IAAI,CAAC;QAChC,kBAAa,GAAG,CAAC,CAAC;QAClB,sBAAiB,GAAG,CAAC,CAAC;QACtB,mBAAc,GAAG,CAAC,CAAC;QACnB,eAAU,GAAG,CAAC,CAAC;QACf,qBAAgB,GAAG,CAAC,CAAC;QACrB,gBAAW,GAAG,KAAK,CAAC;QACpB,aAAQ,GAAG,KAAK,CAAC;QAIjB,wBAAmB,GAAG,KAAK,CAAC;QAGnC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QACtD,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QACtD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,GAAG,QAAQ,SAAS,CAAC;QACrE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,IAAY;QAClB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACnE,CAAC;QAED,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC;QAClC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAEpE,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,cAAc,EAAE,CAAC;YACtB,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;IACF,CAAC;IAED,MAAM;QACL,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,OAAO;QACR,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9C,IAAI,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;QACvB,CAAC;IACF,CAAC;IAED,QAAQ,CAAC,OAAO,GAAqC,EAAE;QACtD,MAAM,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE;YAC3D,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACvB,CAAC,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC5F,MAAM,WAAW,GAAG,SAAS;YAC5B,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC9F,CAAC,CAAC,IAAI,CAAC;QACR,MAAM,UAAU,GAAqB;YACpC,GAAG,cAAc;YACjB,SAAS;YACT,WAAW;YACX,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,IAAI,CAAC,iBAAiB;YAClC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACvB,CAAC;QAEF,IAAI,OAAO,CAAC,kBAAkB,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC;YACxD,IAAI,CAAC,cAAc,EAAE,CAAC;QACvB,CAAC;QAED,OAAO;YACN,OAAO,EAAE,UAAU,CAAC,OAAO;YAC3B,UAAU;YACV,cAAc,EAAE,IAAI,CAAC,YAAY;SACjC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,aAAa;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;YACX,OAAO;QACR,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,oEAAoE;YACpE,sEAAsE;YACtE,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAC9B,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAChC,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;IAED,gBAAgB;QACf,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC9B,CAAC;IAEO,iBAAiB,CAAC,IAAY;QACrC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO;QACR,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,iBAAiB,IAAI,KAAK,CAAC;QAChC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;QACtB,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QACxB,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC;QAED,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,IAAI,WAAW,GAAG,CAAC,CAAC,CAAC;QACrB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC1E,QAAQ,EAAE,CAAC;YACX,WAAW,GAAG,CAAC,CAAC;QACjB,CAAC;QACD,IAAI,QAAQ,KAAK,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,gBAAgB,IAAI,KAAK,CAAC;YAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACzB,CAAC;aAAM,CAAC;YACP,IAAI,CAAC,cAAc,IAAI,QAAQ,CAAC;YAChC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,CAAC,gBAAgB,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAEO,QAAQ;QACf,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,IAAI,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC3C,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;YAC/B,OAAO;QACR,CAAC;QAED,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC;QACjD,OAAO,KAAK,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACjE,KAAK,EAAE,CAAC;QACT,CAAC;QAED,IAAI,CAAC,wBAAwB,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC;QACzG,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAEO,eAAe;QACtB,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,QAAQ,CAAC;QACtB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC;IACpF,CAAC;IAEO,iBAAiB;QACxB,OAAO,CACN,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,QAAQ,CAC/G,CAAC;IACH,CAAC;IAEO,cAAc;QACrB,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACnD,OAAO;QACR,CAAC;QACD,IAAI,IAAqC,CAAC;QAC1C,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,GAAG,IAAI,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACrC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;YACD,wEAAwE;YACxE,wEAAwE;YACxE,yDAAyD;YACzD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;YACzB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACR,yEAAyE;YACzE,0EAA0E;YAC1E,6EAA6E;YAC7E,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAChC,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;YAC9B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC1B,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC;gBACJ,IAAI,EAAE,GAAG,EAAE,CAAC;YACb,CAAC;YAAC,MAAM,CAAC;gBACR,qEAAqE;YACtE,CAAC;QACF,CAAC;IACF,CAAC;CACD","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { APP_NAME } from \"../../config.js\";\nimport { PersistedOutputFile } from \"./persisted-output-file.ts\";\nimport { ensureSessionTempDir } from \"./session-temp-dir.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from \"./truncate.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n\t/**\n\t * Session-scoped directory for the spill file. Defaults to the active\n\t * session's temp directory so spill files are reapable per session.\n\t */\n\ttempDir?: string;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n}\n\nfunction defaultTempFilePath(prefix: string, tempDir: string | undefined): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(ensureSessionTempDir(tempDir), `${prefix}-${id}.log`);\n}\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps only a decoded\n * tail for display snapshots, and opens a temp file when the full output needs\n * to be preserved.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRollingBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly tempDir: string | undefined;\n\tprivate readonly decoder = new TextDecoder();\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate tailText = \"\";\n\tprivate tailBytes = 0;\n\tprivate tailStartsAtLineBoundary = true;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate currentLineBytes = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFile: PersistedOutputFile | undefined;\n\tprivate tempFileUnavailable = false;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.maxRollingBytes = Math.max(this.maxBytes * 2, 1);\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? `${APP_NAME}-output`;\n\t\tthis.tempDir = options.tempDir;\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFile || this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t\tthis.tempFile?.write(data);\n\t\t} else if (data.length > 0) {\n\t\t\tthis.rawChunks.push(data);\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean } = {}): OutputSnapshot {\n\t\tconst tailTruncation = truncateTail(this.getSnapshotText(), {\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t});\n\t\tconst truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;\n\t\tconst truncatedBy = truncated\n\t\t\t? (tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? \"bytes\" : \"lines\"))\n\t\t\t: null;\n\t\tconst truncation: TruncationResult = {\n\t\t\t...tailTruncation,\n\t\t\ttruncated,\n\t\t\ttruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t};\n\n\t\tif (options.persistIfTruncated && truncation.truncated) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.tempFilePath,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tconst file = this.tempFile;\n\t\tif (!file) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFile = undefined;\n\t\ttry {\n\t\t\tawait file.close();\n\t\t} catch (error) {\n\t\t\t// A spill file that failed to flush must not be advertised: a later\n\t\t\t// snapshot reports no path rather than one pointing at a broken file.\n\t\t\tthis.tempFilePath = undefined;\n\t\t\tthis.tempFileUnavailable = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.currentLineBytes;\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst bytes = byteLength(text);\n\t\tthis.totalDecodedBytes += bytes;\n\t\tthis.tailText += text;\n\t\tthis.tailBytes += bytes;\n\t\tif (this.tailBytes > this.maxRollingBytes * 2) {\n\t\t\tthis.trimTail();\n\t\t}\n\n\t\tlet newlines = 0;\n\t\tlet lastNewline = -1;\n\t\tfor (let i = text.indexOf(\"\\n\"); i !== -1; i = text.indexOf(\"\\n\", i + 1)) {\n\t\t\tnewlines++;\n\t\t\tlastNewline = i;\n\t\t}\n\t\tif (newlines === 0) {\n\t\t\tthis.currentLineBytes += bytes;\n\t\t\tthis.hasOpenLine = true;\n\t\t} else {\n\t\t\tthis.completedLines += newlines;\n\t\t\tconst tail = text.slice(lastNewline + 1);\n\t\t\tthis.currentLineBytes = byteLength(tail);\n\t\t\tthis.hasOpenLine = tail.length > 0;\n\t\t}\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate trimTail(): void {\n\t\tconst buffer = Buffer.from(this.tailText, \"utf-8\");\n\t\tif (buffer.length <= this.maxRollingBytes) {\n\t\t\tthis.tailBytes = buffer.length;\n\t\t\treturn;\n\t\t}\n\n\t\tlet start = buffer.length - this.maxRollingBytes;\n\t\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\t\tstart++;\n\t\t}\n\n\t\tthis.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 0x0a;\n\t\tthis.tailText = buffer.subarray(start).toString(\"utf-8\");\n\t\tthis.tailBytes = byteLength(this.tailText);\n\t}\n\n\tprivate getSnapshotText(): string {\n\t\tif (this.tailStartsAtLineBoundary) {\n\t\t\treturn this.tailText;\n\t\t}\n\n\t\tconst firstNewline = this.tailText.indexOf(\"\\n\");\n\t\treturn firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate ensureTempFile(): void {\n\t\tif (this.tempFilePath || this.tempFileUnavailable) {\n\t\t\treturn;\n\t\t}\n\t\tlet file: PersistedOutputFile | undefined;\n\t\ttry {\n\t\t\tconst path = defaultTempFilePath(this.tempFilePrefix, this.tempDir);\n\t\t\tfile = new PersistedOutputFile(path);\n\t\t\tfor (const chunk of this.rawChunks) {\n\t\t\t\tfile.write(chunk);\n\t\t\t}\n\t\t\t// Publish the pair only after creation and replay both succeed. Callers\n\t\t\t// must never observe a path for a writer that did not open or could not\n\t\t\t// accept the output buffered before the spill threshold.\n\t\t\tthis.tempFile = file;\n\t\t\tthis.tempFilePath = path;\n\t\t\tthis.rawChunks = [];\n\t\t} catch {\n\t\t\t// Persistence is a convenience. Refusal by the directory helper, EMFILE,\n\t\t\t// ENOSPC, EACCES, or a replay failure must leave bounded output available\n\t\t\t// without a dangling path, retained raw chunks, or retries on later appends.\n\t\t\tthis.tempFileUnavailable = true;\n\t\t\tthis.tempFilePath = undefined;\n\t\t\tthis.tempFile = undefined;\n\t\t\tthis.rawChunks = [];\n\t\t\ttry {\n\t\t\t\tfile?.end();\n\t\t\t} catch {\n\t\t\t\t// Best effort: there is no path to advertise and no writer to reuse.\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"output-accumulator.js","sourceRoot":"","sources":["../../../src/core/tools/output-accumulator.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { join } from \"node:path\";\nimport { APP_NAME } from \"../../config.js\";\nimport { PersistedOutputFile } from \"./persisted-output-file.ts\";\nimport { ensureSessionTempDir } from \"./session-temp-dir.ts\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, type TruncationResult, truncateTail } from \"./truncate.ts\";\n\nexport interface OutputAccumulatorOptions {\n\tmaxLines?: number;\n\tmaxBytes?: number;\n\ttempFilePrefix?: string;\n\t/**\n\t * Session-scoped directory for the spill file. Defaults to the active\n\t * session's temp directory so spill files are reapable per session.\n\t */\n\ttempDir?: string;\n}\n\nexport interface OutputSnapshot {\n\tcontent: string;\n\ttruncation: TruncationResult;\n\tfullOutputPath?: string;\n}\n\nfunction defaultTempFilePath(prefix: string, tempDir: string | undefined): string {\n\tconst id = randomBytes(8).toString(\"hex\");\n\treturn join(ensureSessionTempDir(tempDir), `${prefix}-${id}.log`);\n}\n\nfunction byteLength(text: string): number {\n\treturn Buffer.byteLength(text, \"utf-8\");\n}\n\n/**\n * Incrementally tracks streaming output with bounded memory.\n *\n * Appends decode chunks with a streaming UTF-8 decoder, keeps only a decoded\n * tail for display snapshots, and opens a temp file when the full output needs\n * to be preserved.\n */\nexport class OutputAccumulator {\n\tprivate readonly maxLines: number;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRollingBytes: number;\n\tprivate readonly tempFilePrefix: string;\n\tprivate readonly tempDir: string | undefined;\n\tprivate readonly decoder = new TextDecoder();\n\n\tprivate rawChunks: Buffer[] = [];\n\tprivate tailText = \"\";\n\tprivate tailBytes = 0;\n\tprivate tailStartsAtLineBoundary = true;\n\tprivate totalRawBytes = 0;\n\tprivate totalDecodedBytes = 0;\n\tprivate completedLines = 0;\n\tprivate totalLines = 0;\n\tprivate currentLineBytes = 0;\n\tprivate hasOpenLine = false;\n\tprivate finished = false;\n\n\tprivate tempFilePath: string | undefined;\n\tprivate tempFile: PersistedOutputFile | undefined;\n\tprivate tempFileUnavailable = false;\n\n\tconstructor(options: OutputAccumulatorOptions = {}) {\n\t\tthis.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\n\t\tthis.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\t\tthis.maxRollingBytes = Math.max(this.maxBytes * 2, 1);\n\t\tthis.tempFilePrefix = options.tempFilePrefix ?? `${APP_NAME}-output`;\n\t\tthis.tempDir = options.tempDir;\n\t}\n\n\tappend(data: Buffer): void {\n\t\tif (this.finished) {\n\t\t\tthrow new Error(\"Cannot append to a finished output accumulator\");\n\t\t}\n\n\t\tthis.totalRawBytes += data.length;\n\t\tthis.appendDecodedText(this.decoder.decode(data, { stream: true }));\n\n\t\tif (this.tempFile || this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t\tthis.tempFile?.write(data);\n\t\t} else if (data.length > 0) {\n\t\t\tthis.rawChunks.push(data);\n\t\t}\n\t}\n\n\tfinish(): void {\n\t\tif (this.finished) {\n\t\t\treturn;\n\t\t}\n\t\tthis.finished = true;\n\t\tthis.appendDecodedText(this.decoder.decode());\n\t\tif (this.shouldUseTempFile()) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\t}\n\n\tsnapshot(options: { persistIfTruncated?: boolean } = {}): OutputSnapshot {\n\t\tconst tailTruncation = truncateTail(this.getSnapshotText(), {\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t});\n\t\tconst truncated = this.totalLines > this.maxLines || this.totalDecodedBytes > this.maxBytes;\n\t\tconst truncatedBy = truncated\n\t\t\t? (tailTruncation.truncatedBy ?? (this.totalDecodedBytes > this.maxBytes ? \"bytes\" : \"lines\"))\n\t\t\t: null;\n\t\tconst truncation: TruncationResult = {\n\t\t\t...tailTruncation,\n\t\t\ttruncated,\n\t\t\ttruncatedBy,\n\t\t\ttotalLines: this.totalLines,\n\t\t\ttotalBytes: this.totalDecodedBytes,\n\t\t\tmaxLines: this.maxLines,\n\t\t\tmaxBytes: this.maxBytes,\n\t\t};\n\n\t\tif (options.persistIfTruncated && truncation.truncated) {\n\t\t\tthis.ensureTempFile();\n\t\t}\n\n\t\treturn {\n\t\t\tcontent: truncation.content,\n\t\t\ttruncation,\n\t\t\tfullOutputPath: this.tempFilePath,\n\t\t};\n\t}\n\n\tasync closeTempFile(): Promise<void> {\n\t\tconst file = this.tempFile;\n\t\tif (!file) {\n\t\t\treturn;\n\t\t}\n\t\tthis.tempFile = undefined;\n\t\ttry {\n\t\t\tawait file.close();\n\t\t} catch (error) {\n\t\t\t// A spill file that failed to flush must not be advertised: a later\n\t\t\t// snapshot reports no path rather than one pointing at a broken file.\n\t\t\tthis.tempFilePath = undefined;\n\t\t\tthis.tempFileUnavailable = true;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tgetLastLineBytes(): number {\n\t\treturn this.currentLineBytes;\n\t}\n\n\tprivate appendDecodedText(text: string): void {\n\t\tif (text.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst bytes = byteLength(text);\n\t\tthis.totalDecodedBytes += bytes;\n\t\tthis.tailText += text;\n\t\tthis.tailBytes += bytes;\n\t\tif (this.tailBytes > this.maxRollingBytes * 2) {\n\t\t\tthis.trimTail();\n\t\t}\n\n\t\tlet newlines = 0;\n\t\tlet lastNewline = -1;\n\t\tfor (let i = text.indexOf(\"\\n\"); i !== -1; i = text.indexOf(\"\\n\", i + 1)) {\n\t\t\tnewlines++;\n\t\t\tlastNewline = i;\n\t\t}\n\t\tif (newlines === 0) {\n\t\t\tthis.currentLineBytes += bytes;\n\t\t\tthis.hasOpenLine = true;\n\t\t} else {\n\t\t\tthis.completedLines += newlines;\n\t\t\tconst tail = text.slice(lastNewline + 1);\n\t\t\tthis.currentLineBytes = byteLength(tail);\n\t\t\tthis.hasOpenLine = tail.length > 0;\n\t\t}\n\t\tthis.totalLines = this.completedLines + (this.hasOpenLine ? 1 : 0);\n\t}\n\n\tprivate trimTail(): void {\n\t\tconst buffer = Buffer.from(this.tailText, \"utf-8\");\n\t\tif (buffer.length <= this.maxRollingBytes) {\n\t\t\tthis.tailBytes = buffer.length;\n\t\t\treturn;\n\t\t}\n\n\t\tlet start = buffer.length - this.maxRollingBytes;\n\t\twhile (start < buffer.length && (buffer[start] & 0xc0) === 0x80) {\n\t\t\tstart++;\n\t\t}\n\n\t\tthis.tailStartsAtLineBoundary = start === 0 ? this.tailStartsAtLineBoundary : buffer[start - 1] === 0x0a;\n\t\tthis.tailText = buffer.subarray(start).toString(\"utf-8\");\n\t\tthis.tailBytes = byteLength(this.tailText);\n\t}\n\n\tprivate getSnapshotText(): string {\n\t\tif (this.tailStartsAtLineBoundary) {\n\t\t\treturn this.tailText;\n\t\t}\n\n\t\tconst firstNewline = this.tailText.indexOf(\"\\n\");\n\t\treturn firstNewline === -1 ? this.tailText : this.tailText.slice(firstNewline + 1);\n\t}\n\n\tprivate shouldUseTempFile(): boolean {\n\t\treturn (\n\t\t\tthis.totalRawBytes > this.maxBytes || this.totalDecodedBytes > this.maxBytes || this.totalLines > this.maxLines\n\t\t);\n\t}\n\n\tprivate ensureTempFile(): void {\n\t\tif (this.tempFilePath || this.tempFileUnavailable) {\n\t\t\treturn;\n\t\t}\n\t\tlet file: PersistedOutputFile | undefined;\n\t\ttry {\n\t\t\tconst path = defaultTempFilePath(this.tempFilePrefix, this.tempDir);\n\t\t\tfile = new PersistedOutputFile(path);\n\t\t\tfor (const chunk of this.rawChunks) {\n\t\t\t\tfile.write(chunk);\n\t\t\t}\n\t\t\t// Publish the pair only after creation and replay both succeed. Callers\n\t\t\t// must never observe a path for a writer that did not open or could not\n\t\t\t// accept the output buffered before the spill threshold.\n\t\t\tthis.tempFile = file;\n\t\t\tthis.tempFilePath = path;\n\t\t\tthis.rawChunks = [];\n\t\t} catch {\n\t\t\t// Persistence is a convenience. Refusal by the directory helper, EMFILE,\n\t\t\t// ENOSPC, EACCES, or a replay failure must leave bounded output available\n\t\t\t// without a dangling path, retained raw chunks, or retries on later appends.\n\t\t\tthis.tempFileUnavailable = true;\n\t\t\tthis.tempFilePath = undefined;\n\t\t\tthis.tempFile = undefined;\n\t\t\tthis.rawChunks = [];\n\t\t\ttry {\n\t\t\t\tfile?.end();\n\t\t\t} catch {\n\t\t\t\t// Best effort: there is no path to advertise and no writer to reuse.\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -153,10 +153,16 @@ export function capPersistedText(text, maxBytes = MAX_PERSISTED_OUTPUT_BYTES) {
|
|
|
153
153
|
* never surface as an uncaught exception on the fire-and-forget path.
|
|
154
154
|
*/
|
|
155
155
|
export class PersistedOutputFile {
|
|
156
|
+
path;
|
|
157
|
+
stream;
|
|
158
|
+
maxBytes;
|
|
159
|
+
/** Bytes that may be written before the marker's reserved space is needed. */
|
|
160
|
+
safeLimit;
|
|
161
|
+
writtenBytes = 0;
|
|
162
|
+
pending = Buffer.alloc(0);
|
|
163
|
+
capReached = false;
|
|
164
|
+
failure;
|
|
156
165
|
constructor(path, options = {}) {
|
|
157
|
-
this.writtenBytes = 0;
|
|
158
|
-
this.pending = Buffer.alloc(0);
|
|
159
|
-
this.capReached = false;
|
|
160
166
|
this.path = path;
|
|
161
167
|
this.maxBytes = options.maxBytes ?? MAX_PERSISTED_OUTPUT_BYTES;
|
|
162
168
|
const markerBytes = Buffer.byteLength(PERSISTED_OUTPUT_TRUNCATION_MARKER, "utf8");
|