bonecode 1.0.0
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/ARCHITECTURE.md +183 -0
- package/README.md +71 -0
- package/bin/bonecode +62 -0
- package/bone/migrations/rag_vectors.sql +258 -0
- package/bone/output/agent/.dockerignore +7 -0
- package/bone/output/agent/.env.example +36 -0
- package/bone/output/agent/.github/workflows/ci.yaml +58 -0
- package/bone/output/agent/AgentDomain.bone.map +350 -0
- package/bone/output/agent/AgentDomain.postman_collection.json +958 -0
- package/bone/output/agent/Dockerfile +22 -0
- package/bone/output/agent/README.md +47 -0
- package/bone/output/agent/admin/index.html +740 -0
- package/bone/output/agent/docker-compose.yaml +22 -0
- package/bone/output/agent/k8s/deployment.yaml +75 -0
- package/bone/output/agent/migrations/agent.sql +36 -0
- package/bone/output/agent/migrations/agent_instance.sql +36 -0
- package/bone/output/agent/migrations/audit_log.sql +18 -0
- package/bone/output/agent/migrations/build_step.sql +34 -0
- package/bone/output/agent/migrations/event_outbox.sql +31 -0
- package/bone/output/agent/migrations/plan.sql +30 -0
- package/bone/output/agent/migrations/task.sql +30 -0
- package/bone/output/agent/migrations/tool_call.sql +33 -0
- package/bone/output/agent/openapi.yaml +1116 -0
- package/bone/output/agent/package.json +36 -0
- package/bone/output/agent/schema.graphql +233 -0
- package/bone/output/agent/sdk/client.ts +231 -0
- package/bone/output/agent/src/algorithms.ts +2 -0
- package/bone/output/agent/src/audit.ts +44 -0
- package/bone/output/agent/src/auth.ts +57 -0
- package/bone/output/agent/src/cron.ts +12 -0
- package/bone/output/agent/src/db.ts +32 -0
- package/bone/output/agent/src/debug.ts +66 -0
- package/bone/output/agent/src/events.ts +243 -0
- package/bone/output/agent/src/extensions.ts +54 -0
- package/bone/output/agent/src/failure_rules.ts +323 -0
- package/bone/output/agent/src/flows.ts +168 -0
- package/bone/output/agent/src/health.ts +43 -0
- package/bone/output/agent/src/index.ts +100 -0
- package/bone/output/agent/src/logger.ts +66 -0
- package/bone/output/agent/src/metrics.ts +75 -0
- package/bone/output/agent/src/migrate.ts +352 -0
- package/bone/output/agent/src/migration_diff.ts +108 -0
- package/bone/output/agent/src/notify.ts +125 -0
- package/bone/output/agent/src/routes/agent_instance.ts +234 -0
- package/bone/output/agent/src/routes/build_step.ts +105 -0
- package/bone/output/agent/src/routes/plan.ts +91 -0
- package/bone/output/agent/src/routes/task.ts +105 -0
- package/bone/output/agent/src/routes/tool_call.ts +166 -0
- package/bone/output/agent/src/schemas.ts +384 -0
- package/bone/output/agent/src/state_machines/agent_instance.ts +24 -0
- package/bone/output/agent/src/state_machines/build_step.ts +22 -0
- package/bone/output/agent/src/state_machines/plan.ts +22 -0
- package/bone/output/agent/src/state_machines/task.ts +22 -0
- package/bone/output/agent/src/state_machines/tool_call.ts +22 -0
- package/bone/output/agent/src/tests.ts +362 -0
- package/bone/output/agent/src/websocket.ts +201 -0
- package/bone/output/agent/tsconfig.json +25 -0
- package/bone/output/rag/.dockerignore +7 -0
- package/bone/output/rag/.env.example +36 -0
- package/bone/output/rag/.github/workflows/ci.yaml +58 -0
- package/bone/output/rag/Dockerfile +22 -0
- package/bone/output/rag/RAGDomain.bone.map +287 -0
- package/bone/output/rag/RAGDomain.postman_collection.json +923 -0
- package/bone/output/rag/README.md +47 -0
- package/bone/output/rag/admin/index.html +818 -0
- package/bone/output/rag/docker-compose.yaml +22 -0
- package/bone/output/rag/k8s/deployment.yaml +75 -0
- package/bone/output/rag/migrations/audit_log.sql +18 -0
- package/bone/output/rag/migrations/code_chunk.sql +34 -0
- package/bone/output/rag/migrations/code_file.sql +33 -0
- package/bone/output/rag/migrations/event_outbox.sql +31 -0
- package/bone/output/rag/migrations/indexing_job.sql +33 -0
- package/bone/output/rag/migrations/knowledge_base.sql +35 -0
- package/bone/output/rag/migrations/memory_entry.sql +34 -0
- package/bone/output/rag/openapi.yaml +1097 -0
- package/bone/output/rag/package.json +36 -0
- package/bone/output/rag/schema.graphql +245 -0
- package/bone/output/rag/sdk/client.ts +234 -0
- package/bone/output/rag/src/algorithms.ts +2 -0
- package/bone/output/rag/src/audit.ts +37 -0
- package/bone/output/rag/src/auth.ts +57 -0
- package/bone/output/rag/src/cron.ts +12 -0
- package/bone/output/rag/src/db.ts +32 -0
- package/bone/output/rag/src/debug.ts +66 -0
- package/bone/output/rag/src/events.ts +243 -0
- package/bone/output/rag/src/extensions.ts +350 -0
- package/bone/output/rag/src/failure_rules.ts +315 -0
- package/bone/output/rag/src/flows.ts +239 -0
- package/bone/output/rag/src/health.ts +43 -0
- package/bone/output/rag/src/index.ts +95 -0
- package/bone/output/rag/src/logger.ts +66 -0
- package/bone/output/rag/src/metrics.ts +75 -0
- package/bone/output/rag/src/migrate.ts +364 -0
- package/bone/output/rag/src/migration_diff.ts +108 -0
- package/bone/output/rag/src/notify.ts +99 -0
- package/bone/output/rag/src/routes/code_chunk.ts +75 -0
- package/bone/output/rag/src/routes/code_file.ts +101 -0
- package/bone/output/rag/src/routes/indexing_job.ts +87 -0
- package/bone/output/rag/src/routes/knowledge_base.ts +230 -0
- package/bone/output/rag/src/routes/memory_entry.ts +87 -0
- package/bone/output/rag/src/schemas.ts +394 -0
- package/bone/output/rag/src/state_machines/code_file.ts +23 -0
- package/bone/output/rag/src/state_machines/indexing_job.ts +22 -0
- package/bone/output/rag/src/state_machines/knowledge_base.ts +23 -0
- package/bone/output/rag/src/state_machines/memory_entry.ts +20 -0
- package/bone/output/rag/src/tests.ts +340 -0
- package/bone/output/rag/tsconfig.json +25 -0
- package/bone/output/session/.dockerignore +7 -0
- package/bone/output/session/.env.example +36 -0
- package/bone/output/session/.github/workflows/ci.yaml +58 -0
- package/bone/output/session/Dockerfile +22 -0
- package/bone/output/session/README.md +47 -0
- package/bone/output/session/SessionDomain.bone.map +350 -0
- package/bone/output/session/SessionDomain.postman_collection.json +958 -0
- package/bone/output/session/admin/index.html +667 -0
- package/bone/output/session/docker-compose.yaml +22 -0
- package/bone/output/session/k8s/deployment.yaml +75 -0
- package/bone/output/session/migrations/audit_log.sql +18 -0
- package/bone/output/session/migrations/event_outbox.sql +31 -0
- package/bone/output/session/migrations/message.sql +31 -0
- package/bone/output/session/migrations/part.sql +28 -0
- package/bone/output/session/migrations/permission.sql +28 -0
- package/bone/output/session/migrations/project.sql +28 -0
- package/bone/output/session/migrations/session.sql +38 -0
- package/bone/output/session/openapi.yaml +1101 -0
- package/bone/output/session/package.json +36 -0
- package/bone/output/session/schema.graphql +222 -0
- package/bone/output/session/sdk/client.ts +225 -0
- package/bone/output/session/src/algorithms.ts +2 -0
- package/bone/output/session/src/audit.ts +44 -0
- package/bone/output/session/src/auth.ts +57 -0
- package/bone/output/session/src/cron.ts +12 -0
- package/bone/output/session/src/db.ts +32 -0
- package/bone/output/session/src/debug.ts +66 -0
- package/bone/output/session/src/events.ts +270 -0
- package/bone/output/session/src/extensions.ts +215 -0
- package/bone/output/session/src/failure_rules.ts +284 -0
- package/bone/output/session/src/flows.ts +168 -0
- package/bone/output/session/src/health.ts +43 -0
- package/bone/output/session/src/index.ts +100 -0
- package/bone/output/session/src/logger.ts +66 -0
- package/bone/output/session/src/metrics.ts +75 -0
- package/bone/output/session/src/migrate.ts +332 -0
- package/bone/output/session/src/migration_diff.ts +108 -0
- package/bone/output/session/src/notify.ts +112 -0
- package/bone/output/session/src/routes/message.ts +93 -0
- package/bone/output/session/src/routes/part.ts +79 -0
- package/bone/output/session/src/routes/permission.ts +79 -0
- package/bone/output/session/src/routes/project.ts +79 -0
- package/bone/output/session/src/routes/session.ts +294 -0
- package/bone/output/session/src/schemas.ts +357 -0
- package/bone/output/session/src/state_machines/session.ts +23 -0
- package/bone/output/session/src/tests.ts +326 -0
- package/bone/output/session/src/websocket.ts +201 -0
- package/bone/output/session/tsconfig.json +25 -0
- package/bone/output/workspace/.dockerignore +7 -0
- package/bone/output/workspace/.env.example +36 -0
- package/bone/output/workspace/.github/workflows/ci.yaml +58 -0
- package/bone/output/workspace/Dockerfile +22 -0
- package/bone/output/workspace/README.md +45 -0
- package/bone/output/workspace/WorkspaceDomain.bone.map +189 -0
- package/bone/output/workspace/WorkspaceDomain.postman_collection.json +621 -0
- package/bone/output/workspace/admin/index.html +485 -0
- package/bone/output/workspace/docker-compose.yaml +22 -0
- package/bone/output/workspace/k8s/deployment.yaml +75 -0
- package/bone/output/workspace/migrations/audit_log.sql +18 -0
- package/bone/output/workspace/migrations/codebase.sql +34 -0
- package/bone/output/workspace/migrations/event_outbox.sql +31 -0
- package/bone/output/workspace/migrations/snapshot.sql +32 -0
- package/bone/output/workspace/migrations/workspace.sql +33 -0
- package/bone/output/workspace/openapi.yaml +721 -0
- package/bone/output/workspace/package.json +36 -0
- package/bone/output/workspace/schema.graphql +153 -0
- package/bone/output/workspace/sdk/client.ts +155 -0
- package/bone/output/workspace/src/algorithms.ts +2 -0
- package/bone/output/workspace/src/audit.ts +37 -0
- package/bone/output/workspace/src/auth.ts +57 -0
- package/bone/output/workspace/src/cron.ts +12 -0
- package/bone/output/workspace/src/db.ts +32 -0
- package/bone/output/workspace/src/debug.ts +66 -0
- package/bone/output/workspace/src/events.ts +243 -0
- package/bone/output/workspace/src/extensions.ts +44 -0
- package/bone/output/workspace/src/failure_rules.ts +153 -0
- package/bone/output/workspace/src/health.ts +43 -0
- package/bone/output/workspace/src/index.ts +89 -0
- package/bone/output/workspace/src/logger.ts +66 -0
- package/bone/output/workspace/src/metrics.ts +75 -0
- package/bone/output/workspace/src/migrate.ts +220 -0
- package/bone/output/workspace/src/migration_diff.ts +108 -0
- package/bone/output/workspace/src/notify.ts +73 -0
- package/bone/output/workspace/src/routes/codebase.ts +87 -0
- package/bone/output/workspace/src/routes/snapshot.ts +127 -0
- package/bone/output/workspace/src/routes/workspace.ts +190 -0
- package/bone/output/workspace/src/schemas.ts +231 -0
- package/bone/output/workspace/src/state_machines/codebase.ts +21 -0
- package/bone/output/workspace/src/state_machines/snapshot.ts +20 -0
- package/bone/output/workspace/src/state_machines/workspace.ts +21 -0
- package/bone/output/workspace/src/tests.ts +249 -0
- package/bone/output/workspace/tsconfig.json +25 -0
- package/compat/opencode_adapter.ts +410 -0
- package/package.json +69 -0
- package/scripts/check_benchmark_session.js +34 -0
- package/scripts/check_finish_event.js +24 -0
- package/scripts/check_parts.js +15 -0
- package/scripts/compile.js +79 -0
- package/scripts/copy_opencode.ps1 +53 -0
- package/scripts/create_functions.sql +129 -0
- package/scripts/migrate.js +85 -0
- package/scripts/migrate_from_opencode.ts +218 -0
- package/scripts/test_agent_loop.js +101 -0
- package/scripts/test_api.ps1 +116 -0
- package/scripts/test_context_builder.js +136 -0
- package/scripts/test_context_builder.ts +97 -0
- package/scripts/test_rag.js +189 -0
- package/scripts/test_stream_events.js +36 -0
- package/scripts/test_websocket_and_saga.js +216 -0
- package/src/cli.ts +475 -0
- package/src/config.ts +162 -0
- package/src/context_builder.ts +598 -0
- package/src/engine/account/account.sql.ts +39 -0
- package/src/engine/account/account.ts +456 -0
- package/src/engine/account/repo.ts +166 -0
- package/src/engine/account/schema.ts +99 -0
- package/src/engine/account/url.ts +8 -0
- package/src/engine/acp/README.md +174 -0
- package/src/engine/acp/agent.ts +1968 -0
- package/src/engine/acp/runtime.ts +22 -0
- package/src/engine/acp/session.ts +122 -0
- package/src/engine/acp/types.ts +24 -0
- package/src/engine/agent/agent.ts +463 -0
- package/src/engine/agent/generate.txt +75 -0
- package/src/engine/agent/prompt/compaction.txt +9 -0
- package/src/engine/agent/prompt/explore.txt +18 -0
- package/src/engine/agent/prompt/scout.txt +36 -0
- package/src/engine/agent/prompt/summary.txt +11 -0
- package/src/engine/agent/prompt/title.txt +44 -0
- package/src/engine/agent/subagent-permissions.ts +34 -0
- package/src/engine/auth/index.ts +96 -0
- package/src/engine/background/background/job.ts +200 -0
- package/src/engine/background/job.ts +200 -0
- package/src/engine/bus/bus-event.ts +45 -0
- package/src/engine/bus/global.ts +22 -0
- package/src/engine/bus/index.ts +203 -0
- package/src/engine/command/command/index.ts +181 -0
- package/src/engine/command/command/template/initialize.txt +66 -0
- package/src/engine/command/command/template/review.txt +101 -0
- package/src/engine/command/index.ts +181 -0
- package/src/engine/command/template/initialize.txt +66 -0
- package/src/engine/command/template/review.txt +101 -0
- package/src/engine/config/agent.ts +172 -0
- package/src/engine/config/attachment.ts +25 -0
- package/src/engine/config/command.ts +62 -0
- package/src/engine/config/config.ts +833 -0
- package/src/engine/config/console-state.ts +14 -0
- package/src/engine/config/entry-name.ts +16 -0
- package/src/engine/config/error.ts +23 -0
- package/src/engine/config/formatter.ts +13 -0
- package/src/engine/config/layout.ts +6 -0
- package/src/engine/config/lsp.ts +43 -0
- package/src/engine/config/managed.ts +71 -0
- package/src/engine/config/markdown.ts +96 -0
- package/src/engine/config/mcp.ts +56 -0
- package/src/engine/config/model-id.ts +5 -0
- package/src/engine/config/parse.ts +79 -0
- package/src/engine/config/paths.ts +45 -0
- package/src/engine/config/permission.ts +58 -0
- package/src/engine/config/plugin.ts +84 -0
- package/src/engine/config/provider.ts +111 -0
- package/src/engine/config/reference.ts +23 -0
- package/src/engine/config/server.ts +19 -0
- package/src/engine/config/skills.ts +14 -0
- package/src/engine/config/variable.ts +90 -0
- package/src/engine/control-plane/adapters/index.ts +41 -0
- package/src/engine/control-plane/adapters/worktree.ts +96 -0
- package/src/engine/control-plane/dev/README.md +19 -0
- package/src/engine/control-plane/dev/debug-workspace-plugin.ts +73 -0
- package/src/engine/control-plane/schema.ts +14 -0
- package/src/engine/control-plane/types.ts +59 -0
- package/src/engine/control-plane/util.ts +39 -0
- package/src/engine/control-plane/workspace-adapter-runtime.ts +51 -0
- package/src/engine/control-plane/workspace-context.ts +26 -0
- package/src/engine/control-plane/workspace.sql.ts +20 -0
- package/src/engine/control-plane/workspace.ts +1072 -0
- package/src/engine/data-migration.ts +161 -0
- package/src/engine/effect/app-runtime.ts +143 -0
- package/src/engine/effect/bootstrap-runtime.ts +29 -0
- package/src/engine/effect/bridge.ts +84 -0
- package/src/engine/effect/config-service.ts +67 -0
- package/src/engine/effect/instance-ref.ts +11 -0
- package/src/engine/effect/instance-registry.ts +12 -0
- package/src/engine/effect/instance-state.ts +72 -0
- package/src/engine/effect/promise.ts +17 -0
- package/src/engine/effect/run-service.ts +47 -0
- package/src/engine/effect/runner.ts +217 -0
- package/src/engine/effect/runtime-flags.ts +74 -0
- package/src/engine/effect/service-use.ts +38 -0
- package/src/engine/env/index.ts +37 -0
- package/src/engine/event-v2-bridge.ts +89 -0
- package/src/engine/file/file/ignore.ts +81 -0
- package/src/engine/file/file/index.ts +651 -0
- package/src/engine/file/file/protected.ts +59 -0
- package/src/engine/file/file/ripgrep.ts +481 -0
- package/src/engine/file/file/watcher.ts +167 -0
- package/src/engine/file/ignore.ts +81 -0
- package/src/engine/file/index.ts +651 -0
- package/src/engine/file/protected.ts +59 -0
- package/src/engine/file/ripgrep.ts +481 -0
- package/src/engine/file/watcher.ts +167 -0
- package/src/engine/format/format/formatter.ts +404 -0
- package/src/engine/format/format/index.ts +209 -0
- package/src/engine/format/formatter.ts +404 -0
- package/src/engine/format/index.ts +209 -0
- package/src/engine/git/git/index.ts +347 -0
- package/src/engine/git/index.ts +347 -0
- package/src/engine/id/id.ts +80 -0
- package/src/engine/ide/index.ts +70 -0
- package/src/engine/image/image/image.ts +176 -0
- package/src/engine/image/image.ts +176 -0
- package/src/engine/index.ts +251 -0
- package/src/engine/installation/index.ts +327 -0
- package/src/engine/lsp/client.ts +707 -0
- package/src/engine/lsp/diagnostic.ts +29 -0
- package/src/engine/lsp/language.ts +121 -0
- package/src/engine/lsp/launch.ts +21 -0
- package/src/engine/lsp/lsp/client.ts +707 -0
- package/src/engine/lsp/lsp/diagnostic.ts +29 -0
- package/src/engine/lsp/lsp/language.ts +121 -0
- package/src/engine/lsp/lsp/launch.ts +21 -0
- package/src/engine/lsp/lsp/lsp.ts +507 -0
- package/src/engine/lsp/lsp/server.ts +2064 -0
- package/src/engine/lsp/lsp.ts +507 -0
- package/src/engine/lsp/server.ts +2064 -0
- package/src/engine/mcp/auth.ts +146 -0
- package/src/engine/mcp/index.ts +958 -0
- package/src/engine/mcp/mcp/auth.ts +146 -0
- package/src/engine/mcp/mcp/index.ts +958 -0
- package/src/engine/mcp/mcp/oauth-callback.ts +232 -0
- package/src/engine/mcp/mcp/oauth-provider.ts +214 -0
- package/src/engine/mcp/oauth-callback.ts +232 -0
- package/src/engine/mcp/oauth-provider.ts +214 -0
- package/src/engine/node.ts +6 -0
- package/src/engine/patch/index.ts +689 -0
- package/src/engine/patch/patch/index.ts +689 -0
- package/src/engine/permission/arity.ts +163 -0
- package/src/engine/permission/evaluate.ts +15 -0
- package/src/engine/permission/index.ts +306 -0
- package/src/engine/permission/permission/arity.ts +163 -0
- package/src/engine/permission/permission/evaluate.ts +15 -0
- package/src/engine/permission/permission/index.ts +306 -0
- package/src/engine/permission/permission/schema.ts +13 -0
- package/src/engine/permission/schema.ts +13 -0
- package/src/engine/plugin/azure.ts +26 -0
- package/src/engine/plugin/cloudflare.ts +76 -0
- package/src/engine/plugin/codex.ts +622 -0
- package/src/engine/plugin/digitalocean.ts +411 -0
- package/src/engine/plugin/github-copilot/copilot.ts +394 -0
- package/src/engine/plugin/github-copilot/models.ts +196 -0
- package/src/engine/plugin/index.ts +295 -0
- package/src/engine/plugin/install.ts +439 -0
- package/src/engine/plugin/loader.ts +216 -0
- package/src/engine/plugin/meta.ts +188 -0
- package/src/engine/plugin/shared.ts +323 -0
- package/src/engine/project/bootstrap-service.ts +9 -0
- package/src/engine/project/bootstrap.ts +75 -0
- package/src/engine/project/instance-context.ts +24 -0
- package/src/engine/project/instance-layer.ts +11 -0
- package/src/engine/project/instance-runtime.ts +16 -0
- package/src/engine/project/instance-store.ts +193 -0
- package/src/engine/project/project.sql.ts +17 -0
- package/src/engine/project/project.ts +537 -0
- package/src/engine/project/schema.ts +13 -0
- package/src/engine/project/vcs.ts +405 -0
- package/src/engine/provider/auth.ts +225 -0
- package/src/engine/provider/error.ts +204 -0
- package/src/engine/provider/model-status.ts +8 -0
- package/src/engine/provider/provider.ts +1843 -0
- package/src/engine/provider/schema.ts +30 -0
- package/src/engine/provider/sdk/copilot/AGENTS.md +1 -0
- package/src/engine/provider/transform.ts +1376 -0
- package/src/engine/pty/index.ts +365 -0
- package/src/engine/pty/input.ts +24 -0
- package/src/engine/pty/pty/index.ts +365 -0
- package/src/engine/pty/pty/input.ts +24 -0
- package/src/engine/pty/pty/pty.bun.ts +26 -0
- package/src/engine/pty/pty/pty.node.ts +27 -0
- package/src/engine/pty/pty/pty.ts +25 -0
- package/src/engine/pty/pty/schema.ts +14 -0
- package/src/engine/pty/pty/ticket.ts +68 -0
- package/src/engine/pty/pty.bun.ts +26 -0
- package/src/engine/pty/pty.node.ts +27 -0
- package/src/engine/pty/pty.ts +25 -0
- package/src/engine/pty/schema.ts +14 -0
- package/src/engine/pty/ticket.ts +68 -0
- package/src/engine/question/index.ts +213 -0
- package/src/engine/question/question/index.ts +213 -0
- package/src/engine/question/question/schema.ts +10 -0
- package/src/engine/question/schema.ts +10 -0
- package/src/engine/reference/reference/reference.ts +241 -0
- package/src/engine/reference/reference/repository-cache.ts +147 -0
- package/src/engine/reference/reference.ts +241 -0
- package/src/engine/reference/repository-cache.ts +147 -0
- package/src/engine/session/compaction.ts +651 -0
- package/src/engine/session/compaction_logic.ts +120 -0
- package/src/engine/session/instruction.ts +238 -0
- package/src/engine/session/instruction_loader.ts +54 -0
- package/src/engine/session/llm.ts +459 -0
- package/src/engine/session/message-error.ts +14 -0
- package/src/engine/session/message-v2.ts +1202 -0
- package/src/engine/session/message.ts +146 -0
- package/src/engine/session/overflow.ts +32 -0
- package/src/engine/session/overflow_check.ts +46 -0
- package/src/engine/session/processor.ts +823 -0
- package/src/engine/session/prompt/anthropic.txt +105 -0
- package/src/engine/session/prompt/beast.txt +147 -0
- package/src/engine/session/prompt/build-switch.txt +5 -0
- package/src/engine/session/prompt/codex.txt +79 -0
- package/src/engine/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/engine/session/prompt/default.txt +105 -0
- package/src/engine/session/prompt/gemini.txt +155 -0
- package/src/engine/session/prompt/gpt.txt +107 -0
- package/src/engine/session/prompt/kimi.txt +95 -0
- package/src/engine/session/prompt/max-steps.txt +16 -0
- package/src/engine/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/engine/session/prompt/plan.txt +26 -0
- package/src/engine/session/prompt/trinity.txt +97 -0
- package/src/engine/session/prompt.ts +671 -0
- package/src/engine/session/provider_transform.ts +187 -0
- package/src/engine/session/retry.ts +200 -0
- package/src/engine/session/retry_logic.ts +65 -0
- package/src/engine/session/revert.ts +162 -0
- package/src/engine/session/run-state.ts +153 -0
- package/src/engine/session/schema.ts +26 -0
- package/src/engine/session/session.sql.ts +137 -0
- package/src/engine/session/session.ts +1011 -0
- package/src/engine/session/status.ts +94 -0
- package/src/engine/session/summary.ts +164 -0
- package/src/engine/session/system.ts +84 -0
- package/src/engine/session/system_prompt.ts +65 -0
- package/src/engine/session/todo.ts +81 -0
- package/src/engine/session/tool_registry.ts +162 -0
- package/src/engine/share/session.ts +61 -0
- package/src/engine/share/share-next.ts +376 -0
- package/src/engine/share/share.sql.ts +13 -0
- package/src/engine/shell/shell/shell.ts +215 -0
- package/src/engine/shell/shell.ts +215 -0
- package/src/engine/skill/discovery.ts +116 -0
- package/src/engine/skill/index.ts +336 -0
- package/src/engine/skill/prompt/customize-opencode.md +377 -0
- package/src/engine/skill/skill/discovery.ts +116 -0
- package/src/engine/skill/skill/index.ts +336 -0
- package/src/engine/skill/skill/prompt/customize-opencode.md +377 -0
- package/src/engine/snapshot/index.ts +762 -0
- package/src/engine/snapshot/snapshot/index.ts +762 -0
- package/src/engine/sync/README.md +179 -0
- package/src/engine/sync/event.sql.ts +17 -0
- package/src/engine/sync/index.ts +410 -0
- package/src/engine/sync/schema.ts +11 -0
- package/src/engine/temporary.ts +33 -0
- package/src/engine/tool/apply_patch.ts +313 -0
- package/src/engine/tool/apply_patch.txt +33 -0
- package/src/engine/tool/edit.ts +711 -0
- package/src/engine/tool/edit.txt +10 -0
- package/src/engine/tool/external-directory.ts +49 -0
- package/src/engine/tool/glob.ts +103 -0
- package/src/engine/tool/glob.txt +6 -0
- package/src/engine/tool/grep.ts +156 -0
- package/src/engine/tool/grep.txt +8 -0
- package/src/engine/tool/invalid.ts +21 -0
- package/src/engine/tool/json-schema.ts +164 -0
- package/src/engine/tool/lsp.ts +113 -0
- package/src/engine/tool/lsp.txt +24 -0
- package/src/engine/tool/mcp-websearch.ts +96 -0
- package/src/engine/tool/plan-enter.txt +14 -0
- package/src/engine/tool/plan-exit.txt +13 -0
- package/src/engine/tool/plan.ts +78 -0
- package/src/engine/tool/question.ts +44 -0
- package/src/engine/tool/question.txt +10 -0
- package/src/engine/tool/read.ts +337 -0
- package/src/engine/tool/read.txt +14 -0
- package/src/engine/tool/registry.ts +472 -0
- package/src/engine/tool/repo_clone.ts +80 -0
- package/src/engine/tool/repo_clone.txt +5 -0
- package/src/engine/tool/repo_overview.ts +279 -0
- package/src/engine/tool/repo_overview.txt +4 -0
- package/src/engine/tool/schema.ts +14 -0
- package/src/engine/tool/shell/id.ts +19 -0
- package/src/engine/tool/shell/prompt.ts +295 -0
- package/src/engine/tool/shell/shell.txt +77 -0
- package/src/engine/tool/shell.ts +647 -0
- package/src/engine/tool/skill.ts +75 -0
- package/src/engine/tool/skill.txt +5 -0
- package/src/engine/tool/task.ts +337 -0
- package/src/engine/tool/task.txt +58 -0
- package/src/engine/tool/task_status.ts +179 -0
- package/src/engine/tool/task_status.txt +13 -0
- package/src/engine/tool/todo.ts +57 -0
- package/src/engine/tool/todowrite.txt +167 -0
- package/src/engine/tool/tool/apply_patch.ts +313 -0
- package/src/engine/tool/tool/apply_patch.txt +33 -0
- package/src/engine/tool/tool/edit.ts +711 -0
- package/src/engine/tool/tool/edit.txt +10 -0
- package/src/engine/tool/tool/external-directory.ts +49 -0
- package/src/engine/tool/tool/glob.ts +103 -0
- package/src/engine/tool/tool/glob.txt +6 -0
- package/src/engine/tool/tool/grep.ts +156 -0
- package/src/engine/tool/tool/grep.txt +8 -0
- package/src/engine/tool/tool/invalid.ts +21 -0
- package/src/engine/tool/tool/json-schema.ts +164 -0
- package/src/engine/tool/tool/lsp.ts +113 -0
- package/src/engine/tool/tool/lsp.txt +24 -0
- package/src/engine/tool/tool/mcp-websearch.ts +96 -0
- package/src/engine/tool/tool/plan-enter.txt +14 -0
- package/src/engine/tool/tool/plan-exit.txt +13 -0
- package/src/engine/tool/tool/plan.ts +78 -0
- package/src/engine/tool/tool/question.ts +44 -0
- package/src/engine/tool/tool/question.txt +10 -0
- package/src/engine/tool/tool/read.ts +337 -0
- package/src/engine/tool/tool/read.txt +14 -0
- package/src/engine/tool/tool/registry.ts +472 -0
- package/src/engine/tool/tool/repo_clone.ts +80 -0
- package/src/engine/tool/tool/repo_clone.txt +5 -0
- package/src/engine/tool/tool/repo_overview.ts +279 -0
- package/src/engine/tool/tool/repo_overview.txt +4 -0
- package/src/engine/tool/tool/schema.ts +14 -0
- package/src/engine/tool/tool/shell/id.ts +19 -0
- package/src/engine/tool/tool/shell/prompt.ts +295 -0
- package/src/engine/tool/tool/shell/shell.txt +77 -0
- package/src/engine/tool/tool/shell.ts +647 -0
- package/src/engine/tool/tool/skill.ts +75 -0
- package/src/engine/tool/tool/skill.txt +5 -0
- package/src/engine/tool/tool/task.ts +337 -0
- package/src/engine/tool/tool/task.txt +58 -0
- package/src/engine/tool/tool/task_status.ts +179 -0
- package/src/engine/tool/tool/task_status.txt +13 -0
- package/src/engine/tool/tool/todo.ts +57 -0
- package/src/engine/tool/tool/todowrite.txt +167 -0
- package/src/engine/tool/tool/tool.ts +164 -0
- package/src/engine/tool/tool/truncate.ts +160 -0
- package/src/engine/tool/tool/truncation-dir.ts +4 -0
- package/src/engine/tool/tool/webfetch.ts +192 -0
- package/src/engine/tool/tool/webfetch.txt +13 -0
- package/src/engine/tool/tool/websearch.ts +143 -0
- package/src/engine/tool/tool/websearch.txt +14 -0
- package/src/engine/tool/tool/write.ts +104 -0
- package/src/engine/tool/tool/write.txt +8 -0
- package/src/engine/tool/tool.ts +164 -0
- package/src/engine/tool/truncate.ts +160 -0
- package/src/engine/tool/truncation-dir.ts +4 -0
- package/src/engine/tool/webfetch.ts +192 -0
- package/src/engine/tool/webfetch.txt +13 -0
- package/src/engine/tool/websearch.ts +143 -0
- package/src/engine/tool/websearch.txt +14 -0
- package/src/engine/tool/write.ts +104 -0
- package/src/engine/tool/write.txt +8 -0
- package/src/engine/util/archive.ts +17 -0
- package/src/engine/util/bom.ts +31 -0
- package/src/engine/util/data-url.ts +9 -0
- package/src/engine/util/defer.ts +10 -0
- package/src/engine/util/effect-http-client.ts +11 -0
- package/src/engine/util/error.ts +88 -0
- package/src/engine/util/filesystem.ts +252 -0
- package/src/engine/util/format.ts +20 -0
- package/src/engine/util/iife.ts +3 -0
- package/src/engine/util/lazy.ts +20 -0
- package/src/engine/util/local-context.ts +25 -0
- package/src/engine/util/locale.ts +86 -0
- package/src/engine/util/media.ts +26 -0
- package/src/engine/util/process.ts +176 -0
- package/src/engine/util/queue.ts +32 -0
- package/src/engine/util/record.ts +3 -0
- package/src/engine/util/repository.ts +158 -0
- package/src/engine/util/rpc.ts +66 -0
- package/src/engine/util/signal.ts +12 -0
- package/src/engine/util/timeout.ts +13 -0
- package/src/engine/util/token.ts +7 -0
- package/src/engine/util/util/archive.ts +17 -0
- package/src/engine/util/util/bom.ts +31 -0
- package/src/engine/util/util/data-url.ts +9 -0
- package/src/engine/util/util/defer.ts +10 -0
- package/src/engine/util/util/effect-http-client.ts +11 -0
- package/src/engine/util/util/error.ts +88 -0
- package/src/engine/util/util/filesystem.ts +252 -0
- package/src/engine/util/util/format.ts +20 -0
- package/src/engine/util/util/iife.ts +3 -0
- package/src/engine/util/util/lazy.ts +20 -0
- package/src/engine/util/util/local-context.ts +25 -0
- package/src/engine/util/util/locale.ts +86 -0
- package/src/engine/util/util/media.ts +26 -0
- package/src/engine/util/util/process.ts +176 -0
- package/src/engine/util/util/queue.ts +32 -0
- package/src/engine/util/util/record.ts +3 -0
- package/src/engine/util/util/repository.ts +158 -0
- package/src/engine/util/util/rpc.ts +66 -0
- package/src/engine/util/util/signal.ts +12 -0
- package/src/engine/util/util/timeout.ts +13 -0
- package/src/engine/util/util/token.ts +7 -0
- package/src/engine/util/util/which.ts +14 -0
- package/src/engine/util/util/wildcard.ts +59 -0
- package/src/engine/util/which.ts +14 -0
- package/src/engine/util/wildcard.ts +59 -0
- package/src/engine/worktree/index.ts +621 -0
- package/src/rag_worker.ts +519 -0
- package/src/server.ts +201 -0
- package/src/tui.ts +637 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
// the approaches in this edit tool are sourced from
|
|
2
|
+
// https://github.com/cline/cline/blob/main/evals/diff-edits/diff-apply/diff-06-23-25.ts
|
|
3
|
+
// https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/utils/editCorrector.ts
|
|
4
|
+
// https://github.com/cline/cline/blob/main/evals/diff-edits/diff-apply/diff-06-26-25.ts
|
|
5
|
+
|
|
6
|
+
import * as path from "path"
|
|
7
|
+
import { Effect, Schema, Semaphore } from "effect"
|
|
8
|
+
import * as Tool from "./tool"
|
|
9
|
+
import { LSP } from "@/lsp/lsp"
|
|
10
|
+
import { createTwoFilesPatch, diffLines } from "diff"
|
|
11
|
+
import DESCRIPTION from "./edit.txt"
|
|
12
|
+
import { File } from "../file"
|
|
13
|
+
import { FileWatcher } from "../file/watcher"
|
|
14
|
+
import { Bus } from "../bus"
|
|
15
|
+
import { Format } from "../format"
|
|
16
|
+
import { InstanceState } from "@/effect/instance-state"
|
|
17
|
+
import { Snapshot } from "@/snapshot"
|
|
18
|
+
import { assertExternalDirectoryEffect } from "./external-directory"
|
|
19
|
+
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
|
20
|
+
import * as Bom from "@/util/bom"
|
|
21
|
+
|
|
22
|
+
function normalizeLineEndings(text: string): string {
|
|
23
|
+
return text.replaceAll("\r\n", "\n")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function detectLineEnding(text: string): "\n" | "\r\n" {
|
|
27
|
+
return text.includes("\r\n") ? "\r\n" : "\n"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function convertToLineEnding(text: string, ending: "\n" | "\r\n"): string {
|
|
31
|
+
if (ending === "\n") return text
|
|
32
|
+
return text.replaceAll("\n", "\r\n")
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const locks = new Map<string, Semaphore.Semaphore>()
|
|
36
|
+
|
|
37
|
+
function lock(filePath: string) {
|
|
38
|
+
const resolvedFilePath = AppFileSystem.resolve(filePath)
|
|
39
|
+
const hit = locks.get(resolvedFilePath)
|
|
40
|
+
if (hit) return hit
|
|
41
|
+
|
|
42
|
+
const next = Semaphore.makeUnsafe(1)
|
|
43
|
+
locks.set(resolvedFilePath, next)
|
|
44
|
+
return next
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export const Parameters = Schema.Struct({
|
|
48
|
+
filePath: Schema.String.annotate({ description: "The absolute path to the file to modify" }),
|
|
49
|
+
oldString: Schema.String.annotate({ description: "The text to replace" }),
|
|
50
|
+
newString: Schema.String.annotate({
|
|
51
|
+
description: "The text to replace it with (must be different from oldString)",
|
|
52
|
+
}),
|
|
53
|
+
replaceAll: Schema.optional(Schema.Boolean).annotate({
|
|
54
|
+
description: "Replace all occurrences of oldString (default false)",
|
|
55
|
+
}),
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
export const EditTool = Tool.define(
|
|
59
|
+
"edit",
|
|
60
|
+
Effect.gen(function* () {
|
|
61
|
+
const lsp = yield* LSP.Service
|
|
62
|
+
const afs = yield* AppFileSystem.Service
|
|
63
|
+
const format = yield* Format.Service
|
|
64
|
+
const bus = yield* Bus.Service
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
description: DESCRIPTION,
|
|
68
|
+
parameters: Parameters,
|
|
69
|
+
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context) =>
|
|
70
|
+
Effect.gen(function* () {
|
|
71
|
+
if (!params.filePath) {
|
|
72
|
+
throw new Error("filePath is required")
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (params.oldString === params.newString) {
|
|
76
|
+
throw new Error("No changes to apply: oldString and newString are identical.")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const instance = yield* InstanceState.context
|
|
80
|
+
const filePath = path.isAbsolute(params.filePath)
|
|
81
|
+
? params.filePath
|
|
82
|
+
: path.join(instance.directory, params.filePath)
|
|
83
|
+
yield* assertExternalDirectoryEffect(ctx, filePath)
|
|
84
|
+
|
|
85
|
+
let diff = ""
|
|
86
|
+
let contentOld = ""
|
|
87
|
+
let contentNew = ""
|
|
88
|
+
yield* lock(filePath).withPermits(1)(
|
|
89
|
+
Effect.gen(function* () {
|
|
90
|
+
if (params.oldString === "") {
|
|
91
|
+
const existed = yield* afs.existsSafe(filePath)
|
|
92
|
+
const source = existed ? yield* Bom.readFile(afs, filePath) : { bom: false, text: "" }
|
|
93
|
+
const next = Bom.split(params.newString)
|
|
94
|
+
const desiredBom = source.bom || next.bom
|
|
95
|
+
contentOld = source.text
|
|
96
|
+
contentNew = next.text
|
|
97
|
+
diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
|
|
98
|
+
yield* ctx.ask({
|
|
99
|
+
permission: "edit",
|
|
100
|
+
patterns: [path.relative(instance.worktree, filePath)],
|
|
101
|
+
always: ["*"],
|
|
102
|
+
metadata: {
|
|
103
|
+
filepath: filePath,
|
|
104
|
+
diff,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
yield* afs.writeWithDirs(filePath, Bom.join(contentNew, desiredBom))
|
|
108
|
+
if (yield* format.file(filePath)) {
|
|
109
|
+
contentNew = yield* Bom.syncFile(afs, filePath, desiredBom)
|
|
110
|
+
}
|
|
111
|
+
yield* bus.publish(File.Event.Edited, { file: filePath })
|
|
112
|
+
yield* bus.publish(FileWatcher.Event.Updated, {
|
|
113
|
+
file: filePath,
|
|
114
|
+
event: existed ? "change" : "add",
|
|
115
|
+
})
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const info = yield* afs.stat(filePath).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
|
120
|
+
if (!info) throw new Error(`File ${filePath} not found`)
|
|
121
|
+
if (info.type === "Directory") throw new Error(`Path is a directory, not a file: ${filePath}`)
|
|
122
|
+
const source = yield* Bom.readFile(afs, filePath)
|
|
123
|
+
contentOld = source.text
|
|
124
|
+
|
|
125
|
+
const ending = detectLineEnding(contentOld)
|
|
126
|
+
const old = convertToLineEnding(normalizeLineEndings(params.oldString), ending)
|
|
127
|
+
const replacement = convertToLineEnding(normalizeLineEndings(params.newString), ending)
|
|
128
|
+
|
|
129
|
+
const next = Bom.split(replace(contentOld, old, replacement, params.replaceAll))
|
|
130
|
+
const desiredBom = source.bom || next.bom
|
|
131
|
+
contentNew = next.text
|
|
132
|
+
|
|
133
|
+
diff = trimDiff(
|
|
134
|
+
createTwoFilesPatch(
|
|
135
|
+
filePath,
|
|
136
|
+
filePath,
|
|
137
|
+
normalizeLineEndings(contentOld),
|
|
138
|
+
normalizeLineEndings(contentNew),
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
yield* ctx.ask({
|
|
142
|
+
permission: "edit",
|
|
143
|
+
patterns: [path.relative(instance.worktree, filePath)],
|
|
144
|
+
always: ["*"],
|
|
145
|
+
metadata: {
|
|
146
|
+
filepath: filePath,
|
|
147
|
+
diff,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
yield* afs.writeWithDirs(filePath, Bom.join(contentNew, desiredBom))
|
|
152
|
+
if (yield* format.file(filePath)) {
|
|
153
|
+
contentNew = yield* Bom.syncFile(afs, filePath, desiredBom)
|
|
154
|
+
}
|
|
155
|
+
yield* bus.publish(File.Event.Edited, { file: filePath })
|
|
156
|
+
yield* bus.publish(FileWatcher.Event.Updated, {
|
|
157
|
+
file: filePath,
|
|
158
|
+
event: "change",
|
|
159
|
+
})
|
|
160
|
+
diff = trimDiff(
|
|
161
|
+
createTwoFilesPatch(
|
|
162
|
+
filePath,
|
|
163
|
+
filePath,
|
|
164
|
+
normalizeLineEndings(contentOld),
|
|
165
|
+
normalizeLineEndings(contentNew),
|
|
166
|
+
),
|
|
167
|
+
)
|
|
168
|
+
}).pipe(Effect.orDie),
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
let additions = 0
|
|
172
|
+
let deletions = 0
|
|
173
|
+
for (const change of diffLines(contentOld, contentNew)) {
|
|
174
|
+
if (change.added) additions += change.count || 0
|
|
175
|
+
if (change.removed) deletions += change.count || 0
|
|
176
|
+
}
|
|
177
|
+
const filediff: Snapshot.FileDiff = {
|
|
178
|
+
file: filePath,
|
|
179
|
+
patch: diff,
|
|
180
|
+
additions,
|
|
181
|
+
deletions,
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
yield* ctx.metadata({
|
|
185
|
+
metadata: {
|
|
186
|
+
diff,
|
|
187
|
+
filediff,
|
|
188
|
+
diagnostics: {},
|
|
189
|
+
},
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
let output = "Edit applied successfully."
|
|
193
|
+
yield* lsp.touchFile(filePath, "document")
|
|
194
|
+
const diagnostics = yield* lsp.diagnostics()
|
|
195
|
+
const normalizedFilePath = AppFileSystem.normalizePath(filePath)
|
|
196
|
+
const block = LSP.Diagnostic.report(filePath, diagnostics[normalizedFilePath] ?? [])
|
|
197
|
+
if (block) output += `\n\nLSP errors detected in this file, please fix:\n${block}`
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
metadata: {
|
|
201
|
+
diagnostics,
|
|
202
|
+
diff,
|
|
203
|
+
filediff,
|
|
204
|
+
},
|
|
205
|
+
title: `${path.relative(instance.worktree, filePath)}`,
|
|
206
|
+
output,
|
|
207
|
+
}
|
|
208
|
+
}),
|
|
209
|
+
}
|
|
210
|
+
}),
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
export type Replacer = (content: string, find: string) => Generator<string, void, unknown>
|
|
214
|
+
|
|
215
|
+
// Similarity thresholds for block anchor fallback matching
|
|
216
|
+
const SINGLE_CANDIDATE_SIMILARITY_THRESHOLD = 0.0
|
|
217
|
+
const MULTIPLE_CANDIDATES_SIMILARITY_THRESHOLD = 0.3
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Levenshtein distance algorithm implementation
|
|
221
|
+
*/
|
|
222
|
+
function levenshtein(a: string, b: string): number {
|
|
223
|
+
// Handle empty strings
|
|
224
|
+
if (a === "" || b === "") {
|
|
225
|
+
return Math.max(a.length, b.length)
|
|
226
|
+
}
|
|
227
|
+
const matrix = Array.from({ length: a.length + 1 }, (_, i) =>
|
|
228
|
+
Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
for (let i = 1; i <= a.length; i++) {
|
|
232
|
+
for (let j = 1; j <= b.length; j++) {
|
|
233
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1
|
|
234
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return matrix[a.length][b.length]
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export const SimpleReplacer: Replacer = function* (_content, find) {
|
|
241
|
+
yield find
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export const LineTrimmedReplacer: Replacer = function* (content, find) {
|
|
245
|
+
const originalLines = content.split("\n")
|
|
246
|
+
const searchLines = find.split("\n")
|
|
247
|
+
|
|
248
|
+
if (searchLines[searchLines.length - 1] === "") {
|
|
249
|
+
searchLines.pop()
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
for (let i = 0; i <= originalLines.length - searchLines.length; i++) {
|
|
253
|
+
let matches = true
|
|
254
|
+
|
|
255
|
+
for (let j = 0; j < searchLines.length; j++) {
|
|
256
|
+
const originalTrimmed = originalLines[i + j].trim()
|
|
257
|
+
const searchTrimmed = searchLines[j].trim()
|
|
258
|
+
|
|
259
|
+
if (originalTrimmed !== searchTrimmed) {
|
|
260
|
+
matches = false
|
|
261
|
+
break
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (matches) {
|
|
266
|
+
let matchStartIndex = 0
|
|
267
|
+
for (let k = 0; k < i; k++) {
|
|
268
|
+
matchStartIndex += originalLines[k].length + 1
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let matchEndIndex = matchStartIndex
|
|
272
|
+
for (let k = 0; k < searchLines.length; k++) {
|
|
273
|
+
matchEndIndex += originalLines[i + k].length
|
|
274
|
+
if (k < searchLines.length - 1) {
|
|
275
|
+
matchEndIndex += 1 // Add newline character except for the last line
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
yield content.substring(matchStartIndex, matchEndIndex)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export const BlockAnchorReplacer: Replacer = function* (content, find) {
|
|
285
|
+
const originalLines = content.split("\n")
|
|
286
|
+
const searchLines = find.split("\n")
|
|
287
|
+
|
|
288
|
+
if (searchLines.length < 3) {
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (searchLines[searchLines.length - 1] === "") {
|
|
293
|
+
searchLines.pop()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const firstLineSearch = searchLines[0].trim()
|
|
297
|
+
const lastLineSearch = searchLines[searchLines.length - 1].trim()
|
|
298
|
+
const searchBlockSize = searchLines.length
|
|
299
|
+
|
|
300
|
+
// Collect all candidate positions where both anchors match
|
|
301
|
+
const candidates: Array<{ startLine: number; endLine: number }> = []
|
|
302
|
+
for (let i = 0; i < originalLines.length; i++) {
|
|
303
|
+
if (originalLines[i].trim() !== firstLineSearch) {
|
|
304
|
+
continue
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Look for the matching last line after this first line
|
|
308
|
+
for (let j = i + 2; j < originalLines.length; j++) {
|
|
309
|
+
if (originalLines[j].trim() === lastLineSearch) {
|
|
310
|
+
candidates.push({ startLine: i, endLine: j })
|
|
311
|
+
break // Only match the first occurrence of the last line
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Return immediately if no candidates
|
|
317
|
+
if (candidates.length === 0) {
|
|
318
|
+
return
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Handle single candidate scenario (using relaxed threshold)
|
|
322
|
+
if (candidates.length === 1) {
|
|
323
|
+
const { startLine, endLine } = candidates[0]
|
|
324
|
+
const actualBlockSize = endLine - startLine + 1
|
|
325
|
+
|
|
326
|
+
let similarity = 0
|
|
327
|
+
let linesToCheck = Math.min(searchBlockSize - 2, actualBlockSize - 2) // Middle lines only
|
|
328
|
+
|
|
329
|
+
if (linesToCheck > 0) {
|
|
330
|
+
for (let j = 1; j < searchBlockSize - 1 && j < actualBlockSize - 1; j++) {
|
|
331
|
+
const originalLine = originalLines[startLine + j].trim()
|
|
332
|
+
const searchLine = searchLines[j].trim()
|
|
333
|
+
const maxLen = Math.max(originalLine.length, searchLine.length)
|
|
334
|
+
if (maxLen === 0) {
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
337
|
+
const distance = levenshtein(originalLine, searchLine)
|
|
338
|
+
similarity += (1 - distance / maxLen) / linesToCheck
|
|
339
|
+
|
|
340
|
+
// Exit early when threshold is reached
|
|
341
|
+
if (similarity >= SINGLE_CANDIDATE_SIMILARITY_THRESHOLD) {
|
|
342
|
+
break
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
// No middle lines to compare, just accept based on anchors
|
|
347
|
+
similarity = 1.0
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (similarity >= SINGLE_CANDIDATE_SIMILARITY_THRESHOLD) {
|
|
351
|
+
let matchStartIndex = 0
|
|
352
|
+
for (let k = 0; k < startLine; k++) {
|
|
353
|
+
matchStartIndex += originalLines[k].length + 1
|
|
354
|
+
}
|
|
355
|
+
let matchEndIndex = matchStartIndex
|
|
356
|
+
for (let k = startLine; k <= endLine; k++) {
|
|
357
|
+
matchEndIndex += originalLines[k].length
|
|
358
|
+
if (k < endLine) {
|
|
359
|
+
matchEndIndex += 1 // Add newline character except for the last line
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
yield content.substring(matchStartIndex, matchEndIndex)
|
|
363
|
+
}
|
|
364
|
+
return
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Calculate similarity for multiple candidates
|
|
368
|
+
let bestMatch: { startLine: number; endLine: number } | null = null
|
|
369
|
+
let maxSimilarity = -1
|
|
370
|
+
|
|
371
|
+
for (const candidate of candidates) {
|
|
372
|
+
const { startLine, endLine } = candidate
|
|
373
|
+
const actualBlockSize = endLine - startLine + 1
|
|
374
|
+
|
|
375
|
+
let similarity = 0
|
|
376
|
+
let linesToCheck = Math.min(searchBlockSize - 2, actualBlockSize - 2) // Middle lines only
|
|
377
|
+
|
|
378
|
+
if (linesToCheck > 0) {
|
|
379
|
+
for (let j = 1; j < searchBlockSize - 1 && j < actualBlockSize - 1; j++) {
|
|
380
|
+
const originalLine = originalLines[startLine + j].trim()
|
|
381
|
+
const searchLine = searchLines[j].trim()
|
|
382
|
+
const maxLen = Math.max(originalLine.length, searchLine.length)
|
|
383
|
+
if (maxLen === 0) {
|
|
384
|
+
continue
|
|
385
|
+
}
|
|
386
|
+
const distance = levenshtein(originalLine, searchLine)
|
|
387
|
+
similarity += 1 - distance / maxLen
|
|
388
|
+
}
|
|
389
|
+
similarity /= linesToCheck // Average similarity
|
|
390
|
+
} else {
|
|
391
|
+
// No middle lines to compare, just accept based on anchors
|
|
392
|
+
similarity = 1.0
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (similarity > maxSimilarity) {
|
|
396
|
+
maxSimilarity = similarity
|
|
397
|
+
bestMatch = candidate
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Threshold judgment
|
|
402
|
+
if (maxSimilarity >= MULTIPLE_CANDIDATES_SIMILARITY_THRESHOLD && bestMatch) {
|
|
403
|
+
const { startLine, endLine } = bestMatch
|
|
404
|
+
let matchStartIndex = 0
|
|
405
|
+
for (let k = 0; k < startLine; k++) {
|
|
406
|
+
matchStartIndex += originalLines[k].length + 1
|
|
407
|
+
}
|
|
408
|
+
let matchEndIndex = matchStartIndex
|
|
409
|
+
for (let k = startLine; k <= endLine; k++) {
|
|
410
|
+
matchEndIndex += originalLines[k].length
|
|
411
|
+
if (k < endLine) {
|
|
412
|
+
matchEndIndex += 1
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
yield content.substring(matchStartIndex, matchEndIndex)
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export const WhitespaceNormalizedReplacer: Replacer = function* (content, find) {
|
|
420
|
+
const normalizeWhitespace = (text: string) => text.replace(/\s+/g, " ").trim()
|
|
421
|
+
const normalizedFind = normalizeWhitespace(find)
|
|
422
|
+
|
|
423
|
+
// Handle single line matches
|
|
424
|
+
const lines = content.split("\n")
|
|
425
|
+
for (let i = 0; i < lines.length; i++) {
|
|
426
|
+
const line = lines[i]
|
|
427
|
+
if (normalizeWhitespace(line) === normalizedFind) {
|
|
428
|
+
yield line
|
|
429
|
+
} else {
|
|
430
|
+
// Only check for substring matches if the full line doesn't match
|
|
431
|
+
const normalizedLine = normalizeWhitespace(line)
|
|
432
|
+
if (normalizedLine.includes(normalizedFind)) {
|
|
433
|
+
// Find the actual substring in the original line that matches
|
|
434
|
+
const words = find.trim().split(/\s+/)
|
|
435
|
+
if (words.length > 0) {
|
|
436
|
+
const pattern = words.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("\\s+")
|
|
437
|
+
try {
|
|
438
|
+
const regex = new RegExp(pattern)
|
|
439
|
+
const match = line.match(regex)
|
|
440
|
+
if (match) {
|
|
441
|
+
yield match[0]
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
// Invalid regex pattern, skip
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Handle multi-line matches
|
|
452
|
+
const findLines = find.split("\n")
|
|
453
|
+
if (findLines.length > 1) {
|
|
454
|
+
for (let i = 0; i <= lines.length - findLines.length; i++) {
|
|
455
|
+
const block = lines.slice(i, i + findLines.length)
|
|
456
|
+
if (normalizeWhitespace(block.join("\n")) === normalizedFind) {
|
|
457
|
+
yield block.join("\n")
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export const IndentationFlexibleReplacer: Replacer = function* (content, find) {
|
|
464
|
+
const removeIndentation = (text: string) => {
|
|
465
|
+
const lines = text.split("\n")
|
|
466
|
+
const nonEmptyLines = lines.filter((line) => line.trim().length > 0)
|
|
467
|
+
if (nonEmptyLines.length === 0) return text
|
|
468
|
+
|
|
469
|
+
const minIndent = Math.min(
|
|
470
|
+
...nonEmptyLines.map((line) => {
|
|
471
|
+
const match = line.match(/^(\s*)/)
|
|
472
|
+
return match ? match[1].length : 0
|
|
473
|
+
}),
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
return lines.map((line) => (line.trim().length === 0 ? line : line.slice(minIndent))).join("\n")
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const normalizedFind = removeIndentation(find)
|
|
480
|
+
const contentLines = content.split("\n")
|
|
481
|
+
const findLines = find.split("\n")
|
|
482
|
+
|
|
483
|
+
for (let i = 0; i <= contentLines.length - findLines.length; i++) {
|
|
484
|
+
const block = contentLines.slice(i, i + findLines.length).join("\n")
|
|
485
|
+
if (removeIndentation(block) === normalizedFind) {
|
|
486
|
+
yield block
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export const EscapeNormalizedReplacer: Replacer = function* (content, find) {
|
|
492
|
+
const unescapeString = (str: string): string => {
|
|
493
|
+
return str.replace(/\\(n|t|r|'|"|`|\\|\n|\$)/g, (match, capturedChar) => {
|
|
494
|
+
switch (capturedChar) {
|
|
495
|
+
case "n":
|
|
496
|
+
return "\n"
|
|
497
|
+
case "t":
|
|
498
|
+
return "\t"
|
|
499
|
+
case "r":
|
|
500
|
+
return "\r"
|
|
501
|
+
case "'":
|
|
502
|
+
return "'"
|
|
503
|
+
case '"':
|
|
504
|
+
return '"'
|
|
505
|
+
case "`":
|
|
506
|
+
return "`"
|
|
507
|
+
case "\\":
|
|
508
|
+
return "\\"
|
|
509
|
+
case "\n":
|
|
510
|
+
return "\n"
|
|
511
|
+
case "$":
|
|
512
|
+
return "$"
|
|
513
|
+
default:
|
|
514
|
+
return match
|
|
515
|
+
}
|
|
516
|
+
})
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const unescapedFind = unescapeString(find)
|
|
520
|
+
|
|
521
|
+
// Try direct match with unescaped find string
|
|
522
|
+
if (content.includes(unescapedFind)) {
|
|
523
|
+
yield unescapedFind
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Also try finding escaped versions in content that match unescaped find
|
|
527
|
+
const lines = content.split("\n")
|
|
528
|
+
const findLines = unescapedFind.split("\n")
|
|
529
|
+
|
|
530
|
+
for (let i = 0; i <= lines.length - findLines.length; i++) {
|
|
531
|
+
const block = lines.slice(i, i + findLines.length).join("\n")
|
|
532
|
+
const unescapedBlock = unescapeString(block)
|
|
533
|
+
|
|
534
|
+
if (unescapedBlock === unescapedFind) {
|
|
535
|
+
yield block
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
export const MultiOccurrenceReplacer: Replacer = function* (content, find) {
|
|
541
|
+
// This replacer yields all exact matches, allowing the replace function
|
|
542
|
+
// to handle multiple occurrences based on replaceAll parameter
|
|
543
|
+
let startIndex = 0
|
|
544
|
+
|
|
545
|
+
while (true) {
|
|
546
|
+
const index = content.indexOf(find, startIndex)
|
|
547
|
+
if (index === -1) break
|
|
548
|
+
|
|
549
|
+
yield find
|
|
550
|
+
startIndex = index + find.length
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
export const TrimmedBoundaryReplacer: Replacer = function* (content, find) {
|
|
555
|
+
const trimmedFind = find.trim()
|
|
556
|
+
|
|
557
|
+
if (trimmedFind === find) {
|
|
558
|
+
// Already trimmed, no point in trying
|
|
559
|
+
return
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Try to find the trimmed version
|
|
563
|
+
if (content.includes(trimmedFind)) {
|
|
564
|
+
yield trimmedFind
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Also try finding blocks where trimmed content matches
|
|
568
|
+
const lines = content.split("\n")
|
|
569
|
+
const findLines = find.split("\n")
|
|
570
|
+
|
|
571
|
+
for (let i = 0; i <= lines.length - findLines.length; i++) {
|
|
572
|
+
const block = lines.slice(i, i + findLines.length).join("\n")
|
|
573
|
+
|
|
574
|
+
if (block.trim() === trimmedFind) {
|
|
575
|
+
yield block
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
export const ContextAwareReplacer: Replacer = function* (content, find) {
|
|
581
|
+
const findLines = find.split("\n")
|
|
582
|
+
if (findLines.length < 3) {
|
|
583
|
+
// Need at least 3 lines to have meaningful context
|
|
584
|
+
return
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Remove trailing empty line if present
|
|
588
|
+
if (findLines[findLines.length - 1] === "") {
|
|
589
|
+
findLines.pop()
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const contentLines = content.split("\n")
|
|
593
|
+
|
|
594
|
+
// Extract first and last lines as context anchors
|
|
595
|
+
const firstLine = findLines[0].trim()
|
|
596
|
+
const lastLine = findLines[findLines.length - 1].trim()
|
|
597
|
+
|
|
598
|
+
// Find blocks that start and end with the context anchors
|
|
599
|
+
for (let i = 0; i < contentLines.length; i++) {
|
|
600
|
+
if (contentLines[i].trim() !== firstLine) continue
|
|
601
|
+
|
|
602
|
+
// Look for the matching last line
|
|
603
|
+
for (let j = i + 2; j < contentLines.length; j++) {
|
|
604
|
+
if (contentLines[j].trim() === lastLine) {
|
|
605
|
+
// Found a potential context block
|
|
606
|
+
const blockLines = contentLines.slice(i, j + 1)
|
|
607
|
+
const block = blockLines.join("\n")
|
|
608
|
+
|
|
609
|
+
// Check if the middle content has reasonable similarity
|
|
610
|
+
// (simple heuristic: at least 50% of non-empty lines should match when trimmed)
|
|
611
|
+
if (blockLines.length === findLines.length) {
|
|
612
|
+
let matchingLines = 0
|
|
613
|
+
let totalNonEmptyLines = 0
|
|
614
|
+
|
|
615
|
+
for (let k = 1; k < blockLines.length - 1; k++) {
|
|
616
|
+
const blockLine = blockLines[k].trim()
|
|
617
|
+
const findLine = findLines[k].trim()
|
|
618
|
+
|
|
619
|
+
if (blockLine.length > 0 || findLine.length > 0) {
|
|
620
|
+
totalNonEmptyLines++
|
|
621
|
+
if (blockLine === findLine) {
|
|
622
|
+
matchingLines++
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (totalNonEmptyLines === 0 || matchingLines / totalNonEmptyLines >= 0.5) {
|
|
628
|
+
yield block
|
|
629
|
+
break // Only match the first occurrence
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
break
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
export function trimDiff(diff: string): string {
|
|
639
|
+
const lines = diff.split("\n")
|
|
640
|
+
const contentLines = lines.filter(
|
|
641
|
+
(line) =>
|
|
642
|
+
(line.startsWith("+") || line.startsWith("-") || line.startsWith(" ")) &&
|
|
643
|
+
!line.startsWith("---") &&
|
|
644
|
+
!line.startsWith("+++"),
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
if (contentLines.length === 0) return diff
|
|
648
|
+
|
|
649
|
+
let min = Infinity
|
|
650
|
+
for (const line of contentLines) {
|
|
651
|
+
const content = line.slice(1)
|
|
652
|
+
if (content.trim().length > 0) {
|
|
653
|
+
const match = content.match(/^(\s*)/)
|
|
654
|
+
if (match) min = Math.min(min, match[1].length)
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (min === Infinity || min === 0) return diff
|
|
658
|
+
const trimmedLines = lines.map((line) => {
|
|
659
|
+
if (
|
|
660
|
+
(line.startsWith("+") || line.startsWith("-") || line.startsWith(" ")) &&
|
|
661
|
+
!line.startsWith("---") &&
|
|
662
|
+
!line.startsWith("+++")
|
|
663
|
+
) {
|
|
664
|
+
const prefix = line[0]
|
|
665
|
+
const content = line.slice(1)
|
|
666
|
+
return prefix + content.slice(min)
|
|
667
|
+
}
|
|
668
|
+
return line
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
return trimmedLines.join("\n")
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
export function replace(content: string, oldString: string, newString: string, replaceAll = false): string {
|
|
675
|
+
if (oldString === newString) {
|
|
676
|
+
throw new Error("No changes to apply: oldString and newString are identical.")
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
let notFound = true
|
|
680
|
+
|
|
681
|
+
for (const replacer of [
|
|
682
|
+
SimpleReplacer,
|
|
683
|
+
LineTrimmedReplacer,
|
|
684
|
+
BlockAnchorReplacer,
|
|
685
|
+
WhitespaceNormalizedReplacer,
|
|
686
|
+
IndentationFlexibleReplacer,
|
|
687
|
+
EscapeNormalizedReplacer,
|
|
688
|
+
TrimmedBoundaryReplacer,
|
|
689
|
+
ContextAwareReplacer,
|
|
690
|
+
MultiOccurrenceReplacer,
|
|
691
|
+
]) {
|
|
692
|
+
for (const search of replacer(content, oldString)) {
|
|
693
|
+
const index = content.indexOf(search)
|
|
694
|
+
if (index === -1) continue
|
|
695
|
+
notFound = false
|
|
696
|
+
if (replaceAll) {
|
|
697
|
+
return content.replaceAll(search, newString)
|
|
698
|
+
}
|
|
699
|
+
const lastIndex = content.lastIndexOf(search)
|
|
700
|
+
if (index !== lastIndex) continue
|
|
701
|
+
return content.substring(0, index) + newString + content.substring(index + search.length)
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (notFound) {
|
|
706
|
+
throw new Error(
|
|
707
|
+
"Could not find oldString in the file. It must match exactly, including whitespace, indentation, and line endings.",
|
|
708
|
+
)
|
|
709
|
+
}
|
|
710
|
+
throw new Error("Found multiple matches for oldString. Provide more surrounding context to make the match unique.")
|
|
711
|
+
}
|