@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,752 @@
|
|
|
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
|
+
* Apply a parsed list of {@link Edit}s to a text body and return the
|
|
5
|
+
* post-edit lines plus any diagnostic warnings. Pure function: no FS, no
|
|
6
|
+
* mutation of the input.
|
|
7
|
+
*
|
|
8
|
+
* Replacement groups are first normalized by {@link repairReplacementBoundaries},
|
|
9
|
+
* which absorbs common model mistakes where a payload restates unchanged range
|
|
10
|
+
* boundaries or duplicates/drops structural closers.
|
|
11
|
+
*/
|
|
12
|
+
import { afterInsertLandingShiftWarning, blockInsertLandingShiftWarning, UNRESOLVED_BLOCK_INTERNAL } from "./messages.js";
|
|
13
|
+
import { cloneCursor } from "./tokenizer.js";
|
|
14
|
+
function isReplacementInsert(edit) {
|
|
15
|
+
return edit.kind === "insert" && edit.mode === "replacement";
|
|
16
|
+
}
|
|
17
|
+
function getCursorAnchors(cursor) {
|
|
18
|
+
return cursor.kind === "before_anchor" || cursor.kind === "after_anchor" ? [cursor.anchor] : [];
|
|
19
|
+
}
|
|
20
|
+
function getEditAnchors(edit) {
|
|
21
|
+
if (edit.kind === "delete")
|
|
22
|
+
return [edit.anchor];
|
|
23
|
+
return getCursorAnchors(edit.cursor);
|
|
24
|
+
}
|
|
25
|
+
function trailingPhantomLine(fileLines) {
|
|
26
|
+
// `split("\n")` on a newline-terminated file yields a trailing "" sentinel.
|
|
27
|
+
// It is addressable for inserts (append-past-end), but it is not real
|
|
28
|
+
// content. Deleting it only strips the file's final newline, so ignore delete
|
|
29
|
+
// edits that land there; inclusive ranges ending at EOF then do the intended
|
|
30
|
+
// thing and delete through the last concrete line.
|
|
31
|
+
return fileLines.length > 1 && fileLines[fileLines.length - 1] === "" ? fileLines.length : 0;
|
|
32
|
+
}
|
|
33
|
+
function dropTrailingPhantomDeletes(edits, fileLines) {
|
|
34
|
+
const phantomLine = trailingPhantomLine(fileLines);
|
|
35
|
+
if (phantomLine === 0)
|
|
36
|
+
return edits;
|
|
37
|
+
return edits.filter(edit => edit.kind !== "delete" || edit.anchor.line !== phantomLine);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Verify every anchored edit points at an existing line. File-version binding is
|
|
41
|
+
* checked once per section via the header hash before this function runs.
|
|
42
|
+
*/
|
|
43
|
+
function validateLineBounds(edits, fileLines) {
|
|
44
|
+
for (const edit of edits) {
|
|
45
|
+
for (const anchor of getEditAnchors(edit)) {
|
|
46
|
+
if (anchor.line < 1 || anchor.line > fileLines.length) {
|
|
47
|
+
throw new Error(`Line ${anchor.line} does not exist (file has ${fileLines.length} lines)`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function cloneAppliedEdit(edit, index) {
|
|
53
|
+
if (edit.kind === "delete")
|
|
54
|
+
return { ...edit, anchor: { ...edit.anchor }, index };
|
|
55
|
+
return { ...edit, cursor: cloneCursor(edit.cursor), index };
|
|
56
|
+
}
|
|
57
|
+
function insertAtStart(fileLines, lineOrigins, lines) {
|
|
58
|
+
if (lines.length === 0)
|
|
59
|
+
return;
|
|
60
|
+
const origins = lines.map(() => "insert");
|
|
61
|
+
if (fileLines.length === 1 && fileLines[0] === "") {
|
|
62
|
+
fileLines.splice(0, 1, ...lines);
|
|
63
|
+
lineOrigins.splice(0, 1, ...origins);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
fileLines.splice(0, 0, ...lines);
|
|
67
|
+
lineOrigins.splice(0, 0, ...origins);
|
|
68
|
+
}
|
|
69
|
+
function insertAtEnd(fileLines, lineOrigins, lines) {
|
|
70
|
+
if (lines.length === 0)
|
|
71
|
+
return undefined;
|
|
72
|
+
const origins = lines.map(() => "insert");
|
|
73
|
+
if (fileLines.length === 1 && fileLines[0] === "") {
|
|
74
|
+
fileLines.splice(0, 1, ...lines);
|
|
75
|
+
lineOrigins.splice(0, 1, ...origins);
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
const hasTrailingNewline = fileLines.length > 0 && fileLines[fileLines.length - 1] === "";
|
|
79
|
+
const insertIndex = hasTrailingNewline ? fileLines.length - 1 : fileLines.length;
|
|
80
|
+
fileLines.splice(insertIndex, 0, ...lines);
|
|
81
|
+
lineOrigins.splice(insertIndex, 0, ...origins);
|
|
82
|
+
return insertIndex + 1;
|
|
83
|
+
}
|
|
84
|
+
function bucketAnchorEditsByLine(edits) {
|
|
85
|
+
const byLine = new Map();
|
|
86
|
+
for (const entry of edits) {
|
|
87
|
+
const line = entry.edit.kind === "delete"
|
|
88
|
+
? entry.edit.anchor.line
|
|
89
|
+
: entry.edit.cursor.kind === "before_anchor" || entry.edit.cursor.kind === "after_anchor"
|
|
90
|
+
? entry.edit.cursor.anchor.line
|
|
91
|
+
: 0;
|
|
92
|
+
const bucket = byLine.get(line);
|
|
93
|
+
if (bucket)
|
|
94
|
+
bucket.push(entry);
|
|
95
|
+
else
|
|
96
|
+
byLine.set(line, [entry]);
|
|
97
|
+
}
|
|
98
|
+
return byLine;
|
|
99
|
+
}
|
|
100
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
101
|
+
// Replacement-boundary repair
|
|
102
|
+
//
|
|
103
|
+
// Models routinely miscount a replacement range's edges. Sometimes the payload
|
|
104
|
+
// re-states unchanged lines that still live on both sides of the range
|
|
105
|
+
// (duplicating a function header and final statement); sometimes it only
|
|
106
|
+
// re-states or omits a structural closer, which leaves delimiter balance broken.
|
|
107
|
+
//
|
|
108
|
+
// A balance-neutral boundary-echo repair fires only when both the leading and
|
|
109
|
+
// trailing payload edges are exact copies of the surviving lines outside the
|
|
110
|
+
// range. One-sided content echoes are left alone unless delimiter-balance repair
|
|
111
|
+
// proves they are duplicated structural boundaries. This preserves intended
|
|
112
|
+
// duplicate statements while absorbing the common "body includes the unchanged
|
|
113
|
+
// wrapper" mistake.
|
|
114
|
+
/** A line that is nothing but closing delimiters: `}`, `)`, `];`, `})`, `},`. */
|
|
115
|
+
export const STRUCTURAL_CLOSER_RE = /^\s*[)\]}]+[;,]?\s*$/;
|
|
116
|
+
/**
|
|
117
|
+
* Net `()` / `[]` / `{}` delta across `lines`, skipping delimiters inside line
|
|
118
|
+
* comments (`//`), block comments, and string/template literals. Block-comment
|
|
119
|
+
* and backtick-template state carry across lines; `"` / `'` reset at EOL since
|
|
120
|
+
* they cannot span lines. Deliberately language-light: constructs it cannot
|
|
121
|
+
* classify (e.g. regex literals) are counted naively, which can only suppress a
|
|
122
|
+
* repair (the safe direction), never force one.
|
|
123
|
+
*/
|
|
124
|
+
function computeDelimiterBalance(lines) {
|
|
125
|
+
const balance = { paren: 0, bracket: 0, brace: 0 };
|
|
126
|
+
let inBlockComment = false;
|
|
127
|
+
let quote = "";
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
for (let i = 0; i < line.length; i++) {
|
|
130
|
+
const ch = line[i];
|
|
131
|
+
if (inBlockComment) {
|
|
132
|
+
if (ch === "*" && line[i + 1] === "/") {
|
|
133
|
+
inBlockComment = false;
|
|
134
|
+
i++;
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (quote) {
|
|
139
|
+
if (ch === "\\")
|
|
140
|
+
i++;
|
|
141
|
+
else if (ch === quote)
|
|
142
|
+
quote = "";
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
146
|
+
quote = ch;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (ch === "/" && line[i + 1] === "/")
|
|
150
|
+
break;
|
|
151
|
+
if (ch === "/" && line[i + 1] === "*") {
|
|
152
|
+
inBlockComment = true;
|
|
153
|
+
i++;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
switch (ch) {
|
|
157
|
+
case "(":
|
|
158
|
+
balance.paren++;
|
|
159
|
+
break;
|
|
160
|
+
case ")":
|
|
161
|
+
balance.paren--;
|
|
162
|
+
break;
|
|
163
|
+
case "[":
|
|
164
|
+
balance.bracket++;
|
|
165
|
+
break;
|
|
166
|
+
case "]":
|
|
167
|
+
balance.bracket--;
|
|
168
|
+
break;
|
|
169
|
+
case "{":
|
|
170
|
+
balance.brace++;
|
|
171
|
+
break;
|
|
172
|
+
case "}":
|
|
173
|
+
balance.brace--;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// `"` / `'` cannot span lines; only backtick templates and block comments do.
|
|
178
|
+
if (quote === '"' || quote === "'")
|
|
179
|
+
quote = "";
|
|
180
|
+
}
|
|
181
|
+
return balance;
|
|
182
|
+
}
|
|
183
|
+
function balanceDelta(a, b) {
|
|
184
|
+
return { paren: a.paren - b.paren, bracket: a.bracket - b.bracket, brace: a.brace - b.brace };
|
|
185
|
+
}
|
|
186
|
+
function balanceNegate(a) {
|
|
187
|
+
return { paren: -a.paren, bracket: -a.bracket, brace: -a.brace };
|
|
188
|
+
}
|
|
189
|
+
function balanceEqual(a, b) {
|
|
190
|
+
return a.paren === b.paren && a.bracket === b.bracket && a.brace === b.brace;
|
|
191
|
+
}
|
|
192
|
+
function balanceIsZero(a) {
|
|
193
|
+
return a.paren === 0 && a.bracket === 0 && a.brace === 0;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Detect a replacement group starting at `start`: a run of `before_anchor`
|
|
197
|
+
* replacement inserts sharing one source op line, immediately followed by the
|
|
198
|
+
* contiguous range deletes for that same op. Mirrors how the parser lowers an
|
|
199
|
+
* `replace N..M:` hunk with a body.
|
|
200
|
+
*/
|
|
201
|
+
function findReplacementGroup(edits, start) {
|
|
202
|
+
const first = edits[start];
|
|
203
|
+
if (first?.kind !== "insert" || first.mode !== "replacement" || first.cursor.kind !== "before_anchor") {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
const { lineNum } = first;
|
|
207
|
+
const anchorLine = first.cursor.anchor.line;
|
|
208
|
+
const insertIndices = [];
|
|
209
|
+
const payload = [];
|
|
210
|
+
let i = start;
|
|
211
|
+
for (; i < edits.length; i++) {
|
|
212
|
+
const edit = edits[i];
|
|
213
|
+
if (edit.kind !== "insert" || edit.mode !== "replacement" || edit.lineNum !== lineNum)
|
|
214
|
+
break;
|
|
215
|
+
if (edit.cursor.kind !== "before_anchor" || edit.cursor.anchor.line !== anchorLine)
|
|
216
|
+
break;
|
|
217
|
+
insertIndices.push(i);
|
|
218
|
+
payload.push(edit.text);
|
|
219
|
+
}
|
|
220
|
+
const deleteIndices = [];
|
|
221
|
+
let expectedLine = anchorLine;
|
|
222
|
+
for (; i < edits.length; i++) {
|
|
223
|
+
const edit = edits[i];
|
|
224
|
+
if (edit.kind !== "delete" || edit.lineNum !== lineNum || edit.anchor.line !== expectedLine)
|
|
225
|
+
break;
|
|
226
|
+
deleteIndices.push(i);
|
|
227
|
+
expectedLine++;
|
|
228
|
+
}
|
|
229
|
+
if (deleteIndices.length === 0)
|
|
230
|
+
return undefined;
|
|
231
|
+
return {
|
|
232
|
+
insertIndices,
|
|
233
|
+
deleteIndices,
|
|
234
|
+
payload,
|
|
235
|
+
startLine: anchorLine,
|
|
236
|
+
endLine: anchorLine + deleteIndices.length - 1,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Largest `k` such that the payload's last `k` lines exactly equal the `k`
|
|
241
|
+
* surviving file lines just below the range AND dropping them zeroes `delta`.
|
|
242
|
+
* Requires a non-zero `delta`: a zero-balance candidate can never account for
|
|
243
|
+
* the imbalance, so intentional duplicates of ordinary statements stay intact,
|
|
244
|
+
* while duplicated structural lines (closers like `});`, openers like `foo(`)
|
|
245
|
+
* are dropped when they exactly explain the imbalance.
|
|
246
|
+
*/
|
|
247
|
+
function findDuplicateSuffix(group, fileLines, delta) {
|
|
248
|
+
if (balanceIsZero(delta))
|
|
249
|
+
return 0;
|
|
250
|
+
const { payload, endLine } = group;
|
|
251
|
+
const maxK = Math.min(payload.length, fileLines.length - endLine);
|
|
252
|
+
for (let k = maxK; k >= 1; k--) {
|
|
253
|
+
let matches = true;
|
|
254
|
+
for (let t = 0; t < k; t++) {
|
|
255
|
+
if (payload[payload.length - k + t] !== fileLines[endLine + t]) {
|
|
256
|
+
matches = false;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (!matches)
|
|
261
|
+
continue;
|
|
262
|
+
if (balanceEqual(computeDelimiterBalance(payload.slice(payload.length - k)), delta))
|
|
263
|
+
return k;
|
|
264
|
+
}
|
|
265
|
+
return 0;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Largest `j` such that the payload's first `j` lines exactly equal the `j`
|
|
269
|
+
* surviving file lines just above the range AND dropping them zeroes `delta`.
|
|
270
|
+
* Requires a non-zero `delta`; see {@link findDuplicateSuffix}.
|
|
271
|
+
*/
|
|
272
|
+
function findDuplicatePrefix(group, fileLines, delta) {
|
|
273
|
+
if (balanceIsZero(delta))
|
|
274
|
+
return 0;
|
|
275
|
+
const { payload, startLine } = group;
|
|
276
|
+
const maxJ = Math.min(payload.length, startLine - 1);
|
|
277
|
+
for (let j = maxJ; j >= 1; j--) {
|
|
278
|
+
let matches = true;
|
|
279
|
+
for (let t = 0; t < j; t++) {
|
|
280
|
+
if (payload[t] !== fileLines[startLine - 1 - j + t]) {
|
|
281
|
+
matches = false;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (!matches)
|
|
286
|
+
continue;
|
|
287
|
+
if (balanceEqual(computeDelimiterBalance(payload.slice(0, j)), delta))
|
|
288
|
+
return j;
|
|
289
|
+
}
|
|
290
|
+
return 0;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Smallest `m` such that the range's last `m` deleted lines are all pure
|
|
294
|
+
* structural closers and sparing them (keeping instead of deleting) zeroes
|
|
295
|
+
* `delta`. The mirror mistake: a range that swallows a closing delimiter the
|
|
296
|
+
* payload never restates.
|
|
297
|
+
*/
|
|
298
|
+
function findDroppedSuffixClosers(group, fileLines, delta) {
|
|
299
|
+
const wanted = balanceNegate(delta);
|
|
300
|
+
const maxM = group.deleteIndices.length;
|
|
301
|
+
for (let m = 1; m <= maxM; m++) {
|
|
302
|
+
if (!STRUCTURAL_CLOSER_RE.test(fileLines[group.endLine - m] ?? ""))
|
|
303
|
+
break;
|
|
304
|
+
if (balanceEqual(computeDelimiterBalance(fileLines.slice(group.endLine - m, group.endLine)), wanted))
|
|
305
|
+
return m;
|
|
306
|
+
}
|
|
307
|
+
return 0;
|
|
308
|
+
}
|
|
309
|
+
function hasNonWhitespace(text) {
|
|
310
|
+
for (let i = 0; i < text.length; i++) {
|
|
311
|
+
const code = text.charCodeAt(i);
|
|
312
|
+
if (code !== 9 && code !== 10 && code !== 11 && code !== 12 && code !== 13 && code !== 32)
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
function countDuplicateLeadingBoundaryLines(group, fileLines) {
|
|
318
|
+
const { payload, startLine } = group;
|
|
319
|
+
const max = Math.min(payload.length, startLine - 1);
|
|
320
|
+
for (let count = max; count >= 1; count--) {
|
|
321
|
+
let matches = true;
|
|
322
|
+
let hasContent = false;
|
|
323
|
+
for (let offset = 0; offset < count; offset++) {
|
|
324
|
+
const line = payload[offset];
|
|
325
|
+
if (line !== fileLines[startLine - 1 - count + offset]) {
|
|
326
|
+
matches = false;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
hasContent ||= hasNonWhitespace(line);
|
|
330
|
+
}
|
|
331
|
+
if (matches && hasContent)
|
|
332
|
+
return count;
|
|
333
|
+
}
|
|
334
|
+
return 0;
|
|
335
|
+
}
|
|
336
|
+
function countDuplicateTrailingBoundaryLines(group, fileLines) {
|
|
337
|
+
const { payload, endLine } = group;
|
|
338
|
+
const max = Math.min(payload.length, fileLines.length - endLine);
|
|
339
|
+
for (let count = max; count >= 1; count--) {
|
|
340
|
+
let matches = true;
|
|
341
|
+
let hasContent = false;
|
|
342
|
+
for (let offset = 0; offset < count; offset++) {
|
|
343
|
+
const line = payload[payload.length - count + offset];
|
|
344
|
+
if (line !== fileLines[endLine + offset]) {
|
|
345
|
+
matches = false;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
hasContent ||= hasNonWhitespace(line);
|
|
349
|
+
}
|
|
350
|
+
if (matches && hasContent)
|
|
351
|
+
return count;
|
|
352
|
+
}
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
function findBoundaryEcho(group, fileLines) {
|
|
356
|
+
const leadingMax = countDuplicateLeadingBoundaryLines(group, fileLines);
|
|
357
|
+
if (leadingMax === 0)
|
|
358
|
+
return undefined;
|
|
359
|
+
const trailingMax = countDuplicateTrailingBoundaryLines(group, fileLines);
|
|
360
|
+
if (trailingMax === 0)
|
|
361
|
+
return undefined;
|
|
362
|
+
// Bail when every payload line could be claimed by a boundary echo: any
|
|
363
|
+
// repair would strip explicit replacement content with no signal that the
|
|
364
|
+
// payload was a mistake rather than an intentional duplication.
|
|
365
|
+
if (leadingMax + trailingMax >= group.payload.length)
|
|
366
|
+
return undefined;
|
|
367
|
+
// Balance-neutrality guard (see header comment): the dropped echo lines must
|
|
368
|
+
// either be delimiter-neutral on their own or exactly cancel the payload/range
|
|
369
|
+
// balance delta. In brace-heavy code where bare closer lines repeat, an
|
|
370
|
+
// "echo" that shifts delimiter balance is structural content the payload
|
|
371
|
+
// placed intentionally — stripping it would corrupt the result.
|
|
372
|
+
const leadingBalance = computeDelimiterBalance(group.payload.slice(0, leadingMax));
|
|
373
|
+
const trailingBalance = computeDelimiterBalance(group.payload.slice(group.payload.length - trailingMax));
|
|
374
|
+
const droppedBalance = balanceDelta(leadingBalance, balanceNegate(trailingBalance));
|
|
375
|
+
if (!balanceIsZero(droppedBalance)) {
|
|
376
|
+
const delta = balanceDelta(computeDelimiterBalance(group.payload), computeDelimiterBalance(fileLines.slice(group.startLine - 1, group.endLine)));
|
|
377
|
+
if (!balanceEqual(droppedBalance, delta))
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
return { leading: leadingMax, trailing: trailingMax };
|
|
381
|
+
}
|
|
382
|
+
function describeBoundaryEchoRepair(group, echo) {
|
|
383
|
+
return (`Auto-repaired a replacement boundary echo at line ${group.startLine}: ` +
|
|
384
|
+
`dropped ${echo.leading} leading and ${echo.trailing} trailing payload line(s) already present outside the range. ` +
|
|
385
|
+
`Issue the payload as the final desired content for the selected range only — never restate unchanged lines bordering the range.`);
|
|
386
|
+
}
|
|
387
|
+
function describeBoundaryRepair(group, action) {
|
|
388
|
+
return (`Auto-repaired a delimiter-balance mismatch in the replacement at line ${group.startLine}: ${action}. ` +
|
|
389
|
+
`Issue the payload as the final desired content only — never restate or omit a closing bracket bordering the range.`);
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Normalize replacement groups so common off-by-one boundaries do not duplicate
|
|
393
|
+
* unchanged surrounding lines or structural closers. Returns the repaired edit
|
|
394
|
+
* list plus one warning per repaired group.
|
|
395
|
+
*/
|
|
396
|
+
function repairReplacementBoundaries(edits, fileLines) {
|
|
397
|
+
const out = [];
|
|
398
|
+
const warnings = [];
|
|
399
|
+
let i = 0;
|
|
400
|
+
while (i < edits.length) {
|
|
401
|
+
const group = findReplacementGroup(edits, i);
|
|
402
|
+
if (!group) {
|
|
403
|
+
out.push(edits[i]);
|
|
404
|
+
i++;
|
|
405
|
+
continue;
|
|
406
|
+
}
|
|
407
|
+
const inserts = group.insertIndices.map(idx => edits[idx]);
|
|
408
|
+
const deletes = group.deleteIndices.map(idx => edits[idx]);
|
|
409
|
+
i = group.deleteIndices[group.deleteIndices.length - 1] + 1;
|
|
410
|
+
const boundaryEcho = findBoundaryEcho(group, fileLines);
|
|
411
|
+
if (boundaryEcho) {
|
|
412
|
+
warnings.push(describeBoundaryEchoRepair(group, boundaryEcho));
|
|
413
|
+
out.push(...inserts.slice(boundaryEcho.leading, inserts.length - boundaryEcho.trailing), ...deletes);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
const delta = balanceDelta(computeDelimiterBalance(group.payload), computeDelimiterBalance(fileLines.slice(group.startLine - 1, group.endLine)));
|
|
417
|
+
if (balanceIsZero(delta)) {
|
|
418
|
+
out.push(...inserts, ...deletes);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
const dupSuffix = findDuplicateSuffix(group, fileLines, delta);
|
|
422
|
+
if (dupSuffix > 0) {
|
|
423
|
+
warnings.push(describeBoundaryRepair(group, `dropped ${dupSuffix} duplicated trailing payload line(s) already present below the range`));
|
|
424
|
+
out.push(...inserts.slice(0, inserts.length - dupSuffix), ...deletes);
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
const dupPrefix = findDuplicatePrefix(group, fileLines, delta);
|
|
428
|
+
if (dupPrefix > 0) {
|
|
429
|
+
warnings.push(describeBoundaryRepair(group, `dropped ${dupPrefix} duplicated leading payload line(s) already present above the range`));
|
|
430
|
+
out.push(...inserts.slice(dupPrefix), ...deletes);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const droppedClosers = findDroppedSuffixClosers(group, fileLines, delta);
|
|
434
|
+
if (droppedClosers > 0) {
|
|
435
|
+
warnings.push(describeBoundaryRepair(group, `kept ${droppedClosers} structural closing line(s) the range deleted without restating`));
|
|
436
|
+
out.push(...inserts, ...deletes.slice(0, deletes.length - droppedClosers));
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
out.push(...inserts, ...deletes);
|
|
440
|
+
}
|
|
441
|
+
return { edits: out, warnings };
|
|
442
|
+
}
|
|
443
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
444
|
+
// After-insert landing correction
|
|
445
|
+
//
|
|
446
|
+
// The body rows of an `insert after N:` hunk carry an implicit depth claim:
|
|
447
|
+
// their leading indentation says how deep the author expects the new lines
|
|
448
|
+
// to sit. Two corrections share that claim, in opposite directions:
|
|
449
|
+
//
|
|
450
|
+
// Outward (any after-insert): when the depth is shallower than line N itself,
|
|
451
|
+
// the hunk is inserting a sibling of some enclosing construct while anchored
|
|
452
|
+
// inside it — the common shape is anchoring on the last statement of a block
|
|
453
|
+
// and writing the body at the parent's depth. Sliding the landing point
|
|
454
|
+
// forward across the structural closer lines that follow (and nothing else —
|
|
455
|
+
// content lines are never crossed) places the body at the depth its
|
|
456
|
+
// indentation names.
|
|
457
|
+
//
|
|
458
|
+
// Inward (block-lowered inserts only): `insert after block N:` anchors on the
|
|
459
|
+
// resolved block's closing line, but a body indented deeper than that closer
|
|
460
|
+
// claims a depth inside the block — the common misreading of the op as
|
|
461
|
+
// "append at the end of block N's body". Sliding the landing point backward
|
|
462
|
+
// across the block's trailing closer lines places the body inside, at its
|
|
463
|
+
// claimed depth. Scoped to block-lowered inserts because there the author
|
|
464
|
+
// named the opener and never saw the closer; a plain `insert after M:` on a
|
|
465
|
+
// closer line stays literal (the escape hatch for genuinely-after content
|
|
466
|
+
// such as method-chain continuations).
|
|
467
|
+
//
|
|
468
|
+
// Both shifts are deliberately conservative: they fire only when the body
|
|
469
|
+
// and anchor indentation are comparable (one is a prefix of the other),
|
|
470
|
+
// cross only pure closing-delimiter lines, stop as soon as depth matches the
|
|
471
|
+
// body's claim, and are abandoned when any other edit in the patch targets a
|
|
472
|
+
// crossed line. Every shift is reported as a warning so the author can
|
|
473
|
+
// re-issue when the original landing was intended.
|
|
474
|
+
/** Leading run of tabs and spaces. */
|
|
475
|
+
function leadingIndent(line) {
|
|
476
|
+
let end = 0;
|
|
477
|
+
while (end < line.length) {
|
|
478
|
+
const code = line.charCodeAt(end);
|
|
479
|
+
if (code !== 9 && code !== 32)
|
|
480
|
+
break;
|
|
481
|
+
end++;
|
|
482
|
+
}
|
|
483
|
+
return line.slice(0, end);
|
|
484
|
+
}
|
|
485
|
+
/** `deeper` strictly extends `shallower` (same indent style, more depth). */
|
|
486
|
+
function isIndentDeeper(deeper, shallower) {
|
|
487
|
+
return deeper.length > shallower.length && deeper.startsWith(shallower);
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Depth of an after-insert hunk's body: the shallowest indentation across its
|
|
491
|
+
* non-blank rows. Returns `undefined` when no depth claim can be made — an
|
|
492
|
+
* all-blank or all-closer body, or rows whose indentation styles are not
|
|
493
|
+
* mutually comparable (tabs vs spaces).
|
|
494
|
+
*/
|
|
495
|
+
function bodyTargetIndent(rows) {
|
|
496
|
+
const nonBlank = rows.filter(hasNonWhitespace);
|
|
497
|
+
if (nonBlank.length === 0)
|
|
498
|
+
return undefined;
|
|
499
|
+
// A body of pure closers re-balances delimiters; it claims no depth.
|
|
500
|
+
if (nonBlank.every(row => STRUCTURAL_CLOSER_RE.test(row)))
|
|
501
|
+
return undefined;
|
|
502
|
+
let target = leadingIndent(nonBlank[0] ?? "");
|
|
503
|
+
for (const row of nonBlank) {
|
|
504
|
+
const indent = leadingIndent(row);
|
|
505
|
+
if (indent.startsWith(target))
|
|
506
|
+
continue;
|
|
507
|
+
if (target.startsWith(indent))
|
|
508
|
+
target = indent;
|
|
509
|
+
else
|
|
510
|
+
return undefined;
|
|
511
|
+
}
|
|
512
|
+
return target;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Resolve where an after-insert hunk anchored on `group.anchor` should land
|
|
516
|
+
* given its body depth `target`: the last structural closer line in the run
|
|
517
|
+
* directly below the anchor whose indentation still covers `target`. Returns
|
|
518
|
+
* `undefined` when the landing stays put.
|
|
519
|
+
*/
|
|
520
|
+
function resolveShiftedLanding(group, target, fileLines, targetedLines) {
|
|
521
|
+
const anchorText = fileLines[group.anchor - 1];
|
|
522
|
+
if (anchorText === undefined || !hasNonWhitespace(anchorText))
|
|
523
|
+
return undefined;
|
|
524
|
+
if (!isIndentDeeper(leadingIndent(anchorText), target))
|
|
525
|
+
return undefined;
|
|
526
|
+
let landing = group.anchor;
|
|
527
|
+
let crossed = 0;
|
|
528
|
+
for (let line = group.anchor + 1; line <= fileLines.length; line++) {
|
|
529
|
+
const text = fileLines[line - 1] ?? "";
|
|
530
|
+
if (!hasNonWhitespace(text))
|
|
531
|
+
continue; // look past blanks, never land on them
|
|
532
|
+
if (!STRUCTURAL_CLOSER_RE.test(text))
|
|
533
|
+
break; // content is never crossed
|
|
534
|
+
const indent = leadingIndent(text);
|
|
535
|
+
if (!indent.startsWith(target))
|
|
536
|
+
break; // shallower than the body — crossing would over-escape
|
|
537
|
+
if (targetedLines.has(line))
|
|
538
|
+
return undefined; // another hunk owns this closer
|
|
539
|
+
landing = line;
|
|
540
|
+
crossed++;
|
|
541
|
+
if (indent.length === target.length)
|
|
542
|
+
break; // depth returned to the body's level
|
|
543
|
+
}
|
|
544
|
+
return landing === group.anchor ? undefined : { line: landing, crossed };
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Resolve where a block-lowered after-insert anchored on the block's closing
|
|
548
|
+
* line should land given a body depth `target` deeper than that closer: just
|
|
549
|
+
* above the block's trailing run of closer lines, bounded below by
|
|
550
|
+
* `blockStart` (an empty block lands the body right after its opener).
|
|
551
|
+
* Returns `undefined` when the landing stays put.
|
|
552
|
+
*/
|
|
553
|
+
function resolveInwardLanding(group, target, blockStart, fileLines, targetedLines) {
|
|
554
|
+
const anchorText = fileLines[group.anchor - 1];
|
|
555
|
+
if (anchorText === undefined || !hasNonWhitespace(anchorText))
|
|
556
|
+
return undefined;
|
|
557
|
+
// Fires only when the block ends in a pure closer the body out-indents.
|
|
558
|
+
// Blocks ending in content (indentation-only languages) already land the
|
|
559
|
+
// body inside the block — nothing to correct.
|
|
560
|
+
if (!STRUCTURAL_CLOSER_RE.test(anchorText))
|
|
561
|
+
return undefined;
|
|
562
|
+
if (!isIndentDeeper(target, leadingIndent(anchorText)))
|
|
563
|
+
return undefined;
|
|
564
|
+
let landing = group.anchor;
|
|
565
|
+
for (let line = group.anchor; line > blockStart; line--) {
|
|
566
|
+
const text = fileLines[line - 1] ?? "";
|
|
567
|
+
if (!hasNonWhitespace(text)) {
|
|
568
|
+
landing = line - 1; // look past trailing blanks, never land after one
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
if (!STRUCTURAL_CLOSER_RE.test(text))
|
|
572
|
+
break; // content reached — land right after it
|
|
573
|
+
const indent = leadingIndent(text);
|
|
574
|
+
if (!isIndentDeeper(target, indent))
|
|
575
|
+
break; // closer at the body's depth — land after it
|
|
576
|
+
// Another hunk owns this closer (the group's own rows put the anchor
|
|
577
|
+
// itself in `targetedLines`; that one is ours to cross).
|
|
578
|
+
if (line !== group.anchor && targetedLines.has(line))
|
|
579
|
+
return undefined;
|
|
580
|
+
landing = line - 1;
|
|
581
|
+
}
|
|
582
|
+
return landing === group.anchor ? undefined : landing;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Slide mis-anchored after-insert hunks to the depth their body indentation
|
|
586
|
+
* claims: outward past the structural closer lines that follow the anchor
|
|
587
|
+
* when the body is shallower, or — for `insert after block N:` lowerings —
|
|
588
|
+
* inward across the block's trailing closers when the body is deeper than
|
|
589
|
+
* the block's closing line. Returns the corrected edit list plus one warning
|
|
590
|
+
* per shifted hunk.
|
|
591
|
+
*/
|
|
592
|
+
function repairAfterInsertLandings(edits, fileLines) {
|
|
593
|
+
// Group plain (non-replacement) after-anchor inserts per authored hunk:
|
|
594
|
+
// rows of one hunk share the anchor line and the patch header line.
|
|
595
|
+
const groups = new Map();
|
|
596
|
+
edits.forEach((edit, idx) => {
|
|
597
|
+
if (edit.kind !== "insert" || edit.mode === "replacement")
|
|
598
|
+
return;
|
|
599
|
+
if (edit.cursor.kind !== "after_anchor")
|
|
600
|
+
return;
|
|
601
|
+
const key = `${edit.cursor.anchor.line}:${edit.lineNum}`;
|
|
602
|
+
const group = groups.get(key);
|
|
603
|
+
if (group === undefined)
|
|
604
|
+
groups.set(key, { anchor: edit.cursor.anchor.line, members: [idx], blockStart: edit.blockStart });
|
|
605
|
+
else
|
|
606
|
+
group.members.push(idx);
|
|
607
|
+
});
|
|
608
|
+
if (groups.size === 0)
|
|
609
|
+
return { edits, warnings: [] };
|
|
610
|
+
// Lines explicitly targeted by any edit; a shift never crosses them.
|
|
611
|
+
const targetedLines = new Set();
|
|
612
|
+
for (const edit of edits) {
|
|
613
|
+
if (edit.kind === "delete")
|
|
614
|
+
targetedLines.add(edit.anchor.line);
|
|
615
|
+
else if (edit.cursor.kind === "before_anchor" || edit.cursor.kind === "after_anchor")
|
|
616
|
+
targetedLines.add(edit.cursor.anchor.line);
|
|
617
|
+
}
|
|
618
|
+
let out;
|
|
619
|
+
const warnings = [];
|
|
620
|
+
const retarget = (group, line) => {
|
|
621
|
+
out ??= [...edits];
|
|
622
|
+
for (const idx of group.members) {
|
|
623
|
+
const edit = out[idx];
|
|
624
|
+
out[idx] = { ...edit, cursor: { kind: "after_anchor", anchor: { line } } };
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
for (const group of groups.values()) {
|
|
628
|
+
const target = bodyTargetIndent(group.members.map(idx => edits[idx].text));
|
|
629
|
+
if (target === undefined)
|
|
630
|
+
continue;
|
|
631
|
+
const outward = resolveShiftedLanding(group, target, fileLines, targetedLines);
|
|
632
|
+
if (outward !== undefined) {
|
|
633
|
+
retarget(group, outward.line);
|
|
634
|
+
warnings.push(afterInsertLandingShiftWarning(group.anchor, outward.line, outward.crossed));
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
if (group.blockStart === undefined)
|
|
638
|
+
continue;
|
|
639
|
+
const inward = resolveInwardLanding(group, target, group.blockStart, fileLines, targetedLines);
|
|
640
|
+
if (inward === undefined)
|
|
641
|
+
continue;
|
|
642
|
+
retarget(group, inward);
|
|
643
|
+
warnings.push(blockInsertLandingShiftWarning(group.blockStart, group.anchor, inward));
|
|
644
|
+
}
|
|
645
|
+
return { edits: out ?? edits, warnings };
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Apply a parsed list of edits to a text body. Pure function — no I/O.
|
|
649
|
+
*
|
|
650
|
+
* Returns the post-edit text and the first changed line number (1-indexed).
|
|
651
|
+
* Throws if an anchor is out of bounds.
|
|
652
|
+
*/
|
|
653
|
+
export function applyEdits(text, edits) {
|
|
654
|
+
if (edits.length === 0)
|
|
655
|
+
return { text, firstChangedLine: undefined };
|
|
656
|
+
// Block edits are deferred until `resolveBlockEdits` expands them into
|
|
657
|
+
// concrete inserts + deletes. Reaching the applier with one still present
|
|
658
|
+
// is an internal wiring bug, not authored-input error.
|
|
659
|
+
for (const edit of edits) {
|
|
660
|
+
if (edit.kind === "block")
|
|
661
|
+
throw new Error(UNRESOLVED_BLOCK_INTERNAL);
|
|
662
|
+
}
|
|
663
|
+
const appliedEdits = edits;
|
|
664
|
+
const fileLines = text.split("\n");
|
|
665
|
+
const lineOrigins = fileLines.map(() => "original");
|
|
666
|
+
let firstChangedLine;
|
|
667
|
+
const trackFirstChanged = (line) => {
|
|
668
|
+
if (firstChangedLine === undefined || line < firstChangedLine)
|
|
669
|
+
firstChangedLine = line;
|
|
670
|
+
};
|
|
671
|
+
const targetEdits = dropTrailingPhantomDeletes(appliedEdits.map((edit, index) => cloneAppliedEdit(edit, index)), fileLines);
|
|
672
|
+
validateLineBounds(targetEdits, fileLines);
|
|
673
|
+
const { edits: repaired, warnings: boundaryWarnings } = repairReplacementBoundaries(targetEdits, fileLines);
|
|
674
|
+
const { edits: landed, warnings: landingWarnings } = repairAfterInsertLandings(repaired, fileLines);
|
|
675
|
+
const warnings = [...boundaryWarnings, ...landingWarnings];
|
|
676
|
+
// Partition edits into bof, eof, and anchor-targeted buckets.
|
|
677
|
+
const bofLines = [];
|
|
678
|
+
const eofLines = [];
|
|
679
|
+
const anchorEdits = [];
|
|
680
|
+
landed.forEach((edit, idx) => {
|
|
681
|
+
if (edit.kind === "insert" && edit.cursor.kind === "bof") {
|
|
682
|
+
bofLines.push(edit.text);
|
|
683
|
+
}
|
|
684
|
+
else if (edit.kind === "insert" && edit.cursor.kind === "eof") {
|
|
685
|
+
eofLines.push(edit.text);
|
|
686
|
+
}
|
|
687
|
+
else {
|
|
688
|
+
anchorEdits.push({ edit, idx });
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
// Apply per-line buckets bottom-up so earlier indices stay valid.
|
|
692
|
+
const byLine = bucketAnchorEditsByLine(anchorEdits);
|
|
693
|
+
for (const line of [...byLine.keys()].sort((a, b) => b - a)) {
|
|
694
|
+
const bucket = byLine.get(line);
|
|
695
|
+
if (!bucket)
|
|
696
|
+
continue;
|
|
697
|
+
bucket.sort((a, b) => a.idx - b.idx);
|
|
698
|
+
const idx = line - 1;
|
|
699
|
+
const currentLine = fileLines[idx] ?? "";
|
|
700
|
+
const beforeInsertLines = [];
|
|
701
|
+
const afterInsertLines = [];
|
|
702
|
+
const replacementLines = [];
|
|
703
|
+
let deleteLine = false;
|
|
704
|
+
for (const { edit } of bucket) {
|
|
705
|
+
if (isReplacementInsert(edit)) {
|
|
706
|
+
replacementLines.push(edit.text);
|
|
707
|
+
}
|
|
708
|
+
else if (edit.kind === "insert" && edit.cursor.kind === "after_anchor") {
|
|
709
|
+
afterInsertLines.push(edit.text);
|
|
710
|
+
}
|
|
711
|
+
else if (edit.kind === "insert") {
|
|
712
|
+
beforeInsertLines.push(edit.text);
|
|
713
|
+
}
|
|
714
|
+
else if (edit.kind === "delete") {
|
|
715
|
+
deleteLine = true;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (beforeInsertLines.length === 0 &&
|
|
719
|
+
replacementLines.length === 0 &&
|
|
720
|
+
afterInsertLines.length === 0 &&
|
|
721
|
+
!deleteLine)
|
|
722
|
+
continue;
|
|
723
|
+
const replacement = deleteLine
|
|
724
|
+
? [...beforeInsertLines, ...replacementLines, ...afterInsertLines]
|
|
725
|
+
: [...beforeInsertLines, ...replacementLines, currentLine, ...afterInsertLines];
|
|
726
|
+
const origins = [];
|
|
727
|
+
for (let i = 0; i < beforeInsertLines.length; i++)
|
|
728
|
+
origins.push("insert");
|
|
729
|
+
for (let i = 0; i < replacementLines.length; i++)
|
|
730
|
+
origins.push(deleteLine ? "replacement" : "insert");
|
|
731
|
+
if (!deleteLine)
|
|
732
|
+
origins.push(lineOrigins[idx] ?? "original");
|
|
733
|
+
for (let i = 0; i < afterInsertLines.length; i++)
|
|
734
|
+
origins.push("insert");
|
|
735
|
+
fileLines.splice(idx, 1, ...replacement);
|
|
736
|
+
lineOrigins.splice(idx, 1, ...origins);
|
|
737
|
+
trackFirstChanged(line);
|
|
738
|
+
}
|
|
739
|
+
if (bofLines.length > 0) {
|
|
740
|
+
insertAtStart(fileLines, lineOrigins, bofLines);
|
|
741
|
+
trackFirstChanged(1);
|
|
742
|
+
}
|
|
743
|
+
const eofChangedLine = insertAtEnd(fileLines, lineOrigins, eofLines);
|
|
744
|
+
if (eofChangedLine !== undefined)
|
|
745
|
+
trackFirstChanged(eofChangedLine);
|
|
746
|
+
return {
|
|
747
|
+
text: fileLines.join("\n"),
|
|
748
|
+
firstChangedLine,
|
|
749
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
//# sourceMappingURL=apply.js.map
|