@bastani/atomic 0.9.2 → 0.9.3-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +57 -0
- package/README.md +2 -2
- package/dist/builtin/cursor/package.json +2 -2
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/direct-tools.ts +4 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/proxy-call.ts +3 -1
- package/dist/builtin/mcp/utils.ts +18 -7
- package/dist/builtin/subagents/CHANGELOG.md +11 -0
- package/dist/builtin/subagents/README.md +6 -6
- package/dist/builtin/subagents/agents/code-simplifier.md +7 -6
- package/dist/builtin/subagents/agents/codebase-analyzer.md +5 -4
- package/dist/builtin/subagents/agents/codebase-locator.md +3 -3
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +10 -10
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +4 -4
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +3 -3
- package/dist/builtin/subagents/agents/codebase-research-locator.md +4 -4
- package/dist/builtin/subagents/agents/debugger.md +5 -5
- package/dist/builtin/subagents/agents/worker.md +56 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +11 -11
- package/dist/builtin/subagents/src/agents/agent-loaders.ts +3 -5
- package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +3 -3
- package/dist/builtin/subagents/src/extension/schemas.ts +2 -2
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +4 -3
- package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +2 -2
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +2 -1
- package/dist/builtin/subagents/src/shared/types-depth.ts +5 -5
- package/dist/builtin/subagents/src/shared/types-runtime.ts +2 -1
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -2
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +13 -0
- package/dist/builtin/workflows/README.md +2 -2
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +11 -6
- package/dist/builtin/workflows/builtin/goal-ledger.ts +33 -1
- package/dist/builtin/workflows/builtin/goal-prompts.ts +23 -28
- package/dist/builtin/workflows/builtin/goal-reducer.ts +2 -2
- package/dist/builtin/workflows/builtin/goal-reports.ts +2 -5
- package/dist/builtin/workflows/builtin/goal-review.ts +1 -1
- package/dist/builtin/workflows/builtin/goal-runner.ts +10 -17
- package/dist/builtin/workflows/builtin/open-claude-design-feedback.ts +3 -3
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +1 -3
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +7 -17
- package/dist/builtin/workflows/builtin/ralph-runner.ts +11 -18
- package/dist/builtin/workflows/builtin/shared-prompts.ts +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/config-loader.ts +35 -15
- package/dist/builtin/workflows/src/extension/discovery.ts +20 -8
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +1 -2
- package/dist/builtin/workflows/src/extension/wiring.ts +1 -1
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +11 -10
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -9
- package/dist/cli/args.js.map +1 -1
- package/dist/config-self-update.d.ts.map +1 -1
- package/dist/config-self-update.js +3 -4
- package/dist/config-self-update.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -5
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts +1 -0
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-bash.js +1 -0
- package/dist/core/agent-session-bash.js.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.js +23 -0
- package/dist/core/agent-session-tool-registry.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -0
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +1 -0
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +29 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +36 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +14 -2
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-metrics.js +50 -1
- package/dist/core/compaction/context-compaction-metrics.js.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-prompt.js +2 -0
- package/dist/core/compaction/context-compaction-prompt.js.map +1 -1
- package/dist/core/compaction/context-compaction-runner.d.ts.map +1 -1
- package/dist/core/compaction/context-compaction-runner.js +1 -1
- package/dist/core/compaction/context-compaction-runner.js.map +1 -1
- package/dist/core/compaction/context-deletion-application.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-application.js +5 -5
- package/dist/core/compaction/context-deletion-application.js.map +1 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +2 -0
- package/dist/core/compaction/context-deletion-targets.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-targets.js +23 -3
- package/dist/core/compaction/context-deletion-targets.js.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +6 -0
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +1 -1
- package/dist/core/compaction/context-deletion-tools.d.ts.map +1 -1
- package/dist/core/compaction/context-deletion-tools.js +18 -10
- package/dist/core/compaction/context-deletion-tools.js.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +1 -1
- package/dist/core/compaction/context-transcript-analysis.js +2 -4
- package/dist/core/compaction/context-transcript-analysis.js.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.js +2 -60
- package/dist/core/copilot-gemini-tool-arguments.js.map +1 -1
- 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/index.d.ts +2 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +11 -3
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +11 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/tool-events.d.ts +13 -13
- package/dist/core/extensions/tool-events.d.ts.map +1 -1
- package/dist/core/extensions/tool-events.js +3 -3
- package/dist/core/extensions/tool-events.js.map +1 -1
- package/dist/core/extensions/types.d.ts +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/flattened-tool-arguments.d.ts +18 -0
- package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
- package/dist/core/flattened-tool-arguments.js +104 -0
- package/dist/core/flattened-tool-arguments.js.map +1 -1
- package/dist/core/sdk-exports.d.ts +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-exports.js +1 -1
- package/dist/core/sdk-exports.js.map +1 -1
- package/dist/core/sdk-types.d.ts +2 -2
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +4 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +18 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts +4 -0
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.js +15 -0
- package/dist/core/settings-manager-resource-accessors.js.map +1 -1
- package/dist/core/settings-types.d.ts +11 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/system-prompt.d.ts +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +3 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/artifact-protocol.d.ts +11 -0
- package/dist/core/tools/artifact-protocol.d.ts.map +1 -0
- package/dist/core/tools/artifact-protocol.js +76 -0
- package/dist/core/tools/artifact-protocol.js.map +1 -0
- package/dist/core/tools/artifacts.d.ts +18 -0
- package/dist/core/tools/artifacts.d.ts.map +1 -0
- package/dist/core/tools/artifacts.js +90 -0
- package/dist/core/tools/artifacts.js.map +1 -0
- package/dist/core/tools/bash-async-jobs.d.ts +20 -0
- package/dist/core/tools/bash-async-jobs.d.ts.map +1 -0
- package/dist/core/tools/bash-async-jobs.js +59 -0
- package/dist/core/tools/bash-async-jobs.js.map +1 -0
- package/dist/core/tools/bash-async-output.d.ts +10 -0
- package/dist/core/tools/bash-async-output.d.ts.map +1 -0
- package/dist/core/tools/bash-async-output.js +80 -0
- package/dist/core/tools/bash-async-output.js.map +1 -0
- package/dist/core/tools/bash-interceptor.d.ts +10 -0
- package/dist/core/tools/bash-interceptor.d.ts.map +1 -0
- package/dist/core/tools/bash-interceptor.js +39 -0
- package/dist/core/tools/bash-interceptor.js.map +1 -0
- package/dist/core/tools/bash-leading-cd.d.ts +7 -0
- package/dist/core/tools/bash-leading-cd.d.ts.map +1 -0
- package/dist/core/tools/bash-leading-cd.js +59 -0
- package/dist/core/tools/bash-leading-cd.js.map +1 -0
- package/dist/core/tools/bash-pty-native.d.ts +14 -0
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -0
- package/dist/core/tools/bash-pty-native.js +71 -0
- package/dist/core/tools/bash-pty-native.js.map +1 -0
- package/dist/core/tools/bash.d.ts +28 -17
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +152 -35
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/block-resolver.d.ts +16 -0
- package/dist/core/tools/block-resolver.d.ts.map +1 -0
- package/dist/core/tools/block-resolver.js +74 -0
- package/dist/core/tools/block-resolver.js.map +1 -0
- package/dist/core/tools/conflict-registry.d.ts +16 -0
- package/dist/core/tools/conflict-registry.d.ts.map +1 -0
- package/dist/core/tools/conflict-registry.js +44 -0
- package/dist/core/tools/conflict-registry.js.map +1 -0
- package/dist/core/tools/directory-tree.d.ts +13 -0
- package/dist/core/tools/directory-tree.d.ts.map +1 -0
- package/dist/core/tools/directory-tree.js +81 -0
- package/dist/core/tools/directory-tree.js.map +1 -0
- package/dist/core/tools/edit.d.ts +4 -29
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +136 -228
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/fetch-url.d.ts +74 -0
- package/dist/core/tools/fetch-url.d.ts.map +1 -0
- package/dist/core/tools/fetch-url.js +518 -0
- package/dist/core/tools/fetch-url.js.map +1 -0
- package/dist/core/tools/find.d.ts +27 -9
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +400 -176
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/glob-path-utils.d.ts +8 -0
- package/dist/core/tools/glob-path-utils.d.ts.map +1 -0
- package/dist/core/tools/glob-path-utils.js +26 -0
- package/dist/core/tools/glob-path-utils.js.map +1 -0
- package/dist/core/tools/grep.d.ts +12 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +141 -17
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hashline-engine/apply.d.ts +11 -0
- package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/apply.js +752 -0
- package/dist/core/tools/hashline-engine/apply.js.map +1 -0
- package/dist/core/tools/hashline-engine/block.d.ts +40 -0
- package/dist/core/tools/hashline-engine/block.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/block.js +117 -0
- package/dist/core/tools/hashline-engine/block.js.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts +15 -0
- package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/diff-preview.js +98 -0
- package/dist/core/tools/hashline-engine/diff-preview.js.map +1 -0
- package/dist/core/tools/hashline-engine/format.d.ts +71 -0
- package/dist/core/tools/hashline-engine/format.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/format.js +178 -0
- package/dist/core/tools/hashline-engine/format.js.map +1 -0
- package/dist/core/tools/hashline-engine/fs.d.ts +81 -0
- package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/fs.js +143 -0
- package/dist/core/tools/hashline-engine/fs.js.map +1 -0
- package/dist/core/tools/hashline-engine/index.d.ts +18 -0
- package/dist/core/tools/hashline-engine/index.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/index.js +20 -0
- package/dist/core/tools/hashline-engine/index.js.map +1 -0
- package/dist/core/tools/hashline-engine/input.d.ts +101 -0
- package/dist/core/tools/hashline-engine/input.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/input.js +398 -0
- package/dist/core/tools/hashline-engine/input.js.map +1 -0
- package/dist/core/tools/hashline-engine/messages.d.ts +99 -0
- package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/messages.js +144 -0
- package/dist/core/tools/hashline-engine/messages.js.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts +45 -0
- package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/mismatch.js +90 -0
- package/dist/core/tools/hashline-engine/mismatch.js.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts +21 -0
- package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/normalize.js +33 -0
- package/dist/core/tools/hashline-engine/normalize.js.map +1 -0
- package/dist/core/tools/hashline-engine/parser.d.ts +24 -0
- package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/parser.js +381 -0
- package/dist/core/tools/hashline-engine/parser.js.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts +118 -0
- package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/patcher.js +341 -0
- package/dist/core/tools/hashline-engine/patcher.js.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts +43 -0
- package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/prefixes.js +135 -0
- package/dist/core/tools/hashline-engine/prefixes.js.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts +41 -0
- package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/recovery.js +168 -0
- package/dist/core/tools/hashline-engine/recovery.js.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts +65 -0
- package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/snapshots.js +108 -0
- package/dist/core/tools/hashline-engine/snapshots.js.map +1 -0
- package/dist/core/tools/hashline-engine/stream.d.ts +3 -0
- package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/stream.js +111 -0
- package/dist/core/tools/hashline-engine/stream.js.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts +69 -0
- package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/tokenizer.js +430 -0
- package/dist/core/tools/hashline-engine/tokenizer.js.map +1 -0
- package/dist/core/tools/hashline-engine/types.d.ts +166 -0
- package/dist/core/tools/hashline-engine/types.d.ts.map +1 -0
- package/dist/core/tools/hashline-engine/types.js +9 -0
- package/dist/core/tools/hashline-engine/types.js.map +1 -0
- package/dist/core/tools/hashline.d.ts +29 -0
- package/dist/core/tools/hashline.d.ts.map +1 -0
- package/dist/core/tools/hashline.js +110 -0
- package/dist/core/tools/hashline.js.map +1 -0
- package/dist/core/tools/index.d.ts +6 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +52 -35
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/notebook.d.ts +38 -0
- package/dist/core/tools/notebook.d.ts.map +1 -0
- package/dist/core/tools/notebook.js +125 -0
- package/dist/core/tools/notebook.js.map +1 -0
- package/dist/core/tools/read-document-extract.d.ts +9 -0
- package/dist/core/tools/read-document-extract.d.ts.map +1 -0
- package/dist/core/tools/read-document-extract.js +212 -0
- package/dist/core/tools/read-document-extract.js.map +1 -0
- package/dist/core/tools/read-selectors.d.ts +24 -0
- package/dist/core/tools/read-selectors.d.ts.map +1 -0
- package/dist/core/tools/read-selectors.js +277 -0
- package/dist/core/tools/read-selectors.js.map +1 -0
- package/dist/core/tools/read-url.d.ts +37 -0
- package/dist/core/tools/read-url.d.ts.map +1 -0
- package/dist/core/tools/read-url.js +39 -0
- package/dist/core/tools/read-url.js.map +1 -0
- package/dist/core/tools/read.d.ts +11 -11
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +224 -94
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts +44 -0
- package/dist/core/tools/resource-selectors.d.ts.map +1 -0
- package/dist/core/tools/resource-selectors.js +808 -0
- package/dist/core/tools/resource-selectors.js.map +1 -0
- package/dist/core/tools/search-details.d.ts +26 -0
- package/dist/core/tools/search-details.d.ts.map +1 -0
- package/dist/core/tools/search-details.js +24 -0
- package/dist/core/tools/search-details.js.map +1 -0
- package/dist/core/tools/search-line-ranges.d.ts +11 -0
- package/dist/core/tools/search-line-ranges.d.ts.map +1 -0
- package/dist/core/tools/search-line-ranges.js +65 -0
- package/dist/core/tools/search-line-ranges.js.map +1 -0
- package/dist/core/tools/search-native.d.ts +97 -0
- package/dist/core/tools/search-native.d.ts.map +1 -0
- package/dist/core/tools/search-native.js +27 -0
- package/dist/core/tools/search-native.js.map +1 -0
- package/dist/core/tools/search.d.ts +24 -0
- package/dist/core/tools/search.d.ts.map +1 -0
- package/dist/core/tools/search.js +573 -0
- package/dist/core/tools/search.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +4 -4
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/truncate.js +3 -3
- package/dist/core/tools/truncate.js.map +1 -1
- package/dist/core/tools/url-ip-guards.d.ts +4 -0
- package/dist/core/tools/url-ip-guards.d.ts.map +1 -0
- package/dist/core/tools/url-ip-guards.js +126 -0
- package/dist/core/tools/url-ip-guards.js.map +1 -0
- package/dist/core/tools/write.d.ts +12 -2
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +166 -14
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +2 -3
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/index-extensions.d.ts +2 -2
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +9 -2
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.js +3 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js +7 -0
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts +2 -0
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.js +0 -5
- package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js +1 -0
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +80 -2
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +3 -0
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +51 -0
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +5 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +5 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +12 -0
- 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-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.d.ts +11 -0
- package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-onboarding.js +220 -0
- package/dist/modes/interactive/interactive-onboarding.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +4 -0
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +6 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.js +9 -4
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +28 -0
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/child-process.js +21 -1
- package/dist/utils/child-process.js.map +1 -1
- package/dist/utils/markit.d.ts +8 -0
- package/dist/utils/markit.d.ts.map +1 -0
- package/dist/utils/markit.js +53 -0
- package/dist/utils/markit.js.map +1 -0
- package/dist/utils/paths.d.ts +2 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +14 -1
- package/dist/utils/paths.js.map +1 -1
- package/docs/compaction.md +16 -1
- package/docs/containerization.md +1 -1
- package/docs/docs.json +1 -0
- package/docs/extensions.md +25 -36
- package/docs/quickstart.md +11 -6
- package/docs/sdk.md +5 -5
- package/docs/settings.md +7 -0
- package/docs/subagents.md +3 -2
- package/docs/tools.md +49 -0
- package/docs/usage.md +3 -3
- package/docs/workflows.md +7 -5
- package/examples/extensions/subagent/README.md +5 -5
- package/examples/extensions/subagent/agents/planner.md +1 -1
- package/examples/extensions/subagent/agents/reviewer.md +1 -1
- package/examples/extensions/subagent/agents/scout.md +2 -2
- package/examples/extensions/subagent/display.ts +3 -3
- package/examples/sdk/05-tools.ts +3 -3
- package/examples/sdk/README.md +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.
|
|
2
|
+
// 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).
|
|
3
|
+
/**
|
|
4
|
+
* High-level patch orchestrator. Reads each section's target file via the
|
|
5
|
+
* configured {@link Filesystem}, strips BOM and normalizes line endings,
|
|
6
|
+
* validates the section snapshot tag (with {@link Recovery}), applies the
|
|
7
|
+
* result back through the same {@link Filesystem}.
|
|
8
|
+
*
|
|
9
|
+
* Two layers:
|
|
10
|
+
* - {@link Patcher.apply} — high-level, preflight-atomic. It validates and
|
|
11
|
+
* applies every section in memory before any write hits disk, then commits
|
|
12
|
+
* in order. It is not write-transactional: a mid-batch filesystem failure
|
|
13
|
+
* can leave earlier sections already written, and the thrown error reports
|
|
14
|
+
* which sections landed.
|
|
15
|
+
* - {@link Patcher.prepare} / {@link Patcher.commit} — granular primitives
|
|
16
|
+
* for callers that need per-section control (e.g. batched LSP flush,
|
|
17
|
+
* custom interleaving). `prepare` performs all the read-side work,
|
|
18
|
+
* validates the section snapshot tag (with recovery), and applies the
|
|
19
|
+
* edits in memory. `commit` writes the prepared result and records a
|
|
20
|
+
* fresh snapshot.
|
|
21
|
+
*
|
|
22
|
+
* Because `prepare` already runs the full apply, a multi-section batch fails
|
|
23
|
+
* before any write when parsing, stale-tag validation, or in-memory apply fails.
|
|
24
|
+
*
|
|
25
|
+
* The patcher itself is stateless across calls; reuse one instance per
|
|
26
|
+
* filesystem configuration.
|
|
27
|
+
*/
|
|
28
|
+
import { applyEdits } from "./apply.js";
|
|
29
|
+
import { hasBlockEdit, resolveBlockEdits } from "./block.js";
|
|
30
|
+
import { computeFileHash, formatHashlineHeader } from "./format.js";
|
|
31
|
+
import { isNotFound } from "./fs.js";
|
|
32
|
+
import { HEADTAIL_DRIFT_WARNING, missingSnapshotTagMessage } from "./messages.js";
|
|
33
|
+
import { MismatchError } from "./mismatch.js";
|
|
34
|
+
import { detectLineEnding, normalizeToLF, restoreLineEndings, stripBom } from "./normalize.js";
|
|
35
|
+
import { Recovery } from "./recovery.js";
|
|
36
|
+
/**
|
|
37
|
+
* Opaque token returned by {@link Patcher.prepare}. Carries the section, the
|
|
38
|
+
* raw file content read off disk, and the in-memory apply result.
|
|
39
|
+
* {@link Patcher.commit} just writes the {@link PreparedSection.applyResult}.
|
|
40
|
+
*/
|
|
41
|
+
export class PreparedSection {
|
|
42
|
+
/** @internal */
|
|
43
|
+
constructor(section, canonicalPath, exists, rawContent, bom, lineEnding, normalized, applyResult, parseWarnings) {
|
|
44
|
+
this.section = section;
|
|
45
|
+
this.canonicalPath = canonicalPath;
|
|
46
|
+
this.exists = exists;
|
|
47
|
+
this.rawContent = rawContent;
|
|
48
|
+
this.bom = bom;
|
|
49
|
+
this.lineEnding = lineEnding;
|
|
50
|
+
this.normalized = normalized;
|
|
51
|
+
this.applyResult = applyResult;
|
|
52
|
+
this.parseWarnings = parseWarnings;
|
|
53
|
+
}
|
|
54
|
+
/** Convenience: returns true when the apply produced no change. */
|
|
55
|
+
get isNoop() {
|
|
56
|
+
return this.applyResult.text === this.normalized;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function hasAnchorScopedEdit(edits) {
|
|
60
|
+
return edits.some(edit => {
|
|
61
|
+
if (edit.kind === "delete")
|
|
62
|
+
return true;
|
|
63
|
+
// A `replace block N:` edit anchors to concrete content on line N.
|
|
64
|
+
if (edit.kind === "block")
|
|
65
|
+
return true;
|
|
66
|
+
return edit.cursor.kind === "before_anchor" || edit.cursor.kind === "after_anchor";
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function assertSectionHashPresent(sectionPath, fileHash) {
|
|
70
|
+
if (fileHash !== undefined)
|
|
71
|
+
return;
|
|
72
|
+
throw new Error(missingSnapshotTagMessage(sectionPath));
|
|
73
|
+
}
|
|
74
|
+
function recoveryToApplyResult(result) {
|
|
75
|
+
return {
|
|
76
|
+
text: result.text,
|
|
77
|
+
firstChangedLine: result.firstChangedLine,
|
|
78
|
+
warnings: result.warnings,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function mergeWarnings(...sources) {
|
|
82
|
+
const out = [];
|
|
83
|
+
for (const source of sources) {
|
|
84
|
+
if (!source)
|
|
85
|
+
continue;
|
|
86
|
+
for (const warning of source)
|
|
87
|
+
out.push(warning);
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
function assertUniqueCanonicalPaths(prepared) {
|
|
92
|
+
const seen = new Map();
|
|
93
|
+
for (const entry of prepared) {
|
|
94
|
+
const previous = seen.get(entry.canonicalPath);
|
|
95
|
+
if (previous !== undefined) {
|
|
96
|
+
throw new Error(`Multiple hashline sections resolve to the same file (${previous} and ${entry.section.path}). Merge their ops under one header before applying.`);
|
|
97
|
+
}
|
|
98
|
+
seen.set(entry.canonicalPath, entry.section.path);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* High-level patcher. Wires a {@link Filesystem} and a required
|
|
103
|
+
* {@link SnapshotStore} together with the parsing + applying core.
|
|
104
|
+
*
|
|
105
|
+
* Construct once per FS configuration; reuse across patches.
|
|
106
|
+
*/
|
|
107
|
+
export class Patcher {
|
|
108
|
+
constructor(options) {
|
|
109
|
+
if (!options.snapshots) {
|
|
110
|
+
throw new Error("Hashline Patcher requires a SnapshotStore; section tags are opaque store pointers.");
|
|
111
|
+
}
|
|
112
|
+
this.fs = options.fs;
|
|
113
|
+
this.snapshots = options.snapshots;
|
|
114
|
+
this.recovery = new Recovery(options.snapshots);
|
|
115
|
+
this.blockResolver = options.blockResolver;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Apply every section in `patch`. `prepare` runs the full apply for each
|
|
119
|
+
* section in memory before any write hits the filesystem, so a
|
|
120
|
+
* multi-section batch fails before writing on parse/validation/apply errors.
|
|
121
|
+
* Write commits are sequential rather than transactional; if a write fails,
|
|
122
|
+
* earlier sections may already be on disk and are listed in the thrown error.
|
|
123
|
+
* Returns one {@link PatchSectionResult} per section in the original patch order.
|
|
124
|
+
*/
|
|
125
|
+
async apply(patch) {
|
|
126
|
+
// Single-section fast path.
|
|
127
|
+
if (patch.sections.length === 1) {
|
|
128
|
+
const prepared = await this.prepare(patch.sections[0]);
|
|
129
|
+
return { sections: [await this.commit(prepared)] };
|
|
130
|
+
}
|
|
131
|
+
// Prepare every section first so any failure (stale hash, missing
|
|
132
|
+
// file, parse error, in-memory no-op) surfaces before any write.
|
|
133
|
+
const prepared = [];
|
|
134
|
+
for (const section of patch.sections)
|
|
135
|
+
prepared.push(await this.prepare(section));
|
|
136
|
+
assertUniqueCanonicalPaths(prepared);
|
|
137
|
+
for (const entry of prepared) {
|
|
138
|
+
if (entry.isNoop) {
|
|
139
|
+
throw new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const results = [];
|
|
143
|
+
for (let index = 0; index < prepared.length; index++) {
|
|
144
|
+
try {
|
|
145
|
+
results.push(await this.commit(prepared[index]));
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
// A mid-batch write failure leaves earlier sections on disk with no
|
|
149
|
+
// rollback; report exactly which sections landed so the caller can
|
|
150
|
+
// re-issue only the missing ones instead of double-applying.
|
|
151
|
+
const written = prepared.slice(0, index).map(entry => entry.section.path);
|
|
152
|
+
const notWritten = prepared.slice(index + 1).map(entry => entry.section.path);
|
|
153
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
154
|
+
throw new Error(`Failed to write ${prepared[index].section.path}: ${message}` +
|
|
155
|
+
(written.length > 0 ? ` Sections already written: ${written.join(", ")}.` : "") +
|
|
156
|
+
(notWritten.length > 0 ? ` Sections not written: ${notWritten.join(", ")}.` : ""), { cause: error });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { sections: results };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Run the preflight pass only: read, parse, validate, apply-in-memory.
|
|
163
|
+
* No writes hit the filesystem. Use for CI checks and dry runs.
|
|
164
|
+
*/
|
|
165
|
+
async preflight(patch) {
|
|
166
|
+
const prepared = [];
|
|
167
|
+
for (const section of patch.sections)
|
|
168
|
+
prepared.push(await this.prepare(section));
|
|
169
|
+
assertUniqueCanonicalPaths(prepared);
|
|
170
|
+
for (const entry of prepared) {
|
|
171
|
+
if (entry.isNoop) {
|
|
172
|
+
throw new Error(`Edits to ${entry.section.path} resulted in no changes being made.`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Read a section's target file, parse the section, validate the snapshot
|
|
178
|
+
* tag (with recovery), and apply the edits in memory. Returns a
|
|
179
|
+
* {@link PreparedSection} which can be fed to {@link commit} to land
|
|
180
|
+
* the result on the filesystem.
|
|
181
|
+
*
|
|
182
|
+
* Throws on parse error, missing-file-for-anchored-edit, or unrecovered
|
|
183
|
+
* tag mismatch ({@link MismatchError}).
|
|
184
|
+
*/
|
|
185
|
+
async prepare(section) {
|
|
186
|
+
const { edits, warnings: parseWarnings } = section.parse();
|
|
187
|
+
assertSectionHashPresent(section.path, section.fileHash);
|
|
188
|
+
const canonicalPath = this.fs.canonicalPath(section.path);
|
|
189
|
+
await this.fs.preflightWrite(section.path);
|
|
190
|
+
const { exists, rawContent } = await this.#tryRead(section.path);
|
|
191
|
+
if (!exists) {
|
|
192
|
+
throw new Error(`File not found: ${section.path}. Use the write tool to create new files.`);
|
|
193
|
+
}
|
|
194
|
+
const { bom, text } = stripBom(rawContent);
|
|
195
|
+
const lineEnding = detectLineEnding(text);
|
|
196
|
+
const normalized = normalizeToLF(text);
|
|
197
|
+
const applyResult = this.#applyWithRecovery({
|
|
198
|
+
section,
|
|
199
|
+
canonicalPath,
|
|
200
|
+
exists,
|
|
201
|
+
normalized,
|
|
202
|
+
edits,
|
|
203
|
+
});
|
|
204
|
+
return new PreparedSection(section, canonicalPath, exists, rawContent, bom, lineEnding, normalized, applyResult, parseWarnings);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Commit a previously {@link prepare}d section to the filesystem.
|
|
208
|
+
* Restores line endings and BOM, writes via the {@link Filesystem}, and
|
|
209
|
+
* records a fresh snapshot in the {@link SnapshotStore} keyed by the
|
|
210
|
+
* filesystem-canonical path.
|
|
211
|
+
*/
|
|
212
|
+
async commit(prepared) {
|
|
213
|
+
const { section, normalized, bom, lineEnding, parseWarnings, exists, applyResult, canonicalPath } = prepared;
|
|
214
|
+
const after = applyResult.text;
|
|
215
|
+
const warnings = mergeWarnings(parseWarnings, applyResult.warnings);
|
|
216
|
+
if (after === normalized) {
|
|
217
|
+
const hash = this.#recordFullSnapshot(canonicalPath, normalized);
|
|
218
|
+
return {
|
|
219
|
+
path: section.path,
|
|
220
|
+
canonicalPath,
|
|
221
|
+
op: "noop",
|
|
222
|
+
before: normalized,
|
|
223
|
+
after: normalized,
|
|
224
|
+
persisted: prepared.rawContent,
|
|
225
|
+
written: prepared.rawContent,
|
|
226
|
+
fileHash: hash,
|
|
227
|
+
header: formatHashlineHeader(section.path, hash),
|
|
228
|
+
warnings,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const persisted = bom + restoreLineEndings(after, lineEnding);
|
|
232
|
+
const write = await this.fs.writeText(section.path, persisted);
|
|
233
|
+
const fileHash = this.#recordFullSnapshot(canonicalPath, after);
|
|
234
|
+
const op = exists ? "update" : "create";
|
|
235
|
+
return {
|
|
236
|
+
path: section.path,
|
|
237
|
+
canonicalPath,
|
|
238
|
+
op,
|
|
239
|
+
before: normalized,
|
|
240
|
+
after,
|
|
241
|
+
persisted,
|
|
242
|
+
written: write.text,
|
|
243
|
+
fileHash,
|
|
244
|
+
header: formatHashlineHeader(section.path, fileHash),
|
|
245
|
+
firstChangedLine: applyResult.firstChangedLine,
|
|
246
|
+
blockResolutions: applyResult.blockResolutions,
|
|
247
|
+
warnings,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
async #tryRead(path) {
|
|
251
|
+
try {
|
|
252
|
+
const content = await this.fs.readText(path);
|
|
253
|
+
return { exists: true, rawContent: content };
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
if (isNotFound(error))
|
|
257
|
+
return { exists: false, rawContent: "" };
|
|
258
|
+
throw error;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
#recordFullSnapshot(canonicalPath, normalized) {
|
|
262
|
+
return this.snapshots.record(canonicalPath, normalized);
|
|
263
|
+
}
|
|
264
|
+
#mismatchError(section, canonicalPath, normalized, expected, hashRecognized) {
|
|
265
|
+
const actualFileHash = this.#recordFullSnapshot(canonicalPath, normalized);
|
|
266
|
+
return new MismatchError({
|
|
267
|
+
path: section.path,
|
|
268
|
+
expectedFileHash: expected,
|
|
269
|
+
actualFileHash,
|
|
270
|
+
fileLines: normalized.split("\n"),
|
|
271
|
+
anchorLines: section.collectAnchorLines(),
|
|
272
|
+
hashRecognized,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
#applyWithRecovery(args) {
|
|
276
|
+
const { section, canonicalPath, exists, normalized, edits } = args;
|
|
277
|
+
const expected = exists ? section.fileHash : undefined;
|
|
278
|
+
const expectedSnapshot = expected === undefined ? null : this.snapshots.byHash(canonicalPath, expected);
|
|
279
|
+
const liveHashMatches = expected !== undefined && computeFileHash(normalized) === expected;
|
|
280
|
+
const liveSnapshot = expected === undefined ? null : this.snapshots.byHashAndText(canonicalPath, expected, normalized);
|
|
281
|
+
const liveMatches = liveHashMatches && liveSnapshot !== null;
|
|
282
|
+
if (liveHashMatches && !liveMatches) {
|
|
283
|
+
throw this.#mismatchError(section, canonicalPath, normalized, expected, expectedSnapshot !== null);
|
|
284
|
+
}
|
|
285
|
+
// Resolve `replace block N:` edits to concrete ranges before recovery
|
|
286
|
+
// runs. Block anchors are expressed against the snapshot the section tag
|
|
287
|
+
// names, so resolve against that exact text:
|
|
288
|
+
// - live content matches the tag (or there is no tag) → resolve against
|
|
289
|
+
// the live, normalized content;
|
|
290
|
+
// - the file drifted → resolve against the tagged snapshot's text so the
|
|
291
|
+
// resulting ranges flow through the 3-way-merge recovery below.
|
|
292
|
+
// When a block edit needs the tagged snapshot but it is unavailable, the
|
|
293
|
+
// range cannot be placed safely — reject with a MismatchError (re-read).
|
|
294
|
+
const blockResolutions = [];
|
|
295
|
+
const resolveWarnings = [];
|
|
296
|
+
let resolved = edits;
|
|
297
|
+
if (hasBlockEdit(edits)) {
|
|
298
|
+
const baseText = expected === undefined || liveMatches ? normalized : expectedSnapshot?.text;
|
|
299
|
+
if (baseText === undefined) {
|
|
300
|
+
throw this.#mismatchError(section, canonicalPath, normalized, expected ?? "", false);
|
|
301
|
+
}
|
|
302
|
+
resolved = resolveBlockEdits(edits, baseText, section.path, this.blockResolver, {
|
|
303
|
+
onUnresolved: "throw",
|
|
304
|
+
onResolved: resolution => blockResolutions.push(resolution),
|
|
305
|
+
onWarning: warning => resolveWarnings.push(warning),
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
const withResolveWarnings = (result) => resolveWarnings.length === 0
|
|
309
|
+
? result
|
|
310
|
+
: { ...result, warnings: [...resolveWarnings, ...(result.warnings ?? [])] };
|
|
311
|
+
// No tag, or the tag still names the live content: an edit anchored at any
|
|
312
|
+
// line is safe to apply, and the resolved block spans line up with what
|
|
313
|
+
// the caller read, so echo them back. (A drifted file falls through to
|
|
314
|
+
// recovery below, where line numbers shift, so resolutions are dropped.)
|
|
315
|
+
if (expected === undefined || liveMatches) {
|
|
316
|
+
const result = applyEdits(normalized, resolved);
|
|
317
|
+
return withResolveWarnings(blockResolutions.length > 0 ? { ...result, blockResolutions } : result);
|
|
318
|
+
}
|
|
319
|
+
// Head/tail-only inserts are position-stable: "start"/"end" cannot move
|
|
320
|
+
// with content drift, so a stale tag is non-fatal. Apply onto the live
|
|
321
|
+
// content and warn instead of hard-failing — unlike an anchored
|
|
322
|
+
// mismatch, which cannot be safely relocated and must reject.
|
|
323
|
+
if (!hasAnchorScopedEdit(resolved)) {
|
|
324
|
+
const result = applyEdits(normalized, resolved);
|
|
325
|
+
return withResolveWarnings({ ...result, warnings: [HEADTAIL_DRIFT_WARNING, ...(result.warnings ?? [])] });
|
|
326
|
+
}
|
|
327
|
+
// File drifted: try to replay the edit against the version the tag
|
|
328
|
+
// names and 3-way-merge it onto the live content.
|
|
329
|
+
const recovered = this.recovery.tryRecover({
|
|
330
|
+
path: canonicalPath,
|
|
331
|
+
currentText: normalized,
|
|
332
|
+
fileHash: expected,
|
|
333
|
+
edits: resolved,
|
|
334
|
+
});
|
|
335
|
+
if (recovered)
|
|
336
|
+
return withResolveWarnings(recoveryToApplyResult(recovered));
|
|
337
|
+
const hashRecognized = expectedSnapshot !== null;
|
|
338
|
+
throw this.#mismatchError(section, canonicalPath, normalized, expected, hashRecognized);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=patcher.js.map
|
|
@@ -0,0 +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 = expected === 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 =\n\t\t\t\texpected === 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"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When a hashline payload is authored against `read`/`search` output, each
|
|
3
|
+
* line is prefixed with either a hashline-mode line number (`123:`) or, for
|
|
4
|
+
* diff-style echoes, a leading `+`. These helpers detect that and recover
|
|
5
|
+
* the raw text. Two strip modes are exposed:
|
|
6
|
+
*
|
|
7
|
+
* - {@link stripNewLinePrefixes} — opportunistic: strips when the input
|
|
8
|
+
* clearly carries hashline or diff prefixes, leaves it alone otherwise.
|
|
9
|
+
* - {@link stripHashlinePrefixes} — strict: only strips when every non-empty
|
|
10
|
+
* content line is hashline-prefixed.
|
|
11
|
+
*
|
|
12
|
+
* These run *before* the tokenizer; they exist because hashline mode is the
|
|
13
|
+
* common case for echoed file content, and erroneously echoed prefixes will
|
|
14
|
+
* otherwise turn every content line into a (malformed) op.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Single-pass variant of {@link stripLeadingHashlinePrefixes} that strips at
|
|
18
|
+
* most one leading hashline prefix (`N:`, `>>>N:`, `+N:` etc.) and does NOT
|
|
19
|
+
* loop. Use this when the input carries at most one snapshot prefix (e.g. a
|
|
20
|
+
* bare body row paste from `read` output) — recursive stripping would corrupt
|
|
21
|
+
* content whose own text starts with `digits:`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function stripOneLeadingHashlinePrefix(line: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Strip whichever prefix scheme the lines appear to be carrying:
|
|
26
|
+
* - hashline line-number prefixes (`123:`) when every content line has one
|
|
27
|
+
* - leading `+` (diff style) when at least half the lines have one
|
|
28
|
+
* - mixed `+<n>:` form when present
|
|
29
|
+
*
|
|
30
|
+
* Returns the lines untouched if no scheme is recognized.
|
|
31
|
+
*/
|
|
32
|
+
export declare function stripNewLinePrefixes(lines: string[]): string[];
|
|
33
|
+
/**
|
|
34
|
+
* Strict variant: strip hashline prefixes only when every content line is
|
|
35
|
+
* hashline-prefixed. Returns the lines unchanged otherwise.
|
|
36
|
+
*/
|
|
37
|
+
export declare function stripHashlinePrefixes(lines: string[]): string[];
|
|
38
|
+
/**
|
|
39
|
+
* Normalize line payloads by stripping read/search line prefixes. `null` /
|
|
40
|
+
* `undefined` yield `[]`; a single multiline string is split on `\n`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function hashlineParseText(edit: string[] | string | null | undefined): string[];
|
|
43
|
+
//# sourceMappingURL=prefixes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefixes.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/prefixes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;GAcG;AAmBH;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElE;AAwCD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAwB9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQ/D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAOtF","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 * When a hashline payload is authored against `read`/`search` output, each\n * line is prefixed with either a hashline-mode line number (`123:`) or, for\n * diff-style echoes, a leading `+`. These helpers detect that and recover\n * the raw text. Two strip modes are exposed:\n *\n * - {@link stripNewLinePrefixes} — opportunistic: strips when the input\n * clearly carries hashline or diff prefixes, leaves it alone otherwise.\n * - {@link stripHashlinePrefixes} — strict: only strips when every non-empty\n * content line is hashline-prefixed.\n *\n * These run *before* the tokenizer; they exist because hashline mode is the\n * common case for echoed file content, and erroneously echoed prefixes will\n * otherwise turn every content line into a (malformed) op.\n */\n\nimport { HL_FILE_HASH_LENGTH } from \"./format.js\";\n\nconst HL_PREFIX_RE = /^\\s*(?:>>>|>>)?\\s*(?:[+*-]\\s*)?\\d+:/;\nconst HL_PREFIX_PLUS_RE = /^\\s*(?:>>>|>>)?\\s*\\+\\s*\\d+:/;\nconst HL_HEADER_RE = new RegExp(`^\\\\s*\\\\[[^#\\\\r\\\\n]+#[0-9a-fA-F]{${HL_FILE_HASH_LENGTH}}\\\\]\\\\s*$`);\nconst DIFF_PLUS_RE = /^[+](?![+])/;\nconst READ_TRUNCATION_NOTICE_RE = /^\\[(?:Showing lines \\d+-\\d+ of \\d+|\\d+ more lines? in (?:file|\\S+))\\b.*\\bUse :L?\\d+/;\n\nfunction stripLeadingHashlinePrefixes(line: string): string {\n\tlet result = line;\n\tlet previous: string;\n\tdo {\n\t\tprevious = result;\n\t\tresult = result.replace(HL_PREFIX_RE, \"\");\n\t} while (result !== previous);\n\treturn result;\n}\n/**\n * Single-pass variant of {@link stripLeadingHashlinePrefixes} that strips at\n * most one leading hashline prefix (`N:`, `>>>N:`, `+N:` etc.) and does NOT\n * loop. Use this when the input carries at most one snapshot prefix (e.g. a\n * bare body row paste from `read` output) — recursive stripping would corrupt\n * content whose own text starts with `digits:`.\n */\nexport function stripOneLeadingHashlinePrefix(line: string): string {\n\treturn line.replace(HL_PREFIX_RE, \"\");\n}\n\ninterface LinePrefixStats {\n\tnonEmpty: number;\n\theaderCount: number;\n\thashPrefixCount: number;\n\tdiffPlusHashPrefixCount: number;\n\tdiffPlusCount: number;\n\ttruncationNoticeCount: number;\n}\n\nfunction collectLinePrefixStats(lines: string[]): LinePrefixStats {\n\tconst stats: LinePrefixStats = {\n\t\tnonEmpty: 0,\n\t\theaderCount: 0,\n\t\thashPrefixCount: 0,\n\t\tdiffPlusHashPrefixCount: 0,\n\t\tdiffPlusCount: 0,\n\t\ttruncationNoticeCount: 0,\n\t};\n\n\tfor (const line of lines) {\n\t\tif (line.length === 0) continue;\n\t\tif (READ_TRUNCATION_NOTICE_RE.test(line)) {\n\t\t\tstats.truncationNoticeCount++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (HL_HEADER_RE.test(line)) {\n\t\t\tstats.nonEmpty++;\n\t\t\tstats.headerCount++;\n\t\t\tcontinue;\n\t\t}\n\t\tstats.nonEmpty++;\n\t\tif (HL_PREFIX_RE.test(line)) stats.hashPrefixCount++;\n\t\tif (HL_PREFIX_PLUS_RE.test(line)) stats.diffPlusHashPrefixCount++;\n\t\tif (DIFF_PLUS_RE.test(line)) stats.diffPlusCount++;\n\t}\n\treturn stats;\n}\n\n/**\n * Strip whichever prefix scheme the lines appear to be carrying:\n * - hashline line-number prefixes (`123:`) when every content line has one\n * - leading `+` (diff style) when at least half the lines have one\n * - mixed `+<n>:` form when present\n *\n * Returns the lines untouched if no scheme is recognized.\n */\nexport function stripNewLinePrefixes(lines: string[]): string[] {\n\tconst stats = collectLinePrefixStats(lines);\n\tif (stats.nonEmpty === 0) return lines;\n\n\tconst contentLineCount = stats.nonEmpty - stats.headerCount;\n\tconst stripHash = contentLineCount > 0 && stats.hashPrefixCount === contentLineCount;\n\tconst stripPlus =\n\t\t!stripHash &&\n\t\tstats.diffPlusHashPrefixCount === 0 &&\n\t\tstats.diffPlusCount > 0 &&\n\t\tstats.diffPlusCount >= stats.nonEmpty * 0.5;\n\n\tif (!stripHash && !stripPlus && stats.diffPlusHashPrefixCount === 0) return lines;\n\n\treturn lines\n\t\t.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !(stripHash && HL_HEADER_RE.test(line)))\n\t\t.map(line => {\n\t\t\tif (stripHash) return stripLeadingHashlinePrefixes(line);\n\t\t\tif (stripPlus) return line.replace(DIFF_PLUS_RE, \"\");\n\t\t\tif (stats.diffPlusHashPrefixCount > 0 && HL_PREFIX_PLUS_RE.test(line)) {\n\t\t\t\treturn line.replace(HL_PREFIX_RE, \"\");\n\t\t\t}\n\t\t\treturn line;\n\t\t});\n}\n\n/**\n * Strict variant: strip hashline prefixes only when every content line is\n * hashline-prefixed. Returns the lines unchanged otherwise.\n */\nexport function stripHashlinePrefixes(lines: string[]): string[] {\n\tconst stats = collectLinePrefixStats(lines);\n\tif (stats.nonEmpty === 0) return lines;\n\tconst contentLineCount = stats.nonEmpty - stats.headerCount;\n\tif (contentLineCount === 0 || stats.hashPrefixCount !== contentLineCount) return lines;\n\treturn lines\n\t\t.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !HL_HEADER_RE.test(line))\n\t\t.map(line => stripLeadingHashlinePrefixes(line));\n}\n\n/**\n * Normalize line payloads by stripping read/search line prefixes. `null` /\n * `undefined` yield `[]`; a single multiline string is split on `\\n`.\n */\nexport function hashlineParseText(edit: string[] | string | null | undefined): string[] {\n\tif (edit == null) return [];\n\tif (typeof edit === \"string\") {\n\t\tconst trimmed = edit.endsWith(\"\\n\") ? edit.slice(0, -1) : edit;\n\t\tedit = trimmed.replaceAll(\"\\r\", \"\").split(\"\\n\");\n\t}\n\treturn stripNewLinePrefixes(edit);\n}\n"]}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.
|
|
2
|
+
// 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).
|
|
3
|
+
/**
|
|
4
|
+
* When a hashline payload is authored against `read`/`search` output, each
|
|
5
|
+
* line is prefixed with either a hashline-mode line number (`123:`) or, for
|
|
6
|
+
* diff-style echoes, a leading `+`. These helpers detect that and recover
|
|
7
|
+
* the raw text. Two strip modes are exposed:
|
|
8
|
+
*
|
|
9
|
+
* - {@link stripNewLinePrefixes} — opportunistic: strips when the input
|
|
10
|
+
* clearly carries hashline or diff prefixes, leaves it alone otherwise.
|
|
11
|
+
* - {@link stripHashlinePrefixes} — strict: only strips when every non-empty
|
|
12
|
+
* content line is hashline-prefixed.
|
|
13
|
+
*
|
|
14
|
+
* These run *before* the tokenizer; they exist because hashline mode is the
|
|
15
|
+
* common case for echoed file content, and erroneously echoed prefixes will
|
|
16
|
+
* otherwise turn every content line into a (malformed) op.
|
|
17
|
+
*/
|
|
18
|
+
import { HL_FILE_HASH_LENGTH } from "./format.js";
|
|
19
|
+
const HL_PREFIX_RE = /^\s*(?:>>>|>>)?\s*(?:[+*-]\s*)?\d+:/;
|
|
20
|
+
const HL_PREFIX_PLUS_RE = /^\s*(?:>>>|>>)?\s*\+\s*\d+:/;
|
|
21
|
+
const HL_HEADER_RE = new RegExp(`^\\s*\\[[^#\\r\\n]+#[0-9a-fA-F]{${HL_FILE_HASH_LENGTH}}\\]\\s*$`);
|
|
22
|
+
const DIFF_PLUS_RE = /^[+](?![+])/;
|
|
23
|
+
const READ_TRUNCATION_NOTICE_RE = /^\[(?:Showing lines \d+-\d+ of \d+|\d+ more lines? in (?:file|\S+))\b.*\bUse :L?\d+/;
|
|
24
|
+
function stripLeadingHashlinePrefixes(line) {
|
|
25
|
+
let result = line;
|
|
26
|
+
let previous;
|
|
27
|
+
do {
|
|
28
|
+
previous = result;
|
|
29
|
+
result = result.replace(HL_PREFIX_RE, "");
|
|
30
|
+
} while (result !== previous);
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Single-pass variant of {@link stripLeadingHashlinePrefixes} that strips at
|
|
35
|
+
* most one leading hashline prefix (`N:`, `>>>N:`, `+N:` etc.) and does NOT
|
|
36
|
+
* loop. Use this when the input carries at most one snapshot prefix (e.g. a
|
|
37
|
+
* bare body row paste from `read` output) — recursive stripping would corrupt
|
|
38
|
+
* content whose own text starts with `digits:`.
|
|
39
|
+
*/
|
|
40
|
+
export function stripOneLeadingHashlinePrefix(line) {
|
|
41
|
+
return line.replace(HL_PREFIX_RE, "");
|
|
42
|
+
}
|
|
43
|
+
function collectLinePrefixStats(lines) {
|
|
44
|
+
const stats = {
|
|
45
|
+
nonEmpty: 0,
|
|
46
|
+
headerCount: 0,
|
|
47
|
+
hashPrefixCount: 0,
|
|
48
|
+
diffPlusHashPrefixCount: 0,
|
|
49
|
+
diffPlusCount: 0,
|
|
50
|
+
truncationNoticeCount: 0,
|
|
51
|
+
};
|
|
52
|
+
for (const line of lines) {
|
|
53
|
+
if (line.length === 0)
|
|
54
|
+
continue;
|
|
55
|
+
if (READ_TRUNCATION_NOTICE_RE.test(line)) {
|
|
56
|
+
stats.truncationNoticeCount++;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (HL_HEADER_RE.test(line)) {
|
|
60
|
+
stats.nonEmpty++;
|
|
61
|
+
stats.headerCount++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
stats.nonEmpty++;
|
|
65
|
+
if (HL_PREFIX_RE.test(line))
|
|
66
|
+
stats.hashPrefixCount++;
|
|
67
|
+
if (HL_PREFIX_PLUS_RE.test(line))
|
|
68
|
+
stats.diffPlusHashPrefixCount++;
|
|
69
|
+
if (DIFF_PLUS_RE.test(line))
|
|
70
|
+
stats.diffPlusCount++;
|
|
71
|
+
}
|
|
72
|
+
return stats;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Strip whichever prefix scheme the lines appear to be carrying:
|
|
76
|
+
* - hashline line-number prefixes (`123:`) when every content line has one
|
|
77
|
+
* - leading `+` (diff style) when at least half the lines have one
|
|
78
|
+
* - mixed `+<n>:` form when present
|
|
79
|
+
*
|
|
80
|
+
* Returns the lines untouched if no scheme is recognized.
|
|
81
|
+
*/
|
|
82
|
+
export function stripNewLinePrefixes(lines) {
|
|
83
|
+
const stats = collectLinePrefixStats(lines);
|
|
84
|
+
if (stats.nonEmpty === 0)
|
|
85
|
+
return lines;
|
|
86
|
+
const contentLineCount = stats.nonEmpty - stats.headerCount;
|
|
87
|
+
const stripHash = contentLineCount > 0 && stats.hashPrefixCount === contentLineCount;
|
|
88
|
+
const stripPlus = !stripHash &&
|
|
89
|
+
stats.diffPlusHashPrefixCount === 0 &&
|
|
90
|
+
stats.diffPlusCount > 0 &&
|
|
91
|
+
stats.diffPlusCount >= stats.nonEmpty * 0.5;
|
|
92
|
+
if (!stripHash && !stripPlus && stats.diffPlusHashPrefixCount === 0)
|
|
93
|
+
return lines;
|
|
94
|
+
return lines
|
|
95
|
+
.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !(stripHash && HL_HEADER_RE.test(line)))
|
|
96
|
+
.map(line => {
|
|
97
|
+
if (stripHash)
|
|
98
|
+
return stripLeadingHashlinePrefixes(line);
|
|
99
|
+
if (stripPlus)
|
|
100
|
+
return line.replace(DIFF_PLUS_RE, "");
|
|
101
|
+
if (stats.diffPlusHashPrefixCount > 0 && HL_PREFIX_PLUS_RE.test(line)) {
|
|
102
|
+
return line.replace(HL_PREFIX_RE, "");
|
|
103
|
+
}
|
|
104
|
+
return line;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Strict variant: strip hashline prefixes only when every content line is
|
|
109
|
+
* hashline-prefixed. Returns the lines unchanged otherwise.
|
|
110
|
+
*/
|
|
111
|
+
export function stripHashlinePrefixes(lines) {
|
|
112
|
+
const stats = collectLinePrefixStats(lines);
|
|
113
|
+
if (stats.nonEmpty === 0)
|
|
114
|
+
return lines;
|
|
115
|
+
const contentLineCount = stats.nonEmpty - stats.headerCount;
|
|
116
|
+
if (contentLineCount === 0 || stats.hashPrefixCount !== contentLineCount)
|
|
117
|
+
return lines;
|
|
118
|
+
return lines
|
|
119
|
+
.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !HL_HEADER_RE.test(line))
|
|
120
|
+
.map(line => stripLeadingHashlinePrefixes(line));
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Normalize line payloads by stripping read/search line prefixes. `null` /
|
|
124
|
+
* `undefined` yield `[]`; a single multiline string is split on `\n`.
|
|
125
|
+
*/
|
|
126
|
+
export function hashlineParseText(edit) {
|
|
127
|
+
if (edit == null)
|
|
128
|
+
return [];
|
|
129
|
+
if (typeof edit === "string") {
|
|
130
|
+
const trimmed = edit.endsWith("\n") ? edit.slice(0, -1) : edit;
|
|
131
|
+
edit = trimmed.replaceAll("\r", "").split("\n");
|
|
132
|
+
}
|
|
133
|
+
return stripNewLinePrefixes(edit);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=prefixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prefixes.js","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/prefixes.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 * When a hashline payload is authored against `read`/`search` output, each\n * line is prefixed with either a hashline-mode line number (`123:`) or, for\n * diff-style echoes, a leading `+`. These helpers detect that and recover\n * the raw text. Two strip modes are exposed:\n *\n * - {@link stripNewLinePrefixes} — opportunistic: strips when the input\n * clearly carries hashline or diff prefixes, leaves it alone otherwise.\n * - {@link stripHashlinePrefixes} — strict: only strips when every non-empty\n * content line is hashline-prefixed.\n *\n * These run *before* the tokenizer; they exist because hashline mode is the\n * common case for echoed file content, and erroneously echoed prefixes will\n * otherwise turn every content line into a (malformed) op.\n */\n\nimport { HL_FILE_HASH_LENGTH } from \"./format.js\";\n\nconst HL_PREFIX_RE = /^\\s*(?:>>>|>>)?\\s*(?:[+*-]\\s*)?\\d+:/;\nconst HL_PREFIX_PLUS_RE = /^\\s*(?:>>>|>>)?\\s*\\+\\s*\\d+:/;\nconst HL_HEADER_RE = new RegExp(`^\\\\s*\\\\[[^#\\\\r\\\\n]+#[0-9a-fA-F]{${HL_FILE_HASH_LENGTH}}\\\\]\\\\s*$`);\nconst DIFF_PLUS_RE = /^[+](?![+])/;\nconst READ_TRUNCATION_NOTICE_RE = /^\\[(?:Showing lines \\d+-\\d+ of \\d+|\\d+ more lines? in (?:file|\\S+))\\b.*\\bUse :L?\\d+/;\n\nfunction stripLeadingHashlinePrefixes(line: string): string {\n\tlet result = line;\n\tlet previous: string;\n\tdo {\n\t\tprevious = result;\n\t\tresult = result.replace(HL_PREFIX_RE, \"\");\n\t} while (result !== previous);\n\treturn result;\n}\n/**\n * Single-pass variant of {@link stripLeadingHashlinePrefixes} that strips at\n * most one leading hashline prefix (`N:`, `>>>N:`, `+N:` etc.) and does NOT\n * loop. Use this when the input carries at most one snapshot prefix (e.g. a\n * bare body row paste from `read` output) — recursive stripping would corrupt\n * content whose own text starts with `digits:`.\n */\nexport function stripOneLeadingHashlinePrefix(line: string): string {\n\treturn line.replace(HL_PREFIX_RE, \"\");\n}\n\ninterface LinePrefixStats {\n\tnonEmpty: number;\n\theaderCount: number;\n\thashPrefixCount: number;\n\tdiffPlusHashPrefixCount: number;\n\tdiffPlusCount: number;\n\ttruncationNoticeCount: number;\n}\n\nfunction collectLinePrefixStats(lines: string[]): LinePrefixStats {\n\tconst stats: LinePrefixStats = {\n\t\tnonEmpty: 0,\n\t\theaderCount: 0,\n\t\thashPrefixCount: 0,\n\t\tdiffPlusHashPrefixCount: 0,\n\t\tdiffPlusCount: 0,\n\t\ttruncationNoticeCount: 0,\n\t};\n\n\tfor (const line of lines) {\n\t\tif (line.length === 0) continue;\n\t\tif (READ_TRUNCATION_NOTICE_RE.test(line)) {\n\t\t\tstats.truncationNoticeCount++;\n\t\t\tcontinue;\n\t\t}\n\t\tif (HL_HEADER_RE.test(line)) {\n\t\t\tstats.nonEmpty++;\n\t\t\tstats.headerCount++;\n\t\t\tcontinue;\n\t\t}\n\t\tstats.nonEmpty++;\n\t\tif (HL_PREFIX_RE.test(line)) stats.hashPrefixCount++;\n\t\tif (HL_PREFIX_PLUS_RE.test(line)) stats.diffPlusHashPrefixCount++;\n\t\tif (DIFF_PLUS_RE.test(line)) stats.diffPlusCount++;\n\t}\n\treturn stats;\n}\n\n/**\n * Strip whichever prefix scheme the lines appear to be carrying:\n * - hashline line-number prefixes (`123:`) when every content line has one\n * - leading `+` (diff style) when at least half the lines have one\n * - mixed `+<n>:` form when present\n *\n * Returns the lines untouched if no scheme is recognized.\n */\nexport function stripNewLinePrefixes(lines: string[]): string[] {\n\tconst stats = collectLinePrefixStats(lines);\n\tif (stats.nonEmpty === 0) return lines;\n\n\tconst contentLineCount = stats.nonEmpty - stats.headerCount;\n\tconst stripHash = contentLineCount > 0 && stats.hashPrefixCount === contentLineCount;\n\tconst stripPlus =\n\t\t!stripHash &&\n\t\tstats.diffPlusHashPrefixCount === 0 &&\n\t\tstats.diffPlusCount > 0 &&\n\t\tstats.diffPlusCount >= stats.nonEmpty * 0.5;\n\n\tif (!stripHash && !stripPlus && stats.diffPlusHashPrefixCount === 0) return lines;\n\n\treturn lines\n\t\t.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !(stripHash && HL_HEADER_RE.test(line)))\n\t\t.map(line => {\n\t\t\tif (stripHash) return stripLeadingHashlinePrefixes(line);\n\t\t\tif (stripPlus) return line.replace(DIFF_PLUS_RE, \"\");\n\t\t\tif (stats.diffPlusHashPrefixCount > 0 && HL_PREFIX_PLUS_RE.test(line)) {\n\t\t\t\treturn line.replace(HL_PREFIX_RE, \"\");\n\t\t\t}\n\t\t\treturn line;\n\t\t});\n}\n\n/**\n * Strict variant: strip hashline prefixes only when every content line is\n * hashline-prefixed. Returns the lines unchanged otherwise.\n */\nexport function stripHashlinePrefixes(lines: string[]): string[] {\n\tconst stats = collectLinePrefixStats(lines);\n\tif (stats.nonEmpty === 0) return lines;\n\tconst contentLineCount = stats.nonEmpty - stats.headerCount;\n\tif (contentLineCount === 0 || stats.hashPrefixCount !== contentLineCount) return lines;\n\treturn lines\n\t\t.filter(line => !READ_TRUNCATION_NOTICE_RE.test(line) && !HL_HEADER_RE.test(line))\n\t\t.map(line => stripLeadingHashlinePrefixes(line));\n}\n\n/**\n * Normalize line payloads by stripping read/search line prefixes. `null` /\n * `undefined` yield `[]`; a single multiline string is split on `\\n`.\n */\nexport function hashlineParseText(edit: string[] | string | null | undefined): string[] {\n\tif (edit == null) return [];\n\tif (typeof edit === \"string\") {\n\t\tconst trimmed = edit.endsWith(\"\\n\") ? edit.slice(0, -1) : edit;\n\t\tedit = trimmed.replaceAll(\"\\r\", \"\").split(\"\\n\");\n\t}\n\treturn stripNewLinePrefixes(edit);\n}\n"]}
|