@bastani/atomic 0.9.8 → 0.9.9-alpha.2
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 +36 -0
- package/dist/builtin/cursor/CHANGELOG.md +12 -0
- package/dist/builtin/cursor/package.json +3 -3
- package/dist/builtin/intercom/CHANGELOG.md +13 -0
- package/dist/builtin/intercom/package.json +3 -3
- package/dist/builtin/mcp/CHANGELOG.md +13 -0
- package/dist/builtin/mcp/package.json +4 -4
- package/dist/builtin/subagents/CHANGELOG.md +13 -0
- package/dist/builtin/subagents/package.json +5 -5
- package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +8 -2
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +2 -1
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +2 -0
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +2 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +6 -0
- package/dist/builtin/subagents/src/shared/types-config.ts +4 -0
- package/dist/builtin/subagents/src/shared/types-depth.ts +29 -2
- package/dist/builtin/web-access/CHANGELOG.md +13 -0
- package/dist/builtin/web-access/package.json +3 -3
- package/dist/builtin/web-access/web-search-tool.ts +1 -2
- package/dist/builtin/workflows/CHANGELOG.md +29 -0
- package/dist/builtin/workflows/README.md +17 -8
- package/dist/builtin/workflows/builtin/goal-prompts.ts +8 -2
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +26 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +8 -3
- package/dist/builtin/workflows/builtin/ralph-runner.ts +2 -0
- package/dist/builtin/workflows/builtin/shared-prompts.ts +24 -1
- package/dist/builtin/workflows/package.json +3 -3
- package/dist/builtin/workflows/src/durable/backend.ts +53 -15
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +245 -0
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +213 -0
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +120 -170
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +84 -8
- package/dist/builtin/workflows/src/durable/dbos-metadata.ts +98 -0
- package/dist/builtin/workflows/src/durable/dbos-tombstone.ts +27 -0
- package/dist/builtin/workflows/src/durable/factory.ts +1 -1
- package/dist/builtin/workflows/src/durable/file-backend.ts +247 -241
- package/dist/builtin/workflows/src/durable/file-lock.ts +153 -0
- package/dist/builtin/workflows/src/durable/file-state.ts +104 -0
- package/dist/builtin/workflows/src/durable/format-version.ts +12 -0
- package/dist/builtin/workflows/src/durable/index.ts +12 -0
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +16 -27
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +20 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +29 -29
- package/dist/builtin/workflows/src/durable/scoped-backend.ts +20 -3
- package/dist/builtin/workflows/src/durable/stage-primitive.ts +29 -8
- package/dist/builtin/workflows/src/durable/types.ts +3 -0
- package/dist/builtin/workflows/src/engine/primitives/task.ts +1 -0
- package/dist/builtin/workflows/src/engine/run.ts +14 -14
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +39 -9
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +10 -0
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +133 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +15 -40
- package/dist/builtin/workflows/src/extension/wiring.ts +9 -6
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +226 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +1 -0
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +66 -112
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +5 -5
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +16 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +50 -43
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-output.ts +91 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-direct.ts +95 -46
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +3 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +3 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-options.ts +36 -7
- package/dist/builtin/workflows/src/runs/shared/worktree-cache-lifecycle.ts +25 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-cwd.ts +103 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-generation.ts +57 -0
- package/dist/builtin/workflows/src/runs/shared/worktree-git.ts +134 -8
- package/dist/builtin/workflows/src/runs/shared/worktree.ts +2 -0
- package/dist/builtin/workflows/src/shared/resumable-workflow-notices.ts +43 -0
- package/dist/builtin/workflows/src/shared/serializable.ts +1 -1
- package/dist/builtin/workflows/src/shared/timing.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +5 -3
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +1 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +24 -14
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +43 -13
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/internal-intercom-broker.d.ts.map +1 -1
- package/dist/bun/register-bedrock.d.ts.map +1 -1
- package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
- package/dist/bun/split-loader.d.ts.map +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/initial-message.d.ts.map +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/project-trust.d.ts.map +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/config-self-update.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/core/agent-session-accessors.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -7
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-bash.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +6 -34
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +95 -233
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-export.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +0 -4
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +1 -5
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -6
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-models.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-retry.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-skill-block.d.ts.map +1 -1
- package/dist/core/agent-session-state.d.ts.map +1 -1
- package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
- package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-types.d.ts +2 -12
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/anthropic-thinking-guard.d.ts.map +1 -1
- package/dist/core/async/format.d.ts.map +1 -1
- package/dist/core/async/job-manager.d.ts.map +1 -1
- package/dist/core/async/session-manager.d.ts.map +1 -1
- package/dist/core/async/types.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/auth-guidance.d.ts.map +1 -1
- package/dist/core/auth-storage-backends.d.ts.map +1 -1
- package/dist/core/auth-storage.d.ts +4 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/builtin-packages.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction-boundary.d.ts +9 -0
- package/dist/core/compaction/compaction-boundary.d.ts.map +1 -0
- package/dist/core/compaction/compaction-boundary.js +115 -0
- package/dist/core/compaction/compaction-boundary.js.map +1 -0
- package/dist/core/compaction/compaction-parameters.d.ts +5 -0
- package/dist/core/compaction/compaction-parameters.d.ts.map +1 -0
- package/dist/core/compaction/compaction-parameters.js +27 -0
- package/dist/core/compaction/compaction-parameters.js.map +1 -0
- package/dist/core/compaction/compaction-runner.d.ts +14 -0
- package/dist/core/compaction/compaction-runner.d.ts.map +1 -0
- package/dist/core/compaction/compaction-runner.js +29 -0
- package/dist/core/compaction/compaction-runner.js.map +1 -0
- package/dist/core/compaction/compaction-types.d.ts +79 -0
- package/dist/core/compaction/compaction-types.d.ts.map +1 -0
- package/dist/core/compaction/compaction-types.js +6 -0
- package/dist/core/compaction/compaction-types.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/deleted-ranges.d.ts +6 -0
- package/dist/core/compaction/deleted-ranges.d.ts.map +1 -0
- package/dist/core/compaction/deleted-ranges.js +134 -0
- package/dist/core/compaction/deleted-ranges.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -1
- package/dist/core/compaction/index.d.ts.map +1 -1
- package/dist/core/compaction/index.js +7 -1
- package/dist/core/compaction/index.js.map +1 -1
- package/dist/core/compaction/range-planner.d.ts +21 -0
- package/dist/core/compaction/range-planner.d.ts.map +1 -0
- package/dist/core/compaction/range-planner.js +145 -0
- package/dist/core/compaction/range-planner.js.map +1 -0
- package/dist/core/compaction/transcript-serialization.d.ts +11 -0
- package/dist/core/compaction/transcript-serialization.d.ts.map +1 -0
- package/dist/core/compaction/transcript-serialization.js +104 -0
- package/dist/core/compaction/transcript-serialization.js.map +1 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/context-window.d.ts.map +1 -1
- package/dist/core/copilot-anthropic-sse-repair.d.ts.map +1 -1
- package/dist/core/copilot-errors.d.ts.map +1 -1
- package/dist/core/copilot-gemini-payload-sanitizer.d.ts.map +1 -1
- package/dist/core/copilot-gemini-reasoning.d.ts.map +1 -1
- package/dist/core/copilot-gemini-tool-arguments.d.ts.map +1 -1
- package/dist/core/copilot-hosts.d.ts.map +1 -1
- package/dist/core/copilot-model-catalog.d.ts.map +1 -1
- package/dist/core/copilot-model-static-fallbacks.d.ts.map +1 -1
- package/dist/core/copilot-model-synthesis.d.ts.map +1 -1
- package/dist/core/defaults.d.ts.map +1 -1
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/template-script.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/command-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.d.ts +2 -2
- 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/event-results.d.ts +2 -2
- package/dist/core/extensions/event-results.d.ts.map +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/event-types.d.ts.map +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-core.d.ts.map +1 -1
- package/dist/core/extensions/loader-discovery.d.ts.map +1 -1
- package/dist/core/extensions/loader-resources.d.ts.map +1 -1
- package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/message-types.d.ts.map +1 -1
- package/dist/core/extensions/provider-types.d.ts.map +1 -1
- package/dist/core/extensions/reactive-widget.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-events.d.ts.map +1 -1
- package/dist/core/extensions/runner-handlers.d.ts.map +1 -1
- package/dist/core/extensions/runner-project-trust.d.ts.map +1 -1
- package/dist/core/extensions/runner-registries.d.ts.map +1 -1
- package/dist/core/extensions/runner-shortcuts.d.ts.map +1 -1
- package/dist/core/extensions/runner-ui.d.ts.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/session-events.d.ts +7 -7
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/extensions/tool-events.d.ts.map +1 -1
- package/dist/core/extensions/tool-types.d.ts.map +1 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/wrapper.d.ts.map +1 -1
- package/dist/core/flattened-tool-arguments.d.ts.map +1 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/messages.d.ts +4 -0
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +11 -0
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry-auth.d.ts.map +1 -1
- package/dist/core/model-registry-builtins.d.ts.map +1 -1
- package/dist/core/model-registry-builtins.js.map +1 -1
- package/dist/core/model-registry-custom-loader.d.ts.map +1 -1
- package/dist/core/model-registry-custom-loader.js.map +1 -1
- package/dist/core/model-registry-dynamic.d.ts.map +1 -1
- package/dist/core/model-registry-loader.d.ts.map +1 -1
- package/dist/core/model-registry-schemas.d.ts +65 -13
- package/dist/core/model-registry-schemas.d.ts.map +1 -1
- package/dist/core/model-registry-schemas.js +5 -1
- package/dist/core/model-registry-schemas.js.map +1 -1
- package/dist/core/model-registry-types.d.ts.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-resolver-cli.d.ts.map +1 -1
- package/dist/core/model-resolver-defaults.d.ts.map +1 -1
- package/dist/core/model-resolver-initial.d.ts.map +1 -1
- package/dist/core/model-resolver-patterns.d.ts.map +1 -1
- package/dist/core/model-resolver-scope.d.ts.map +1 -1
- package/dist/core/model-resolver-types.d.ts.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/openai-responses-payload-sanitizer.d.ts.map +1 -1
- package/dist/core/output-guard.d.ts.map +1 -1
- package/dist/core/package-manager-auto-resources.d.ts.map +1 -1
- package/dist/core/package-manager-command.d.ts.map +1 -1
- package/dist/core/package-manager-constants.d.ts.map +1 -1
- package/dist/core/package-manager-env.d.ts.map +1 -1
- package/dist/core/package-manager-git.d.ts.map +1 -1
- package/dist/core/package-manager-manifest.d.ts.map +1 -1
- package/dist/core/package-manager-npm.d.ts.map +1 -1
- package/dist/core/package-manager-operations.d.ts.map +1 -1
- package/dist/core/package-manager-paths.d.ts.map +1 -1
- package/dist/core/package-manager-progress.d.ts.map +1 -1
- package/dist/core/package-manager-resolver.d.ts.map +1 -1
- package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -1
- package/dist/core/package-manager-resource-collector.d.ts.map +1 -1
- package/dist/core/package-manager-resource-files.d.ts.map +1 -1
- package/dist/core/package-manager-resource-patterns.d.ts.map +1 -1
- package/dist/core/package-manager-settings.d.ts.map +1 -1
- package/dist/core/package-manager-source.d.ts.map +1 -1
- package/dist/core/package-manager-types.d.ts.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/prompt-templates-async.d.ts.map +1 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-context-usage.d.ts.map +1 -1
- package/dist/core/provider-context-usage.js +1 -2
- package/dist/core/provider-context-usage.js.map +1 -1
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resource-loader-assets.d.ts.map +1 -1
- package/dist/core/resource-loader-context-files.d.ts.map +1 -1
- package/dist/core/resource-loader-core.d.ts.map +1 -1
- package/dist/core/resource-loader-discovery.d.ts.map +1 -1
- package/dist/core/resource-loader-extensions.d.ts.map +1 -1
- package/dist/core/resource-loader-helpers.d.ts.map +1 -1
- package/dist/core/resource-loader-internals.d.ts.map +1 -1
- package/dist/core/resource-loader-package-resources.d.ts.map +1 -1
- package/dist/core/resource-loader-paths.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-source-info.d.ts.map +1 -1
- package/dist/core/resource-loader-types.d.ts.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/sdk-exports.d.ts.map +1 -1
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/session-cwd.d.ts.map +1 -1
- package/dist/core/session-entry-normalization.d.ts.map +1 -1
- package/dist/core/session-manager-archive.d.ts +2 -1
- package/dist/core/session-manager-archive.d.ts.map +1 -1
- package/dist/core/session-manager-archive.js +2 -2
- package/dist/core/session-manager-archive.js.map +1 -1
- package/dist/core/session-manager-classification.d.ts +9 -0
- package/dist/core/session-manager-classification.d.ts.map +1 -0
- package/dist/core/session-manager-classification.js +37 -0
- package/dist/core/session-manager-classification.js.map +1 -0
- package/dist/core/session-manager-core.d.ts +4 -4
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +13 -8
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +4 -3
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +12 -10
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts +6 -23
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +23 -256
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +3 -3
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-migrations.d.ts.map +1 -1
- package/dist/core/session-manager-paths.d.ts.map +1 -1
- package/dist/core/session-manager-storage.d.ts +1 -1
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +3 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +14 -15
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager-validation.d.ts.map +1 -1
- package/dist/core/session-manager.d.ts +3 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-core.d.ts.map +1 -1
- package/dist/core/settings-manager-internals.d.ts.map +1 -1
- package/dist/core/settings-manager-resource-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-merge.d.ts.map +1 -1
- package/dist/core/settings-storage.d.ts.map +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/skills-async.d.ts.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/source-info.d.ts.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/telemetry.d.ts.map +1 -1
- package/dist/core/thinking-blocks.d.ts.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/tools/artifact-protocol.d.ts.map +1 -1
- package/dist/core/tools/artifacts.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/config.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/index.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/inline-input.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/row-intent.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/contract.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/derivations.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/focus.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/selectors/projections.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/state.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/format-answer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/response-envelope.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/types.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/tool/validate-questionnaire.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/body-residual-spacer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/component-binding.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/option-list-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/markdown-content-cache.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-box-renderer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-layout-decider.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-pane.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/tab-bar.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/props-adapter.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/stateful-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/tab-components.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/tab-content-strategy.d.ts.map +1 -1
- package/dist/core/tools/bash-async-execution.d.ts.map +1 -1
- package/dist/core/tools/bash-async-jobs.d.ts.map +1 -1
- package/dist/core/tools/bash-async-output.d.ts.map +1 -1
- package/dist/core/tools/bash-interceptor.d.ts.map +1 -1
- package/dist/core/tools/bash-leading-cd.d.ts.map +1 -1
- package/dist/core/tools/bash-pty-native.d.ts.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/block-resolver.d.ts.map +1 -1
- package/dist/core/tools/conflict-registry.d.ts.map +1 -1
- package/dist/core/tools/directory-tree.d.ts.map +1 -1
- package/dist/core/tools/edit-diff-preserve.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/fetch-url.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/glob-path-utils.d.ts.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/apply.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/block.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/diff-preview.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/format.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/fs.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/index.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/input.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/mismatch.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/normalize.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/patcher.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/prefixes.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/recovery.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/snapshots.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/stream.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/types.d.ts.map +1 -1
- package/dist/core/tools/hashline.d.ts.map +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/notebook.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/oversized-tool-result.d.ts.map +1 -1
- package/dist/core/tools/path-utils.d.ts.map +1 -1
- package/dist/core/tools/read-document-extract.d.ts.map +1 -1
- package/dist/core/tools/read-selectors.d.ts.map +1 -1
- package/dist/core/tools/read-url.d.ts.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/resource-selectors.d.ts.map +1 -1
- package/dist/core/tools/search-details.d.ts.map +1 -1
- package/dist/core/tools/search-line-ranges.d.ts.map +1 -1
- package/dist/core/tools/search-native.d.ts.map +1 -1
- package/dist/core/tools/search.d.ts.map +1 -1
- package/dist/core/tools/structured-output.d.ts.map +1 -1
- package/dist/core/tools/todos-execute.d.ts.map +1 -1
- package/dist/core/tools/todos-locks.d.ts.map +1 -1
- package/dist/core/tools/todos-model.d.ts.map +1 -1
- package/dist/core/tools/todos-mutations.d.ts.map +1 -1
- package/dist/core/tools/todos-paths.d.ts.map +1 -1
- package/dist/core/tools/todos-render.d.ts.map +1 -1
- package/dist/core/tools/todos-storage.d.ts.map +1 -1
- package/dist/core/tools/todos-types.d.ts.map +1 -1
- package/dist/core/tools/todos-types.js +1 -1
- package/dist/core/tools/todos-types.js.map +1 -1
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +6 -2
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/tool-limits.d.ts.map +1 -1
- package/dist/core/tools/truncate.d.ts.map +1 -1
- package/dist/core/tools/url-ip-guards.d.ts.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/typebox-compat.d.ts +12 -0
- package/dist/core/typebox-compat.d.ts.map +1 -0
- package/dist/core/typebox-compat.js +10 -0
- package/dist/core/typebox-compat.js.map +1 -0
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/main-app-mode.d.ts.map +1 -1
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-early-input.d.ts.map +1 -1
- package/dist/main-session-options.d.ts.map +1 -1
- package/dist/main-session.d.ts +1 -0
- package/dist/main-session.d.ts.map +1 -1
- package/dist/main-session.js +7 -0
- package/dist/main-session.js.map +1 -1
- package/dist/main-stdio.d.ts.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/migrations-config-values.d.ts.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/atomic-banner.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +4 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +12 -22
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +5 -11
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +3 -0
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +1 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-terminal-cleanup.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js +1 -1
- package/dist/modes/interactive/components/chat-session-host-utils.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +1 -0
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts +20 -0
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js +48 -0
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -0
- package/dist/modes/interactive/components/config-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-window-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-delete.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-header.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-list.js +3 -0
- package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-tree.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-utils.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-options.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-submenus.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-component.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-help.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-label-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-model.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector-viewport.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
- package/dist/modes/interactive/components/working-status.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +3 -47
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-child-ordering.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-context.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-custom-ui.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode-deps.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js +1 -1
- package/dist/modes/interactive/interactive-mode-deps.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +5 -3
- 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-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-onboarding.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-queueing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +21 -12
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-disclosure.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-resource-paths.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-resource-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/model-search.d.ts.map +1 -1
- package/dist/modes/interactive/theme/color-utils.d.ts.map +1 -1
- package/dist/modes/interactive/theme/export-colors.d.ts.map +1 -1
- package/dist/modes/interactive/theme/global-theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/terminal-detection.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-parse.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/tui-theme.d.ts.map +1 -1
- package/dist/modes/interactive/whimsical-messages.d.ts.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -5
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +1 -6
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +0 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-extension-ui.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-responses.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-session-binding.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -11
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli-parser.d.ts.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/changelog.d.ts.map +1 -1
- package/dist/utils/child-process.d.ts.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/deprecation.d.ts.map +1 -1
- package/dist/utils/event-loop.d.ts.map +1 -1
- package/dist/utils/exif-orientation.d.ts.map +1 -1
- package/dist/utils/frontmatter.d.ts.map +1 -1
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/git-env.d.ts.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/html.d.ts.map +1 -1
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-process.d.ts.map +1 -1
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-worker.d.ts.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/json.d.ts.map +1 -1
- package/dist/utils/markit.d.ts.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/module-require.d.ts.map +1 -1
- package/dist/utils/open-browser.d.ts.map +1 -1
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/photon.d.ts.map +1 -1
- package/dist/utils/pi-user-agent.d.ts.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/sleep.d.ts.map +1 -1
- package/dist/utils/split-launcher.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/windows-self-update.d.ts.map +1 -1
- package/docs/compaction.md +97 -772
- package/docs/custom-provider.md +7 -1
- package/docs/extensions.md +31 -33
- package/docs/json.md +2 -2
- package/docs/rpc.md +32 -24
- package/docs/sdk.md +3 -3
- package/docs/session-format.md +49 -30
- package/docs/sessions.md +5 -3
- package/docs/settings.md +14 -4
- package/docs/usage.md +1 -1
- package/docs/workflows.md +30 -15
- package/examples/extensions/README.md +3 -1
- package/examples/extensions/custom-compaction.ts +14 -58
- package/examples/extensions/handoff.ts +2 -3
- package/examples/extensions/subagent/schemas.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -2
- package/examples/extensions/todo.ts +1 -2
- package/npm-shrinkwrap.json +214 -98
- package/package.json +12 -12
- package/dist/core/compaction/context-assistant-turns.d.ts +0 -42
- package/dist/core/compaction/context-assistant-turns.d.ts.map +0 -1
- package/dist/core/compaction/context-assistant-turns.js +0 -87
- package/dist/core/compaction/context-assistant-turns.js.map +0 -1
- package/dist/core/compaction/context-compaction-critical.d.ts +0 -15
- package/dist/core/compaction/context-compaction-critical.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-critical.js +0 -57
- package/dist/core/compaction/context-compaction-critical.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts +0 -18
- package/dist/core/compaction/context-compaction-eviction-alternates.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction-alternates.js +0 -186
- package/dist/core/compaction/context-compaction-eviction-alternates.js.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.d.ts +0 -12
- package/dist/core/compaction/context-compaction-eviction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-eviction.js +0 -222
- package/dist/core/compaction/context-compaction-eviction.js.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.d.ts +0 -28
- package/dist/core/compaction/context-compaction-metrics.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-metrics.js +0 -107
- package/dist/core/compaction/context-compaction-metrics.js.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.d.ts +0 -9
- package/dist/core/compaction/context-compaction-prompt.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-prompt.js +0 -163
- package/dist/core/compaction/context-compaction-prompt.js.map +0 -1
- package/dist/core/compaction/context-compaction-runner.d.ts +0 -11
- package/dist/core/compaction/context-compaction-runner.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-runner.js +0 -273
- package/dist/core/compaction/context-compaction-runner.js.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.d.ts +0 -5
- package/dist/core/compaction/context-compaction-strategy.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-strategy.js +0 -27
- package/dist/core/compaction/context-compaction-strategy.js.map +0 -1
- package/dist/core/compaction/context-compaction-types.d.ts +0 -75
- package/dist/core/compaction/context-compaction-types.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction-types.js +0 -6
- package/dist/core/compaction/context-compaction-types.js.map +0 -1
- package/dist/core/compaction/context-compaction.d.ts +0 -10
- package/dist/core/compaction/context-compaction.d.ts.map +0 -1
- package/dist/core/compaction/context-compaction.js +0 -8
- package/dist/core/compaction/context-compaction.js.map +0 -1
- package/dist/core/compaction/context-deletion-application.d.ts +0 -14
- package/dist/core/compaction/context-deletion-application.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-application.js +0 -261
- package/dist/core/compaction/context-deletion-application.js.map +0 -1
- package/dist/core/compaction/context-deletion-store.d.ts +0 -78
- package/dist/core/compaction/context-deletion-store.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-store.js +0 -162
- package/dist/core/compaction/context-deletion-store.js.map +0 -1
- package/dist/core/compaction/context-deletion-targets.d.ts +0 -43
- package/dist/core/compaction/context-deletion-targets.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-targets.js +0 -292
- package/dist/core/compaction/context-deletion-targets.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts +0 -193
- package/dist/core/compaction/context-deletion-tool-definitions.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-definitions.js +0 -98
- package/dist/core/compaction/context-deletion-tool-definitions.js.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts +0 -19
- package/dist/core/compaction/context-deletion-tool-helpers.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tool-helpers.js +0 -210
- package/dist/core/compaction/context-deletion-tool-helpers.js.map +0 -1
- package/dist/core/compaction/context-deletion-tools.d.ts +0 -4
- package/dist/core/compaction/context-deletion-tools.d.ts.map +0 -1
- package/dist/core/compaction/context-deletion-tools.js +0 -403
- package/dist/core/compaction/context-deletion-tools.js.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.d.ts +0 -11
- package/dist/core/compaction/context-transcript-analysis.d.ts.map +0 -1
- package/dist/core/compaction/context-transcript-analysis.js +0 -228
- package/dist/core/compaction/context-transcript-analysis.js.map +0 -1
- package/dist/core/session-manager-tool-dependencies.d.ts +0 -10
- package/dist/core/session-manager-tool-dependencies.d.ts.map +0 -1
- package/dist/core/session-manager-tool-dependencies.js +0 -133
- package/dist/core/session-manager-tool-dependencies.js.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts +0 -17
- package/dist/modes/interactive/components/context-compaction-summary-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/context-compaction-summary-message.js +0 -83
- package/dist/modes/interactive/components/context-compaction-summary-message.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAOtF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,UAAU;;;;;;EAMmB,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AA+FtD,MAAM,WAAW,eAAe;IAAG,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAA;CAAE;AAsCxU,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IACpI,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACpI;AAKD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA6CD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAmRhE;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { statSync } from \"node:fs\";\nimport { stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { normalizePathLikeInput, splitPathLikeGlob } from \"./glob-path-utils.ts\";\nimport { loadNativeSearchBinding } from \"./search-native.ts\";\nimport { pathExists, resolveToCwd } from \"./path-utils.ts\";\nimport { resolveInternalSelector, type InternalResourceContext } from \"./resource-selectors.ts\";\nimport { getTextOutput } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from \"./truncate.ts\";\nconst toPosixPath = (value: string): string => value.split(path.sep).join(\"/\");\nconst findSchema = Type.Object({\n\tpaths: Type.Array(Type.String({ description: \"File, directory, or glob path to find.\" }), { description: \"Paths or glob paths to find.\", minItems: 1 }),\n\thidden: Type.Optional(Type.Boolean({ description: \"Include hidden files. Defaults to true.\" })),\n\tgitignore: Type.Optional(Type.Boolean({ description: \"Respect gitignore. Defaults to true.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of results, clamped to 1-200.\", minimum: 1, maximum: 200 })),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds; default 5, clamped to 0.5..60.\", minimum: 0.5, maximum: 60 })),\n}, { additionalProperties: false });\nexport type FindToolInput = Static<typeof findSchema>;\nconst DEFAULT_LIMIT = 200;\nconst MAX_LIMIT = 200;\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst MIN_TIMEOUT_MS = 500;\nconst MAX_TIMEOUT_MS = 60_000;\ninterface FindTarget { searchPath: string; pattern: string; exactPathInput: boolean; inputPath: string }\nfunction normalizeLimit(limit: number | undefined): number { return limit === undefined || !Number.isFinite(limit) ? DEFAULT_LIMIT : Math.max(1, Math.min(MAX_LIMIT, Math.floor(limit))); }\nfunction normalizeTimeoutMs(timeout: number | undefined): number { return timeout === undefined || !Number.isFinite(timeout) ? DEFAULT_TIMEOUT_MS : Math.max(MIN_TIMEOUT_MS, Math.min(MAX_TIMEOUT_MS, Math.floor(timeout * 1000))); }\nfunction formatTimeoutSeconds(timeoutMs: number): string { const seconds = timeoutMs / 1000; return Number.isInteger(seconds) ? String(seconds) : seconds.toFixed(1); }\nasync function resolveFindInternal(input: string, cwd: string, ctx?: InternalResourceContext): Promise<string> { const parsed = splitPathLikeGlob(input); if (!/^[a-z]+:\\/\\//i.test(parsed.basePath)) return input; for (const resolve of [ctx?.internalRouter?.resolve, ctx?.internalResourceRouter?.resolve, ctx?.resolveInternalUrl]) { const resolved = await resolve?.(parsed.basePath); if (typeof resolved === \"string\") return parsed.glob ? `${resolved}/${parsed.glob}` : resolved; } const fallback = resolveInternalSelector(parsed.basePath, cwd); return fallback ? parsed.glob ? `${fallback}/${parsed.glob}` : fallback : input; }\nfunction isWindowsAbsolutePath(value: string): boolean { return /^[A-Za-z]:[\\\\/]/.test(value) || value.startsWith(\"\\\\\\\\\"); }\nfunction resolveFindBackendPath(input: string, cwd: string, customBackend: boolean): string { if (!customBackend) return resolveToCwd(input, cwd); if (input === \".\" || input === \"\") return cwd; if (input.startsWith(\"/\") || isWindowsAbsolutePath(input)) return input; if (cwd.includes(\"\\\\\") || isWindowsAbsolutePath(cwd)) return path.resolve(cwd, input); return `${cwd.replace(/\\/+$/, \"\")}/${input}`; }\nasync function delimiterInExistingGlobRoot(value: string, cwd: string, ops: FindOperations, customBackend: boolean): Promise<boolean> { const parsed = splitPathLikeGlob(value); return !!parsed.glob && /[;,\\s]/.test(parsed.basePath) && await ops.exists(resolveFindBackendPath(parsed.basePath, cwd, customBackend)); }\nasync function expandDelimitedFindPaths(pathsValue: string[] | undefined, cwd: string, ops: FindOperations, ctx?: InternalResourceContext, customBackend = false): Promise<string[]> {\n\tif (!pathsValue?.length) throw new Error(\"find.paths must include at least one path or glob.\"); const expanded: string[] = [];\n\tfor (const input of pathsValue) { const raw = normalizePathLikeInput(input); if (raw === \"\") throw new Error(\"find.paths entries must not be empty.\"); const resolvedRaw = await resolveFindInternal(raw, cwd, ctx); const rawParsed = splitPathLikeGlob(resolvedRaw);\n\t\tif ((rawParsed.glob === undefined && await ops.exists(resolveFindBackendPath(rawParsed.basePath, cwd, customBackend))) || await delimiterInExistingGlobRoot(resolvedRaw, cwd, ops, customBackend)) { expanded.push(resolvedRaw); continue; }\n\t\tconst parts = await Promise.all(raw.split(/[;,\\s]+/).map(normalizePathLikeInput).filter(Boolean).map((part) => resolveFindInternal(part, cwd, ctx)));\n\t\tconst delimiterCanSplit = /[;,]/.test(raw) ? (await Promise.all(parts.map((part) => ops.exists(resolveFindBackendPath(splitPathLikeGlob(part).basePath, cwd, customBackend))))).some(Boolean) : (await Promise.all(parts.map((part) => ops.exists(resolveFindBackendPath(splitPathLikeGlob(part).basePath, cwd, customBackend))))).every(Boolean);\n\t\tif (parts.length > 1 && delimiterCanSplit) expanded.push(...parts); else expanded.push(resolvedRaw);\n\t}\n\treturn expanded;\n}\nfunction normalizeFindTargets(cwd: string, pathsValue: string[] | undefined, customBackend = false): FindTarget[] {\n\tif (!pathsValue || pathsValue.length === 0) throw new Error(\"find.paths must include at least one path or glob.\");\n\treturn pathsValue.map((searchPath) => {\n\t\tconst parsed = splitPathLikeGlob(searchPath);\n\t\tconst target = { searchPath: resolveFindBackendPath(parsed.basePath, cwd, customBackend), pattern: parsed.glob ?? \"**/*\", exactPathInput: parsed.glob === undefined, inputPath: searchPath };\n\t\tif (path.parse(target.searchPath).root === target.searchPath) throw new Error(\"Refusing to search filesystem root with find; provide a narrower path.\");\n\t\treturn target;\n\t});\n}\nfunction relativizeFoundPath(foundPath: string, searchPath: string): string {\n\tconst hadTrailingSlash = foundPath.endsWith(\"/\") || foundPath.endsWith(\"\\\\\");\n\tconst relativePath = path.relative(searchPath, foundPath) || path.basename(foundPath);\n\tconst outputPath = hadTrailingSlash && !relativePath.endsWith(\"/\") ? `${relativePath}/` : relativePath;\n\treturn toPosixPath(outputPath);\n}\nfunction formatExactFoundPath(foundPath: string, cwd: string): string { return toPosixPath(path.relative(cwd, foundPath) || path.basename(foundPath)); }\nfunction containsHiddenSegment(value: string): boolean { return toPosixPath(value).split(\"/\").some((part) => part.startsWith(\".\") && part.length > 1); }\nfunction findTargetMentionsNodeModules(target: FindTarget): boolean { return target.pattern.includes(\"node_modules\") || toPosixPath(target.searchPath).split(\"/\").includes(\"node_modules\"); }\nfunction formatFoundPath(foundPath: string, searchPath: string, searchPaths: string[], cwd: string): string {\n\tlet absoluteFoundPath = path.isAbsolute(foundPath) ? foundPath : path.resolve(searchPath, foundPath);\n\tif (foundPath.endsWith(\"/\") && !absoluteFoundPath.endsWith(\"/\")) absoluteFoundPath += \"/\";\n\tconst relative = relativizeFoundPath(absoluteFoundPath, searchPath);\n\tif (searchPaths.length <= 1) return relative;\n\tconst rootLabel = toPosixPath(path.relative(cwd, searchPath) || path.basename(searchPath) || \".\");\n\treturn `${rootLabel}/${relative}`;\n}\ninterface FindTreeNode {\n\tfiles: Set<string>;\n\tdirs: Map<string, FindTreeNode>;\n}\nfunction createFindTreeNode(): FindTreeNode { return { files: new Set(), dirs: new Map() }; }\nfunction formatFindTree(relativized: string[]): string {\n\tconst root = createFindTreeNode();\n\tfor (const item of relativized) {\n\t\tconst isDir = item.endsWith(\"/\");\n\t\tconst parts = item.replace(/\\/+$/g, \"\").split(\"/\").filter(Boolean);\n\t\tif (parts.length === 0) continue;\n\t\tlet node = root;\n\t\tconst dirParts = isDir ? parts : parts.slice(0, -1);\n\t\tfor (const dir of dirParts) {\n\t\t\tlet child = node.dirs.get(dir);\n\t\t\tif (!child) {\n\t\t\t\tchild = createFindTreeNode();\n\t\t\t\tnode.dirs.set(dir, child);\n\t\t\t}\n\t\t\tnode = child;\n\t\t}\n\t\tif (!isDir) node.files.add(parts[parts.length - 1]!);\n\t}\n\tconst lines: string[] = [];\n\tconst collapse = (dir: string, node: FindTreeNode): { label: string; node: FindTreeNode } => {\n\t\tconst parts = [dir];\n\t\tlet current = node;\n\t\twhile (current.files.size === 0 && current.dirs.size === 1) {\n\t\t\tconst [[nextDir, nextNode]] = [...current.dirs.entries()];\n\t\t\tparts.push(nextDir!);\n\t\t\tcurrent = nextNode!;\n\t\t}\n\t\treturn { label: parts.join(\"/\"), node: current };\n\t};\n\tconst render = (node: FindTreeNode, depth: number): void => {\n\t\tfor (const file of [...node.files].sort()) lines.push(file);\n\t\tfor (const [dir, child] of [...node.dirs.entries()].sort(([a], [b]) => a.localeCompare(b))) {\n\t\t\tconst folded = collapse(dir, child);\n\t\t\tlines.push(`${\"#\".repeat(depth + 1)} ${folded.label}/`);\n\t\t\trender(folded.node, depth + 1);\n\t\t}\n\t};\n\trender(root, 0);\n\treturn lines.join(\"\\n\");\n}\nexport interface FindToolDetails { truncation?: TruncationResult; resultLimitReached?: number; timedOut?: boolean; truncated?: boolean; skippedMissingPaths?: string[]; missingPaths?: string[]; scopePath?: string; fileCount?: number; files?: string[]; meta?: { limits?: { resultLimit?: number }; truncation?: TruncationResult } }\nfunction buildFindResult(\n\trelativized: string[],\n\teffectiveLimit: number,\n\ttimedOut: boolean,\n\ttimeoutMs: number,\n\tskippedMissingPaths: string[] = [],\n\tresultLimitReached = false,\n): {\n\tcontent: Array<{ type: \"text\"; text: string }>;\n\tdetails: FindToolDetails | undefined;\n} {\n\tconst rawOutput = relativized.length > 0 ? formatFindTree(relativized) : \"No files found matching pattern\";\n\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\tlet resultOutput = truncation.content;\n\tconst details: FindToolDetails = { scopePath: \".\", fileCount: relativized.length, files: relativized, meta: { limits: { resultLimit: effectiveLimit } } };\n\tconst notices: string[] = [];\n\tif (resultLimitReached) {\n\t\tnotices.push(`${effectiveLimit} results limit reached. Refine pattern or path to narrow results`);\n\t\tdetails.resultLimitReached = effectiveLimit;\n\t}\n\tif (timedOut) { notices.push(`find timed out after ${formatTimeoutSeconds(timeoutMs)}s; returning ${relativized.length} partial matches — increase timeout or narrow pattern`); details.timedOut = true; details.truncated = true; }\n\tif (skippedMissingPaths.length > 0) {\n\t\tnotices.push(`Skipped missing paths: ${skippedMissingPaths.join(\", \")}`);\n\t\tdetails.skippedMissingPaths = skippedMissingPaths;\n\t\tdetails.missingPaths = skippedMissingPaths;\n\t}\n\tif (truncation.truncated) {\n\t\tnotices.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit reached`);\n\t\tdetails.truncation = truncation;\n\t\tdetails.meta = { ...(details.meta ?? {}), truncation };\n\t\tdetails.truncated = true;\n\t}\n\tif (notices.length > 0) {\n\t\tresultOutput += `\\n\\n[${notices.join(\". \")}]`;\n\t}\n\treturn { content: [{ type: \"text\", text: resultOutput }], details };\n}\n/** Pluggable operations for remote/container find backends. */\nexport interface FindOperations {\n\tstat?: (path: string) => Promise<{ isFile: boolean; isDirectory: boolean }> | { isFile: boolean; isDirectory: boolean } | undefined;\n\texists: (path: string) => Promise<boolean> | boolean;\n\tglob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number; hidden: boolean }) => Promise<string[]> | string[];\n}\nconst defaultFindOperations: FindOperations = {\n\texists: pathExists,\n\tglob: () => [],\n};\nexport interface FindToolOptions {\n\t/** Custom operations for find. Default: local filesystem plus fd */\n\toperations?: FindOperations;\n}\nfunction stripTrailingForwardSlashes(value: string): string { let end = value.length; while (end > 0 && value[end - 1] === \"/\") end--; return value.slice(0, end); }\n\nfunction formatFindCall(\n\targs: { paths?: string[]; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst paths = Array.isArray(args?.paths) ? args.paths.map((item) => splitPathLikeGlob(item).glob ? item : `${stripTrailingForwardSlashes(item)}/**/*`).join(\", \") : \"<paths>\";\n\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"find\"))} ${theme.fg(\"accent\", paths)}`;\n\tif (args?.limit !== undefined) text += theme.fg(\"toolOutput\", ` (limit ${args.limit})`);\n\treturn text;\n}\nfunction formatFindResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: FindToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 20;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"Expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t}\n\tconst resultLimit = result.details?.resultLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst timedOut = result.details?.timedOut;\n\tif (resultLimit || truncation?.truncated || timedOut) {\n\t\tconst warnings: string[] = [];\n\t\tif (resultLimit) warnings.push(`${resultLimit} results limit`);\n\t\tif (timedOut) warnings.push(\"timeout\");\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\nexport function createFindToolDefinition(\n\tcwd: string,\n\toptions?: FindToolOptions,\n): ToolDefinition<typeof findSchema, FindToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\treturn {\n\t\tname: \"find\",\n\t\tlabel: \"find\",\n\t\tdescription: \"Find filesystem paths by glob; use search when you need content matches instead of path matches.\",\n\t\tpromptSnippet: \"Find filesystem paths by glob.\",\n\t\tparameters: findSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\tparams: FindToolInput,\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stopChild: (() => void) | undefined;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tstopChild = undefined;\n\t\t\t\t\tfn();\n\t\t\t\t};\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tstopChild?.();\n\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t};\n\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tconst { limit, hidden, gitignore, timeout } = params;\n\t\t\t\tconst paths = params.paths;\n\t\t\t\tconst resourceCtx = _ctx as InternalResourceContext | undefined;\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst ops = customOps ?? defaultFindOperations;\n\t\t\t\t\t\tconst targets = normalizeFindTargets(cwd, await expandDelimitedFindPaths(paths, cwd, ops, resourceCtx, !!customOps), !!customOps);\n\t\t\t\t\t\tconst searchPaths = targets.map((target) => target.searchPath);\n\t\t\t\t\t\tconst effectiveLimit = normalizeLimit(limit);\n\t\t\t\t\t\tconst timeoutMs = normalizeTimeoutMs(timeout);\n\t\t\t\t\t\tconst emitUpdate = (files: string[]) => _onUpdate?.({ content: [{ type: \"text\", text: files.join(\"\\n\") || \"No files found matching pattern\" }], details: { scopePath: \".\", files, fileCount: files.length, truncated: false } });\n\t\t\t\t\t\tconst exactFileResults: string[] = [];\n\t\t\t\t\t\tconst searchableTargets: FindTarget[] = [];\n\t\t\t\t\t\tconst skippedMissingPaths: string[] = [];\n\t\t\t\t\t\tfor (const target of targets) {\n\t\t\t\t\t\t\tif (target.searchPath === path.parse(target.searchPath).root) throw new Error(\"Refusing to search filesystem root with find; provide a narrower path.\");\n\t\t\t\t\t\t\tconst stat = customOps ? await customOps.stat?.(target.searchPath) : await fsStat(target.searchPath).catch(() => undefined);\n\t\t\t\t\t\t\tif (!stat && targets.length > 1 && !customOps) {\n\t\t\t\t\t\t\t\tskippedMissingPaths.push(target.inputPath);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!stat && targets.length === 1 && !customOps) {\n\t\t\t\t\t\t\t\tthrow new Error(`ENOENT: Path not found: ${target.searchPath}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (target.exactPathInput) {\n\t\t\t\t\t\t\t\tconst isFile = typeof stat?.isFile === \"function\" ? stat.isFile() : stat?.isFile;\n\t\t\t\t\t\t\t\tif (isFile) {\n\t\t\t\t\t\t\t\t\texactFileResults.push(formatExactFoundPath(target.searchPath, cwd));\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsearchableTargets.push(target);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (exactFileResults.length > effectiveLimit || searchableTargets.length === 0) {\n\t\t\t\t\t\t\tconst resultLimitReached = exactFileResults.length > effectiveLimit;\n\t\t\t\t\t\t\tsettle(() => resolve(buildFindResult(exactFileResults.slice(0, effectiveLimit), effectiveLimit, false, timeoutMs, skippedMissingPaths, resultLimitReached)));\n\t\t\t\t\t\t\temitUpdate(exactFileResults.slice(0, effectiveLimit));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (customOps?.glob) {\n\t\t\t\t\t\t\tconst deadline = Date.now() + timeoutMs;\n\t\t\t\t\t\t\tlet timedOut = false;\n\t\t\t\t\t\t\tconst relativized: string[] = [...exactFileResults];\n\t\t\t\t\t\t\tlet customLimitReached = false;\n\t\t\t\t\t\t\tfor (const target of searchableTargets) {\n\t\t\t\t\t\t\t\tif (!(await ops.exists(target.searchPath))) {\n\t\t\t\t\t\t\t\t\tif (targets.length > 1) {\n\t\t\t\t\t\t\t\t\t\tskippedMissingPaths.push(target.inputPath);\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${target.searchPath}`)));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst remaining = effectiveLimit - relativized.length;\n\t\t\t\t\t\t\t\tconst remainingMs = deadline - Date.now();\n\t\t\t\t\t\t\t\tif (remaining <= 0) {\n\t\t\t\t\t\t\t\t\tconst ignore = findTargetMentionsNodeModules(target) ? [\"**/.git/**\"] : [\"**/node_modules/**\", \"**/.git/**\"];\n\t\t\t\t\t\t\t\t\tconst probe = await Promise.resolve(ops.glob(target.pattern, target.searchPath, { ignore, limit: 1, hidden: hidden !== false }));\n\t\t\t\t\t\t\t\t\tif (probe.some((p) => hidden !== false || !containsHiddenSegment(p))) customLimitReached = true;\n\t\t\t\t\t\t\t\t\tif (customLimitReached) break;\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (remainingMs <= 0) {\n\t\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst timeoutResult = Symbol(\"find-timeout\");\n\t\t\t\t\t\t\t\tlet raceTimer: ReturnType<typeof setTimeout> | undefined;\n\t\t\t\t\t\t\t\tconst ignore = findTargetMentionsNodeModules(target) ? [\"**/.git/**\"] : [\"**/node_modules/**\", \"**/.git/**\"];\n\t\t\t\t\t\t\t\tconst results = await Promise.race<string[] | symbol>([\n\t\t\t\t\t\t\t\t\tPromise.resolve(ops.glob(target.pattern, target.searchPath, { ignore, limit: remaining + 1, hidden: hidden !== false })),\n\t\t\t\t\t\t\t\t\tnew Promise<typeof timeoutResult>((resolveTimeout) => {\n\t\t\t\t\t\t\t\t\t\traceTimer = setTimeout(() => resolveTimeout(timeoutResult), remainingMs);\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t\t\tif (raceTimer) clearTimeout(raceTimer);\n\t\t\t\t\t\t\t\tif (!Array.isArray(results)) {\n\t\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (target.exactPathInput && results.length === 0) { const stat = await customOps.stat?.(target.searchPath); if (!stat?.isDirectory) relativized.push(formatExactFoundPath(target.searchPath, cwd)); continue; }\n\t\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst visible = results.filter((p) => hidden !== false || !containsHiddenSegment(p));\n\t\t\t\t\t\t\t\tif (visible.length > remaining) customLimitReached = true;\n\t\t\t\t\t\t\t\trelativized.push(...visible.slice(0, remaining).map((p) => formatFoundPath(p, target.searchPath, searchPaths, cwd)));\n\t\t\t\t\t\t\t\temitUpdate(relativized);\n\t\t\t\t\t\t\t\tif (customLimitReached) break;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsettle(() => resolve(buildFindResult(relativized, effectiveLimit, timedOut, timeoutMs, skippedMissingPaths, customLimitReached)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst nativeBinding = loadNativeSearchBinding();\n\t\t\t\t\t\tif (nativeBinding) {\n\t\t\t\t\t\t\tconst matches: { path: string; mtime: number }[] = exactFileResults.map((path) => ({ path, mtime: Number.POSITIVE_INFINITY }));\n\t\t\t\t\t\t\tlet timedOut = false;\n\t\t\t\t\t\t\tconst deadline = Date.now() + timeoutMs;\n\t\t\t\t\t\t\tfor (const target of searchableTargets) {\n\t\t\t\t\t\t\t\tconst remainingMs = deadline - Date.now();\n\t\t\t\t\t\t\t\tif (remainingMs <= 0) {\n\t\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst result = await nativeBinding.glob({\n\t\t\t\t\t\t\t\t\t\tpattern: target.pattern,\n\t\t\t\t\t\t\t\t\t\tpath: target.searchPath,\n\t\t\t\t\t\t\t\t\t\trecursive: false,\n\t\t\t\t\t\t\t\t\t\thidden: hidden !== false,\n\t\t\t\t\t\t\t\t\t\tgitignore: gitignore !== false,\n\t\t\t\t\t\t\t\t\t\tincludeNodeModules: findTargetMentionsNodeModules(target),\n\t\t\t\t\t\t\t\t\t\tmaxResults: effectiveLimit + 1,\n\t\t\t\t\t\t\t\t\t\tcache: false,\n\t\t\t\t\t\t\t\t\t\tsortByMtime: true,\n\t\t\t\t\t\t\t\t\t\ttimeoutMs: remainingMs,\n\t\t\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\tmatches.push(...result.matches.map((match) => { const fileType = match.fileType ?? (match as { file_type?: number }).file_type; const isDir = (fileType === 2 || fileType === \"Dir\" || (fileType === undefined && statSync(path.resolve(target.searchPath, match.path), { throwIfNoEntry: false })?.isDirectory())) && !match.path.endsWith(\"/\"); const matchPath = isDir ? `${match.path}/` : match.path; return { path: formatFoundPath(matchPath, target.searchPath, searchPaths, cwd), mtime: match.mtime ?? 0 }; }));\n\t\t\t\t\t\t\t\t\temitUpdate(matches.map((match) => match.path));\n\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\tif (String(error).toLowerCase().includes(\"timed out\")) {\n\t\t\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst uniqueMatches = [...matches.reduce((map, match) => { const previous = map.get(match.path); if (!previous || match.mtime > previous.mtime) map.set(match.path, match); return map; }, new Map<string, { path: string; mtime: number }>()).values()];\n\t\t\t\t\t\t\tuniqueMatches.sort((a, b) => b.mtime - a.mtime || a.path.localeCompare(b.path));\n\t\t\t\t\t\t\tconst resultLimitReached = uniqueMatches.length > effectiveLimit;\n\t\t\t\t\t\t\tsettle(() => resolve(buildFindResult(uniqueMatches.slice(0, effectiveLimit).map((match) => match.path), effectiveLimit, timedOut, timeoutMs, skippedMissingPaths, resultLimitReached)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst fdPath = await ensureTool(\"fd\", true);\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!fdPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"fd is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet timedOut = false;\n\t\t\t\t\t\tconst relativized: string[] = [...exactFileResults];\n\t\t\t\t\t\tconst deadline = Date.now() + timeoutMs;\n\t\t\t\t\t\tconst runFdForTarget = async (target: FindTarget, remaining: number): Promise<boolean> => {\n\t\t\t\t\t\t\tconst args: string[] = [\"--glob\", \"--color=never\", \"--no-require-git\", \"--max-results\", String(remaining + 1)];\n\t\t\t\t\t\t\tif (hidden !== false) args.push(\"--hidden\");\n\t\t\t\t\t\t\tif (gitignore === false) args.push(\"--no-ignore\");\n\t\t\t\t\t\t\tif (!findTargetMentionsNodeModules(target)) args.push(\"--exclude\", \"node_modules\");\n\t\t\t\t\t\t\tlet fdPattern = target.pattern;\n\t\t\t\t\t\t\tif (target.pattern.includes(\"/\")) {\n\t\t\t\t\t\t\t\targs.push(\"--full-path\");\n\t\t\t\t\t\t\t\tif (!target.pattern.startsWith(\"/\") && !target.pattern.startsWith(\"**/\") && target.pattern !== \"**\") fdPattern = `**/${target.pattern}`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\targs.push(\"--\", fdPattern, target.searchPath);\n\t\t\t\t\t\t\tconst remainingMs = deadline - Date.now();\n\t\t\t\t\t\t\tif (remainingMs <= 0) {\n\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn await new Promise<boolean>((resolveTarget, rejectTarget) => {\n\t\t\t\t\t\t\t\tconst child = spawn(fdPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\t\t\tconst lines: string[] = [];\n\t\t\t\t\t\t\t\tstopChild = () => {\n\t\t\t\t\t\t\t\t\tif (!child.killed) child.kill();\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tconst targetTimer = setTimeout(() => {\n\t\t\t\t\t\t\t\t\ttimedOut = true;\n\t\t\t\t\t\t\t\t\tstopChild?.();\n\t\t\t\t\t\t\t\t}, remainingMs);\n\t\t\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\t\t\tclearTimeout(targetTimer);\n\t\t\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\trl.on(\"line\", (line) => lines.push(line));\n\t\t\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\t\t\trejectTarget(new Error(`Failed to run fd: ${error.message}`));\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tchild.on(\"close\", (code) => {\n\t\t\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\t\t\t\trejectTarget(new Error(\"Operation aborted\"));\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (!timedOut && code !== 0 && lines.length === 0) {\n\t\t\t\t\t\t\t\t\t\trejectTarget(new Error(stderr.trim() || `fd exited with code ${code}`));\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tfor (const rawLine of lines.slice(0, remaining)) {\n\t\t\t\t\t\t\t\t\t\tconst line = rawLine.replace(/\\r$/, \"\").trim();\n\t\t\t\t\t\t\t\t\t\tif (line) { const found = statSync(path.resolve(target.searchPath, line), { throwIfNoEntry: false })?.isDirectory() && !line.endsWith(\"/\") ? `${line}/` : line; relativized.push(formatFoundPath(found, target.searchPath, searchPaths, cwd)); }\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\temitUpdate(relativized);\n\t\t\t\t\t\t\t\t\tresolveTarget(lines.length > Math.max(0, remaining));\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet resultLimitReached = false;\n\t\t\t\t\t\tfor (const target of searchableTargets) {\n\t\t\t\t\t\t\tconst remaining = effectiveLimit - relativized.length;\n\t\t\t\t\t\t\tif (timedOut) break;\n\t\t\t\t\t\t\tif (remaining <= 0) { if (await runFdForTarget(target, 0)) { resultLimitReached = true; break; } continue; }\n\t\t\t\t\t\t\tconst targetLimitReached = await runFdForTarget(target, remaining);\n\t\t\t\t\t\t\tif (targetLimitReached) { resultLimitReached = true; break; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsettle(() => resolve(buildFindResult(relativized.slice(0, effectiveLimit), effectiveLimit, timedOut, timeoutMs, skippedMissingPaths, resultLimitReached)));\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst error = e instanceof Error ? e : new Error(String(e));\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatFindResult(result, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\nexport function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema> {\n\treturn wrapToolDefinition(createFindToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/core/tools/find.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAOtF,OAAO,EAAiC,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEnG,QAAA,MAAM,UAAU;;;;;;EAMmB,CAAC;AACpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AA+FtD,MAAM,WAAW,eAAe;IAAG,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,UAAU,CAAC,EAAE,gBAAgB,CAAA;KAAE,CAAA;CAAE;AAsCxU,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC9B,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IACpI,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;CACpI;AAKD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AA6CD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAmRhE;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glob-path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/glob-path-utils.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAalE"
|
|
1
|
+
{"version":3,"file":"glob-path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/glob-path-utils.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,iBAAiB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAalE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAKtF,OAAO,EAIN,KAAK,gBAAgB,EAGrB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;EAsBmB,CAAC;AAEpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAeD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,yEAAyE;IACzE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2JAA2J;IAC3J,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAqED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsUhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@earendil-works/pi-agent-core\";\nimport { Text } from \"@earendil-works/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { loadNativeSearchBinding, type NativeGrepMatch } from \"./search-native.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateHead,\n\ttruncateLine,\n} from \"./truncate.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\ttype: Type.Optional(Type.String({ description: \"File type filter for native grep.\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tcontextBefore: Type.Optional(Type.Number({ description: \"Lines to show before each match.\" })),\n\tcontextAfter: Type.Optional(Type.Number({ description: \"Lines to show after each match.\" })),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n\toffset: Type.Optional(Type.Number({ description: \"Skip first N matches.\" })),\n\tmode: Type.Optional(Type.Union([Type.Literal(\"content\"), Type.Literal(\"count\"), Type.Literal(\"filesWithMatches\")])),\n\tmaxCountPerFile: Type.Optional(Type.Number({ description: \"Maximum matches per file.\" })),\n\thidden: Type.Optional(Type.Boolean({ description: \"Search hidden files (default true).\" })),\n\tcache: Type.Optional(Type.Boolean({ description: \"Use native cache.\" })),\n\ttimeoutMs: Type.Optional(Type.Number({ description: \"Native grep timeout in milliseconds.\" })),\n\tgitignore: Type.Optional(Type.Boolean({ description: \"Respect .gitignore files (default: true)\" })),\n}, { additionalProperties: false });\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n}\n\ntype RipgrepMatchEvent = {\n\ttype: \"match\";\n\tdata?: {\n\t\tpath?: { text?: unknown };\n\t\tline_number?: unknown;\n\t\tlines?: { text?: unknown };\n\t};\n};\n\nfunction isRipgrepMatchEvent(event: unknown): event is RipgrepMatchEvent {\n\treturn typeof event === \"object\" && event !== null && \"type\" in event && event.type === \"match\";\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus ripgrep */\n\toperations?: GrepOperations;\n\t/** Enable shared native filesystem scan cache. Defaults to false; search callers also disable it to stay fresh across out-of-band filesystem mutations. */\n\tnativeCache?: boolean;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\") : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: typeof import(\"../../modes/interactive/theme/theme.ts\").theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"Expand\")}${theme.fg(\"muted\", \")\")}`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction formatNativeGrepMatch(match: NativeGrepMatch, displayPath: string): string[] {\n\tconst lines: string[] = [];\n\tfor (const contextLine of match.contextBefore ?? []) {\n\t\tlines.push(`${displayPath}-${contextLine.lineNumber}- ${contextLine.line}`);\n\t}\n\tlines.push(`${displayPath}:${match.lineNumber}: ${match.line}`);\n\tfor (const contextLine of match.contextAfter ?? []) {\n\t\tlines.push(`${displayPath}-${contextLine.lineNumber}- ${contextLine.line}`);\n\t}\n\treturn lines;\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tparameters: grepSchema,\n\t\tasync execute(\n\t\t\t_toolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t\tgitignore,\n\t\t\t\ttype,\n\t\t\t\tcontextBefore,\n\t\t\t\tcontextAfter,\n\t\t\t\toffset,\n\t\t\t\tmode,\n\t\t\t\tmaxCountPerFile,\n\t\t\t\thidden,\n\t\t\t\tcache,\n\t\t\t\ttimeoutMs,\n\t\t\t}: GrepToolInput,\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst contextBeforeValue = contextBefore ?? contextValue;\n\t\t\t\t\t\tconst contextAfterValue = contextAfter ?? contextValue;\n\t\t\t\t\t\tconst nativeCache = options?.nativeCache === true;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tif (!path.isAbsolute(filePath)) return filePath.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) return relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && !literal) {\n\t\t\t\t\t\t\tconst nativeBinding = loadNativeSearchBinding();\n\t\t\t\t\t\t\tif (nativeBinding) {\n\t\t\t\t\t\t\t\tconst nativeResult = await nativeBinding.grep({\n\t\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\t\tpath: searchPath,\n\t\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\thidden: hidden ?? true,\n\t\t\t\t\t\t\t\tgitignore: gitignore !== false,\n\t\t\t\t\t\t\t\tcache: cache ?? nativeCache,\n\t\t\t\t\t\t\t\tmaxCount: mode === \"count\" ? undefined : effectiveLimit + 1,\n\t\t\t\t\t\t\t\toffset,\n\t\t\t\t\t\t\t\tcontext: contextBefore === undefined && contextAfter === undefined ? contextValue : undefined,\n\t\t\t\t\t\t\t\tcontextBefore,\n\t\t\t\t\t\t\t\tcontextAfter,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\t\tmaxCountPerFile,\n\t\t\t\t\t\t\t\tmaxColumns: GREP_MAX_LINE_LENGTH,\n\t\t\t\t\t\t\t\tmultiline: pattern.includes(\"\\n\") || pattern.includes(\"\\\\n\"),\n\t\t\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t\t\ttimeoutMs: timeoutMs ?? 30_000,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tif (nativeResult.error) throw new Error(nativeResult.error);\n\t\t\t\t\t\t\t\tif (nativeResult.matches.length === 0) {\n\t\t\t\t\t\t\t\t\tsettle(() => resolve({ content: [{ type: \"text\", text: mode === \"count\" ? \"0\" : \"No matches found\" }], details: undefined }));\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst visibleMatches = nativeResult.matches.slice(0, effectiveLimit);\n\t\t\t\t\t\t\t\tconst filesOutput = mode === \"filesWithMatches\" && !isDirectory && (offset ?? 0) > 0 ? \"\" : visibleMatches.map((match) => formatPath(match.path)).join(\"\\n\");\n\t\t\t\t\t\t\t\tconst countOutput = String(Math.max(0, nativeResult.totalMatches - (offset ?? 0)));\n\t\t\t\t\t\t\t\tconst rawOutput = mode === \"count\" ? countOutput : mode === \"filesWithMatches\" ? (filesOutput || \"No matches found\") : visibleMatches.flatMap((match) => formatNativeGrepMatch(match, formatPath(match.path))).join(\"\\n\");\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\t\tif (nativeResult.matches.length > effectiveLimit || nativeResult.limitReached) {\n\t\t\t\t\t\t\t\t\tnotices.push(`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`);\n\t\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (visibleMatches.some((match) => match.truncated)) {\n\t\t\t\t\t\t\t\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\t\tsettle(() => resolve({ content: [{ type: \"text\", text: output }], details: Object.keys(details).length > 0 ? details : undefined }));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\"];\n\t\t\t\t\t\tif (hidden !== false) args.push(\"--hidden\");\n\t\t\t\t\t\tif (gitignore === false) args.push(\"--no-ignore\");\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (pattern.includes(\"\\n\") || pattern.includes(\"\\\\n\")) args.push(\"--multiline\");\n\t\t\t\t\t\tif (type) args.push(\"--type\", type);\n\t\t\t\t\t\tif (maxCountPerFile !== undefined) args.push(\"--max-count\", String(maxCountPerFile));\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\t\t\t\t\tconst timeoutTimer = timeoutMs !== undefined ? setTimeout(() => stopChild(), timeoutMs) : undefined;\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (!child.killed) {\n\t\t\t\t\t\t\t\tkilledDueToLimit = dueToLimit;\n\t\t\t\t\t\t\t\tchild.kill();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextBeforeValue > 0 ? Math.max(1, lineNumber - contextBeforeValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextAfterValue > 0 ? Math.min(lines.length, lineNumber + contextAfterValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\tlet seenMatches = 0, seenFiles = 0; const seenFilePaths = new Set<string>(), filesWithMatches = new Set<string>();\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || (mode !== \"count\" && mode !== \"filesWithMatches\" && matchCount >= effectiveLimit)) return;\n\t\t\t\t\t\t\tlet event: unknown;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line) as unknown;\n\t\t\t\t\t\t\t} catch { return; }\n\t\t\t\t\t\t\tif (isRipgrepMatchEvent(event)) {\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tif (mode === \"filesWithMatches\") { if (typeof filePath === \"string\") { const formatted = formatPath(filePath); if (!seenFilePaths.has(formatted)) { seenFilePaths.add(formatted); seenFiles++; if (offset === undefined || seenFiles > offset) filesWithMatches.add(formatted); } } matchCount = filesWithMatches.size; if (matchCount >= effectiveLimit) { matchLimitReached = true; stopChild(true); } return; }\n\t\t\t\t\t\t\t\tseenMatches++;\n\t\t\t\t\t\t\t\tif (mode !== \"count\" && offset !== undefined && seenMatches <= offset) return;\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (typeof filePath === \"string\") filesWithMatches.add(formatPath(filePath));\n\t\t\t\t\t\t\t\tif (typeof filePath === \"string\" && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText: typeof lineText === \"string\" ? lineText : undefined });\n\t\t\t\t\t\t\t\tif (mode !== \"count\" && matchCount >= effectiveLimit) { matchLimitReached = true; stopChild(true); }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tchild.on(\"error\", (error) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Failed to run ripgrep: ${error.message}`)));\n\t\t\t\t\t\t});\n\t\t\t\t\t\tchild.on(\"close\", async (code) => {\n\t\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\t\tsettle(() => resolve({ content: [{ type: \"text\", text: mode === \"count\" ? \"0\" : \"No matches found\" }], details: undefined }));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (mode === \"count\" || mode === \"filesWithMatches\") {\n\t\t\t\t\t\t\t\tsettle(() => resolve({ content: [{ type: \"text\", text: mode === \"count\" ? String(Math.max(0, matchCount - (offset ?? 0))) : ([...filesWithMatches].join(\"\\n\") || \"No matches found\") }], details: matchLimitReached ? { matchLimitReached: effectiveLimit } : undefined }));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\t\tif (contextBeforeValue === 0 && contextAfterValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\t\t\tconst sanitized = match.lineText\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r\\n/g, \"\\n\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\r/g, \"\")\n\t\t\t\t\t\t\t\t\t\t.replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\t\toutputLines.push(`${relativePath}:${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\t\toutputLines.push(...block);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t\t// Apply byte truncation. There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\t\tconst truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });\n\t\t\t\t\t\t\tlet output = truncation.content;\n\t\t\t\t\t\t\tconst details: GrepToolDetails = {};\n\t\t\t\t\t\t\t// Build actionable notices for truncation and match limits.\n\t\t\t\t\t\t\tconst notices: string[] = [];\n\t\t\t\t\t\t\tif (matchLimitReached) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`${effectiveLimit} matches limit reached. Use limit=${effectiveLimit * 2} for more, or refine pattern`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.matchLimitReached = effectiveLimit;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (truncation.truncated) {\n\t\t\t\t\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t\t\t\t\t\t\tdetails.truncation = truncation;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\t\t\tnotices.push(\n\t\t\t\t\t\t\t\t\t`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tdetails.linesTruncated = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAI/D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AAKtF,OAAO,EAIN,KAAK,gBAAgB,EAGrB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;;;EAsBmB,CAAC;AAEpC,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAGtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAeD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,yEAAyE;IACzE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2JAA2J;IAC3J,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAqED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsUhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/apply.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAU,WAAW,EAAU,IAAI,EAAE,MAAM,YAAY,CAAC;AAsHpE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,QAAyB,CAAC;AAklB3D;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,WAAW,CAqG5E","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 * Apply a parsed list of {@link Edit}s to a text body and return the\n * post-edit lines plus any diagnostic warnings. Pure function: no FS, no\n * mutation of the input.\n *\n * Replacement groups are first normalized by {@link repairReplacementBoundaries},\n * which absorbs common model mistakes where a payload restates unchanged range\n * boundaries or duplicates/drops structural closers.\n */\nimport { afterInsertLandingShiftWarning, blockInsertLandingShiftWarning, UNRESOLVED_BLOCK_INTERNAL } from \"./messages.js\";\nimport { cloneCursor } from \"./tokenizer.js\";\nimport type { Anchor, ApplyResult, Cursor, Edit } from \"./types.js\";\n\ntype LineOrigin = \"original\" | \"insert\" | \"replacement\";\n\ntype InsertEdit = Extract<Edit, { kind: \"insert\" }>;\ntype DeleteEdit = Extract<Edit, { kind: \"delete\" }>;\ntype AppliedEdit = InsertEdit | DeleteEdit;\n\ninterface IndexedEdit {\n\tedit: AppliedEdit;\n\tidx: number;\n}\n\nfunction isReplacementInsert(edit: Edit): edit is InsertEdit & { mode: \"replacement\" } {\n\treturn edit.kind === \"insert\" && edit.mode === \"replacement\";\n}\n\nfunction getCursorAnchors(cursor: Cursor): Anchor[] {\n\treturn cursor.kind === \"before_anchor\" || cursor.kind === \"after_anchor\" ? [cursor.anchor] : [];\n}\n\nfunction getEditAnchors(edit: AppliedEdit): Anchor[] {\n\tif (edit.kind === \"delete\") return [edit.anchor];\n\treturn getCursorAnchors(edit.cursor);\n}\n\nfunction trailingPhantomLine(fileLines: readonly string[]): number {\n\t// `split(\"\\n\")` on a newline-terminated file yields a trailing \"\" sentinel.\n\t// It is addressable for inserts (append-past-end), but it is not real\n\t// content. Deleting it only strips the file's final newline, so ignore delete\n\t// edits that land there; inclusive ranges ending at EOF then do the intended\n\t// thing and delete through the last concrete line.\n\treturn fileLines.length > 1 && fileLines[fileLines.length - 1] === \"\" ? fileLines.length : 0;\n}\n\nfunction dropTrailingPhantomDeletes(edits: AppliedEdit[], fileLines: readonly string[]): AppliedEdit[] {\n\tconst phantomLine = trailingPhantomLine(fileLines);\n\tif (phantomLine === 0) return edits;\n\treturn edits.filter(edit => edit.kind !== \"delete\" || edit.anchor.line !== phantomLine);\n}\n\n/**\n * Verify every anchored edit points at an existing line. File-version binding is\n * checked once per section via the header hash before this function runs.\n */\nfunction validateLineBounds(edits: readonly AppliedEdit[], fileLines: readonly string[]): void {\n\tfor (const edit of edits) {\n\t\tfor (const anchor of getEditAnchors(edit)) {\n\t\t\tif (anchor.line < 1 || anchor.line > fileLines.length) {\n\t\t\t\tthrow new Error(`Line ${anchor.line} does not exist (file has ${fileLines.length} lines)`);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction cloneAppliedEdit(edit: AppliedEdit, index: number): AppliedEdit {\n\tif (edit.kind === \"delete\") return { ...edit, anchor: { ...edit.anchor }, index };\n\treturn { ...edit, cursor: cloneCursor(edit.cursor), index };\n}\n\nfunction insertAtStart(fileLines: string[], lineOrigins: LineOrigin[], lines: string[]): void {\n\tif (lines.length === 0) return;\n\tconst origins = lines.map((): LineOrigin => \"insert\");\n\tif (fileLines.length === 1 && fileLines[0] === \"\") {\n\t\tfileLines.splice(0, 1, ...lines);\n\t\tlineOrigins.splice(0, 1, ...origins);\n\t\treturn;\n\t}\n\tfileLines.splice(0, 0, ...lines);\n\tlineOrigins.splice(0, 0, ...origins);\n}\n\nfunction insertAtEnd(fileLines: string[], lineOrigins: LineOrigin[], lines: string[]): number | undefined {\n\tif (lines.length === 0) return undefined;\n\tconst origins = lines.map((): LineOrigin => \"insert\");\n\tif (fileLines.length === 1 && fileLines[0] === \"\") {\n\t\tfileLines.splice(0, 1, ...lines);\n\t\tlineOrigins.splice(0, 1, ...origins);\n\t\treturn 1;\n\t}\n\tconst hasTrailingNewline = fileLines.length > 0 && fileLines[fileLines.length - 1] === \"\";\n\tconst insertIndex = hasTrailingNewline ? fileLines.length - 1 : fileLines.length;\n\tfileLines.splice(insertIndex, 0, ...lines);\n\tlineOrigins.splice(insertIndex, 0, ...origins);\n\treturn insertIndex + 1;\n}\n\nfunction bucketAnchorEditsByLine(edits: IndexedEdit[]): Map<number, IndexedEdit[]> {\n\tconst byLine = new Map<number, IndexedEdit[]>();\n\tfor (const entry of edits) {\n\t\tconst line =\n\t\t\tentry.edit.kind === \"delete\"\n\t\t\t\t? entry.edit.anchor.line\n\t\t\t\t: entry.edit.cursor.kind === \"before_anchor\" || entry.edit.cursor.kind === \"after_anchor\"\n\t\t\t\t\t? entry.edit.cursor.anchor.line\n\t\t\t\t\t: 0;\n\t\tconst bucket = byLine.get(line);\n\t\tif (bucket) bucket.push(entry);\n\t\telse byLine.set(line, [entry]);\n\t}\n\treturn byLine;\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// Replacement-boundary repair\n//\n// Models routinely miscount a replacement range's edges. Sometimes the payload\n// re-states unchanged lines that still live on both sides of the range\n// (duplicating a function header and final statement); sometimes it only\n// re-states or omits a structural closer, which leaves delimiter balance broken.\n//\n// A balance-neutral boundary-echo repair fires only when both the leading and\n// trailing payload edges are exact copies of the surviving lines outside the\n// range. One-sided content echoes are left alone unless delimiter-balance repair\n// proves they are duplicated structural boundaries. This preserves intended\n// duplicate statements while absorbing the common \"body includes the unchanged\n// wrapper\" mistake.\n\n/** A line that is nothing but closing delimiters: `}`, `)`, `];`, `})`, `},`. */\nexport const STRUCTURAL_CLOSER_RE = /^\\s*[)\\]}]+[;,]?\\s*$/;\n\ninterface DelimiterBalance {\n\tparen: number;\n\tbracket: number;\n\tbrace: number;\n}\n\n/**\n * Net `()` / `[]` / `{}` delta across `lines`, skipping delimiters inside line\n * comments (`//`), block comments, and string/template literals. Block-comment\n * and backtick-template state carry across lines; `\"` / `'` reset at EOL since\n * they cannot span lines. Deliberately language-light: constructs it cannot\n * classify (e.g. regex literals) are counted naively, which can only suppress a\n * repair (the safe direction), never force one.\n */\nfunction computeDelimiterBalance(lines: readonly string[]): DelimiterBalance {\n\tconst balance: DelimiterBalance = { paren: 0, bracket: 0, brace: 0 };\n\tlet inBlockComment = false;\n\tlet quote = \"\";\n\tfor (const line of lines) {\n\t\tfor (let i = 0; i < line.length; i++) {\n\t\t\tconst ch = line[i];\n\t\t\tif (inBlockComment) {\n\t\t\t\tif (ch === \"*\" && line[i + 1] === \"/\") {\n\t\t\t\t\tinBlockComment = false;\n\t\t\t\t\ti++;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (quote) {\n\t\t\t\tif (ch === \"\\\\\") i++;\n\t\t\t\telse if (ch === quote) quote = \"\";\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ch === '\"' || ch === \"'\" || ch === \"`\") {\n\t\t\t\tquote = ch;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (ch === \"/\" && line[i + 1] === \"/\") break;\n\t\t\tif (ch === \"/\" && line[i + 1] === \"*\") {\n\t\t\t\tinBlockComment = true;\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tswitch (ch) {\n\t\t\t\tcase \"(\":\n\t\t\t\t\tbalance.paren++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \")\":\n\t\t\t\t\tbalance.paren--;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"[\":\n\t\t\t\t\tbalance.bracket++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"]\":\n\t\t\t\t\tbalance.bracket--;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"{\":\n\t\t\t\t\tbalance.brace++;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"}\":\n\t\t\t\t\tbalance.brace--;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// `\"` / `'` cannot span lines; only backtick templates and block comments do.\n\t\tif (quote === '\"' || quote === \"'\") quote = \"\";\n\t}\n\treturn balance;\n}\n\nfunction balanceDelta(a: DelimiterBalance, b: DelimiterBalance): DelimiterBalance {\n\treturn { paren: a.paren - b.paren, bracket: a.bracket - b.bracket, brace: a.brace - b.brace };\n}\n\nfunction balanceNegate(a: DelimiterBalance): DelimiterBalance {\n\treturn { paren: -a.paren, bracket: -a.bracket, brace: -a.brace };\n}\n\nfunction balanceEqual(a: DelimiterBalance, b: DelimiterBalance): boolean {\n\treturn a.paren === b.paren && a.bracket === b.bracket && a.brace === b.brace;\n}\n\nfunction balanceIsZero(a: DelimiterBalance): boolean {\n\treturn a.paren === 0 && a.bracket === 0 && a.brace === 0;\n}\n\ninterface ReplacementGroup {\n\t/** Positions in the edit array of the payload inserts, in payload order. */\n\tinsertIndices: number[];\n\t/** Positions in the edit array of the range deletes, ascending by line. */\n\tdeleteIndices: number[];\n\tpayload: string[];\n\t/** First deleted line (1-indexed). */\n\tstartLine: number;\n\t/** Last deleted line (1-indexed). */\n\tendLine: number;\n}\n\n/**\n * Detect a replacement group starting at `start`: a run of `before_anchor`\n * replacement inserts sharing one source op line, immediately followed by the\n * contiguous range deletes for that same op. Mirrors how the parser lowers an\n * `replace N..M:` hunk with a body.\n */\nfunction findReplacementGroup(edits: readonly AppliedEdit[], start: number): ReplacementGroup | undefined {\n\tconst first = edits[start];\n\tif (first?.kind !== \"insert\" || first.mode !== \"replacement\" || first.cursor.kind !== \"before_anchor\") {\n\t\treturn undefined;\n\t}\n\tconst { lineNum } = first;\n\tconst anchorLine = first.cursor.anchor.line;\n\tconst insertIndices: number[] = [];\n\tconst payload: string[] = [];\n\tlet i = start;\n\tfor (; i < edits.length; i++) {\n\t\tconst edit = edits[i];\n\t\tif (edit.kind !== \"insert\" || edit.mode !== \"replacement\" || edit.lineNum !== lineNum) break;\n\t\tif (edit.cursor.kind !== \"before_anchor\" || edit.cursor.anchor.line !== anchorLine) break;\n\t\tinsertIndices.push(i);\n\t\tpayload.push(edit.text);\n\t}\n\tconst deleteIndices: number[] = [];\n\tlet expectedLine = anchorLine;\n\tfor (; i < edits.length; i++) {\n\t\tconst edit = edits[i];\n\t\tif (edit.kind !== \"delete\" || edit.lineNum !== lineNum || edit.anchor.line !== expectedLine) break;\n\t\tdeleteIndices.push(i);\n\t\texpectedLine++;\n\t}\n\tif (deleteIndices.length === 0) return undefined;\n\treturn {\n\t\tinsertIndices,\n\t\tdeleteIndices,\n\t\tpayload,\n\t\tstartLine: anchorLine,\n\t\tendLine: anchorLine + deleteIndices.length - 1,\n\t};\n}\n\n/**\n * Largest `k` such that the payload's last `k` lines exactly equal the `k`\n * surviving file lines just below the range AND dropping them zeroes `delta`.\n * Requires a non-zero `delta`: a zero-balance candidate can never account for\n * the imbalance, so intentional duplicates of ordinary statements stay intact,\n * while duplicated structural lines (closers like `});`, openers like `foo(`)\n * are dropped when they exactly explain the imbalance.\n */\nfunction findDuplicateSuffix(group: ReplacementGroup, fileLines: readonly string[], delta: DelimiterBalance): number {\n\tif (balanceIsZero(delta)) return 0;\n\tconst { payload, endLine } = group;\n\tconst maxK = Math.min(payload.length, fileLines.length - endLine);\n\tfor (let k = maxK; k >= 1; k--) {\n\t\tlet matches = true;\n\t\tfor (let t = 0; t < k; t++) {\n\t\t\tif (payload[payload.length - k + t] !== fileLines[endLine + t]) {\n\t\t\t\tmatches = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!matches) continue;\n\t\tif (balanceEqual(computeDelimiterBalance(payload.slice(payload.length - k)), delta)) return k;\n\t}\n\treturn 0;\n}\n\n/**\n * Largest `j` such that the payload's first `j` lines exactly equal the `j`\n * surviving file lines just above the range AND dropping them zeroes `delta`.\n * Requires a non-zero `delta`; see {@link findDuplicateSuffix}.\n */\nfunction findDuplicatePrefix(group: ReplacementGroup, fileLines: readonly string[], delta: DelimiterBalance): number {\n\tif (balanceIsZero(delta)) return 0;\n\tconst { payload, startLine } = group;\n\tconst maxJ = Math.min(payload.length, startLine - 1);\n\tfor (let j = maxJ; j >= 1; j--) {\n\t\tlet matches = true;\n\t\tfor (let t = 0; t < j; t++) {\n\t\t\tif (payload[t] !== fileLines[startLine - 1 - j + t]) {\n\t\t\t\tmatches = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!matches) continue;\n\t\tif (balanceEqual(computeDelimiterBalance(payload.slice(0, j)), delta)) return j;\n\t}\n\treturn 0;\n}\n\n/**\n * Smallest `m` such that the range's last `m` deleted lines are all pure\n * structural closers and sparing them (keeping instead of deleting) zeroes\n * `delta`. The mirror mistake: a range that swallows a closing delimiter the\n * payload never restates.\n */\nfunction findDroppedSuffixClosers(\n\tgroup: ReplacementGroup,\n\tfileLines: readonly string[],\n\tdelta: DelimiterBalance,\n): number {\n\tconst wanted = balanceNegate(delta);\n\tconst maxM = group.deleteIndices.length;\n\tfor (let m = 1; m <= maxM; m++) {\n\t\tif (!STRUCTURAL_CLOSER_RE.test(fileLines[group.endLine - m] ?? \"\")) break;\n\t\tif (balanceEqual(computeDelimiterBalance(fileLines.slice(group.endLine - m, group.endLine)), wanted)) return m;\n\t}\n\treturn 0;\n}\n\ninterface BoundaryEcho {\n\tleading: number;\n\ttrailing: number;\n}\n\nfunction hasNonWhitespace(text: string): boolean {\n\tfor (let i = 0; i < text.length; i++) {\n\t\tconst code = text.charCodeAt(i);\n\t\tif (code !== 9 && code !== 10 && code !== 11 && code !== 12 && code !== 13 && code !== 32) return true;\n\t}\n\treturn false;\n}\n\nfunction countDuplicateLeadingBoundaryLines(group: ReplacementGroup, fileLines: readonly string[]): number {\n\tconst { payload, startLine } = group;\n\tconst max = Math.min(payload.length, startLine - 1);\n\tfor (let count = max; count >= 1; count--) {\n\t\tlet matches = true;\n\t\tlet hasContent = false;\n\t\tfor (let offset = 0; offset < count; offset++) {\n\t\t\tconst line = payload[offset];\n\t\t\tif (line !== fileLines[startLine - 1 - count + offset]) {\n\t\t\t\tmatches = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\thasContent ||= hasNonWhitespace(line);\n\t\t}\n\t\tif (matches && hasContent) return count;\n\t}\n\treturn 0;\n}\n\nfunction countDuplicateTrailingBoundaryLines(group: ReplacementGroup, fileLines: readonly string[]): number {\n\tconst { payload, endLine } = group;\n\tconst max = Math.min(payload.length, fileLines.length - endLine);\n\tfor (let count = max; count >= 1; count--) {\n\t\tlet matches = true;\n\t\tlet hasContent = false;\n\t\tfor (let offset = 0; offset < count; offset++) {\n\t\t\tconst line = payload[payload.length - count + offset];\n\t\t\tif (line !== fileLines[endLine + offset]) {\n\t\t\t\tmatches = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\thasContent ||= hasNonWhitespace(line);\n\t\t}\n\t\tif (matches && hasContent) return count;\n\t}\n\treturn 0;\n}\n\nfunction findBoundaryEcho(group: ReplacementGroup, fileLines: readonly string[]): BoundaryEcho | undefined {\n\tconst leadingMax = countDuplicateLeadingBoundaryLines(group, fileLines);\n\tif (leadingMax === 0) return undefined;\n\tconst trailingMax = countDuplicateTrailingBoundaryLines(group, fileLines);\n\tif (trailingMax === 0) return undefined;\n\t// Bail when every payload line could be claimed by a boundary echo: any\n\t// repair would strip explicit replacement content with no signal that the\n\t// payload was a mistake rather than an intentional duplication.\n\tif (leadingMax + trailingMax >= group.payload.length) return undefined;\n\t// Balance-neutrality guard (see header comment): the dropped echo lines must\n\t// either be delimiter-neutral on their own or exactly cancel the payload/range\n\t// balance delta. In brace-heavy code where bare closer lines repeat, an\n\t// \"echo\" that shifts delimiter balance is structural content the payload\n\t// placed intentionally — stripping it would corrupt the result.\n\tconst leadingBalance = computeDelimiterBalance(group.payload.slice(0, leadingMax));\n\tconst trailingBalance = computeDelimiterBalance(group.payload.slice(group.payload.length - trailingMax));\n\tconst droppedBalance = balanceDelta(leadingBalance, balanceNegate(trailingBalance));\n\tif (!balanceIsZero(droppedBalance)) {\n\t\tconst delta = balanceDelta(\n\t\t\tcomputeDelimiterBalance(group.payload),\n\t\t\tcomputeDelimiterBalance(fileLines.slice(group.startLine - 1, group.endLine)),\n\t\t);\n\t\tif (!balanceEqual(droppedBalance, delta)) return undefined;\n\t}\n\treturn { leading: leadingMax, trailing: trailingMax };\n}\n\nfunction describeBoundaryEchoRepair(group: ReplacementGroup, echo: BoundaryEcho): string {\n\treturn (\n\t\t`Auto-repaired a replacement boundary echo at line ${group.startLine}: ` +\n\t\t`dropped ${echo.leading} leading and ${echo.trailing} trailing payload line(s) already present outside the range. ` +\n\t\t`Issue the payload as the final desired content for the selected range only — never restate unchanged lines bordering the range.`\n\t);\n}\n\nfunction describeBoundaryRepair(group: ReplacementGroup, action: string): string {\n\treturn (\n\t\t`Auto-repaired a delimiter-balance mismatch in the replacement at line ${group.startLine}: ${action}. ` +\n\t\t`Issue the payload as the final desired content only — never restate or omit a closing bracket bordering the range.`\n\t);\n}\n\n/**\n * Normalize replacement groups so common off-by-one boundaries do not duplicate\n * unchanged surrounding lines or structural closers. Returns the repaired edit\n * list plus one warning per repaired group.\n */\nfunction repairReplacementBoundaries(\n\tedits: readonly AppliedEdit[],\n\tfileLines: readonly string[],\n): {\n\tedits: AppliedEdit[];\n\twarnings: string[];\n} {\n\tconst out: AppliedEdit[] = [];\n\tconst warnings: string[] = [];\n\tlet i = 0;\n\twhile (i < edits.length) {\n\t\tconst group = findReplacementGroup(edits, i);\n\t\tif (!group) {\n\t\t\tout.push(edits[i]);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst inserts = group.insertIndices.map(idx => edits[idx]);\n\t\tconst deletes = group.deleteIndices.map(idx => edits[idx]);\n\t\ti = group.deleteIndices[group.deleteIndices.length - 1] + 1;\n\n\t\tconst boundaryEcho = findBoundaryEcho(group, fileLines);\n\t\tif (boundaryEcho) {\n\t\t\twarnings.push(describeBoundaryEchoRepair(group, boundaryEcho));\n\t\t\tout.push(...inserts.slice(boundaryEcho.leading, inserts.length - boundaryEcho.trailing), ...deletes);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst delta = balanceDelta(\n\t\t\tcomputeDelimiterBalance(group.payload),\n\t\t\tcomputeDelimiterBalance(fileLines.slice(group.startLine - 1, group.endLine)),\n\t\t);\n\t\tif (balanceIsZero(delta)) {\n\t\t\tout.push(...inserts, ...deletes);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst dupSuffix = findDuplicateSuffix(group, fileLines, delta);\n\t\tif (dupSuffix > 0) {\n\t\t\twarnings.push(\n\t\t\t\tdescribeBoundaryRepair(\n\t\t\t\t\tgroup,\n\t\t\t\t\t`dropped ${dupSuffix} duplicated trailing payload line(s) already present below the range`,\n\t\t\t\t),\n\t\t\t);\n\t\t\tout.push(...inserts.slice(0, inserts.length - dupSuffix), ...deletes);\n\t\t\tcontinue;\n\t\t}\n\t\tconst dupPrefix = findDuplicatePrefix(group, fileLines, delta);\n\t\tif (dupPrefix > 0) {\n\t\t\twarnings.push(\n\t\t\t\tdescribeBoundaryRepair(\n\t\t\t\t\tgroup,\n\t\t\t\t\t`dropped ${dupPrefix} duplicated leading payload line(s) already present above the range`,\n\t\t\t\t),\n\t\t\t);\n\t\t\tout.push(...inserts.slice(dupPrefix), ...deletes);\n\t\t\tcontinue;\n\t\t}\n\t\tconst droppedClosers = findDroppedSuffixClosers(group, fileLines, delta);\n\t\tif (droppedClosers > 0) {\n\t\t\twarnings.push(\n\t\t\t\tdescribeBoundaryRepair(\n\t\t\t\t\tgroup,\n\t\t\t\t\t`kept ${droppedClosers} structural closing line(s) the range deleted without restating`,\n\t\t\t\t),\n\t\t\t);\n\t\t\tout.push(...inserts, ...deletes.slice(0, deletes.length - droppedClosers));\n\t\t\tcontinue;\n\t\t}\n\t\tout.push(...inserts, ...deletes);\n\t}\n\treturn { edits: out, warnings };\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// After-insert landing correction\n//\n// The body rows of an `insert after N:` hunk carry an implicit depth claim:\n// their leading indentation says how deep the author expects the new lines\n// to sit. Two corrections share that claim, in opposite directions:\n//\n// Outward (any after-insert): when the depth is shallower than line N itself,\n// the hunk is inserting a sibling of some enclosing construct while anchored\n// inside it — the common shape is anchoring on the last statement of a block\n// and writing the body at the parent's depth. Sliding the landing point\n// forward across the structural closer lines that follow (and nothing else —\n// content lines are never crossed) places the body at the depth its\n// indentation names.\n//\n// Inward (block-lowered inserts only): `insert after block N:` anchors on the\n// resolved block's closing line, but a body indented deeper than that closer\n// claims a depth inside the block — the common misreading of the op as\n// \"append at the end of block N's body\". Sliding the landing point backward\n// across the block's trailing closer lines places the body inside, at its\n// claimed depth. Scoped to block-lowered inserts because there the author\n// named the opener and never saw the closer; a plain `insert after M:` on a\n// closer line stays literal (the escape hatch for genuinely-after content\n// such as method-chain continuations).\n//\n// Both shifts are deliberately conservative: they fire only when the body\n// and anchor indentation are comparable (one is a prefix of the other),\n// cross only pure closing-delimiter lines, stop as soon as depth matches the\n// body's claim, and are abandoned when any other edit in the patch targets a\n// crossed line. Every shift is reported as a warning so the author can\n// re-issue when the original landing was intended.\n\n/** Leading run of tabs and spaces. */\nfunction leadingIndent(line: string): string {\n\tlet end = 0;\n\twhile (end < line.length) {\n\t\tconst code = line.charCodeAt(end);\n\t\tif (code !== 9 && code !== 32) break;\n\t\tend++;\n\t}\n\treturn line.slice(0, end);\n}\n\n/** `deeper` strictly extends `shallower` (same indent style, more depth). */\nfunction isIndentDeeper(deeper: string, shallower: string): boolean {\n\treturn deeper.length > shallower.length && deeper.startsWith(shallower);\n}\n\ninterface AfterInsertGroup {\n\t/** Anchor line shared by every insert row of the hunk. */\n\tanchor: number;\n\t/** Indices into the edit list, in patch order. */\n\tmembers: number[];\n\t/** First line of the resolved block when lowered from `insert after block N:`. */\n\tblockStart?: number;\n}\n\n/**\n * Depth of an after-insert hunk's body: the shallowest indentation across its\n * non-blank rows. Returns `undefined` when no depth claim can be made — an\n * all-blank or all-closer body, or rows whose indentation styles are not\n * mutually comparable (tabs vs spaces).\n */\nfunction bodyTargetIndent(rows: readonly string[]): string | undefined {\n\tconst nonBlank = rows.filter(hasNonWhitespace);\n\tif (nonBlank.length === 0) return undefined;\n\t// A body of pure closers re-balances delimiters; it claims no depth.\n\tif (nonBlank.every(row => STRUCTURAL_CLOSER_RE.test(row))) return undefined;\n\tlet target = leadingIndent(nonBlank[0] ?? \"\");\n\tfor (const row of nonBlank) {\n\t\tconst indent = leadingIndent(row);\n\t\tif (indent.startsWith(target)) continue;\n\t\tif (target.startsWith(indent)) target = indent;\n\t\telse return undefined;\n\t}\n\treturn target;\n}\n\n/**\n * Resolve where an after-insert hunk anchored on `group.anchor` should land\n * given its body depth `target`: the last structural closer line in the run\n * directly below the anchor whose indentation still covers `target`. Returns\n * `undefined` when the landing stays put.\n */\nfunction resolveShiftedLanding(\n\tgroup: AfterInsertGroup,\n\ttarget: string,\n\tfileLines: readonly string[],\n\ttargetedLines: ReadonlySet<number>,\n): { line: number; crossed: number } | undefined {\n\tconst anchorText = fileLines[group.anchor - 1];\n\tif (anchorText === undefined || !hasNonWhitespace(anchorText)) return undefined;\n\tif (!isIndentDeeper(leadingIndent(anchorText), target)) return undefined;\n\n\tlet landing = group.anchor;\n\tlet crossed = 0;\n\tfor (let line = group.anchor + 1; line <= fileLines.length; line++) {\n\t\tconst text = fileLines[line - 1] ?? \"\";\n\t\tif (!hasNonWhitespace(text)) continue; // look past blanks, never land on them\n\t\tif (!STRUCTURAL_CLOSER_RE.test(text)) break; // content is never crossed\n\t\tconst indent = leadingIndent(text);\n\t\tif (!indent.startsWith(target)) break; // shallower than the body — crossing would over-escape\n\t\tif (targetedLines.has(line)) return undefined; // another hunk owns this closer\n\t\tlanding = line;\n\t\tcrossed++;\n\t\tif (indent.length === target.length) break; // depth returned to the body's level\n\t}\n\treturn landing === group.anchor ? undefined : { line: landing, crossed };\n}\n\n/**\n * Resolve where a block-lowered after-insert anchored on the block's closing\n * line should land given a body depth `target` deeper than that closer: just\n * above the block's trailing run of closer lines, bounded below by\n * `blockStart` (an empty block lands the body right after its opener).\n * Returns `undefined` when the landing stays put.\n */\nfunction resolveInwardLanding(\n\tgroup: AfterInsertGroup,\n\ttarget: string,\n\tblockStart: number,\n\tfileLines: readonly string[],\n\ttargetedLines: ReadonlySet<number>,\n): number | undefined {\n\tconst anchorText = fileLines[group.anchor - 1];\n\tif (anchorText === undefined || !hasNonWhitespace(anchorText)) return undefined;\n\t// Fires only when the block ends in a pure closer the body out-indents.\n\t// Blocks ending in content (indentation-only languages) already land the\n\t// body inside the block — nothing to correct.\n\tif (!STRUCTURAL_CLOSER_RE.test(anchorText)) return undefined;\n\tif (!isIndentDeeper(target, leadingIndent(anchorText))) return undefined;\n\n\tlet landing = group.anchor;\n\tfor (let line = group.anchor; line > blockStart; line--) {\n\t\tconst text = fileLines[line - 1] ?? \"\";\n\t\tif (!hasNonWhitespace(text)) {\n\t\t\tlanding = line - 1; // look past trailing blanks, never land after one\n\t\t\tcontinue;\n\t\t}\n\t\tif (!STRUCTURAL_CLOSER_RE.test(text)) break; // content reached — land right after it\n\t\tconst indent = leadingIndent(text);\n\t\tif (!isIndentDeeper(target, indent)) break; // closer at the body's depth — land after it\n\t\t// Another hunk owns this closer (the group's own rows put the anchor\n\t\t// itself in `targetedLines`; that one is ours to cross).\n\t\tif (line !== group.anchor && targetedLines.has(line)) return undefined;\n\t\tlanding = line - 1;\n\t}\n\treturn landing === group.anchor ? undefined : landing;\n}\n\n/**\n * Slide mis-anchored after-insert hunks to the depth their body indentation\n * claims: outward past the structural closer lines that follow the anchor\n * when the body is shallower, or — for `insert after block N:` lowerings —\n * inward across the block's trailing closers when the body is deeper than\n * the block's closing line. Returns the corrected edit list plus one warning\n * per shifted hunk.\n */\nfunction repairAfterInsertLandings(\n\tedits: readonly AppliedEdit[],\n\tfileLines: readonly string[],\n): { edits: readonly AppliedEdit[]; warnings: string[] } {\n\t// Group plain (non-replacement) after-anchor inserts per authored hunk:\n\t// rows of one hunk share the anchor line and the patch header line.\n\tconst groups = new Map<string, AfterInsertGroup>();\n\tedits.forEach((edit, idx) => {\n\t\tif (edit.kind !== \"insert\" || edit.mode === \"replacement\") return;\n\t\tif (edit.cursor.kind !== \"after_anchor\") return;\n\t\tconst key = `${edit.cursor.anchor.line}:${edit.lineNum}`;\n\t\tconst group = groups.get(key);\n\t\tif (group === undefined)\n\t\t\tgroups.set(key, { anchor: edit.cursor.anchor.line, members: [idx], blockStart: edit.blockStart });\n\t\telse group.members.push(idx);\n\t});\n\tif (groups.size === 0) return { edits, warnings: [] };\n\n\t// Lines explicitly targeted by any edit; a shift never crosses them.\n\tconst targetedLines = new Set<number>();\n\tfor (const edit of edits) {\n\t\tif (edit.kind === \"delete\") targetedLines.add(edit.anchor.line);\n\t\telse if (edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\")\n\t\t\ttargetedLines.add(edit.cursor.anchor.line);\n\t}\n\n\tlet out: AppliedEdit[] | undefined;\n\tconst warnings: string[] = [];\n\tconst retarget = (group: AfterInsertGroup, line: number): void => {\n\t\tout ??= [...edits];\n\t\tfor (const idx of group.members) {\n\t\t\tconst edit = out[idx] as InsertEdit;\n\t\t\tout[idx] = { ...edit, cursor: { kind: \"after_anchor\", anchor: { line } } };\n\t\t}\n\t};\n\tfor (const group of groups.values()) {\n\t\tconst target = bodyTargetIndent(group.members.map(idx => (edits[idx] as InsertEdit).text));\n\t\tif (target === undefined) continue;\n\t\tconst outward = resolveShiftedLanding(group, target, fileLines, targetedLines);\n\t\tif (outward !== undefined) {\n\t\t\tretarget(group, outward.line);\n\t\t\twarnings.push(afterInsertLandingShiftWarning(group.anchor, outward.line, outward.crossed));\n\t\t\tcontinue;\n\t\t}\n\t\tif (group.blockStart === undefined) continue;\n\t\tconst inward = resolveInwardLanding(group, target, group.blockStart, fileLines, targetedLines);\n\t\tif (inward === undefined) continue;\n\t\tretarget(group, inward);\n\t\twarnings.push(blockInsertLandingShiftWarning(group.blockStart, group.anchor, inward));\n\t}\n\treturn { edits: out ?? edits, warnings };\n}\n\n/**\n * Apply a parsed list of edits to a text body. Pure function — no I/O.\n *\n * Returns the post-edit text and the first changed line number (1-indexed).\n * Throws if an anchor is out of bounds.\n */\nexport function applyEdits(text: string, edits: readonly Edit[]): ApplyResult {\n\tif (edits.length === 0) return { text, firstChangedLine: undefined };\n\n\t// Block edits are deferred until `resolveBlockEdits` expands them into\n\t// concrete inserts + deletes. Reaching the applier with one still present\n\t// is an internal wiring bug, not authored-input error.\n\tfor (const edit of edits) {\n\t\tif (edit.kind === \"block\") throw new Error(UNRESOLVED_BLOCK_INTERNAL);\n\t}\n\tconst appliedEdits = edits as readonly AppliedEdit[];\n\n\tconst fileLines = text.split(\"\\n\");\n\tconst lineOrigins: LineOrigin[] = fileLines.map(() => \"original\");\n\n\tlet firstChangedLine: number | undefined;\n\tconst trackFirstChanged = (line: number) => {\n\t\tif (firstChangedLine === undefined || line < firstChangedLine) firstChangedLine = line;\n\t};\n\n\tconst targetEdits = dropTrailingPhantomDeletes(\n\t\tappliedEdits.map((edit, index) => cloneAppliedEdit(edit, index)),\n\t\tfileLines,\n\t);\n\tvalidateLineBounds(targetEdits, fileLines);\n\tconst { edits: repaired, warnings: boundaryWarnings } = repairReplacementBoundaries(targetEdits, fileLines);\n\tconst { edits: landed, warnings: landingWarnings } = repairAfterInsertLandings(repaired, fileLines);\n\tconst warnings = [...boundaryWarnings, ...landingWarnings];\n\n\t// Partition edits into bof, eof, and anchor-targeted buckets.\n\tconst bofLines: string[] = [];\n\tconst eofLines: string[] = [];\n\tconst anchorEdits: IndexedEdit[] = [];\n\tlanded.forEach((edit, idx) => {\n\t\tif (edit.kind === \"insert\" && edit.cursor.kind === \"bof\") {\n\t\t\tbofLines.push(edit.text);\n\t\t} else if (edit.kind === \"insert\" && edit.cursor.kind === \"eof\") {\n\t\t\teofLines.push(edit.text);\n\t\t} else {\n\t\t\tanchorEdits.push({ edit, idx });\n\t\t}\n\t});\n\n\t// Apply per-line buckets bottom-up so earlier indices stay valid.\n\tconst byLine = bucketAnchorEditsByLine(anchorEdits);\n\tfor (const line of [...byLine.keys()].sort((a, b) => b - a)) {\n\t\tconst bucket = byLine.get(line);\n\t\tif (!bucket) continue;\n\t\tbucket.sort((a, b) => a.idx - b.idx);\n\n\t\tconst idx = line - 1;\n\t\tconst currentLine = fileLines[idx] ?? \"\";\n\t\tconst beforeInsertLines: string[] = [];\n\t\tconst afterInsertLines: string[] = [];\n\t\tconst replacementLines: string[] = [];\n\t\tlet deleteLine = false;\n\n\t\tfor (const { edit } of bucket) {\n\t\t\tif (isReplacementInsert(edit)) {\n\t\t\t\treplacementLines.push(edit.text);\n\t\t\t} else if (edit.kind === \"insert\" && edit.cursor.kind === \"after_anchor\") {\n\t\t\t\tafterInsertLines.push(edit.text);\n\t\t\t} else if (edit.kind === \"insert\") {\n\t\t\t\tbeforeInsertLines.push(edit.text);\n\t\t\t} else if (edit.kind === \"delete\") {\n\t\t\t\tdeleteLine = true;\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\tbeforeInsertLines.length === 0 &&\n\t\t\treplacementLines.length === 0 &&\n\t\t\tafterInsertLines.length === 0 &&\n\t\t\t!deleteLine\n\t\t)\n\t\t\tcontinue;\n\n\t\tconst replacement = deleteLine\n\t\t\t? [...beforeInsertLines, ...replacementLines, ...afterInsertLines]\n\t\t\t: [...beforeInsertLines, ...replacementLines, currentLine, ...afterInsertLines];\n\t\tconst origins: LineOrigin[] = [];\n\t\tfor (let i = 0; i < beforeInsertLines.length; i++) origins.push(\"insert\");\n\t\tfor (let i = 0; i < replacementLines.length; i++) origins.push(deleteLine ? \"replacement\" : \"insert\");\n\t\tif (!deleteLine) origins.push(lineOrigins[idx] ?? \"original\");\n\t\tfor (let i = 0; i < afterInsertLines.length; i++) origins.push(\"insert\");\n\n\t\tfileLines.splice(idx, 1, ...replacement);\n\t\tlineOrigins.splice(idx, 1, ...origins);\n\t\ttrackFirstChanged(line);\n\t}\n\n\tif (bofLines.length > 0) {\n\t\tinsertAtStart(fileLines, lineOrigins, bofLines);\n\t\ttrackFirstChanged(1);\n\t}\n\tconst eofChangedLine = insertAtEnd(fileLines, lineOrigins, eofLines);\n\tif (eofChangedLine !== undefined) trackFirstChanged(eofChangedLine);\n\n\treturn {\n\t\ttext: fileLines.join(\"\\n\"),\n\t\tfirstChangedLine,\n\t\t...(warnings.length > 0 ? { warnings } : {}),\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/apply.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAU,WAAW,EAAU,IAAI,EAAE,MAAM,YAAY,CAAC;AAsHpE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,QAAyB,CAAC;AAklB3D;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,WAAW,CAqG5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/block.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAU,IAAI,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,OAAO,GAAE,wBAA6B,GACpC,SAAS,IAAI,EAAE,CAuFjB"
|
|
1
|
+
{"version":3,"file":"block.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/block.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAU,IAAI,EAAE,MAAM,YAAY,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACxC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;IACnD;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wEAAwE;AACxE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,OAAO,GAAE,wBAA6B,GACpC,SAAS,IAAI,EAAE,CAuFjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-preview.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/diff-preview.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA+DzE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,kBAAkB,CAgD1G"
|
|
1
|
+
{"version":3,"file":"diff-preview.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/diff-preview.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AA+DzE,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB,GAAG,kBAAkB,CAgD1G"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/format.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,qDAAqD;AACrD,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,sDAAsD;AACtD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,mEAAmE;AACnE,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,sEAAsE;AACtE,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,oEAAoE;AACpE,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,0DAA0D;AAC1D,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,mEAAmE;AACnE,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAMpC,+EAA+E;AAC/E,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C,oDAAoD;AACpD,eAAO,MAAM,sBAAsB,gBAAwB,CAAC;AAE5D,iDAAiD;AACjD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAQ,GAAG,MAAM,CAErE;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,gBAAqC,CAAC;AACtE,yDAAyD;AACzD,eAAO,MAAM,2BAA2B,kBAA6B,CAAC;AACtE,yFAAyF;AACzF,eAAO,MAAM,uBAAuB,QAAgC,CAAC;AACrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,YAAI,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAuEvE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,SAAK,GAAG,MAAM,CAG9D;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAGvE","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 * Hashline format primitives: sigils, separators, regex fragments, and\n * display helpers. These are the single source of truth for the parser, the\n * tokenizer, the prompt, and the formal grammar.\n */\n\nimport type { Cursor } from \"./types.js\";\n\n/** File-section header delimiters: `[path#hash]`. */\nexport const HL_FILE_PREFIX = \"[\";\nexport const HL_FILE_SUFFIX = \"]\";\n\n/** Payload sigil for literal body rows. */\nexport const HL_PAYLOAD_REPLACE = \"+\";\n\n/** Hunk-header keyword for concrete line replacement. */\nexport const HL_REPLACE_KEYWORD = \"replace\";\n/** Hunk-header sub-keyword: `replace block N:` resolves N to a tree-sitter block range. */\nexport const HL_BLOCK_KEYWORD = \"block\";\n/** Hunk-header keyword for concrete line deletion. */\nexport const HL_DELETE_KEYWORD = \"delete\";\n/** Hunk-header keyword for insertion operations. */\nexport const HL_INSERT_KEYWORD = \"insert\";\n/** Insert position keyword for inserting before a concrete line. */\nexport const HL_INSERT_BEFORE = \"before\";\n/** Insert position keyword for inserting after a concrete line. */\nexport const HL_INSERT_AFTER = \"after\";\n/** Insert position keyword for inserting at the start of the file. */\nexport const HL_INSERT_HEAD = \"head\";\n/** Insert position keyword for inserting at the end of the file. */\nexport const HL_INSERT_TAIL = \"tail\";\n/** Hunk-header terminator for body-bearing operations. */\nexport const HL_HEADER_COLON = \":\";\n\n/** Separator between a hashline file path and its opaque snapshot tag. */\nexport const HL_FILE_HASH_SEP = \"#\";\n\n/** Separator between two line numbers in a range, e.g. `5..10`. */\nexport const HL_RANGE_SEP = \"..\";\n\n/** Separator between a line number and displayed line content in hashline mode. */\nexport const HL_LINE_BODY_SEP = \":\";\n\nfunction regexEscape(str: string): string {\n\treturn str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/** Bare positive line-number Lid (no decorations, no captures, no anchors). */\nexport const HL_LINE_RE_RAW = `[1-9]\\\\d*`;\n\n/** Capture-group form of {@link HL_LINE_RE_RAW}. */\nexport const HL_LINE_CAPTURE_RE_RAW = `(${HL_LINE_RE_RAW})`;\n\n/** Format a concrete replacement hunk header. */\nexport function formatReplaceHeader(start: number, end: number): string {\n\treturn `${HL_REPLACE_KEYWORD} ${start}${HL_RANGE_SEP}${end}${HL_HEADER_COLON}`;\n}\n\n/** Format a concrete deletion hunk header. */\nexport function formatDeleteHeader(start: number, end = start): string {\n\treturn start === end ? `${HL_DELETE_KEYWORD} ${start}` : `${HL_DELETE_KEYWORD} ${start}${HL_RANGE_SEP}${end}`;\n}\n\n/** Format an insertion hunk header for a cursor position. */\nexport function formatInsertHeader(cursor: Cursor): string {\n\tswitch (cursor.kind) {\n\t\tcase \"before_anchor\":\n\t\t\treturn `${HL_INSERT_KEYWORD} ${HL_INSERT_BEFORE} ${cursor.anchor.line}${HL_HEADER_COLON}`;\n\t\tcase \"after_anchor\":\n\t\t\treturn `${HL_INSERT_KEYWORD} ${HL_INSERT_AFTER} ${cursor.anchor.line}${HL_HEADER_COLON}`;\n\t\tcase \"bof\":\n\t\t\treturn `${HL_INSERT_KEYWORD} ${HL_INSERT_HEAD}${HL_HEADER_COLON}`;\n\t\tcase \"eof\":\n\t\t\treturn `${HL_INSERT_KEYWORD} ${HL_INSERT_TAIL}${HL_HEADER_COLON}`;\n\t}\n}\n\n/** Number of hex characters in a content-derived file-hash tag. */\nexport const HL_FILE_HASH_LENGTH = 4;\n/** Canonical uppercase hexadecimal content-hash tag carried by a hashline section header. */\nexport const HL_FILE_HASH_RE_RAW = `[0-9A-F]{${HL_FILE_HASH_LENGTH}}`;\n/** Capture-group form of {@link HL_FILE_HASH_RE_RAW}. */\nexport const HL_FILE_HASH_CAPTURE_RE_RAW = `(${HL_FILE_HASH_RE_RAW})`;\n/** Regex-escaped form of {@link HL_LINE_BODY_SEP}, safe for embedding inside a regex. */\nexport const HL_LINE_BODY_SEP_RE_RAW = regexEscape(HL_LINE_BODY_SEP);\n/**\n * Representative file-hash tags for use in user-facing error messages and\n * prompt examples.\n */\nexport const HL_FILE_HASH_EXAMPLES = [\"1A2B\", \"3C4D\", \"9F3E\"] as const;\n/**\n * Normalize text before hashing: trim trailing `[ \\t\\r]` from every line (and\n * the final line) in a single pass so CRLF endings and display-trimmed lines\n * do not invalidate a tag.\n */\nfunction normalizeFileHashText(text: string): string {\n\treturn text.replace(/[ \\t\\r]+(?=\\n|$)/g, \"\");\n}\n/**\n * Compute the content-derived hash tag carried by a hashline section header.\n * The tag is a 4-hex fingerprint of the whole file's normalized text: any read\n * of byte-identical content mints the same tag, and a follow-up edit anchored\n * at any line validates whenever the live file still hashes to it.\n */\n// xxHash32 (canonical, seed 0) to match upstream Bun.hash.xxHash32 so section tags\n// are byte-identical to oh-my-pi for identical content. Pure-JS for Node runtime.\nconst XXH_PRIME32_1 = 0x9e3779b1;\nconst XXH_PRIME32_2 = 0x85ebca77;\nconst XXH_PRIME32_3 = 0xc2b2ae3d;\nconst XXH_PRIME32_4 = 0x27d4eb2f;\nconst XXH_PRIME32_5 = 0x165667b1;\nfunction xxhRotl(value: number, bits: number): number {\n\treturn (value << bits) | (value >>> (32 - bits));\n}\nfunction xxhRound(acc: number, input: number): number {\n\tacc = (acc + Math.imul(input, XXH_PRIME32_2)) | 0;\n\tacc = xxhRotl(acc, 13);\n\treturn Math.imul(acc, XXH_PRIME32_1) | 0;\n}\nfunction xxHash32(bytes: Uint8Array): number {\n\tconst len = bytes.length;\n\tlet index = 0;\n\tlet h32: number;\n\tconst readU32 = (offset: number): number =>\n\t\t(bytes[offset]! | (bytes[offset + 1]! << 8) | (bytes[offset + 2]! << 16) | (bytes[offset + 3]! << 24)) >>> 0;\n\tif (len >= 16) {\n\t\tlet v1 = (XXH_PRIME32_1 + XXH_PRIME32_2) | 0;\n\t\tlet v2 = XXH_PRIME32_2 | 0;\n\t\tlet v3 = 0;\n\t\tlet v4 = -XXH_PRIME32_1 | 0;\n\t\tconst limit = len - 16;\n\t\twhile (index <= limit) {\n\t\t\tv1 = xxhRound(v1, readU32(index)); index += 4;\n\t\t\tv2 = xxhRound(v2, readU32(index)); index += 4;\n\t\t\tv3 = xxhRound(v3, readU32(index)); index += 4;\n\t\t\tv4 = xxhRound(v4, readU32(index)); index += 4;\n\t\t}\n\t\th32 = (xxhRotl(v1, 1) + xxhRotl(v2, 7) + xxhRotl(v3, 12) + xxhRotl(v4, 18)) | 0;\n\t} else {\n\t\th32 = XXH_PRIME32_5 | 0;\n\t}\n\th32 = (h32 + len) | 0;\n\twhile (index + 4 <= len) {\n\t\th32 = (h32 + Math.imul(readU32(index), XXH_PRIME32_3)) | 0;\n\t\th32 = Math.imul(xxhRotl(h32, 17), XXH_PRIME32_4) | 0;\n\t\tindex += 4;\n\t}\n\twhile (index < len) {\n\t\th32 = (h32 + Math.imul(bytes[index]!, XXH_PRIME32_5)) | 0;\n\t\th32 = Math.imul(xxhRotl(h32, 11), XXH_PRIME32_1) | 0;\n\t\tindex += 1;\n\t}\n\th32 ^= h32 >>> 15;\n\th32 = Math.imul(h32, XXH_PRIME32_2);\n\th32 ^= h32 >>> 13;\n\th32 = Math.imul(h32, XXH_PRIME32_3);\n\th32 ^= h32 >>> 16;\n\treturn h32 >>> 0;\n}\nconst xxhEncoder = new TextEncoder();\nexport function computeFileHash(text: string): string {\n\tconst normalized = normalizeFileHashText(text);\n\tconst low16 = xxHash32(xxhEncoder.encode(normalized)) & 0xffff;\n\treturn low16.toString(16).padStart(HL_FILE_HASH_LENGTH, \"0\").toUpperCase();\n}\n\n/**\n * Format a comma-separated list of example anchors with an optional line-number\n * prefix, quoted for inclusion in error messages: `\"160\", \"42\", \"7\"`.\n */\nexport function describeAnchorExamples(linePrefix = \"\"): string {\n\tconst examples = linePrefix ? [linePrefix, `${linePrefix.slice(0, -1) || \"4\"}2`, \"7\"] : [\"160\", \"42\", \"7\"];\n\treturn examples.map(e => `\"${e}\"`).join(\", \");\n}\n\n/** Format a hashline section header for a file path and snapshot tag. */\nexport function formatHashlineHeader(filePath: string, fileHash: string): string {\n\treturn `${HL_FILE_PREFIX}${filePath}${HL_FILE_HASH_SEP}${fileHash}${HL_FILE_SUFFIX}`;\n}\n\n/** Formats a single numbered line as `LINE:TEXT`. */\nexport function formatNumberedLine(lineNumber: number, line: string): string {\n\treturn `${lineNumber}${HL_LINE_BODY_SEP}${line}`;\n}\n\n/** Format file text with hashline-mode line-number prefixes for display. */\nexport function formatNumberedLines(text: string, startLine = 1): string {\n\tconst lines = text.split(\"\\n\");\n\treturn lines.map((line, i) => formatNumberedLine(startLine + i, line)).join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/format.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,qDAAqD;AACrD,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAC5C,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,UAAU,CAAC;AACxC,sDAAsD;AACtD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAC1C,oEAAoE;AACpE,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,mEAAmE;AACnE,eAAO,MAAM,eAAe,UAAU,CAAC;AACvC,sEAAsE;AACtE,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,oEAAoE;AACpE,eAAO,MAAM,cAAc,SAAS,CAAC;AACrC,0DAA0D;AAC1D,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC,mEAAmE;AACnE,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAMpC,+EAA+E;AAC/E,eAAO,MAAM,cAAc,cAAc,CAAC;AAE1C,oDAAoD;AACpD,eAAO,MAAM,sBAAsB,gBAAwB,CAAC;AAE5D,iDAAiD;AACjD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,SAAQ,GAAG,MAAM,CAErE;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWzD;AAED,mEAAmE;AACnE,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,gBAAqC,CAAC;AACtE,yDAAyD;AACzD,eAAO,MAAM,2BAA2B,kBAA6B,CAAC;AACtE,yFAAyF;AACzF,eAAO,MAAM,uBAAuB,QAAgC,CAAC;AACrE;;;GAGG;AACH,eAAO,MAAM,qBAAqB,YAAI,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAuEvE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIpD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,SAAK,GAAG,MAAM,CAG9D;AAED,yEAAyE;AACzE,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED,qDAAqD;AACrD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3E;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAGvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/fs.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,YAAY;IAEzB,YAAY,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAIxC;CACD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIlD;AAED;;;;;;;;;;GAUG;AACH,8BAAsB,UAAU;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjD,kFAAkF;IAC5E,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;IAErD,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAExE,6FAA6F;IACvF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ3C;IAED;;;;;OAKG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElC;CACD;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;;IAGjD,YAAY,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAKxD;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5C;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3C;IAED,mEAAmE;IACnE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEvC;IAED,gEAAgE;IAChE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpC;IAED,sEAAsE;IACtE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5B;IAED,wBAAwB;IACxB,KAAK,IAAI,IAAI,CAEZ;IAED,uCAAuC;IACvC,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAE5C;CACD;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,UAAU;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5C;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE;IAED,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElC;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3C;CACD"
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/fs.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,YAAY;IAEzB,YAAY,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAIxC;CACD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIlD;AAED;;;;;;;;;;GAUG;AACH,8BAAsB,UAAU;IAC/B,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjD,kFAAkF;IAC5E,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;IAErD,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAExE,6FAA6F;IACvF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ3C;IAED;;;;;OAKG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElC;CACD;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;;IAGjD,YAAY,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EAKxD;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI5C;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3C;IAED,mEAAmE;IACnE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEvC;IAED,gEAAgE;IAChE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEpC;IAED,sEAAsE;IACtE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5B;IAED,wBAAwB;IACxB,KAAK,IAAI,IAAI,CAEZ;IAED,uCAAuC;IACvC,OAAO,IAAI,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAE5C;CACD;AAED;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,UAAU;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5C;IAEK,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGnE;IAED,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElC;IAEK,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3C;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/input.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA+EjF,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACb;AA+CD;;;;GAIG;AACH,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK7E;AAyED;;;;;GAKG;AACH,qBAAa,YAAY;;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,YAAY,GAAG,EAAE,UAAU,EAI1B;IAED;;;;OAIG;IACH,KAAK,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAGtD;IAED,qCAAqC;IACrC,IAAI,KAAK,IAAI,SAAS,IAAI,EAAE,CAE3B;IAED,uDAAuD;IACvD,IAAI,QAAQ,IAAI,SAAS,MAAM,EAAE,CAEhC;IAED;;;;OAIG;IACH,IAAI,mBAAmB,IAAI,OAAO,CAOjC;IAED,+EAA+E;IAC/E,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAgBtC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,WAAW,CAchE;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,WAAW,CAYvE;CACD;AAED;;;;;;GAMG;AACH,qBAAa,KAAK;IACjB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAE3C,OAAO,eAEN;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK,CAG7D;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,YAAY,CAK1E;CACD","sourcesContent":["// @generated vendored verbatim from oh-my-pi packages/hashline @ 15b5c1397fc -- DO NOT EDIT.\n// Parity source for the Atomic hashline edit engine (issue #1483); adapted only for Atomic's Node runtime (relative imports, Bun->Node host calls, erasable constructor syntax).\n/**\n * Top-level patch parser. Splits an authored hashline input into a list of\n * {@link PatchSection}s, each rooted at a `[PATH#HASH]` header, then exposes\n * a {@link Patch} class that gives lazy access to the parsed edits per\n * section.\n *\n * The splitter is purely lexical — it doesn't know whether a section's path\n * actually exists. That's the patcher's job.\n */\nimport * as path from \"node:path\";\nimport { applyEdits } from \"./apply.js\";\nimport { resolveBlockEdits } from \"./block.js\";\nimport { HL_FILE_HASH_EXAMPLES, HL_FILE_HASH_LENGTH, HL_FILE_HASH_SEP, HL_FILE_PREFIX, HL_FILE_SUFFIX } from \"./format.js\";\nimport { parsePatch, parsePatchStreaming } from \"./parser.js\";\nimport { Tokenizer } from \"./tokenizer.js\";\nimport type { ApplyResult, BlockResolver, Edit, SplitOptions } from \"./types.js\";\n\n// Pure classification — single shared tokenizer is safe.\nconst TOKENIZER = new Tokenizer();\n\nfunction unquoteHashlinePath(pathText: string): string {\n\tif (pathText.length < 2) return pathText;\n\tconst first = pathText[0];\n\tconst last = pathText[pathText.length - 1];\n\tif ((first === '\"' || first === \"'\") && first === last) return pathText.slice(1, -1);\n\treturn pathText;\n}\n\n/**\n * Strip apply_patch-style noise that models reflexively prepend to the\n * path. Examples observed in benchmark traces:\n *\n * `Update File:foo.ts`, `Update:foo.ts`, `UpdateFile:foo.ts`,\n * `Update/File:foo.ts`, `Update-file:foo.ts`, `Update(File):foo.ts`,\n * `Update<File:foo.ts`, `Add File:foo.ts`, `Delete File:foo.ts`,\n * `Move to:foo.ts`, `***foo.ts`, `***Update File:foo.ts`.\n *\n * We strip a leading `***` (the model duplicating the header sigil) and a\n * leading `(Update|Add|Delete|Move)[<separator>]*(File|to)?[<separator>]*:`\n * keyword block, case-insensitive. The remaining text is the real path.\n */\nconst APPLY_PATCH_PATH_NOISE_RE =\n\t/^\\*{0,3}\\s*(?:(?:update|add|delete|move)[^A-Za-z0-9]*(?:file|to)?[^A-Za-z0-9]*:)?\\s*\\*{0,3}\\s*/i;\n\nfunction stripApplyPatchPathNoise(pathText: string): string {\n\treturn pathText.replace(APPLY_PATCH_PATH_NOISE_RE, \"\");\n}\n\n/**\n * Best-effort recovery for bracketed header lines the strict tokenizer\n * rejects. Strips apply_patch keyword noise (`Update File:`, `Update:`,\n * etc.) and an extra leading `***` (some models emit a hybrid\n * `[***foo.ts#HASH]` shape), then expects `PATH(#HASH)?`.\n * Returns `null` when no clean path can be salvaged.\n */\nfunction tryParseRecoveryHeader(line: string, cwd?: string): RawSection | null {\n\tif (!line.startsWith(HL_FILE_PREFIX) || !line.endsWith(HL_FILE_SUFFIX)) return null;\n\tconst body = stripApplyPatchPathNoise(line.slice(HL_FILE_PREFIX.length, line.length - HL_FILE_SUFFIX.length).trim());\n\tif (body.length === 0) return null;\n\n\t// Trailing `#XXXX` is the tag; everything before it is the path. The\n\t// path may contain whitespace (Windows OneDrive folders, Program Files,\n\t// etc.), so we anchor the tag at end-of-body rather than scanning\n\t// forward and stopping at the first space.\n\tconst trailing = new RegExp(`#([0-9A-Fa-f]{${HL_FILE_HASH_LENGTH}})\\\\s*$`).exec(body);\n\tlet pathText: string;\n\tlet fileHash: string | undefined;\n\tif (trailing !== null) {\n\t\tpathText = body.slice(0, trailing.index);\n\t\tfileHash = trailing[1].toUpperCase();\n\t} else {\n\t\tpathText = body.replace(/\\s+$/, \"\");\n\t}\n\n\t// Same rule as the strict tokenizer: the hashline header grammar uses\n\t// `#` as the path/tag separator and does not allow `#` inside\n\t// filenames. Anything `#` left in the path body — short tags, non-hex\n\t// tags, over-long tags, stale-tag copy-paste, line-suffixed tags —\n\t// means the header is malformed, not a path with an embedded hash.\n\tif (pathText.includes(\"#\")) return null;\n\n\tconst path = normalizeHashlinePath(pathText, cwd);\n\tif (path.length === 0) return null;\n\treturn fileHash !== undefined ? { path, fileHash, diff: \"\" } : { path, diff: \"\" };\n}\n\nfunction normalizeHashlinePath(rawPath: string, cwd?: string): string {\n\tconst unquoted = stripApplyPatchPathNoise(unquoteHashlinePath(rawPath.trim()));\n\tif (!cwd || !path.isAbsolute(unquoted)) return unquoted;\n\tconst relative = path.relative(path.resolve(cwd), path.resolve(unquoted));\n\tconst isWithinCwd = relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n\treturn isWithinCwd ? relative || \".\" : unquoted;\n}\n\ninterface RawSection {\n\tpath: string;\n\tfileHash?: string;\n\tdiff: string;\n}\n\n/**\n * Parse a `[PATH]` or `[PATH#hash]` header line. Returns `null` for lines that do\n * not start with `[`. Throws the strict \"Input header must be …\" error\n * when a bracketed line fails the strict shape (so malformed paths\n * surface immediately instead of being silently re-classified as payload).\n */\nfunction parseHashlineHeaderLine(line: string, cwd?: string): RawSection | null {\n\tconst trimmed = line.trimEnd();\n\tif (!trimmed.startsWith(HL_FILE_PREFIX)) return null;\n\n\tconst token = TOKENIZER.tokenize(trimmed);\n\tif (token.kind !== \"header\") {\n\t\t// Recovery: try to extract a path from the raw line after stripping\n\t\t// apply_patch noise. This handles `[*** Update File:foo.ts#CB5A]` and\n\t\t// the half-dozen variants models actually emit.\n\t\tconst recovered = tryParseRecoveryHeader(trimmed, cwd);\n\t\tif (recovered !== null) return recovered;\n\t\tthrow new Error(\n\t\t\t`Input header must be ${HL_FILE_PREFIX}PATH${HL_FILE_SUFFIX} or ${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}TAG${HL_FILE_SUFFIX} with a ${HL_FILE_HASH_LENGTH}-hex content-hash tag; got ${JSON.stringify(trimmed)}.`,\n\t\t);\n\t}\n\n\tconst parsedPath = normalizeHashlinePath(token.path, cwd);\n\tif (parsedPath.length === 0) {\n\t\tthrow new Error(`Input header \"${HL_FILE_PREFIX}${HL_FILE_SUFFIX}\" is empty; provide a file path.`);\n\t}\n\treturn token.fileHash !== undefined\n\t\t? { path: parsedPath, fileHash: token.fileHash, diff: \"\" }\n\t\t: { path: parsedPath, diff: \"\" };\n}\n\nfunction stripLeadingBlankLines(input: string): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst lines = stripped.split(\"\\n\");\n\twhile (lines.length > 0) {\n\t\tconst head = lines[0].replace(/\\r$/, \"\");\n\t\tif (head.trim().length === 0 || TOKENIZER.tokenize(head).kind === \"envelope-begin\") {\n\t\t\tlines.shift();\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\treturn lines.join(\"\\n\");\n}\n\n/**\n * Returns true when the input contains at least one line that the tokenizer\n * recognizes as a hashline op. Used by streaming previews to decide whether\n * the partial input is worth treating as a hashline patch yet.\n */\nexport function containsRecognizableHashlineOperations(input: string): boolean {\n\tfor (const line of input.split(/\\r?\\n/)) {\n\t\tif (TOKENIZER.isOp(line)) return true;\n\t}\n\treturn false;\n}\n\nfunction normalizeFallbackInput(input: string, options: SplitOptions): string {\n\tconst stripped = input.startsWith(\"\\uFEFF\") ? input.slice(1) : input;\n\tconst hasExplicitHeader = stripped\n\t\t.split(/\\r?\\n/)\n\t\t.some(rawLine => parseHashlineHeaderLine(rawLine, options.cwd) !== null);\n\tif (hasExplicitHeader) return input;\n\n\tif (!options.path || !containsRecognizableHashlineOperations(input)) return input;\n\tconst fallbackPath = normalizeHashlinePath(options.path, options.cwd);\n\tif (fallbackPath.length === 0) return input;\n\treturn `${HL_FILE_PREFIX}${fallbackPath}${HL_FILE_SUFFIX}\\n${input}`;\n}\n\nfunction splitRawSections(input: string, options: SplitOptions = {}): RawSection[] {\n\tconst stripped = stripLeadingBlankLines(normalizeFallbackInput(input, options));\n\tconst lines = stripped.split(/\\r?\\n/);\n\tconst firstLine = lines[0] ?? \"\";\n\n\tif (parseHashlineHeaderLine(firstLine, options.cwd) === null) {\n\t\t// Catch unified-diff hunk-header contamination on the first line so\n\t\t// the model sees a focused error.\n\t\tconst firstTrimmed = firstLine.trimEnd();\n\t\tif (/^@@\\s+[-+]?\\d+,\\d+\\s+[-+]?\\d+,\\d+\\s+@@/.test(firstTrimmed)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"unified-diff hunk header (`@@ -N,M +N,M @@`) is not valid in hashline. \" +\n\t\t\t\t\t`File sections start with \\`${HL_FILE_PREFIX}path${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\\`; use \\`replace\\`, \\`delete\\`, or \\`insert\\` ops.`,\n\t\t\t);\n\t\t}\n\t\tconst preview = JSON.stringify(firstLine.slice(0, 120));\n\t\tthrow new Error(\n\t\t\t`input must begin with \"${HL_FILE_PREFIX}PATH${HL_FILE_HASH_SEP}HASH${HL_FILE_SUFFIX}\" on the first non-blank line for anchored edits; got: ${preview}. ` +\n\t\t\t\t`Example: \"${HL_FILE_PREFIX}src/foo.ts${HL_FILE_HASH_SEP}${HL_FILE_HASH_EXAMPLES[0]}${HL_FILE_SUFFIX}\" then edit ops.`,\n\t\t);\n\t}\n\n\tconst sections: RawSection[] = [];\n\tlet current: RawSection | undefined;\n\tlet currentLines: string[] = [];\n\n\tconst flush = () => {\n\t\tif (!current) return;\n\t\tconst hasOps = currentLines.some(line => line.trim().length > 0);\n\t\tif (hasOps) sections.push({ ...current, diff: currentLines.join(\"\\n\") });\n\t\tcurrentLines = [];\n\t};\n\n\tfor (const line of lines) {\n\t\tconst trimmed = line.trimEnd();\n\t\tconst token = TOKENIZER.tokenize(line);\n\t\tif (token.kind === \"envelope-end\" || token.kind === \"abort\") break;\n\t\tif (token.kind === \"envelope-begin\") continue;\n\n\t\t// Route every bracket-prefixed line through parseHashlineHeaderLine so\n\t\t// malformed headers still raise the strict \"Input header must be …\"\n\t\t// diagnostic (the tokenizer alone would silently classify them as\n\t\t// payload).\n\t\tif (trimmed.startsWith(HL_FILE_PREFIX)) {\n\t\t\tconst header = parseHashlineHeaderLine(line, options.cwd);\n\t\t\tif (header !== null) {\n\t\t\t\tflush();\n\t\t\t\tcurrent = header;\n\t\t\t\tcurrentLines = [];\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tcurrentLines.push(line);\n\t}\n\tflush();\n\treturn sections;\n}\n\n/**\n * Snapshot of one section in a parsed {@link Patch}: a target file plus the\n * lazily-parsed list of edits that should land on it. Constructed by\n * {@link Patch.parse}; consumers usually iterate `patch.sections` rather\n * than build these directly.\n */\nexport class PatchSection {\n\treadonly path: string;\n\treadonly fileHash: string | undefined;\n\treadonly diff: string;\n\t#parsed: { edits: Edit[]; warnings: string[] } | undefined;\n\n\tconstructor(raw: RawSection) {\n\t\tthis.path = raw.path;\n\t\tthis.fileHash = raw.fileHash;\n\t\tthis.diff = raw.diff;\n\t}\n\n\t/**\n\t * Parse this section's diff body. Cached: subsequent calls return the\n\t * same `{ edits, warnings }` object so callers can safely call this from\n\t * multiple paths (preflight, apply, diff-preview).\n\t */\n\tparse(): { edits: Edit[]; warnings: readonly string[] } {\n\t\tthis.#parsed ??= parsePatch(this.diff);\n\t\treturn this.#parsed;\n\t}\n\n\t/** Parsed edits for this section. */\n\tget edits(): readonly Edit[] {\n\t\treturn this.parse().edits;\n\t}\n\n\t/** Warnings emitted during parsing of this section. */\n\tget warnings(): readonly string[] {\n\t\treturn this.parse().warnings;\n\t}\n\n\t/**\n\t * True when at least one edit anchors to concrete file content. Pure\n\t * `insert head:` / `insert tail:` literal inserts do not count: those are\n\t * safe to apply to files that don't yet exist.\n\t */\n\tget hasAnchorScopedEdit(): boolean {\n\t\treturn this.edits.some(edit => {\n\t\t\tif (edit.kind === \"delete\") return true;\n\t\t\t// A `replace block N:` edit is anchored to concrete content on line N.\n\t\t\tif (edit.kind === \"block\") return true;\n\t\t\treturn edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\";\n\t\t});\n\t}\n\n\t/** Anchor lines touched by this section, sorted ascending and deduplicated. */\n\tcollectAnchorLines(): readonly number[] {\n\t\tconst lines = new Set<number>();\n\t\tfor (const edit of this.edits) {\n\t\t\tif (edit.kind === \"delete\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.kind === \"block\") {\n\t\t\t\tlines.add(edit.anchor.line);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (edit.cursor.kind === \"before_anchor\" || edit.cursor.kind === \"after_anchor\") {\n\t\t\t\tlines.add(edit.cursor.anchor.line);\n\t\t\t}\n\t\t}\n\t\treturn [...lines].sort((a, b) => a - b);\n\t}\n\n\t/**\n\t * Apply this section's edits to `text` and return the post-edit result.\n\t * Pure: does no I/O, does not validate the section snapshot tag. The\n\t * {@link Patcher} owns tag validation and recovery; reach for this\n\t * method directly when you've already validated the file content and\n\t * just want the result.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block throws (this is the final, authoritative preview path).\n\t */\n\tapplyTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = this.parse();\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"throw\",\n\t\t\tonWarning: warning => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\t// Preserve parse warnings so consumers don't need to call `parse()`\n\t\t// separately.\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n\n\t/**\n\t * Streaming-tolerant counterpart to {@link applyTo}. Uses\n\t * {@link parsePatchStreaming} so a trailing in-flight op (no payload yet,\n\t * or a per-token parse error mid-stream) does not throw or emit a phantom\n\t * empty-payload edit. Intended for incremental diff previews; the writer\n\t * path should always use {@link applyTo}.\n\t *\n\t * `blockResolver` resolves any `replace block N:` edits against `text`; an\n\t * unresolvable block is silently dropped so a half-written file does not\n\t * throw mid-stream.\n\t */\n\tapplyPartialTo(text: string, blockResolver?: BlockResolver): ApplyResult {\n\t\tconst { edits, warnings } = parsePatchStreaming(this.diff);\n\t\tconst resolveWarnings: string[] = [];\n\t\tconst resolved = resolveBlockEdits(edits, text, this.path, blockResolver, {\n\t\t\tonUnresolved: \"drop\",\n\t\t\tonWarning: warning => resolveWarnings.push(warning),\n\t\t});\n\t\tconst result = applyEdits(text, resolved);\n\t\tconst merged = [...warnings, ...resolveWarnings, ...(result.warnings ?? [])];\n\t\treturn merged.length > 0\n\t\t\t? { ...result, warnings: merged }\n\t\t\t: { text: result.text, firstChangedLine: result.firstChangedLine };\n\t}\n}\n\n/**\n * A parsed hashline patch — zero or more {@link PatchSection}s, each rooted\n * at a `[PATH#HASH]` header. Construct via {@link Patch.parse}.\n *\n * `Patch` is pure data: parsing is line-anchored and does not look at the\n * filesystem. To apply a patch, hand it to {@link Patcher.apply}.\n */\nexport class Patch {\n\treadonly sections: readonly PatchSection[];\n\n\tprivate constructor(sections: PatchSection[]) {\n\t\tthis.sections = sections;\n\t}\n\n\t/**\n\t * Parse `input` into a {@link Patch}. `options.cwd` resolves absolute\n\t * paths inside headers to cwd-relative form; `options.path` provides a\n\t * fallback when the input lacks a header but contains hashline ops\n\t * (useful for streaming previews).\n\t *\n\t * Consecutive sections targeting the same path are merged into a single\n\t * section with concatenated diff bodies. Anchors authored against the\n\t * same file snapshot must be applied as one batch; otherwise the first\n\t * sub-edit shifts line numbers out from under the second's anchors and\n\t * validation fails.\n\t */\n\tstatic parse(input: string, options: SplitOptions = {}): Patch {\n\t\tconst raw = mergeSamePathSections(splitRawSections(input, options));\n\t\treturn new Patch(raw.map(section => new PatchSection(section)));\n\t}\n\n\t/**\n\t * Parse `input` and return only the first section. Throws if the input\n\t * has zero sections. Convenience for the single-section case where the\n\t * caller already knows the patch is one hunk.\n\t */\n\tstatic parseSingle(input: string, options: SplitOptions = {}): PatchSection {\n\t\tconst patch = Patch.parse(input, options);\n\t\tconst first = patch.sections[0];\n\t\tif (!first) throw new Error(\"Patch input did not produce any sections.\");\n\t\treturn first;\n\t}\n}\n\n/**\n * Collapse consecutive or interleaved sections targeting the same path into a\n * single section with concatenated diffs. Anchors authored against the same\n * file snapshot must be applied as one batch; otherwise the first sub-edit\n * shifts line numbers out from under the second's anchors and validation\n * fails. Path order is preserved by first occurrence.\n */\nfunction mergeSamePathSections(sections: RawSection[]): RawSection[] {\n\tconst byPath = new Map<string, { fileHash?: string; diffs: string[] }>();\n\tfor (const section of sections) {\n\t\tconst existing = byPath.get(section.path);\n\t\tif (existing) {\n\t\t\tif (\n\t\t\t\texisting.fileHash !== undefined &&\n\t\t\t\tsection.fileHash !== undefined &&\n\t\t\t\texisting.fileHash !== section.fileHash\n\t\t\t) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Conflicting hashline snapshot tags for ${section.path}: #${existing.fileHash} and #${section.fileHash}. Re-read the file and retry with one current header.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (existing.fileHash === undefined && section.fileHash !== undefined) existing.fileHash = section.fileHash;\n\t\t\texisting.diffs.push(section.diff);\n\t\t\tcontinue;\n\t\t}\n\t\tbyPath.set(section.path, {\n\t\t\t...(section.fileHash !== undefined ? { fileHash: section.fileHash } : {}),\n\t\t\tdiffs: [section.diff],\n\t\t});\n\t}\n\treturn Array.from(byPath, ([sectionPath, entry]) => ({\n\t\tpath: sectionPath,\n\t\t...(entry.fileHash !== undefined ? { fileHash: entry.fileHash } : {}),\n\t\tdiff: entry.diffs.join(\"\\n\"),\n\t}));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/input.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA+EjF,UAAU,UAAU;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACb;AA+CD;;;;GAIG;AACH,wBAAgB,sCAAsC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAK7E;AAyED;;;;;GAKG;AACH,qBAAa,YAAY;;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAGtB,YAAY,GAAG,EAAE,UAAU,EAI1B;IAED;;;;OAIG;IACH,KAAK,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAGtD;IAED,qCAAqC;IACrC,IAAI,KAAK,IAAI,SAAS,IAAI,EAAE,CAE3B;IAED,uDAAuD;IACvD,IAAI,QAAQ,IAAI,SAAS,MAAM,EAAE,CAEhC;IAED;;;;OAIG;IACH,IAAI,mBAAmB,IAAI,OAAO,CAOjC;IAED,+EAA+E;IAC/E,kBAAkB,IAAI,SAAS,MAAM,EAAE,CAgBtC;IAED;;;;;;;;;OASG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,WAAW,CAchE;IAED;;;;;;;;;;OAUG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,WAAW,CAYvE;CACD;AAED;;;;;;GAMG;AACH,qBAAa,KAAK;IACjB,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;IAE3C,OAAO,eAEN;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,KAAK,CAG7D;IAED;;;;OAIG;IACH,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,YAAY,CAK1E;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/messages.ts"],"names":[],"mappings":"AAEA,oFAAoF;AAIpF,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5G;AAED,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC,oEAAoE;AACpE,eAAO,MAAM,8BAA8B,qJACmG,CAAC;AAE/I,mEAAmE;AACnE,eAAO,MAAM,sCAAsC,0JACgG,CAAC;AAEpJ,yDAAyD;AACzD,eAAO,MAAM,4BAA4B,sFAC2C,CAAC;AAErF,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,uHACiF,CAAC;AAEjH,iCAAiC;AACjC,eAAO,MAAM,aAAa,6FAA6F,CAAC;AAExH,4CAA4C;AAC5C,eAAO,MAAM,WAAW,qGAC2E,CAAC;AAEpG;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,MAAM,EACZ,EAAE,GAAE,SAAS,GAAG,QAAoB,EACpC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,CAWR;AAED,4GAA4G;AAC5G,eAAO,MAAM,0BAA0B,0IACiG,CAAC;AAEzI;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,wCAAwC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,yGACiE,CAAC;AAExG,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,oFAAoF,CAAC;AAEtH,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,0FACiD,CAAC;AAEzF,gCAAgC;AAChC,eAAO,MAAM,YAAY,kDAAkD,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/G;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAElH;AAED,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,qHAC6E,CAAC;AAEpH,6DAA6D;AAC7D,eAAO,MAAM,8BAA8B,4HAC+E,CAAC;AAE3H;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,wLAC0I,CAAC;AAEvL;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,sMAC4J,CAAC;AAEhM;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErE","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/** Centralized error/warning text for the hashline parser, applier, and patcher. */\n\nimport { formatNumberedLine, HL_FILE_HASH_SEP, HL_FILE_PREFIX, HL_FILE_SUFFIX } from \"./format.js\";\n\n/** Lines of context shown either side of a hash mismatch. */\nexport const MISMATCH_CONTEXT = 2;\n\n/**\n * Numbered `LINE:TEXT` rows around `anchorLines` (±{@link MISMATCH_CONTEXT}),\n * `*`-marking anchors, `...` between non-adjacent runs. Out-of-range anchors\n * contribute no rows.\n */\nexport function formatAnchoredContext(anchorLines: readonly number[], fileLines: readonly string[]): string[] {\n\tconst displayLines = new Set<number>();\n\tfor (const line of anchorLines) {\n\t\tif (line < 1 || line > fileLines.length) continue;\n\t\tconst lo = Math.max(1, line - MISMATCH_CONTEXT);\n\t\tconst hi = Math.min(fileLines.length, line + MISMATCH_CONTEXT);\n\t\tfor (let lineNum = lo; lineNum <= hi; lineNum++) displayLines.add(lineNum);\n\t}\n\tconst anchorSet = new Set(anchorLines);\n\tconst rows: string[] = [];\n\tlet previous = -1;\n\tfor (const lineNum of [...displayLines].sort((a, b) => a - b)) {\n\t\tif (previous !== -1 && lineNum > previous + 1) rows.push(\"...\");\n\t\tprevious = lineNum;\n\t\tconst marker = anchorSet.has(lineNum) ? \"*\" : \" \";\n\t\trows.push(`${marker}${formatNumberedLine(lineNum, fileLines[lineNum - 1] ?? \"\")}`);\n\t}\n\treturn rows;\n}\n\n/** Optional patch envelope start marker; silently consumed. */\nexport const BEGIN_PATCH_MARKER = \"*** Begin Patch\";\n\n/** Optional patch envelope end marker; terminates parsing. */\nexport const END_PATCH_MARKER = \"*** End Patch\";\n\n/**\n * Truncation sentinel emitted by an agent loop mid-call. Ends parsing like\n * {@link END_PATCH_MARKER}, without a warning.\n */\nexport const ABORT_MARKER = \"*** Abort\";\n\n/** Two consecutive hunks targeted the exact same concrete range. */\nexport const REPLACE_PAIR_COALESCED_WARNING =\n\t\"Two hunks targeted the same range; kept only the second. One `replace N..M:` hunk per range — the body is the final content, never old+new.\";\n\n/** Bare bodyless hunk followed by an overlapping concrete hunk. */\nexport const REPLACE_PAIR_COALESCED_OVERLAP_WARNING =\n\t\"Dropped a bare hunk overlapped by the concrete hunk after it. One `replace N..M:` hunk per range — the body is the final content, never old+new.\";\n\n/** Bare body rows auto-converted to literal `+` rows. */\nexport const BARE_BODY_AUTO_PIPED_WARNING =\n\t\"Auto-prefixed bare body row(s) with `+`. Body rows must be `+TEXT` literal lines.\";\n\n/** Unified-diff-style `-` row in a hunk body. */\nexport const MINUS_ROW_REJECTED =\n\t\"`-` rows are not valid; the range already names the lines being changed. For a literal `-` line, write `+-…`.\";\n\n/** Replace hunk with no body. */\nexport const EMPTY_REPLACE = \"`replace N..M:` needs at least one `+TEXT` body row. To delete lines, use `delete N..M`.\";\n\n/** `replace block N:` hunk with no body. */\nexport const EMPTY_BLOCK =\n\t\"`replace block N:` needs at least one `+TEXT` body row. To delete a block, use `delete block N`.\";\n\n/**\n * Block-anchored replace/delete could not resolve to a syntactic block\n * (unsupported language, blank/out-of-range line, no node beginning on N, or\n * parse error). Appends a {@link formatAnchoredContext} preview when\n * `fileLines` is given. `insert after block N:` never reaches this — it is\n * lowered to plain `insert after N:` instead (see\n * {@link insertAfterBlockUnresolvedLoweredWarning}).\n */\nexport function blockUnresolvedMessage(\n\tline: number,\n\top: \"replace\" | \"delete\" = \"replace\",\n\tfileLines?: readonly string[],\n): string {\n\tconst phrase = op === \"delete\" ? `delete block ${line}` : `replace block ${line}:`;\n\tconst fallback = op === \"delete\" ? `delete ${line}..M` : `replace ${line}..M:`;\n\tlet message =\n\t\t`\\`${phrase}\\` could not resolve a syntactic block beginning on line ${line} ` +\n\t\t`(unsupported language, blank/closer line, or parse error). Use \\`${fallback}\\` with explicit lines.`;\n\tif (fileLines) {\n\t\tconst context = formatAnchoredContext([line], fileLines);\n\t\tif (context.length > 0) message += `\\n\\n${context.join(\"\\n\")}`;\n\t}\n\treturn message;\n}\n\n/** Block-anchored edit reached a path with no {@link BlockResolver} wired in — a host-configuration bug. */\nexport const BLOCK_RESOLVER_UNAVAILABLE =\n\t\"`replace block`/`delete block`/`insert after block` are not available here (no block resolver configured). Use a concrete line range.\";\n\n/**\n * `insert after block N:` anchored on a closing-delimiter line, lowered to\n * plain `insert after N:` — the closer ends a block, and inserting after it\n * is exactly what the plain form does.\n */\nexport function insertAfterBlockCloserLoweredWarning(line: number): string {\n\treturn `\\`insert after block ${line}:\\` anchors on a closing delimiter, so it was applied as plain \\`insert after ${line}:\\`. Anchor on the line that OPENS the construct.`;\n}\n\n/**\n * `insert after block N:` anchor unresolvable (unsupported language, blank\n * line, parse error, or no resolver), lowered to plain `insert after N:` —\n * applying with a warning beats failing the patch.\n */\nexport function insertAfterBlockUnresolvedLoweredWarning(line: number): string {\n\treturn `\\`insert after block ${line}:\\` could not resolve a syntactic block on line ${line}, so it was applied as plain \\`insert after ${line}:\\`. Verify the landing line; anchor on a line that OPENS a construct.`;\n}\n\n/**\n * Internal invariant: `applyEdits` received an unresolved `replace block N:`\n * edit; `resolveBlockEdits` must run first. Wiring bug, not authored input.\n */\nexport const UNRESOLVED_BLOCK_INTERNAL =\n\t\"internal error: unresolved `replace block` edit reached the applier (resolveBlockEdits was not run).\";\n\n/** Delete hunk received a body row. */\nexport const DELETE_TAKES_NO_BODY = \"`delete N..M` does not take body rows. Remove the body, or use `replace N..M:`.\";\n\n/** `delete block N` hunk received a body row. */\nexport const DELETE_BLOCK_TAKES_NO_BODY =\n\t\"`delete block N` does not take body rows. Remove the body, or use `replace block N:`.\";\n\n/** Insert hunk with no body. */\nexport const EMPTY_INSERT = \"`insert` needs at least one `+TEXT` body row.\";\n\n/**\n * `insert after` body indented shallower than the anchor: the landing slid\n * forward past trailing closer lines — the common \"anchored on the last line\n * I read instead of after the block\" mistake.\n */\nexport function afterInsertLandingShiftWarning(anchorLine: number, landingLine: number, crossed: number): string {\n\treturn `insert after ${anchorLine}: body indented shallower than the anchor, so the landing moved past ${crossed} closing line${crossed === 1 ? \"\" : \"s\"} to after line ${landingLine}. For the deeper position inside the block, re-issue with the body indented to match.`;\n}\n\n/**\n * `insert after block N:` body indented deeper than the block's closer: the\n * landing was pulled inside the block — a deeper body almost always means\n * \"append inside the block's body\".\n */\nexport function blockInsertLandingShiftWarning(blockStart: number, closerLine: number, landingLine: number): string {\n\treturn `insert after block ${blockStart}: body indented deeper than closing line ${closerLine}, so it was placed inside the block, after line ${landingLine}. \\`insert after block\\` lands AFTER the block at sibling depth — if inside was intended, use plain \\`insert after ${closerLine}:\\`.`;\n}\n\n/** `Recovery`: an external write matched a cached snapshot. */\nexport const RECOVERY_EXTERNAL_WARNING =\n\t\"Recovered from a stale file hash using a previous read snapshot (file changed externally between read and edit).\";\n\n/** `Recovery`: a prior in-session edit advanced the hash. */\nexport const RECOVERY_SESSION_CHAIN_WARNING =\n\t\"Recovered from a stale file hash using an earlier in-session snapshot (a prior edit in this session advanced the hash).\";\n\n/**\n * `Recovery`: session-chain replay fast-path. Less certain than\n * {@link RECOVERY_SESSION_CHAIN_WARNING} — the 3-way merge refused, the\n * anchor-content gate passed, but a coincidental insert+delete earlier in\n * the chain could still misplace an anchor — hence the verify hedge.\n */\nexport const RECOVERY_SESSION_REPLAY_WARNING =\n\t\"Recovered by replaying your edits onto the current file content (a prior in-session edit changed the lines you re-targeted with a stale hash). Verify the diff matches your intent.\";\n\n/**\n * `insert head:`/`insert tail:` applied despite a stale snapshot tag.\n * Head/tail position is content-independent, so drift is non-fatal: apply\n * onto live content and warn instead of hard-failing.\n */\nexport const HEADTAIL_DRIFT_WARNING =\n\t\"Applied the `insert head:`/`insert tail:` edit despite a stale snapshot tag (file changed since your read) — head/tail position is content-independent. Re-read if the drift was unexpected.\";\n\n/**\n * Section omitted the mandatory snapshot tag. Shared by the apply\n * ({@link Patcher.prepare}) and preview/diff paths so both stay in lockstep.\n */\nexport function missingSnapshotTagMessage(sectionPath: string): string {\n\treturn `Missing hashline snapshot tag for ${sectionPath}; use \\`${HL_FILE_PREFIX}${sectionPath}${HL_FILE_HASH_SEP}tag${HL_FILE_SUFFIX}\\` from your latest read/search output. To create a new file, use the write tool.`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/messages.ts"],"names":[],"mappings":"AAEA,oFAAoF;AAIpF,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5G;AAED,+DAA+D;AAC/D,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AAEpD,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,YAAY,cAAc,CAAC;AAExC,oEAAoE;AACpE,eAAO,MAAM,8BAA8B,qJACmG,CAAC;AAE/I,mEAAmE;AACnE,eAAO,MAAM,sCAAsC,0JACgG,CAAC;AAEpJ,yDAAyD;AACzD,eAAO,MAAM,4BAA4B,sFAC2C,CAAC;AAErF,iDAAiD;AACjD,eAAO,MAAM,kBAAkB,uHACiF,CAAC;AAEjH,iCAAiC;AACjC,eAAO,MAAM,aAAa,6FAA6F,CAAC;AAExH,4CAA4C;AAC5C,eAAO,MAAM,WAAW,qGAC2E,CAAC;AAEpG;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,IAAI,EAAE,MAAM,EACZ,EAAE,GAAE,SAAS,GAAG,QAAoB,EACpC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,CAWR;AAED,4GAA4G;AAC5G,eAAO,MAAM,0BAA0B,0IACiG,CAAC;AAEzI;;;;GAIG;AACH,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,wCAAwC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB,yGACiE,CAAC;AAExG,uCAAuC;AACvC,eAAO,MAAM,oBAAoB,oFAAoF,CAAC;AAEtH,iDAAiD;AACjD,eAAO,MAAM,0BAA0B,0FACiD,CAAC;AAEzF,gCAAgC;AAChC,eAAO,MAAM,YAAY,kDAAkD,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/G;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAElH;AAED,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,qHAC6E,CAAC;AAEpH,6DAA6D;AAC7D,eAAO,MAAM,8BAA8B,4HAC+E,CAAC;AAE3H;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,wLAC0I,CAAC;AAEvL;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,sMAC4J,CAAC;AAEhM;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mismatch.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/mismatch.ts"],"names":[],"mappings":"AAcA,qFAAqF;AACrF,wBAAgB,2BAA2B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAQtD;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IAEjC,YAAY,OAAO,EAAE,eAAe,EASnC;IAED,IAAI,cAAc,IAAI,MAAM,CAS3B;IAED,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CAazD;IAED,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAE5D;IAED,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAMrD;CACD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAIhF"
|
|
1
|
+
{"version":3,"file":"mismatch.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/mismatch.ts"],"names":[],"mappings":"AAcA,qFAAqF;AACrF,wBAAgB,2BAA2B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAQtD;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IAEjC,YAAY,OAAO,EAAE,eAAe,EASnC;IAED,IAAI,cAAc,IAAI,MAAM,CAS3B;IAED,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CAazD;IAED,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAE5D;IAED,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAMrD;CACD;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAIhF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/normalize.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAO5D;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wDAAwD;AACxD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3E;AAED,MAAM,WAAW,SAAS;IACzB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;CACb;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD"
|
|
1
|
+
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/normalize.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;AAE9C,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAO5D;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wDAAwD;AACxD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3E;AAED,MAAM,WAAW,SAAS;IACzB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;CACb;AAED,kFAAkF;AAClF,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAEnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/parser.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAmD,KAAK,KAAK,EAAa,MAAM,gBAAgB,CAAC;AACxG,OAAO,KAAK,EAAkB,IAAI,EAAE,MAAM,YAAY,CAAC;AAyFvD,qBAAa,QAAQ;;IAkBpB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CA0CvB;IAED,GAAG,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAK3C;IAED,YAAY,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAQpD;IAED,KAAK,IAAI,IAAI,CAOZ;CAqMD;AAOD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAK9E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAMvF","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 * Token-driven state machine that turns a stream of {@link Token}s into a\n * flat list of {@link Edit}s. Sits between the {@link Tokenizer} and the\n * applier.\n */\nimport { HL_PAYLOAD_REPLACE } from \"./format.js\";\nimport {\n\tBARE_BODY_AUTO_PIPED_WARNING,\n\tDELETE_BLOCK_TAKES_NO_BODY,\n\tDELETE_TAKES_NO_BODY,\n\tEMPTY_BLOCK,\n\tEMPTY_INSERT,\n\tMINUS_ROW_REJECTED,\n} from \"./messages.js\";\nimport { stripOneLeadingHashlinePrefix } from \"./prefixes.js\";\nimport { type BlockTarget, cloneCursor, type ParsedRange, type Token, Tokenizer } from \"./tokenizer.js\";\nimport type { Anchor, Cursor, Edit } from \"./types.js\";\n\nfunction validateRangeOrder(range: ParsedRange, lineNum: number): void {\n\tif (range.end.line < range.start.line) {\n\t\tthrow new Error(`line ${lineNum}: range ${range.start.line}..${range.end.line} ends before it starts.`);\n\t}\n}\n\nfunction expandRange(range: ParsedRange): Anchor[] {\n\tconst anchors: Anchor[] = [];\n\tfor (let line = range.start.line; line <= range.end.line; line++) anchors.push({ line });\n\treturn anchors;\n}\n\nfunction isSkippableCommentLine(line: string): boolean {\n\treturn line.trimStart().startsWith(\"#\");\n}\n\n/**\n * Stripped remainder of a bare `N: <value>` row that is a lone quoted or\n * numeric literal (optionally comma-terminated) — the shape of a numeric-keyed\n * dict/YAML body rather than read-output paste.\n */\nconst BARE_LITERAL_VALUE_RE = /^\\s*(?:\"[^\"]*\"|'[^']*'|[-+]?\\d+(?:\\.\\d+)?)\\s*,?\\s*$/;\n\nfunction detectApplyPatchContamination(text: string, _hasPending: boolean): string | null {\n\tconst trimmed = text.trimStart();\n\tif (trimmed.length === 0) return null;\n\tif (\n\t\ttrimmed.startsWith(\"*** Update File:\") ||\n\t\ttrimmed.startsWith(\"*** Add File:\") ||\n\t\ttrimmed.startsWith(\"*** Delete File:\") ||\n\t\ttrimmed.startsWith(\"*** Move to:\")\n\t) {\n\t\tconst preview = trimmed.length > 48 ? `${trimmed.slice(0, 48)}…` : trimmed;\n\t\treturn (\n\t\t\t`apply_patch sentinel ${JSON.stringify(preview)} is not valid in hashline. ` +\n\t\t\t\"File sections start with `[path#HASH]` (no `Update File:` / `Add File:` keyword). \" +\n\t\t\t\"Use `replace N..M:`, `delete N..M`, or `insert before|after|head|tail:` ops.\"\n\t\t);\n\t}\n\tif (/^@@\\s+[-+]?\\d+,\\d+\\s+[-+]?\\d+,\\d+\\s+@@/.test(trimmed)) {\n\t\treturn (\n\t\t\t\"unified-diff hunk header (`@@ -N,M +N,M @@`) is not valid in hashline. \" +\n\t\t\t\"Use `replace N..M:`, `delete N..M`, or `insert before|after|head|tail:` ops.\"\n\t\t);\n\t}\n\tif (trimmed.startsWith(\"@@\")) {\n\t\tconst preview = trimmed.length > 48 ? `${trimmed.slice(0, 48)}…` : trimmed;\n\t\treturn (\n\t\t\t`\\`@@\\`-bracketed hunk header ${JSON.stringify(preview)} is not valid in hashline. ` +\n\t\t\t\"Drop the `@@ ... @@` brackets and write a verb header such as `replace N..M:`.\"\n\t\t);\n\t}\n\tif (/^delete\\s+[1-9]\\d*(?:\\s*(?:\\.\\.|-|…|\\s)\\s*[1-9]\\d*)?\\s*:/.test(trimmed)) {\n\t\treturn \"`delete N..M` has no colon and no body. Remove the colon and body rows.\";\n\t}\n\tif (/^[1-9]\\d*\\s*$/.test(trimmed)) {\n\t\treturn `hunk headers need a verb. Use \\`replace ${trimmed}..${trimmed}:\\` to replace, or \\`delete ${trimmed}\\` to delete.`;\n\t}\n\tconst bareRange = /^([1-9]\\d*)\\s*[-. …]+\\s*([1-9]\\d*)\\s*:?$/.exec(trimmed);\n\tif (bareRange !== null) {\n\t\treturn (\n\t\t\t`bare range hunk header ${JSON.stringify(trimmed)} is not valid. ` +\n\t\t\t`Hunk headers need a verb: write \\`replace ${bareRange[1]}..${bareRange[2]}:\\` or \\`delete ${bareRange[1]}..${bareRange[2]}\\`.`\n\t\t);\n\t}\n\treturn null;\n}\n\ninterface PendingComment {\n\tlineNum: number;\n\ttext: string;\n}\n\ntype PayloadRow = { kind: \"literal\"; text: string; lineNum: number; bare?: boolean };\n\ninterface Pending {\n\ttarget: BlockTarget;\n\tlineNum: number;\n\tpayloads: PayloadRow[];\n\t/**\n\t * Blank rows seen after the body started. Interior blanks are committed to\n\t * the payload when the next non-blank row arrives; trailing blanks before\n\t * the next header/op are layout separators and are discarded on flush.\n\t */\n\tdeferredBlanks: PayloadRow[];\n}\n\nexport class Executor {\n\t#edits: Edit[] = [];\n\t#warnings: string[] = [];\n\t#editIndex = 0;\n\t#pending: Pending | undefined;\n\t#terminated = false;\n\t#skippableComments: PendingComment[] = [];\n\n\t#discardPendingSkippableComments(): void {\n\t\tthis.#skippableComments = [];\n\t}\n\n\t#consumePendingSkippableComments(): void {\n\t\tif (this.#skippableComments.length === 0) return;\n\t\tfor (const comment of this.#skippableComments) this.#handleRaw(comment.text, comment.lineNum);\n\t\tthis.#skippableComments = [];\n\t}\n\n\tfeed(token: Token): void {\n\t\tif (this.#terminated) return;\n\t\tswitch (token.kind) {\n\t\t\tcase \"envelope-begin\":\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\treturn;\n\t\t\tcase \"envelope-end\":\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\tthis.#terminated = true;\n\t\t\t\treturn;\n\t\t\tcase \"abort\":\n\t\t\t\tthis.#terminated = true;\n\t\t\t\treturn;\n\t\t\tcase \"header\":\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\tthis.#flushPending();\n\t\t\t\treturn;\n\t\t\tcase \"blank\":\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\tthis.#handleBlank(\"\", token.lineNum);\n\t\t\t\treturn;\n\t\t\tcase \"payload-literal\":\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\tthis.#handleLiteralPayload(token.text, token.lineNum);\n\t\t\t\treturn;\n\t\t\tcase \"raw\":\n\t\t\t\tif (this.#pending === undefined && isSkippableCommentLine(token.text)) {\n\t\t\t\t\tthis.#skippableComments.push({ text: token.text, lineNum: token.lineNum });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.#consumePendingSkippableComments();\n\t\t\t\tthis.#handleRaw(token.text, token.lineNum);\n\t\t\t\treturn;\n\t\t\tcase \"op-block\":\n\t\t\t\tthis.#discardPendingSkippableComments();\n\t\t\t\tif (token.target.kind === \"replace\" || token.target.kind === \"delete\") {\n\t\t\t\t\tvalidateRangeOrder(token.target.range, token.lineNum);\n\t\t\t\t}\n\t\t\t\tthis.#flushPending();\n\t\t\t\tthis.#pending = { target: token.target, lineNum: token.lineNum, payloads: [], deferredBlanks: [] };\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tend(): { edits: Edit[]; warnings: string[] } {\n\t\tthis.#consumePendingSkippableComments();\n\t\tthis.#flushPending();\n\t\tthis.#validateNoOverlappingDeletes();\n\t\treturn { edits: this.#edits, warnings: this.#warnings };\n\t}\n\n\tendStreaming(): { edits: Edit[]; warnings: string[] } {\n\t\tthis.#consumePendingSkippableComments();\n\t\tif (this.#pending && this.#pending.payloads.length > 0) this.#flushPending();\n\t\telse if (this.#pending?.target.kind === \"delete\" || this.#pending?.target.kind === \"delete_block\")\n\t\t\tthis.#flushPending();\n\t\telse this.#pending = undefined;\n\t\tthis.#validateNoOverlappingDeletes();\n\t\treturn { edits: this.#edits, warnings: this.#warnings };\n\t}\n\n\treset(): void {\n\t\tthis.#edits = [];\n\t\tthis.#warnings = [];\n\t\tthis.#editIndex = 0;\n\t\tthis.#pending = undefined;\n\t\tthis.#skippableComments = [];\n\t\tthis.#terminated = false;\n\t}\n\n\t#validateNoOverlappingDeletes(): void {\n\t\tconst sourceLinesByAnchor = new Map<number, number[]>();\n\t\tfor (const edit of this.#edits) {\n\t\t\tif (edit.kind !== \"delete\") continue;\n\t\t\tlet sourceLines = sourceLinesByAnchor.get(edit.anchor.line);\n\t\t\tif (sourceLines === undefined) {\n\t\t\t\tsourceLines = [];\n\t\t\t\tsourceLinesByAnchor.set(edit.anchor.line, sourceLines);\n\t\t\t}\n\t\t\tif (!sourceLines.includes(edit.lineNum)) sourceLines.push(edit.lineNum);\n\t\t}\n\t\tfor (const [anchorLine, sourceLines] of sourceLinesByAnchor) {\n\t\t\tif (sourceLines.length < 2) continue;\n\t\t\tconst [firstBlock, secondBlock] = [...sourceLines].sort((a, b) => a - b);\n\t\t\tthrow new Error(\n\t\t\t\t`line ${secondBlock}: anchor line ${anchorLine} is already targeted by another hunk on line ${firstBlock}. ` +\n\t\t\t\t\t\"Issue ONE hunk per range; payload is only the final desired content, never a before/after pair.\",\n\t\t\t);\n\t\t}\n\t}\n\n\t#handleLiteralPayload(text: string, lineNum: number): void {\n\t\tconst pending = this.#pending;\n\t\tif (!pending) {\n\t\t\tthrow new Error(\n\t\t\t\t`line ${lineNum}: payload line has no preceding hunk header. ` +\n\t\t\t\t\t`Got ${JSON.stringify(`${HL_PAYLOAD_REPLACE}${text}`)}.`,\n\t\t\t);\n\t\t}\n\t\tif (pending.target.kind === \"delete\") throw new Error(`line ${lineNum}: ${DELETE_TAKES_NO_BODY}`);\n\t\tif (pending.target.kind === \"delete_block\") throw new Error(`line ${lineNum}: ${DELETE_BLOCK_TAKES_NO_BODY}`);\n\t\tthis.#commitDeferredBlanks(pending);\n\t\tpending.payloads.push({ kind: \"literal\", text, lineNum });\n\t}\n\n\t#handleRaw(text: string, lineNum: number): void {\n\t\tconst contamination = detectApplyPatchContamination(text, this.#pending !== undefined);\n\t\tif (contamination !== null) throw new Error(`line ${lineNum}: ${contamination}`);\n\t\tif (this.#pending) {\n\t\t\tif (text.trim().length === 0) {\n\t\t\t\tthis.#handleBlank(text, lineNum);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.#pending.target.kind === \"delete\") throw new Error(`line ${lineNum}: ${DELETE_TAKES_NO_BODY}`);\n\t\t\tif (this.#pending.target.kind === \"delete_block\")\n\t\t\t\tthrow new Error(`line ${lineNum}: ${DELETE_BLOCK_TAKES_NO_BODY}`);\n\t\t\tif (text.trimStart().charCodeAt(0) === 45 /* - */) throw new Error(`line ${lineNum}: ${MINUS_ROW_REJECTED}`);\n\t\t\tif (!this.#warnings.includes(BARE_BODY_AUTO_PIPED_WARNING)) this.#warnings.push(BARE_BODY_AUTO_PIPED_WARNING);\n\t\t\tthis.#commitDeferredBlanks(this.#pending);\n\t\t\t// Defer read-output line-number stripping to #flushPending: a bare\n\t\t\t// \"N:text\" row is only a copy-paste artifact from snapshot output\n\t\t\t// when *every* bare row in the hunk carries that prefix. Stripping a\n\t\t\t// row in isolation would corrupt a genuine body that merely starts\n\t\t\t// with \"digits:\" (YAML ports \"42:hello\", timestamps \"12:30\") when it\n\t\t\t// sits next to an unprefixed sibling. Rows with an explicit \"+\" go\n\t\t\t// through #handleLiteralPayload and are never bare, never stripped.\n\t\t\tthis.#pending.payloads.push({ kind: \"literal\", text, lineNum, bare: true });\n\t\t\treturn;\n\t\t}\n\t\tif (text.trim().length === 0) return;\n\t\tthrow new Error(\n\t\t\t`line ${lineNum}: payload line has no preceding hunk header. ` +\n\t\t\t\t`Use \\`replace N..M:\\`, \\`delete N..M\\`, or \\`insert before|after|head|tail:\\` above the body. Got ${JSON.stringify(text)}.`,\n\t\t);\n\t}\n\n\t/**\n\t * A blank row inside a hunk body is ambiguous: interior blanks are body\n\t * content (a bare-pasted body legitimately contains empty lines), while\n\t * blanks before the body starts or trailing into the next op are layout.\n\t * Defer them; {@link #commitDeferredBlanks} folds them in only when a later\n\t * non-blank row proves they were interior.\n\t */\n\t#handleBlank(text: string, lineNum: number): void {\n\t\tconst pending = this.#pending;\n\t\tif (!pending) return;\n\t\tif (pending.target.kind === \"delete\" || pending.target.kind === \"delete_block\") return;\n\t\tif (pending.payloads.length === 0) return;\n\t\tpending.deferredBlanks.push({ kind: \"literal\", text, lineNum, bare: true });\n\t}\n\n\t#commitDeferredBlanks(pending: Pending): void {\n\t\tif (pending.deferredBlanks.length === 0) return;\n\t\tif (!this.#warnings.includes(BARE_BODY_AUTO_PIPED_WARNING)) this.#warnings.push(BARE_BODY_AUTO_PIPED_WARNING);\n\t\tpending.payloads.push(...pending.deferredBlanks);\n\t\tpending.deferredBlanks = [];\n\t}\n\n\t/**\n\t * Strip a single read-output line-number prefix (`N:`) from every bare body\n\t * row, but only when *all* bare rows carry one. A uniform set of prefixes is\n\t * the signature of content pasted straight from `read`/`search` output; a\n\t * mixed set means the `N:` is genuine payload content and must stay. Rows\n\t * authored with an explicit `+` are not bare and are never touched.\n\t */\n\t#stripBarePrefixesIfUniform(payloads: PayloadRow[]): void {\n\t\tlet sawBare = false;\n\t\tlet allLiteralValues = true;\n\t\tfor (const row of payloads) {\n\t\t\tif (!row.bare || row.text.trim().length === 0) continue;\n\t\t\tsawBare = true;\n\t\t\tconst stripped = stripOneLeadingHashlinePrefix(row.text);\n\t\t\tif (stripped === row.text) return;\n\t\t\tallLiteralValues &&= BARE_LITERAL_VALUE_RE.test(stripped);\n\t\t}\n\t\tif (!sawBare) return;\n\t\t// A body where every stripped remainder is a lone quoted/numeric literal\n\t\t// (optionally comma-terminated) is the shape of a numeric-keyed dict or\n\t\t// YAML mapping (`1: \"one\",`), not read-output paste; stripping the \"N:\"\n\t\t// keys would mangle every line. Leave such bodies untouched.\n\t\tif (allLiteralValues) return;\n\t\tfor (const row of payloads) {\n\t\t\tif (row.bare && row.text.trim().length > 0) row.text = stripOneLeadingHashlinePrefix(row.text);\n\t\t}\n\t}\n\n\t#pushInsert(cursor: Cursor, text: string, lineNum: number, mode?: \"replacement\"): void {\n\t\tthis.#edits.push({\n\t\t\tkind: \"insert\",\n\t\t\tcursor: cloneCursor(cursor),\n\t\t\ttext,\n\t\t\tlineNum,\n\t\t\tindex: this.#editIndex++,\n\t\t\t...(mode === undefined ? {} : { mode }),\n\t\t});\n\t}\n\n\t#pushDelete(anchor: Anchor, lineNum: number): void {\n\t\tthis.#edits.push({ kind: \"delete\", anchor: { ...anchor }, lineNum, index: this.#editIndex++ });\n\t}\n\n\t#pushBlock(anchor: Anchor, payloads: readonly PayloadRow[], lineNum: number, mode?: \"insert_after\"): void {\n\t\tthis.#edits.push({\n\t\t\tkind: \"block\",\n\t\t\tanchor: { ...anchor },\n\t\t\tpayloads: payloads.map(payload => payload.text),\n\t\t\t...(mode === undefined ? {} : { mode }),\n\t\t\tlineNum,\n\t\t\tindex: this.#editIndex++,\n\t\t});\n\t}\n\n\t#emitPayloadRows(cursor: Cursor, payloads: readonly PayloadRow[], lineNum: number, mode?: \"replacement\"): void {\n\t\tfor (const payload of payloads) this.#pushInsert(cursor, payload.text, lineNum, mode);\n\t}\n\n\t#flushPending(): void {\n\t\tconst pending = this.#pending;\n\t\tif (!pending) return;\n\t\tconst { target, lineNum, payloads } = pending;\n\t\tthis.#stripBarePrefixesIfUniform(payloads);\n\t\tthis.#pending = undefined;\n\t\tif (target.kind === \"delete\") {\n\t\t\tfor (const anchor of expandRange(target.range)) this.#pushDelete(anchor, lineNum);\n\t\t\treturn;\n\t\t}\n\t\tif (target.kind === \"delete_block\") {\n\t\t\t// A block edit with no payloads resolves to a pure block deletion.\n\t\t\tthis.#pushBlock(target.anchor, [], lineNum);\n\t\t\treturn;\n\t\t}\n\t\tif (target.kind === \"block\") {\n\t\t\tif (payloads.length === 0) throw new Error(`line ${lineNum}: ${EMPTY_BLOCK}`);\n\t\t\tthis.#pushBlock(target.anchor, payloads, lineNum);\n\t\t\treturn;\n\t\t}\n\t\tif (target.kind === \"insert_after_block\") {\n\t\t\tif (payloads.length === 0) throw new Error(`line ${lineNum}: ${EMPTY_INSERT}`);\n\t\t\tthis.#pushBlock(target.anchor, payloads, lineNum, \"insert_after\");\n\t\t\treturn;\n\t\t}\n\t\tif (payloads.length === 0) {\n\t\t\tif (target.kind === \"replace\") {\n\t\t\t\tfor (const anchor of expandRange(target.range)) this.#pushDelete(anchor, lineNum);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow new Error(`line ${lineNum}: ${EMPTY_INSERT}`);\n\t\t}\n\t\tif (target.kind === \"replace\") {\n\t\t\tconst cursor: Cursor = { kind: \"before_anchor\", anchor: { ...target.range.start } };\n\t\t\tthis.#emitPayloadRows(cursor, payloads, lineNum, \"replacement\");\n\t\t\tfor (const anchor of expandRange(target.range)) this.#pushDelete(anchor, lineNum);\n\t\t\treturn;\n\t\t}\n\t\tif (target.kind === \"insert_before\") {\n\t\t\tthis.#emitPayloadRows({ kind: \"before_anchor\", anchor: { ...target.anchor } }, payloads, lineNum);\n\t\t\treturn;\n\t\t}\n\t\tif (target.kind === \"insert_after\") {\n\t\t\tthis.#emitPayloadRows({ kind: \"after_anchor\", anchor: { ...target.anchor } }, payloads, lineNum);\n\t\t\treturn;\n\t\t}\n\t\tconst cursor: Cursor = target.kind === \"bof\" ? { kind: \"bof\" } : { kind: \"eof\" };\n\t\tthis.#emitPayloadRows(cursor, payloads, lineNum);\n\t}\n}\n\nfunction drain(executor: Executor, tokenizer: Tokenizer): { edits: Edit[]; warnings: string[] } {\n\tfor (const token of tokenizer.end()) executor.feed(token);\n\treturn executor.end();\n}\n\nexport function parsePatch(diff: string): { edits: Edit[]; warnings: string[] } {\n\tconst tokenizer = new Tokenizer();\n\tconst executor = new Executor();\n\tfor (const token of tokenizer.feed(diff)) executor.feed(token);\n\treturn drain(executor, tokenizer);\n}\n\nexport function parsePatchStreaming(diff: string): { edits: Edit[]; warnings: string[] } {\n\tconst tokenizer = new Tokenizer();\n\tconst executor = new Executor();\n\tfor (const token of tokenizer.feed(diff)) executor.feed(token);\n\tfor (const token of tokenizer.end()) executor.feed(token);\n\treturn executor.endStreaming();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/hashline-engine/parser.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAmD,KAAK,KAAK,EAAa,MAAM,gBAAgB,CAAC;AACxG,OAAO,KAAK,EAAkB,IAAI,EAAE,MAAM,YAAY,CAAC;AAyFvD,qBAAa,QAAQ;;IAkBpB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CA0CvB;IAED,GAAG,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAK3C;IAED,YAAY,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAQpD;IAED,KAAK,IAAI,IAAI,CAOZ;CAqMD;AAOD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAK9E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAMvF"}
|