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,96 @@
|
|
|
1
|
+
import { Duration, Effect, Schema } from "effect"
|
|
2
|
+
import { HttpClient, HttpClientRequest } from "effect/unstable/http"
|
|
3
|
+
|
|
4
|
+
export const EXA_URL = process.env.EXA_API_KEY
|
|
5
|
+
? `https://mcp.exa.ai/mcp?exaApiKey=${encodeURIComponent(process.env.EXA_API_KEY)}`
|
|
6
|
+
: "https://mcp.exa.ai/mcp"
|
|
7
|
+
export const PARALLEL_URL = "https://search.parallel.ai/mcp"
|
|
8
|
+
|
|
9
|
+
const McpResult = Schema.Struct({
|
|
10
|
+
result: Schema.Struct({
|
|
11
|
+
content: Schema.Array(
|
|
12
|
+
Schema.Struct({
|
|
13
|
+
type: Schema.String,
|
|
14
|
+
text: Schema.String,
|
|
15
|
+
}),
|
|
16
|
+
),
|
|
17
|
+
}),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const decode = Schema.decodeUnknownEffect(Schema.fromJsonString(McpResult))
|
|
21
|
+
|
|
22
|
+
const parsePayload = (payload: string) =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const trimmed = payload.trim()
|
|
25
|
+
if (!trimmed.startsWith("{")) return undefined
|
|
26
|
+
const data = yield* decode(trimmed)
|
|
27
|
+
return data.result.content.find((item) => item.text)?.text
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
export const parseResponse = Effect.fn("McpWebSearch.parseResponse")(function* (body: string) {
|
|
31
|
+
const trimmed = body.trim()
|
|
32
|
+
const direct = trimmed ? yield* parsePayload(trimmed) : undefined
|
|
33
|
+
if (direct) return direct
|
|
34
|
+
|
|
35
|
+
for (const line of body.split("\n")) {
|
|
36
|
+
if (!line.startsWith("data: ")) continue
|
|
37
|
+
const data = yield* parsePayload(line.substring(6))
|
|
38
|
+
if (data) return data
|
|
39
|
+
}
|
|
40
|
+
return undefined
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
export const SearchArgs = Schema.Struct({
|
|
44
|
+
query: Schema.String,
|
|
45
|
+
type: Schema.String,
|
|
46
|
+
numResults: Schema.Number,
|
|
47
|
+
livecrawl: Schema.String,
|
|
48
|
+
contextMaxCharacters: Schema.optional(Schema.Number),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
export const ParallelSearchArgs = Schema.Struct({
|
|
52
|
+
objective: Schema.String,
|
|
53
|
+
search_queries: Schema.Array(Schema.String),
|
|
54
|
+
session_id: Schema.optional(Schema.String),
|
|
55
|
+
model_name: Schema.optional(Schema.String),
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
const McpRequest = <F extends Schema.Struct.Fields>(args: Schema.Struct<F>) =>
|
|
59
|
+
Schema.Struct({
|
|
60
|
+
jsonrpc: Schema.Literal("2.0"),
|
|
61
|
+
id: Schema.Literal(1),
|
|
62
|
+
method: Schema.Literal("tools/call"),
|
|
63
|
+
params: Schema.Struct({
|
|
64
|
+
name: Schema.String,
|
|
65
|
+
arguments: args,
|
|
66
|
+
}),
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
export const call = <F extends Schema.Struct.Fields>(
|
|
70
|
+
http: HttpClient.HttpClient,
|
|
71
|
+
url: string,
|
|
72
|
+
tool: string,
|
|
73
|
+
args: Schema.Struct<F>,
|
|
74
|
+
value: Schema.Struct.Type<F>,
|
|
75
|
+
timeout: Duration.Input,
|
|
76
|
+
headers?: Record<string, string>,
|
|
77
|
+
) =>
|
|
78
|
+
Effect.gen(function* () {
|
|
79
|
+
const request = yield* HttpClientRequest.post(url).pipe(
|
|
80
|
+
HttpClientRequest.accept("application/json, text/event-stream"),
|
|
81
|
+
HttpClientRequest.setHeaders(headers ?? {}),
|
|
82
|
+
HttpClientRequest.schemaBodyJson(McpRequest(args))({
|
|
83
|
+
jsonrpc: "2.0" as const,
|
|
84
|
+
id: 1 as const,
|
|
85
|
+
method: "tools/call" as const,
|
|
86
|
+
params: { name: tool, arguments: value },
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
const response = yield* HttpClient.filterStatusOk(http)
|
|
90
|
+
.execute(request)
|
|
91
|
+
.pipe(
|
|
92
|
+
Effect.timeoutOrElse({ duration: timeout, orElse: () => Effect.die(new Error(`${tool} request timed out`)) }),
|
|
93
|
+
)
|
|
94
|
+
const body = yield* response.text
|
|
95
|
+
return yield* parseResponse(body)
|
|
96
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Use this tool to suggest switching to plan agent when the user's request would benefit from planning before implementation.
|
|
2
|
+
|
|
3
|
+
If they explicitly mention wanting to create a plan ALWAYS call this tool first.
|
|
4
|
+
|
|
5
|
+
This tool will ask the user if they want to switch to plan agent.
|
|
6
|
+
|
|
7
|
+
Call this tool when:
|
|
8
|
+
- The user's request is complex and would benefit from planning first
|
|
9
|
+
- You want to research and design before making changes
|
|
10
|
+
- The task involves multiple files or significant architectural decisions
|
|
11
|
+
|
|
12
|
+
Do NOT call this tool:
|
|
13
|
+
- For simple, straightforward tasks
|
|
14
|
+
- When the user explicitly wants immediate implementation
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Use this tool when you have completed the planning phase and are ready to exit plan agent.
|
|
2
|
+
|
|
3
|
+
This tool will ask the user if they want to switch to build agent to start implementing the plan.
|
|
4
|
+
|
|
5
|
+
Call this tool:
|
|
6
|
+
- After you have written a complete plan to the plan file
|
|
7
|
+
- After you have clarified any questions with the user
|
|
8
|
+
- When you are confident the plan is ready for implementation
|
|
9
|
+
|
|
10
|
+
Do NOT call this tool:
|
|
11
|
+
- Before you have created or finalized the plan
|
|
12
|
+
- If you still have unanswered questions about the implementation
|
|
13
|
+
- If the user has indicated they want to continue planning
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import path from "path"
|
|
2
|
+
import { Effect, Schema } from "effect"
|
|
3
|
+
import * as Tool from "./tool"
|
|
4
|
+
import { Question } from "../question"
|
|
5
|
+
import { Session } from "@/session/session"
|
|
6
|
+
import { MessageV2 } from "../session/message-v2"
|
|
7
|
+
import { Provider } from "@/provider/provider"
|
|
8
|
+
import { InstanceState } from "@/effect/instance-state"
|
|
9
|
+
import { MessageID, PartID } from "../session/schema"
|
|
10
|
+
import EXIT_DESCRIPTION from "./plan-exit.txt"
|
|
11
|
+
|
|
12
|
+
export const Parameters = Schema.Struct({})
|
|
13
|
+
|
|
14
|
+
export const PlanExitTool = Tool.define(
|
|
15
|
+
"plan_exit",
|
|
16
|
+
Effect.gen(function* () {
|
|
17
|
+
const session = yield* Session.Service
|
|
18
|
+
const question = yield* Question.Service
|
|
19
|
+
const provider = yield* Provider.Service
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
description: EXIT_DESCRIPTION,
|
|
23
|
+
parameters: Parameters,
|
|
24
|
+
execute: (_params: {}, ctx: Tool.Context) =>
|
|
25
|
+
Effect.gen(function* () {
|
|
26
|
+
const instance = yield* InstanceState.context
|
|
27
|
+
const info = yield* session.get(ctx.sessionID)
|
|
28
|
+
const plan = path.relative(instance.worktree, Session.plan(info, instance))
|
|
29
|
+
const answers = yield* question.ask({
|
|
30
|
+
sessionID: ctx.sessionID,
|
|
31
|
+
questions: [
|
|
32
|
+
{
|
|
33
|
+
question: `Plan at ${plan} is complete. Would you like to switch to the build agent and start implementing?`,
|
|
34
|
+
header: "Build Agent",
|
|
35
|
+
custom: false,
|
|
36
|
+
options: [
|
|
37
|
+
{ label: "Yes", description: "Switch to build agent and start implementing the plan" },
|
|
38
|
+
{ label: "No", description: "Stay with plan agent to continue refining the plan" },
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
tool: ctx.callID ? { messageID: ctx.messageID, callID: ctx.callID } : undefined,
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
if (answers[0]?.[0] === "No") yield* new Question.RejectedError()
|
|
46
|
+
|
|
47
|
+
const messages = yield* session.messages({ sessionID: ctx.sessionID }).pipe(Effect.orDie)
|
|
48
|
+
const lastUser = messages.findLast((item) => item.info.role === "user" && item.info.model)
|
|
49
|
+
const model =
|
|
50
|
+
lastUser?.info.role === "user" && lastUser.info.model ? lastUser.info.model : yield* provider.defaultModel()
|
|
51
|
+
|
|
52
|
+
const msg: MessageV2.User = {
|
|
53
|
+
id: MessageID.ascending(),
|
|
54
|
+
sessionID: ctx.sessionID,
|
|
55
|
+
role: "user",
|
|
56
|
+
time: { created: Date.now() },
|
|
57
|
+
agent: "build",
|
|
58
|
+
model,
|
|
59
|
+
}
|
|
60
|
+
yield* session.updateMessage(msg)
|
|
61
|
+
yield* session.updatePart({
|
|
62
|
+
id: PartID.ascending(),
|
|
63
|
+
messageID: msg.id,
|
|
64
|
+
sessionID: ctx.sessionID,
|
|
65
|
+
type: "text",
|
|
66
|
+
text: `The plan at ${plan} has been approved, you can now edit files. Execute the plan`,
|
|
67
|
+
synthetic: true,
|
|
68
|
+
} satisfies MessageV2.TextPart)
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
title: "Switching to build agent",
|
|
72
|
+
output: "User approved switching to build agent. Wait for further instructions.",
|
|
73
|
+
metadata: {},
|
|
74
|
+
}
|
|
75
|
+
}).pipe(Effect.orDie),
|
|
76
|
+
}
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Effect, Schema } from "effect"
|
|
2
|
+
import * as Tool from "./tool"
|
|
3
|
+
import { Question } from "../question"
|
|
4
|
+
import DESCRIPTION from "./question.txt"
|
|
5
|
+
|
|
6
|
+
export const Parameters = Schema.Struct({
|
|
7
|
+
questions: Schema.mutable(Schema.Array(Question.Prompt)).annotate({ description: "Questions to ask" }),
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
type Metadata = {
|
|
11
|
+
answers: ReadonlyArray<Question.Answer>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const QuestionTool = Tool.define<typeof Parameters, Metadata, Question.Service>(
|
|
15
|
+
"question",
|
|
16
|
+
Effect.gen(function* () {
|
|
17
|
+
const question = yield* Question.Service
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
description: DESCRIPTION,
|
|
21
|
+
parameters: Parameters,
|
|
22
|
+
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context<Metadata>) =>
|
|
23
|
+
Effect.gen(function* () {
|
|
24
|
+
const answers = yield* question.ask({
|
|
25
|
+
sessionID: ctx.sessionID,
|
|
26
|
+
questions: params.questions,
|
|
27
|
+
tool: ctx.callID ? { messageID: ctx.messageID, callID: ctx.callID } : undefined,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const formatted = params.questions
|
|
31
|
+
.map((q, i) => `"${q.question}"="${answers[i]?.length ? answers[i].join(", ") : "Unanswered"}"`)
|
|
32
|
+
.join(", ")
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
title: `Asked ${params.questions.length} question${params.questions.length > 1 ? "s" : ""}`,
|
|
36
|
+
output: `User has answered your questions: ${formatted}. You can now continue with the user's answers in mind.`,
|
|
37
|
+
metadata: {
|
|
38
|
+
answers,
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
}).pipe(Effect.orDie),
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
2
|
+
1. Gather user preferences or requirements
|
|
3
|
+
2. Clarify ambiguous instructions
|
|
4
|
+
3. Get decisions on implementation choices as you work
|
|
5
|
+
4. Offer choices to the user about what direction to take.
|
|
6
|
+
|
|
7
|
+
Usage notes:
|
|
8
|
+
- When `custom` is enabled (default), a "Type your own answer" option is added automatically; don't include "Other" or catch-all options
|
|
9
|
+
- Answers are returned as arrays of labels; set `multiple: true` to allow selecting more than one
|
|
10
|
+
- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { Effect, Option, Schema, Scope, Stream } from "effect"
|
|
2
|
+
import { NonNegativeInt } from "@opencode-ai/core/schema"
|
|
3
|
+
import * as path from "path"
|
|
4
|
+
import * as Tool from "./tool"
|
|
5
|
+
import { AppFileSystem } from "@opencode-ai/core/filesystem"
|
|
6
|
+
import { LSP } from "@/lsp/lsp"
|
|
7
|
+
import DESCRIPTION from "./read.txt"
|
|
8
|
+
import { InstanceState } from "@/effect/instance-state"
|
|
9
|
+
import { assertExternalDirectoryEffect } from "./external-directory"
|
|
10
|
+
import { Instruction } from "../session/instruction"
|
|
11
|
+
import { isPdfAttachment, sniffAttachmentMime } from "@/util/media"
|
|
12
|
+
import { Reference } from "@/reference/reference"
|
|
13
|
+
|
|
14
|
+
const DEFAULT_READ_LIMIT = 2000
|
|
15
|
+
const MAX_LINE_LENGTH = 2000
|
|
16
|
+
const MAX_LINE_SUFFIX = `... (line truncated to ${MAX_LINE_LENGTH} chars)`
|
|
17
|
+
const MAX_BYTES = 50 * 1024
|
|
18
|
+
const MAX_BYTES_LABEL = `${MAX_BYTES / 1024} KB`
|
|
19
|
+
const SAMPLE_BYTES = 4096
|
|
20
|
+
const SUPPORTED_IMAGE_MIMES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"])
|
|
21
|
+
|
|
22
|
+
// `offset` and `limit` were originally `z.coerce.number()` — the runtime
|
|
23
|
+
// coercion was useful when the tool was called from a shell but serves no
|
|
24
|
+
// purpose in the LLM tool-call path (the model emits typed JSON). The JSON
|
|
25
|
+
// Schema output is identical (`type: "number"`), so the LLM view is
|
|
26
|
+
// unchanged; purely CLI-facing uses must now send numbers rather than strings.
|
|
27
|
+
export const Parameters = Schema.Struct({
|
|
28
|
+
filePath: Schema.String.annotate({ description: "The absolute path to the file or directory to read" }),
|
|
29
|
+
offset: Schema.optional(NonNegativeInt).annotate({
|
|
30
|
+
description: "The line number to start reading from (1-indexed)",
|
|
31
|
+
}),
|
|
32
|
+
limit: Schema.optional(NonNegativeInt).annotate({
|
|
33
|
+
description: "The maximum number of lines to read (defaults to 2000)",
|
|
34
|
+
}),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const ReadTool = Tool.define(
|
|
38
|
+
"read",
|
|
39
|
+
Effect.gen(function* () {
|
|
40
|
+
const fs = yield* AppFileSystem.Service
|
|
41
|
+
const instruction = yield* Instruction.Service
|
|
42
|
+
const lsp = yield* LSP.Service
|
|
43
|
+
const reference = yield* Reference.Service
|
|
44
|
+
const scope = yield* Scope.Scope
|
|
45
|
+
|
|
46
|
+
const miss = Effect.fn("ReadTool.miss")(function* (filepath: string) {
|
|
47
|
+
const dir = path.dirname(filepath)
|
|
48
|
+
const base = path.basename(filepath)
|
|
49
|
+
const items = yield* fs.readDirectory(dir).pipe(
|
|
50
|
+
Effect.map((items) =>
|
|
51
|
+
items
|
|
52
|
+
.filter(
|
|
53
|
+
(item) =>
|
|
54
|
+
item.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(item.toLowerCase()),
|
|
55
|
+
)
|
|
56
|
+
.map((item) => path.join(dir, item))
|
|
57
|
+
.slice(0, 3),
|
|
58
|
+
),
|
|
59
|
+
Effect.catch(() => Effect.succeed([] as string[])),
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if (items.length > 0) {
|
|
63
|
+
return yield* Effect.fail(
|
|
64
|
+
new Error(`File not found: ${filepath}\n\nDid you mean one of these?\n${items.join("\n")}`),
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return yield* Effect.fail(new Error(`File not found: ${filepath}`))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const list = Effect.fn("ReadTool.list")(function* (filepath: string) {
|
|
72
|
+
const items = yield* fs.readDirectoryEntries(filepath)
|
|
73
|
+
return yield* Effect.forEach(
|
|
74
|
+
items,
|
|
75
|
+
Effect.fnUntraced(function* (item) {
|
|
76
|
+
if (item.type === "directory") return item.name + "/"
|
|
77
|
+
if (item.type !== "symlink") return item.name
|
|
78
|
+
|
|
79
|
+
const target = yield* fs.stat(path.join(filepath, item.name)).pipe(Effect.catch(() => Effect.void))
|
|
80
|
+
if (target?.type === "Directory") return item.name + "/"
|
|
81
|
+
return item.name
|
|
82
|
+
}),
|
|
83
|
+
{ concurrency: "unbounded" },
|
|
84
|
+
).pipe(Effect.map((items: string[]) => items.sort((a, b) => a.localeCompare(b))))
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const warm = Effect.fn("ReadTool.warm")(function* (filepath: string) {
|
|
88
|
+
yield* lsp.touchFile(filepath).pipe(Effect.ignore, Effect.forkIn(scope))
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
const readSample = Effect.fn("ReadTool.readSample")(function* (
|
|
92
|
+
filepath: string,
|
|
93
|
+
fileSize: number,
|
|
94
|
+
sampleSize: number,
|
|
95
|
+
) {
|
|
96
|
+
if (fileSize === 0) return new Uint8Array()
|
|
97
|
+
|
|
98
|
+
return yield* Effect.scoped(
|
|
99
|
+
Effect.gen(function* () {
|
|
100
|
+
const file = yield* fs.open(filepath, { flag: "r" })
|
|
101
|
+
return Option.getOrElse(yield* file.readAlloc(Math.min(sampleSize, fileSize)), () => new Uint8Array())
|
|
102
|
+
}),
|
|
103
|
+
)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const lines = Effect.fn("ReadTool.lines")(function* (filepath: string, opts: { limit: number; offset: number }) {
|
|
107
|
+
const start = opts.offset - 1
|
|
108
|
+
const raw: string[] = []
|
|
109
|
+
const flags = { bytes: 0, count: 0, cut: false, more: false, done: false }
|
|
110
|
+
|
|
111
|
+
// Note: prefer manual TextDecoder over Stream.decodeText — when the source stream
|
|
112
|
+
// ends without flushing, decodeText drops the final unterminated line. We also
|
|
113
|
+
// avoid Stream.runForEachWhile (it currently swallows the final unterminated
|
|
114
|
+
// line of the upstream splitLines pipeline) and instead toggle a `done` flag
|
|
115
|
+
// and ignore subsequent lines.
|
|
116
|
+
const decoder = new TextDecoder("utf-8")
|
|
117
|
+
yield* fs.stream(filepath).pipe(
|
|
118
|
+
Stream.map((bytes) => decoder.decode(bytes, { stream: true })),
|
|
119
|
+
Stream.splitLines,
|
|
120
|
+
Stream.runForEach((text) =>
|
|
121
|
+
Effect.sync(() => {
|
|
122
|
+
if (flags.done) return
|
|
123
|
+
flags.count += 1
|
|
124
|
+
if (flags.count <= start) return
|
|
125
|
+
|
|
126
|
+
if (raw.length >= opts.limit) {
|
|
127
|
+
flags.more = true
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const line = text.length > MAX_LINE_LENGTH ? text.substring(0, MAX_LINE_LENGTH) + MAX_LINE_SUFFIX : text
|
|
132
|
+
const size = Buffer.byteLength(line, "utf-8") + (raw.length > 0 ? 1 : 0)
|
|
133
|
+
if (flags.bytes + size > MAX_BYTES) {
|
|
134
|
+
flags.cut = true
|
|
135
|
+
flags.more = true
|
|
136
|
+
flags.done = true
|
|
137
|
+
return
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
raw.push(line)
|
|
141
|
+
flags.bytes += size
|
|
142
|
+
}),
|
|
143
|
+
),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
return { raw, count: flags.count, cut: flags.cut, more: flags.more, offset: opts.offset }
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
const isBinaryFile = (filepath: string, bytes: Uint8Array) => {
|
|
150
|
+
const ext = path.extname(filepath).toLowerCase()
|
|
151
|
+
switch (ext) {
|
|
152
|
+
case ".zip":
|
|
153
|
+
case ".tar":
|
|
154
|
+
case ".gz":
|
|
155
|
+
case ".exe":
|
|
156
|
+
case ".dll":
|
|
157
|
+
case ".so":
|
|
158
|
+
case ".class":
|
|
159
|
+
case ".jar":
|
|
160
|
+
case ".war":
|
|
161
|
+
case ".7z":
|
|
162
|
+
case ".doc":
|
|
163
|
+
case ".docx":
|
|
164
|
+
case ".xls":
|
|
165
|
+
case ".xlsx":
|
|
166
|
+
case ".ppt":
|
|
167
|
+
case ".pptx":
|
|
168
|
+
case ".odt":
|
|
169
|
+
case ".ods":
|
|
170
|
+
case ".odp":
|
|
171
|
+
case ".bin":
|
|
172
|
+
case ".dat":
|
|
173
|
+
case ".obj":
|
|
174
|
+
case ".o":
|
|
175
|
+
case ".a":
|
|
176
|
+
case ".lib":
|
|
177
|
+
case ".wasm":
|
|
178
|
+
case ".pyc":
|
|
179
|
+
case ".pyo":
|
|
180
|
+
return true
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (bytes.length === 0) return false
|
|
184
|
+
|
|
185
|
+
let nonPrintableCount = 0
|
|
186
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
187
|
+
if (bytes[i] === 0) return true
|
|
188
|
+
if (bytes[i] < 9 || (bytes[i] > 13 && bytes[i] < 32)) {
|
|
189
|
+
nonPrintableCount++
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return nonPrintableCount / bytes.length > 0.3
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const run = Effect.fn("ReadTool.execute")(function* (
|
|
197
|
+
params: Schema.Schema.Type<typeof Parameters>,
|
|
198
|
+
ctx: Tool.Context,
|
|
199
|
+
) {
|
|
200
|
+
const instance = yield* InstanceState.context
|
|
201
|
+
let filepath = params.filePath
|
|
202
|
+
if (!path.isAbsolute(filepath)) {
|
|
203
|
+
filepath = path.resolve(instance.directory, filepath)
|
|
204
|
+
}
|
|
205
|
+
if (process.platform === "win32") {
|
|
206
|
+
filepath = AppFileSystem.normalizePath(filepath)
|
|
207
|
+
}
|
|
208
|
+
yield* reference.ensure(filepath)
|
|
209
|
+
const title = path.relative(instance.worktree, filepath)
|
|
210
|
+
|
|
211
|
+
const stat = yield* fs.stat(filepath).pipe(
|
|
212
|
+
Effect.catchIf(
|
|
213
|
+
(err) => "reason" in err && err.reason._tag === "NotFound",
|
|
214
|
+
() => Effect.succeed(undefined),
|
|
215
|
+
),
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
yield* assertExternalDirectoryEffect(ctx, filepath, {
|
|
219
|
+
bypass: Boolean(ctx.extra?.["bypassCwdCheck"]) || (yield* reference.contains(filepath)),
|
|
220
|
+
kind: stat?.type === "Directory" ? "directory" : "file",
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
yield* ctx.ask({
|
|
224
|
+
permission: "read",
|
|
225
|
+
patterns: [path.relative(instance.worktree, filepath)],
|
|
226
|
+
always: ["*"],
|
|
227
|
+
metadata: {},
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
if (!stat) return yield* miss(filepath)
|
|
231
|
+
|
|
232
|
+
if (stat.type === "Directory") {
|
|
233
|
+
const items = yield* list(filepath)
|
|
234
|
+
const limit = params.limit ?? DEFAULT_READ_LIMIT
|
|
235
|
+
const offset = params.offset || 1
|
|
236
|
+
const start = offset - 1
|
|
237
|
+
const sliced = items.slice(start, start + limit)
|
|
238
|
+
const truncated = start + sliced.length < items.length
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
title,
|
|
242
|
+
output: [
|
|
243
|
+
`<path>${filepath}</path>`,
|
|
244
|
+
`<type>directory</type>`,
|
|
245
|
+
`<entries>`,
|
|
246
|
+
sliced.join("\n"),
|
|
247
|
+
truncated
|
|
248
|
+
? `\n(Showing ${sliced.length} of ${items.length} entries. Use 'offset' parameter to read beyond entry ${offset + sliced.length})`
|
|
249
|
+
: `\n(${items.length} entries)`,
|
|
250
|
+
`</entries>`,
|
|
251
|
+
].join("\n"),
|
|
252
|
+
metadata: {
|
|
253
|
+
preview: sliced.slice(0, 20).join("\n"),
|
|
254
|
+
truncated,
|
|
255
|
+
loaded: [] as string[],
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const loaded = yield* instruction.resolve(ctx.messages, filepath, ctx.messageID)
|
|
261
|
+
const sample = yield* readSample(filepath, Number(stat.size), SAMPLE_BYTES)
|
|
262
|
+
|
|
263
|
+
const mime = sniffAttachmentMime(sample, AppFileSystem.mimeType(filepath))
|
|
264
|
+
const isImage = SUPPORTED_IMAGE_MIMES.has(mime)
|
|
265
|
+
|
|
266
|
+
if (isImage || isPdfAttachment(mime)) {
|
|
267
|
+
const bytes = yield* fs.readFile(filepath)
|
|
268
|
+
const msg = isPdfAttachment(mime) ? "PDF read successfully" : "Image read successfully"
|
|
269
|
+
return {
|
|
270
|
+
title,
|
|
271
|
+
output: msg,
|
|
272
|
+
metadata: {
|
|
273
|
+
preview: msg,
|
|
274
|
+
truncated: false,
|
|
275
|
+
loaded: loaded.map((item) => item.filepath),
|
|
276
|
+
},
|
|
277
|
+
attachments: [
|
|
278
|
+
{
|
|
279
|
+
type: "file" as const,
|
|
280
|
+
mime,
|
|
281
|
+
url: `data:${mime};base64,${Buffer.from(bytes).toString("base64")}`,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (isBinaryFile(filepath, sample)) {
|
|
288
|
+
return yield* Effect.fail(new Error(`Cannot read binary file: ${filepath}`))
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const file = yield* lines(filepath, { limit: params.limit ?? DEFAULT_READ_LIMIT, offset: params.offset || 1 })
|
|
292
|
+
if (file.count < file.offset && !(file.count === 0 && file.offset === 1)) {
|
|
293
|
+
return yield* Effect.fail(
|
|
294
|
+
new Error(`Offset ${file.offset} is out of range for this file (${file.count} lines)`),
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let output = [`<path>${filepath}</path>`, `<type>file</type>`, "<content>\n"].join("\n")
|
|
299
|
+
output += file.raw.map((line, i) => `${i + file.offset}: ${line}`).join("\n")
|
|
300
|
+
|
|
301
|
+
const last = file.offset + file.raw.length - 1
|
|
302
|
+
const next = last + 1
|
|
303
|
+
const truncated = file.more || file.cut
|
|
304
|
+
if (file.cut) {
|
|
305
|
+
output += `\n\n(Output capped at ${MAX_BYTES_LABEL}. Showing lines ${file.offset}-${last}. Use offset=${next} to continue.)`
|
|
306
|
+
} else if (file.more) {
|
|
307
|
+
output += `\n\n(Showing lines ${file.offset}-${last} of ${file.count}. Use offset=${next} to continue.)`
|
|
308
|
+
} else {
|
|
309
|
+
output += `\n\n(End of file - total ${file.count} lines)`
|
|
310
|
+
}
|
|
311
|
+
output += "\n</content>"
|
|
312
|
+
|
|
313
|
+
yield* warm(filepath)
|
|
314
|
+
|
|
315
|
+
if (loaded.length > 0) {
|
|
316
|
+
output += `\n\n<system-reminder>\n${loaded.map((item) => item.content).join("\n\n")}\n</system-reminder>`
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
title,
|
|
321
|
+
output,
|
|
322
|
+
metadata: {
|
|
323
|
+
preview: file.raw.slice(0, 20).join("\n"),
|
|
324
|
+
truncated,
|
|
325
|
+
loaded: loaded.map((item) => item.filepath),
|
|
326
|
+
},
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
description: DESCRIPTION,
|
|
332
|
+
parameters: Parameters,
|
|
333
|
+
execute: (params: Schema.Schema.Type<typeof Parameters>, ctx: Tool.Context) =>
|
|
334
|
+
run(params, ctx).pipe(Effect.orDie),
|
|
335
|
+
}
|
|
336
|
+
}),
|
|
337
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Read a file or directory from the local filesystem. If the path does not exist, an error is returned.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
- The filePath parameter should be an absolute path.
|
|
5
|
+
- By default, this tool returns up to 2000 lines from the start of the file.
|
|
6
|
+
- The offset parameter is the line number to start from (1-indexed).
|
|
7
|
+
- To read later sections, call this tool again with a larger offset.
|
|
8
|
+
- Use the grep tool to find specific content in large files or files with long lines.
|
|
9
|
+
- If you are unsure of the correct file path, use the glob tool to look up filenames by glob pattern.
|
|
10
|
+
- Contents are returned with each line prefixed by its line number as `<line>: <content>`. For example, if a file has contents "foo\n", you will receive "1: foo\n". For directories, entries are returned one per line (without line numbers) with a trailing `/` for subdirectories.
|
|
11
|
+
- Any line longer than 2000 characters is truncated.
|
|
12
|
+
- Call this tool in parallel when you know there are multiple files you want to read.
|
|
13
|
+
- Avoid tiny repeated slices (30 line chunks). If you need more context, read a larger window.
|
|
14
|
+
- This tool can read image files and PDFs and return them as file attachments.
|