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,598 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BoneCode Context Builder
|
|
3
|
+
*
|
|
4
|
+
* Builds rich codebase context using structural strategies that work
|
|
5
|
+
* without any embedding model:
|
|
6
|
+
* 1. Postgres full-text search (BM25-ranked via ts_rank)
|
|
7
|
+
* 2. Git recency (recently changed files are more relevant)
|
|
8
|
+
* 3. Session history (files read/edited in this session)
|
|
9
|
+
* 4. Import graph expansion (pull in direct dependencies)
|
|
10
|
+
* 5. Instruction file injection (AGENTS.md / CLAUDE.md proximity)
|
|
11
|
+
*
|
|
12
|
+
* OPTIONAL UPGRADE — set EMBEDDING_PROVIDER in .env to enable hybrid search:
|
|
13
|
+
* When EMBEDDING_PROVIDER is set, vector similarity search is added on top
|
|
14
|
+
* of FTS using the bonecode_hybrid_search() stored function (RRF fusion).
|
|
15
|
+
* Without it, pure FTS + structural strategies run — still better than
|
|
16
|
+
* OpenCode's reactive grep approach.
|
|
17
|
+
*
|
|
18
|
+
* To enable embeddings, add to .env:
|
|
19
|
+
* EMBEDDING_PROVIDER=openai # or: ollama, voyage, openai_compatible
|
|
20
|
+
* EMBEDDING_MODEL=text-embedding-3-small
|
|
21
|
+
* EMBEDDING_API_KEY=sk-... # defaults to OPENAI_API_KEY
|
|
22
|
+
* EMBEDDING_BASE_URL= # for local/compatible endpoints
|
|
23
|
+
* EMBEDDING_DIMENSIONS=1536
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import * as fs from "fs";
|
|
27
|
+
import * as path from "path";
|
|
28
|
+
import { pool } from "../bone/output/session/src/db";
|
|
29
|
+
import { logger } from "../bone/output/session/src/logger";
|
|
30
|
+
|
|
31
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
export interface ContextChunk {
|
|
34
|
+
file_path: string;
|
|
35
|
+
content: string;
|
|
36
|
+
start_line: number;
|
|
37
|
+
end_line: number;
|
|
38
|
+
language?: string;
|
|
39
|
+
symbol_name?: string;
|
|
40
|
+
symbol_type?: string;
|
|
41
|
+
relevance_score: number;
|
|
42
|
+
source: "fts" | "vector" | "hybrid" | "import_graph" | "git_recency" | "session_history" | "instruction" | "entrypoint";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ContextResult {
|
|
46
|
+
chunks: ContextChunk[];
|
|
47
|
+
instruction_files: string[];
|
|
48
|
+
summary: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface ContextOptions {
|
|
52
|
+
session_id: string;
|
|
53
|
+
project_id: string;
|
|
54
|
+
worktree: string;
|
|
55
|
+
query: string;
|
|
56
|
+
max_chunks?: number;
|
|
57
|
+
max_chars?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─── Embedding availability check ────────────────────────────────────────────
|
|
61
|
+
|
|
62
|
+
export function embeddingsEnabled(): boolean {
|
|
63
|
+
return !!(process.env.EMBEDDING_PROVIDER && process.env.EMBEDDING_PROVIDER !== "none");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ─── Main entry point ─────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
export async function buildContext(opts: ContextOptions): Promise<ContextResult> {
|
|
69
|
+
const {
|
|
70
|
+
session_id, project_id, worktree, query,
|
|
71
|
+
max_chunks = 12,
|
|
72
|
+
max_chars = 12_000,
|
|
73
|
+
} = opts;
|
|
74
|
+
|
|
75
|
+
const chunks: ContextChunk[] = [];
|
|
76
|
+
const seen = new Set<string>(); // deduplicate by file_path:start_line
|
|
77
|
+
|
|
78
|
+
// Run structural strategies in parallel (always active)
|
|
79
|
+
const [ftsChunks, gitChunks, sessionChunks, instructionFiles] = await Promise.all([
|
|
80
|
+
searchFTS(project_id, query, 20).catch(() => []),
|
|
81
|
+
getGitRecentFiles(worktree, query, 10).catch(() => []),
|
|
82
|
+
getSessionHistory(session_id, worktree, 8).catch(() => []),
|
|
83
|
+
findInstructionFiles(worktree, query).catch(() => []),
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// Optional: vector search upgrade when EMBEDDING_PROVIDER is configured
|
|
87
|
+
// Replaces FTS with hybrid search (vector + FTS + RRF) for better recall
|
|
88
|
+
let vectorChunks: ContextChunk[] = [];
|
|
89
|
+
if (embeddingsEnabled() && query.trim()) {
|
|
90
|
+
vectorChunks = await searchVector(project_id, query, 20).catch((e) => {
|
|
91
|
+
logger.error("vector_search_failed", { event: "context", metadata: { error: e.message } });
|
|
92
|
+
return [];
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Merge: prefer vector/hybrid results over pure FTS when available
|
|
97
|
+
const primaryChunks = vectorChunks.length > 0 ? vectorChunks : ftsChunks;
|
|
98
|
+
for (const c of primaryChunks) {
|
|
99
|
+
const key = `${c.file_path}:${c.start_line}`;
|
|
100
|
+
if (!seen.has(key)) { seen.add(key); chunks.push(c); }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Add git-recent files not already covered
|
|
104
|
+
for (const c of gitChunks) {
|
|
105
|
+
const key = `${c.file_path}:${c.start_line}`;
|
|
106
|
+
if (!seen.has(key)) { seen.add(key); chunks.push(c); }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add session history files
|
|
110
|
+
for (const c of sessionChunks) {
|
|
111
|
+
const key = `${c.file_path}:${c.start_line}`;
|
|
112
|
+
if (!seen.has(key)) { seen.add(key); chunks.push(c); }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Expand top results via import graph
|
|
116
|
+
const topFiles = chunks.slice(0, 5).map(c => c.file_path);
|
|
117
|
+
const importChunks = await expandImportGraph(worktree, topFiles, seen, 6).catch(() => []);
|
|
118
|
+
for (const c of importChunks) {
|
|
119
|
+
const key = `${c.file_path}:${c.start_line}`;
|
|
120
|
+
if (!seen.has(key)) { seen.add(key); chunks.push(c); }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Sort by relevance score descending
|
|
124
|
+
chunks.sort((a, b) => b.relevance_score - a.relevance_score);
|
|
125
|
+
|
|
126
|
+
// Trim to budget
|
|
127
|
+
const trimmed = trimToCharBudget(chunks.slice(0, max_chunks), max_chars);
|
|
128
|
+
|
|
129
|
+
const mode = embeddingsEnabled() && vectorChunks.length > 0 ? "hybrid" : "structural";
|
|
130
|
+
const sources = [...new Set(trimmed.map(c => c.source))].join(", ");
|
|
131
|
+
const summary = trimmed.length > 0
|
|
132
|
+
? `${trimmed.length} chunks [${mode}] from ${[...new Set(trimmed.map(c => path.basename(c.file_path)))].slice(0, 5).join(", ")} (${sources})`
|
|
133
|
+
: "no relevant context found";
|
|
134
|
+
|
|
135
|
+
return { chunks: trimmed, instruction_files: instructionFiles, summary };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ─── Strategy 2: Vector Search (optional — requires EMBEDDING_PROVIDER) ───────
|
|
139
|
+
// Uses the bonecode_hybrid_search() stored function (RRF: vector + FTS).
|
|
140
|
+
// Only called when EMBEDDING_PROVIDER is set in .env.
|
|
141
|
+
|
|
142
|
+
async function searchVector(project_id: string, query: string, limit: number): Promise<ContextChunk[]> {
|
|
143
|
+
if (!query.trim()) return [];
|
|
144
|
+
|
|
145
|
+
// Embed the query using the configured provider
|
|
146
|
+
const { embed_text } = await import("../bone/output/rag/src/extensions");
|
|
147
|
+
const model = process.env.EMBEDDING_MODEL || "text-embedding-nomic-embed-text-v1.5";
|
|
148
|
+
const queryEmbedding = await embed_text(query, model);
|
|
149
|
+
const embStr = "[" + queryEmbedding.join(",") + "]";
|
|
150
|
+
|
|
151
|
+
// Use the stored hybrid search function (RRF fusion of vector + FTS)
|
|
152
|
+
const result = await pool.query(`
|
|
153
|
+
SELECT
|
|
154
|
+
cf.file_path,
|
|
155
|
+
cc.content,
|
|
156
|
+
cc.start_line,
|
|
157
|
+
cc.end_line,
|
|
158
|
+
cc.language,
|
|
159
|
+
cc.symbol_name,
|
|
160
|
+
cc.symbol_type,
|
|
161
|
+
h.rrf_score,
|
|
162
|
+
h.vector_score,
|
|
163
|
+
h.text_score
|
|
164
|
+
FROM bonecode_hybrid_search($1, $2::vector, $3, NULL, NULL, $4) h
|
|
165
|
+
JOIN code_chunks cc ON cc.id = h.chunk_id
|
|
166
|
+
JOIN code_files cf ON cf.id = cc.code_file_id
|
|
167
|
+
JOIN knowledge_bases kb ON kb.id = cc.knowledge_base_id
|
|
168
|
+
WHERE kb.project_id = $5
|
|
169
|
+
ORDER BY h.rrf_score DESC
|
|
170
|
+
`, [
|
|
171
|
+
// knowledge_base_id — find the ready KB for this project
|
|
172
|
+
await getReadyKBId(project_id),
|
|
173
|
+
embStr,
|
|
174
|
+
query,
|
|
175
|
+
limit,
|
|
176
|
+
project_id,
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
return result.rows.map((row: any) => ({
|
|
180
|
+
file_path: row.file_path,
|
|
181
|
+
content: row.content,
|
|
182
|
+
start_line: Number(row.start_line),
|
|
183
|
+
end_line: Number(row.end_line),
|
|
184
|
+
language: row.language,
|
|
185
|
+
symbol_name: row.symbol_name,
|
|
186
|
+
symbol_type: row.symbol_type,
|
|
187
|
+
relevance_score: parseFloat(row.rrf_score) * 1000,
|
|
188
|
+
source: "hybrid" as const,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async function getReadyKBId(project_id: string): Promise<string> {
|
|
193
|
+
const result = await pool.query(
|
|
194
|
+
`SELECT id FROM knowledge_bases WHERE project_id = $1 AND state = 'ready' ORDER BY updated_at DESC LIMIT 1`,
|
|
195
|
+
[project_id]
|
|
196
|
+
);
|
|
197
|
+
return result.rows[0]?.id || "";
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ─── Strategy 3: Postgres Full-Text Search ────────────────────────────────────
|
|
201
|
+
// Uses the tsvector index already on code_chunks.content.
|
|
202
|
+
// BM25-ranked via ts_rank — no embedding needed.
|
|
203
|
+
|
|
204
|
+
async function searchFTS(project_id: string, query: string, limit: number): Promise<ContextChunk[]> {
|
|
205
|
+
if (!query.trim()) return [];
|
|
206
|
+
|
|
207
|
+
// Extract meaningful terms — strip common words, keep identifiers
|
|
208
|
+
const terms = extractSearchTerms(query);
|
|
209
|
+
if (terms.length === 0) return [];
|
|
210
|
+
|
|
211
|
+
// Sanitize each term: keep only alphanumeric + underscore to prevent tsquery injection.
|
|
212
|
+
// Each term is passed as a separate $N parameter and assembled server-side via plainto_tsquery
|
|
213
|
+
// for the rank, and individual prefix-match queries ORed together for the filter.
|
|
214
|
+
const safeTsQuery = terms
|
|
215
|
+
.map(t => t.replace(/[^a-z0-9_]/g, ""))
|
|
216
|
+
.filter(t => t.length >= 2)
|
|
217
|
+
.map(t => `${t}:*`)
|
|
218
|
+
.join(" | ");
|
|
219
|
+
|
|
220
|
+
if (!safeTsQuery) return [];
|
|
221
|
+
|
|
222
|
+
const result = await pool.query(`
|
|
223
|
+
SELECT
|
|
224
|
+
cf.file_path,
|
|
225
|
+
cc.content,
|
|
226
|
+
cc.start_line,
|
|
227
|
+
cc.end_line,
|
|
228
|
+
cc.language,
|
|
229
|
+
cc.symbol_name,
|
|
230
|
+
cc.symbol_type,
|
|
231
|
+
ts_rank(
|
|
232
|
+
to_tsvector('english', cc.content),
|
|
233
|
+
to_tsquery('english', $2)
|
|
234
|
+
) AS score
|
|
235
|
+
FROM code_chunks cc
|
|
236
|
+
JOIN code_files cf ON cf.id = cc.code_file_id
|
|
237
|
+
JOIN knowledge_bases kb ON kb.id = cc.knowledge_base_id
|
|
238
|
+
WHERE kb.project_id = $1
|
|
239
|
+
AND to_tsvector('english', cc.content) @@ to_tsquery('english', $2)
|
|
240
|
+
ORDER BY score DESC
|
|
241
|
+
LIMIT $3
|
|
242
|
+
`, [project_id, safeTsQuery, limit]);
|
|
243
|
+
|
|
244
|
+
return result.rows.map((row: any) => ({
|
|
245
|
+
file_path: row.file_path,
|
|
246
|
+
content: row.content,
|
|
247
|
+
start_line: Number(row.start_line),
|
|
248
|
+
end_line: Number(row.end_line),
|
|
249
|
+
language: row.language,
|
|
250
|
+
symbol_name: row.symbol_name,
|
|
251
|
+
symbol_type: row.symbol_type,
|
|
252
|
+
relevance_score: parseFloat(row.score) * 100,
|
|
253
|
+
source: "fts" as const,
|
|
254
|
+
}));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ─── Strategy 2: Git Recency ──────────────────────────────────────────────────
|
|
258
|
+
// Files changed in recent commits are more likely to be relevant.
|
|
259
|
+
// Also filters by query terms appearing in the diff.
|
|
260
|
+
|
|
261
|
+
async function getGitRecentFiles(worktree: string, query: string, limit: number): Promise<ContextChunk[]> {
|
|
262
|
+
if (!fs.existsSync(path.join(worktree, ".git"))) return [];
|
|
263
|
+
|
|
264
|
+
const { execFile } = require("child_process");
|
|
265
|
+
const { promisify } = require("util");
|
|
266
|
+
const exec = promisify(execFile);
|
|
267
|
+
|
|
268
|
+
// Get files changed in last 20 commits
|
|
269
|
+
let changedFiles: string[] = [];
|
|
270
|
+
try {
|
|
271
|
+
const { stdout } = await exec("git", [
|
|
272
|
+
"log", "--name-only", "--pretty=format:", "-20", "--diff-filter=AM"
|
|
273
|
+
], { cwd: worktree, timeout: 5000 });
|
|
274
|
+
changedFiles = stdout.split("\n")
|
|
275
|
+
.map((f: string) => f.trim())
|
|
276
|
+
.filter((f: string) => f && !f.startsWith("."))
|
|
277
|
+
.filter((f: string, i: number, arr: string[]) => arr.indexOf(f) === i) // deduplicate
|
|
278
|
+
.slice(0, 30);
|
|
279
|
+
} catch {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const terms = extractSearchTerms(query);
|
|
284
|
+
const chunks: ContextChunk[] = [];
|
|
285
|
+
|
|
286
|
+
for (const relPath of changedFiles.slice(0, limit * 2)) {
|
|
287
|
+
const fullPath = path.join(worktree, relPath);
|
|
288
|
+
if (!fs.existsSync(fullPath)) continue;
|
|
289
|
+
|
|
290
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
291
|
+
const codeExts = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".cs", ".cpp", ".c"]);
|
|
292
|
+
if (!codeExts.has(ext)) continue;
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
const content = fs.readFileSync(fullPath, "utf-8");
|
|
296
|
+
const lines = content.split("\n");
|
|
297
|
+
|
|
298
|
+
// Score by how many query terms appear in the file
|
|
299
|
+
const contentLower = content.toLowerCase();
|
|
300
|
+
const termScore = terms.filter(t => contentLower.includes(t.toLowerCase())).length;
|
|
301
|
+
if (termScore === 0 && terms.length > 0) continue;
|
|
302
|
+
|
|
303
|
+
// Extract the most relevant section (around first term match)
|
|
304
|
+
const firstMatch = findFirstTermMatch(lines, terms);
|
|
305
|
+
const startLine = Math.max(0, firstMatch - 10);
|
|
306
|
+
const endLine = Math.min(lines.length - 1, firstMatch + 40);
|
|
307
|
+
const snippet = lines.slice(startLine, endLine + 1).join("\n");
|
|
308
|
+
|
|
309
|
+
chunks.push({
|
|
310
|
+
file_path: fullPath,
|
|
311
|
+
content: snippet,
|
|
312
|
+
start_line: startLine + 1,
|
|
313
|
+
end_line: endLine + 1,
|
|
314
|
+
language: extToLanguage(ext),
|
|
315
|
+
relevance_score: 30 + termScore * 10,
|
|
316
|
+
source: "git_recency",
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
if (chunks.length >= limit) break;
|
|
320
|
+
} catch { continue; }
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return chunks;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ─── Strategy 3: Session History ─────────────────────────────────────────────
|
|
327
|
+
// Files the agent has already read/edited in this session are highly relevant.
|
|
328
|
+
|
|
329
|
+
async function getSessionHistory(session_id: string, worktree: string, limit: number): Promise<ContextChunk[]> {
|
|
330
|
+
// Look at tool_calls in this session for read_file / edit_file / write_file
|
|
331
|
+
const result = await pool.query(`
|
|
332
|
+
SELECT DISTINCT
|
|
333
|
+
tc.tool_input->>'path' AS file_path,
|
|
334
|
+
tc.tool_name,
|
|
335
|
+
tc.created_at
|
|
336
|
+
FROM tool_calls tc
|
|
337
|
+
WHERE tc.session_id = $1
|
|
338
|
+
AND tc.tool_name IN ('read_file', 'edit_file', 'write_file', 'read', 'edit', 'write')
|
|
339
|
+
AND tc.tool_input->>'path' IS NOT NULL
|
|
340
|
+
AND tc.state = 'done'
|
|
341
|
+
ORDER BY tc.created_at DESC
|
|
342
|
+
LIMIT $2
|
|
343
|
+
`, [session_id, limit * 2]);
|
|
344
|
+
|
|
345
|
+
const chunks: ContextChunk[] = [];
|
|
346
|
+
const seen = new Set<string>();
|
|
347
|
+
|
|
348
|
+
for (const row of result.rows) {
|
|
349
|
+
let filePath = row.file_path as string;
|
|
350
|
+
if (!path.isAbsolute(filePath)) filePath = path.join(worktree, filePath);
|
|
351
|
+
if (seen.has(filePath) || !fs.existsSync(filePath)) continue;
|
|
352
|
+
seen.add(filePath);
|
|
353
|
+
|
|
354
|
+
try {
|
|
355
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
356
|
+
const lines = content.split("\n");
|
|
357
|
+
// Take first 60 lines as context (usually the most important part)
|
|
358
|
+
const snippet = lines.slice(0, 60).join("\n");
|
|
359
|
+
|
|
360
|
+
chunks.push({
|
|
361
|
+
file_path: filePath,
|
|
362
|
+
content: snippet,
|
|
363
|
+
start_line: 1,
|
|
364
|
+
end_line: Math.min(60, lines.length),
|
|
365
|
+
language: extToLanguage(path.extname(filePath)),
|
|
366
|
+
relevance_score: 50, // high — agent already touched this file
|
|
367
|
+
source: "session_history",
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
if (chunks.length >= limit) break;
|
|
371
|
+
} catch { continue; }
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return chunks;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ─── Strategy 4: Import Graph Expansion ──────────────────────────────────────
|
|
378
|
+
// Given a set of relevant files, pull in their direct imports.
|
|
379
|
+
// This ensures the LLM has the types/interfaces/utilities the relevant code depends on.
|
|
380
|
+
|
|
381
|
+
async function expandImportGraph(
|
|
382
|
+
worktree: string,
|
|
383
|
+
seedFiles: string[],
|
|
384
|
+
seen: Set<string>,
|
|
385
|
+
limit: number
|
|
386
|
+
): Promise<ContextChunk[]> {
|
|
387
|
+
const chunks: ContextChunk[] = [];
|
|
388
|
+
const toExpand = [...seedFiles];
|
|
389
|
+
|
|
390
|
+
for (const filePath of toExpand) {
|
|
391
|
+
if (chunks.length >= limit) break;
|
|
392
|
+
if (!fs.existsSync(filePath)) continue;
|
|
393
|
+
|
|
394
|
+
const imports = extractImports(filePath);
|
|
395
|
+
for (const importPath of imports) {
|
|
396
|
+
if (chunks.length >= limit) break;
|
|
397
|
+
|
|
398
|
+
const resolved = resolveImport(filePath, importPath, worktree);
|
|
399
|
+
if (!resolved || seen.has(`${resolved}:1`)) continue;
|
|
400
|
+
|
|
401
|
+
try {
|
|
402
|
+
const content = fs.readFileSync(resolved, "utf-8");
|
|
403
|
+
const lines = content.split("\n");
|
|
404
|
+
// For imported files, extract just the exports/public API (first 80 lines usually covers it)
|
|
405
|
+
const snippet = lines.slice(0, 80).join("\n");
|
|
406
|
+
|
|
407
|
+
seen.add(`${resolved}:1`);
|
|
408
|
+
chunks.push({
|
|
409
|
+
file_path: resolved,
|
|
410
|
+
content: snippet,
|
|
411
|
+
start_line: 1,
|
|
412
|
+
end_line: Math.min(80, lines.length),
|
|
413
|
+
language: extToLanguage(path.extname(resolved)),
|
|
414
|
+
relevance_score: 20, // lower — indirect dependency
|
|
415
|
+
source: "import_graph",
|
|
416
|
+
});
|
|
417
|
+
} catch { continue; }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return chunks;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ─── Strategy 5: Instruction Files ───────────────────────────────────────────
|
|
425
|
+
// Find AGENTS.md, CLAUDE.md, OPENCODE.md near the worktree root.
|
|
426
|
+
// Same approach as OpenCode's instruction.ts.
|
|
427
|
+
|
|
428
|
+
async function findInstructionFiles(worktree: string, _query: string): Promise<string[]> {
|
|
429
|
+
const candidates = ["AGENTS.md", "CLAUDE.md", "OPENCODE.md", ".bonecode/instructions.md", "CONTEXT.md"];
|
|
430
|
+
const found: string[] = [];
|
|
431
|
+
|
|
432
|
+
// Check worktree root and one level down
|
|
433
|
+
const dirsToCheck = [worktree];
|
|
434
|
+
try {
|
|
435
|
+
const entries = fs.readdirSync(worktree, { withFileTypes: true });
|
|
436
|
+
for (const e of entries) {
|
|
437
|
+
if (e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules") {
|
|
438
|
+
dirsToCheck.push(path.join(worktree, e.name));
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} catch {}
|
|
442
|
+
|
|
443
|
+
for (const dir of dirsToCheck.slice(0, 5)) {
|
|
444
|
+
for (const name of candidates) {
|
|
445
|
+
const p = path.join(dir, name);
|
|
446
|
+
if (fs.existsSync(p)) {
|
|
447
|
+
found.push(p);
|
|
448
|
+
break; // one per directory
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return found;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// ─── Format for LLM ───────────────────────────────────────────────────────────
|
|
457
|
+
|
|
458
|
+
export function formatContextForPrompt(result: ContextResult, worktree: string): string {
|
|
459
|
+
if (result.chunks.length === 0 && result.instruction_files.length === 0) return "";
|
|
460
|
+
|
|
461
|
+
const parts: string[] = [];
|
|
462
|
+
|
|
463
|
+
// Instruction files first (highest priority)
|
|
464
|
+
for (const instrPath of result.instruction_files) {
|
|
465
|
+
try {
|
|
466
|
+
const content = fs.readFileSync(instrPath, "utf-8").trim();
|
|
467
|
+
if (content) {
|
|
468
|
+
const rel = path.relative(worktree, instrPath);
|
|
469
|
+
parts.push(`<!-- Instructions from ${rel} -->\n${content}`);
|
|
470
|
+
}
|
|
471
|
+
} catch {}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Code chunks
|
|
475
|
+
if (result.chunks.length > 0) {
|
|
476
|
+
parts.push("## Relevant Codebase Context\n");
|
|
477
|
+
for (let i = 0; i < result.chunks.length; i++) {
|
|
478
|
+
const c = result.chunks[i];
|
|
479
|
+
const rel = path.relative(worktree, c.file_path);
|
|
480
|
+
const header = c.symbol_name
|
|
481
|
+
? `[${i + 1}] ${rel}:${c.start_line}-${c.end_line} (${c.symbol_type}: ${c.symbol_name})`
|
|
482
|
+
: `[${i + 1}] ${rel}:${c.start_line}-${c.end_line}`;
|
|
483
|
+
parts.push(`${header}\n\`\`\`${c.language || ""}\n${c.content.trim()}\n\`\`\``);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return parts.join("\n\n");
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
491
|
+
|
|
492
|
+
function extractSearchTerms(query: string): string[] {
|
|
493
|
+
// Extract meaningful identifiers and terms from the query
|
|
494
|
+
// Remove common English stop words, keep code identifiers
|
|
495
|
+
const stopWords = new Set([
|
|
496
|
+
"the", "a", "an", "is", "are", "was", "were", "be", "been", "being",
|
|
497
|
+
"have", "has", "had", "do", "does", "did", "will", "would", "could",
|
|
498
|
+
"should", "may", "might", "shall", "can", "need", "dare", "ought",
|
|
499
|
+
"used", "to", "of", "in", "for", "on", "with", "at", "by", "from",
|
|
500
|
+
"up", "about", "into", "through", "during", "before", "after",
|
|
501
|
+
"above", "below", "between", "out", "off", "over", "under",
|
|
502
|
+
"again", "further", "then", "once", "here", "there", "when",
|
|
503
|
+
"where", "why", "how", "all", "both", "each", "few", "more",
|
|
504
|
+
"most", "other", "some", "such", "no", "nor", "not", "only",
|
|
505
|
+
"own", "same", "so", "than", "too", "very", "just", "but",
|
|
506
|
+
"and", "or", "if", "as", "it", "its", "this", "that", "these",
|
|
507
|
+
"those", "i", "me", "my", "we", "our", "you", "your", "he", "she",
|
|
508
|
+
"him", "her", "they", "them", "what", "which", "who", "whom",
|
|
509
|
+
"implement", "create", "make", "build", "write", "add", "fix",
|
|
510
|
+
"update", "change", "modify", "use", "using", "get", "set",
|
|
511
|
+
"return", "returns", "function", "method", "class", "file",
|
|
512
|
+
"code", "please", "want", "need", "help", "show", "tell",
|
|
513
|
+
]);
|
|
514
|
+
|
|
515
|
+
return query
|
|
516
|
+
.toLowerCase()
|
|
517
|
+
.replace(/[^\w\s]/g, " ")
|
|
518
|
+
.split(/\s+/)
|
|
519
|
+
.filter(t => t.length >= 3 && !stopWords.has(t))
|
|
520
|
+
.filter((t, i, arr) => arr.indexOf(t) === i) // deduplicate
|
|
521
|
+
.slice(0, 8); // max 8 terms for FTS query
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
function findFirstTermMatch(lines: string[], terms: string[]): number {
|
|
525
|
+
if (terms.length === 0) return 0;
|
|
526
|
+
for (let i = 0; i < lines.length; i++) {
|
|
527
|
+
const lower = lines[i].toLowerCase();
|
|
528
|
+
if (terms.some(t => lower.includes(t))) return i;
|
|
529
|
+
}
|
|
530
|
+
return 0;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function extToLanguage(ext: string): string {
|
|
534
|
+
const map: Record<string, string> = {
|
|
535
|
+
".ts": "typescript", ".tsx": "typescript",
|
|
536
|
+
".js": "javascript", ".jsx": "javascript", ".mjs": "javascript",
|
|
537
|
+
".py": "python", ".go": "go", ".rs": "rust", ".java": "java",
|
|
538
|
+
".cs": "csharp", ".cpp": "cpp", ".c": "c", ".rb": "ruby",
|
|
539
|
+
".php": "php", ".swift": "swift", ".kt": "kotlin",
|
|
540
|
+
".md": "markdown", ".json": "json", ".yaml": "yaml", ".toml": "toml",
|
|
541
|
+
".sql": "sql", ".sh": "bash",
|
|
542
|
+
};
|
|
543
|
+
return map[ext.toLowerCase()] || "text";
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function extractImports(filePath: string): string[] {
|
|
547
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
548
|
+
const imports: string[] = [];
|
|
549
|
+
|
|
550
|
+
try {
|
|
551
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
552
|
+
|
|
553
|
+
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
554
|
+
// ES imports: import ... from "..."
|
|
555
|
+
const esImports = content.matchAll(/^import\s+.*?from\s+['"]([^'"]+)['"]/gm);
|
|
556
|
+
for (const m of esImports) imports.push(m[1]);
|
|
557
|
+
// require(): const x = require("...")
|
|
558
|
+
const requires = content.matchAll(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g);
|
|
559
|
+
for (const m of requires) imports.push(m[1]);
|
|
560
|
+
} else if (ext === ".py") {
|
|
561
|
+
const pyImports = content.matchAll(/^(?:from\s+(\S+)\s+import|import\s+(\S+))/gm);
|
|
562
|
+
for (const m of pyImports) imports.push((m[1] || m[2]).replace(/\./g, "/"));
|
|
563
|
+
} else if (ext === ".go") {
|
|
564
|
+
const goImports = content.matchAll(/"([^"]+)"/g);
|
|
565
|
+
for (const m of goImports) if (m[1].includes("/")) imports.push(m[1].split("/").slice(-1)[0]);
|
|
566
|
+
}
|
|
567
|
+
} catch {}
|
|
568
|
+
|
|
569
|
+
// Only keep relative imports (not node_modules)
|
|
570
|
+
return imports.filter(i => i.startsWith(".") || i.startsWith("/"));
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
function resolveImport(fromFile: string, importPath: string, worktree: string): string | null {
|
|
574
|
+
const dir = path.dirname(fromFile);
|
|
575
|
+
const base = path.isAbsolute(importPath) ? importPath : path.resolve(dir, importPath);
|
|
576
|
+
|
|
577
|
+
// Try with various extensions
|
|
578
|
+
const exts = ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"];
|
|
579
|
+
for (const ext of exts) {
|
|
580
|
+
const candidate = base + ext;
|
|
581
|
+
if (fs.existsSync(candidate) && candidate.startsWith(worktree)) {
|
|
582
|
+
return candidate;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return null;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
function trimToCharBudget(chunks: ContextChunk[], maxChars: number): ContextChunk[] {
|
|
589
|
+
const result: ContextChunk[] = [];
|
|
590
|
+
let total = 0;
|
|
591
|
+
for (const c of chunks) {
|
|
592
|
+
const size = c.content.length;
|
|
593
|
+
if (total + size > maxChars && result.length > 0) break;
|
|
594
|
+
result.push(c);
|
|
595
|
+
total += size;
|
|
596
|
+
}
|
|
597
|
+
return result;
|
|
598
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { sqliteTable, text, integer, primaryKey } from "drizzle-orm/sqlite-core"
|
|
2
|
+
|
|
3
|
+
import { type AccessToken, type AccountID, type OrgID, type RefreshToken } from "./schema"
|
|
4
|
+
import { Timestamps } from "../storage/schema.sql"
|
|
5
|
+
|
|
6
|
+
export const AccountTable = sqliteTable("account", {
|
|
7
|
+
id: text().$type<AccountID>().primaryKey(),
|
|
8
|
+
email: text().notNull(),
|
|
9
|
+
url: text().notNull(),
|
|
10
|
+
access_token: text().$type<AccessToken>().notNull(),
|
|
11
|
+
refresh_token: text().$type<RefreshToken>().notNull(),
|
|
12
|
+
token_expiry: integer(),
|
|
13
|
+
...Timestamps,
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
export const AccountStateTable = sqliteTable("account_state", {
|
|
17
|
+
id: integer().primaryKey(),
|
|
18
|
+
active_account_id: text()
|
|
19
|
+
.$type<AccountID>()
|
|
20
|
+
.references(() => AccountTable.id, { onDelete: "set null" }),
|
|
21
|
+
active_org_id: text().$type<OrgID>(),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// LEGACY
|
|
25
|
+
export const ControlAccountTable = sqliteTable(
|
|
26
|
+
"control_account",
|
|
27
|
+
{
|
|
28
|
+
email: text().notNull(),
|
|
29
|
+
url: text().notNull(),
|
|
30
|
+
access_token: text().$type<AccessToken>().notNull(),
|
|
31
|
+
refresh_token: text().$type<RefreshToken>().notNull(),
|
|
32
|
+
token_expiry: integer(),
|
|
33
|
+
active: integer({ mode: "boolean" })
|
|
34
|
+
.notNull()
|
|
35
|
+
.$default(() => false),
|
|
36
|
+
...Timestamps,
|
|
37
|
+
},
|
|
38
|
+
(table) => [primaryKey({ columns: [table.email, table.url] })],
|
|
39
|
+
)
|