bonecode 1.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +64 -50
- package/bone/output/agent/.dockerignore +7 -7
- package/bone/output/agent/.env.example +36 -36
- package/bone/output/agent/.github/workflows/ci.yaml +58 -58
- package/bone/output/agent/AgentDomain.bone.map +349 -349
- package/bone/output/agent/AgentDomain.postman_collection.json +957 -957
- package/bone/output/agent/Dockerfile +22 -22
- package/bone/output/agent/README.md +47 -47
- package/bone/output/agent/admin/index.html +739 -739
- package/bone/output/agent/docker-compose.yaml +22 -22
- package/bone/output/agent/k8s/deployment.yaml +75 -75
- package/bone/output/agent/migrations/agent.sql +36 -36
- package/bone/output/agent/migrations/agent_instance.sql +36 -36
- package/bone/output/agent/migrations/audit_log.sql +18 -18
- package/bone/output/agent/migrations/build_step.sql +34 -34
- package/bone/output/agent/migrations/event_outbox.sql +31 -31
- package/bone/output/agent/migrations/plan.sql +30 -30
- package/bone/output/agent/migrations/task.sql +30 -30
- package/bone/output/agent/migrations/tool_call.sql +33 -33
- package/bone/output/agent/openapi.yaml +1116 -1116
- package/bone/output/agent/package.json +35 -35
- package/bone/output/agent/schema.graphql +233 -233
- package/bone/output/agent/sdk/client.ts +231 -231
- package/bone/output/agent/src/algorithms.ts +2 -2
- package/bone/output/agent/src/audit.ts +44 -44
- package/bone/output/agent/src/auth.ts +57 -57
- package/bone/output/agent/src/cron.ts +12 -12
- package/bone/output/agent/src/db.ts +31 -31
- package/bone/output/agent/src/debug.ts +66 -66
- package/bone/output/agent/src/events.ts +243 -243
- package/bone/output/agent/src/extensions.ts +54 -54
- package/bone/output/agent/src/failure_rules.ts +322 -322
- package/bone/output/agent/src/flows.ts +168 -168
- package/bone/output/agent/src/health.ts +43 -43
- package/bone/output/agent/src/index.ts +99 -99
- package/bone/output/agent/src/logger.ts +69 -66
- package/bone/output/agent/src/metrics.ts +75 -75
- package/bone/output/agent/src/migrate.ts +351 -351
- package/bone/output/agent/src/migration_diff.ts +108 -108
- package/bone/output/agent/src/notify.ts +125 -125
- package/bone/output/agent/src/routes/plan.ts +91 -91
- package/bone/output/agent/src/routes/task.ts +105 -105
- package/bone/output/agent/src/routes/tool_call.ts +166 -166
- package/bone/output/agent/src/schemas.ts +384 -384
- package/bone/output/agent/src/state_machines/agent_instance.ts +24 -24
- package/bone/output/agent/src/state_machines/build_step.ts +22 -22
- package/bone/output/agent/src/state_machines/plan.ts +22 -22
- package/bone/output/agent/src/state_machines/task.ts +22 -22
- package/bone/output/agent/src/state_machines/tool_call.ts +22 -22
- package/bone/output/agent/src/tests.ts +361 -361
- package/bone/output/agent/src/websocket.ts +200 -200
- package/bone/output/agent/tsconfig.json +24 -24
- package/bone/output/rag/.dockerignore +7 -7
- package/bone/output/rag/.env.example +36 -36
- package/bone/output/rag/.github/workflows/ci.yaml +58 -58
- package/bone/output/rag/Dockerfile +22 -22
- package/bone/output/rag/RAGDomain.bone.map +286 -286
- package/bone/output/rag/RAGDomain.postman_collection.json +922 -922
- package/bone/output/rag/README.md +47 -47
- package/bone/output/rag/admin/index.html +817 -817
- package/bone/output/rag/docker-compose.yaml +22 -22
- package/bone/output/rag/k8s/deployment.yaml +75 -75
- package/bone/output/rag/migrations/audit_log.sql +18 -18
- package/bone/output/rag/migrations/code_chunk.sql +34 -34
- package/bone/output/rag/migrations/code_file.sql +33 -33
- package/bone/output/rag/migrations/event_outbox.sql +31 -31
- package/bone/output/rag/migrations/indexing_job.sql +33 -33
- package/bone/output/rag/migrations/knowledge_base.sql +35 -35
- package/bone/output/rag/migrations/memory_entry.sql +34 -34
- package/bone/output/rag/openapi.yaml +1097 -1097
- package/bone/output/rag/package.json +35 -35
- package/bone/output/rag/schema.graphql +245 -245
- package/bone/output/rag/sdk/client.ts +234 -234
- package/bone/output/rag/src/algorithms.ts +2 -2
- package/bone/output/rag/src/audit.ts +37 -37
- package/bone/output/rag/src/auth.ts +57 -57
- package/bone/output/rag/src/cron.ts +12 -12
- package/bone/output/rag/src/db.ts +31 -31
- package/bone/output/rag/src/debug.ts +66 -66
- package/bone/output/rag/src/events.ts +243 -243
- package/bone/output/rag/src/extensions.ts +350 -350
- package/bone/output/rag/src/failure_rules.ts +314 -314
- package/bone/output/rag/src/flows.ts +239 -239
- package/bone/output/rag/src/health.ts +43 -43
- package/bone/output/rag/src/index.ts +94 -94
- package/bone/output/rag/src/logger.ts +69 -66
- package/bone/output/rag/src/metrics.ts +75 -75
- package/bone/output/rag/src/migrate.ts +363 -363
- package/bone/output/rag/src/migration_diff.ts +108 -108
- package/bone/output/rag/src/notify.ts +99 -99
- package/bone/output/rag/src/routes/code_chunk.ts +75 -75
- package/bone/output/rag/src/routes/code_file.ts +101 -101
- package/bone/output/rag/src/routes/indexing_job.ts +87 -87
- package/bone/output/rag/src/routes/knowledge_base.ts +230 -230
- package/bone/output/rag/src/routes/memory_entry.ts +87 -87
- package/bone/output/rag/src/schemas.ts +394 -394
- package/bone/output/rag/src/state_machines/code_file.ts +23 -23
- package/bone/output/rag/src/state_machines/indexing_job.ts +22 -22
- package/bone/output/rag/src/state_machines/knowledge_base.ts +23 -23
- package/bone/output/rag/src/state_machines/memory_entry.ts +20 -20
- package/bone/output/rag/src/tests.ts +339 -339
- package/bone/output/rag/tsconfig.json +24 -24
- package/bone/output/session/.dockerignore +7 -7
- package/bone/output/session/.env.example +36 -36
- package/bone/output/session/.github/workflows/ci.yaml +58 -58
- package/bone/output/session/Dockerfile +22 -22
- package/bone/output/session/README.md +47 -47
- package/bone/output/session/SessionDomain.bone.map +349 -349
- package/bone/output/session/SessionDomain.postman_collection.json +957 -957
- package/bone/output/session/admin/index.html +666 -666
- package/bone/output/session/docker-compose.yaml +22 -22
- package/bone/output/session/k8s/deployment.yaml +75 -75
- package/bone/output/session/migrations/audit_log.sql +18 -18
- package/bone/output/session/migrations/event_outbox.sql +31 -31
- package/bone/output/session/migrations/message.sql +31 -31
- package/bone/output/session/migrations/part.sql +28 -28
- package/bone/output/session/migrations/permission.sql +28 -28
- package/bone/output/session/migrations/project.sql +28 -28
- package/bone/output/session/migrations/session.sql +38 -38
- package/bone/output/session/openapi.yaml +1101 -1101
- package/bone/output/session/package.json +35 -35
- package/bone/output/session/schema.graphql +222 -222
- package/bone/output/session/sdk/client.ts +225 -225
- package/bone/output/session/src/algorithms.ts +2 -2
- package/bone/output/session/src/audit.ts +44 -44
- package/bone/output/session/src/auth.ts +57 -57
- package/bone/output/session/src/cron.ts +12 -12
- package/bone/output/session/src/db.ts +31 -31
- package/bone/output/session/src/debug.ts +66 -66
- package/bone/output/session/src/events.ts +270 -270
- package/bone/output/session/src/extensions.ts +215 -215
- package/bone/output/session/src/failure_rules.ts +283 -283
- package/bone/output/session/src/flows.ts +168 -168
- package/bone/output/session/src/health.ts +43 -43
- package/bone/output/session/src/index.ts +99 -99
- package/bone/output/session/src/logger.ts +67 -66
- package/bone/output/session/src/metrics.ts +75 -75
- package/bone/output/session/src/migrate.ts +331 -331
- package/bone/output/session/src/migration_diff.ts +108 -108
- package/bone/output/session/src/notify.ts +112 -112
- package/bone/output/session/src/routes/message.ts +93 -93
- package/bone/output/session/src/routes/part.ts +79 -79
- package/bone/output/session/src/routes/permission.ts +79 -79
- package/bone/output/session/src/routes/project.ts +79 -79
- package/bone/output/session/src/routes/session.ts +294 -294
- package/bone/output/session/src/schemas.ts +357 -357
- package/bone/output/session/src/state_machines/session.ts +23 -23
- package/bone/output/session/src/tests.ts +325 -325
- package/bone/output/session/src/websocket.ts +223 -200
- package/bone/output/session/tsconfig.json +24 -24
- package/bone/output/workspace/.dockerignore +7 -7
- package/bone/output/workspace/.env.example +36 -36
- package/bone/output/workspace/.github/workflows/ci.yaml +58 -58
- package/bone/output/workspace/Dockerfile +22 -22
- package/bone/output/workspace/README.md +45 -45
- package/bone/output/workspace/WorkspaceDomain.bone.map +188 -188
- package/bone/output/workspace/WorkspaceDomain.postman_collection.json +620 -620
- package/bone/output/workspace/admin/index.html +484 -484
- package/bone/output/workspace/docker-compose.yaml +22 -22
- package/bone/output/workspace/k8s/deployment.yaml +75 -75
- package/bone/output/workspace/migrations/audit_log.sql +18 -18
- package/bone/output/workspace/migrations/codebase.sql +34 -34
- package/bone/output/workspace/migrations/event_outbox.sql +31 -31
- package/bone/output/workspace/migrations/snapshot.sql +32 -32
- package/bone/output/workspace/migrations/workspace.sql +33 -33
- package/bone/output/workspace/openapi.yaml +721 -721
- package/bone/output/workspace/package.json +35 -35
- package/bone/output/workspace/schema.graphql +153 -153
- package/bone/output/workspace/sdk/client.ts +155 -155
- package/bone/output/workspace/src/algorithms.ts +2 -2
- package/bone/output/workspace/src/audit.ts +37 -37
- package/bone/output/workspace/src/auth.ts +57 -57
- package/bone/output/workspace/src/cron.ts +12 -12
- package/bone/output/workspace/src/db.ts +31 -31
- package/bone/output/workspace/src/debug.ts +66 -66
- package/bone/output/workspace/src/events.ts +243 -243
- package/bone/output/workspace/src/extensions.ts +44 -44
- package/bone/output/workspace/src/failure_rules.ts +152 -152
- package/bone/output/workspace/src/health.ts +43 -43
- package/bone/output/workspace/src/index.ts +88 -88
- package/bone/output/workspace/src/logger.ts +69 -66
- package/bone/output/workspace/src/metrics.ts +75 -75
- package/bone/output/workspace/src/migrate.ts +219 -219
- package/bone/output/workspace/src/migration_diff.ts +108 -108
- package/bone/output/workspace/src/notify.ts +73 -73
- package/bone/output/workspace/src/routes/codebase.ts +87 -87
- package/bone/output/workspace/src/routes/snapshot.ts +127 -127
- package/bone/output/workspace/src/routes/workspace.ts +190 -190
- package/bone/output/workspace/src/schemas.ts +231 -231
- package/bone/output/workspace/src/state_machines/codebase.ts +21 -21
- package/bone/output/workspace/src/state_machines/snapshot.ts +20 -20
- package/bone/output/workspace/src/state_machines/workspace.ts +21 -21
- package/bone/output/workspace/src/tests.ts +248 -248
- package/bone/output/workspace/tsconfig.json +24 -24
- package/compat/opencode_adapter.ts +94 -17
- package/package.json +15 -2
- package/src/cli.ts +66 -107
- package/src/db_adapter.ts +354 -0
- package/src/engine/account/account.sql.ts +39 -39
- package/src/engine/account/account.ts +456 -456
- package/src/engine/account/repo.ts +166 -166
- package/src/engine/account/schema.ts +99 -99
- package/src/engine/account/url.ts +8 -8
- package/src/engine/acp/README.md +174 -174
- package/src/engine/acp/agent.ts +1968 -1968
- package/src/engine/acp/runtime.ts +22 -22
- package/src/engine/acp/session.ts +122 -122
- package/src/engine/acp/types.ts +24 -24
- package/src/engine/agent/agent.ts +463 -463
- package/src/engine/agent/generate.txt +75 -75
- package/src/engine/agent/prompt/compaction.txt +9 -9
- package/src/engine/agent/prompt/explore.txt +18 -18
- package/src/engine/agent/prompt/scout.txt +36 -36
- package/src/engine/agent/prompt/summary.txt +11 -11
- package/src/engine/agent/prompt/title.txt +44 -44
- package/src/engine/agent/subagent-permissions.ts +34 -34
- package/src/engine/auth/index.ts +96 -96
- package/src/engine/background/background/job.ts +200 -200
- package/src/engine/background/job.ts +200 -200
- package/src/engine/bus/bus-event.ts +45 -45
- package/src/engine/bus/global.ts +22 -22
- package/src/engine/bus/index.ts +203 -203
- package/src/engine/command/command/index.ts +181 -181
- package/src/engine/command/command/template/initialize.txt +66 -66
- package/src/engine/command/command/template/review.txt +101 -101
- package/src/engine/command/index.ts +181 -181
- package/src/engine/command/template/initialize.txt +66 -66
- package/src/engine/command/template/review.txt +101 -101
- package/src/engine/config/agent.ts +172 -172
- package/src/engine/config/attachment.ts +25 -25
- package/src/engine/config/command.ts +62 -62
- package/src/engine/config/config.ts +833 -833
- package/src/engine/config/console-state.ts +14 -14
- package/src/engine/config/entry-name.ts +16 -16
- package/src/engine/config/error.ts +23 -23
- package/src/engine/config/formatter.ts +13 -13
- package/src/engine/config/layout.ts +6 -6
- package/src/engine/config/lsp.ts +43 -43
- package/src/engine/config/managed.ts +71 -71
- package/src/engine/config/markdown.ts +96 -96
- package/src/engine/config/mcp.ts +56 -56
- package/src/engine/config/model-id.ts +5 -5
- package/src/engine/config/parse.ts +79 -79
- package/src/engine/config/paths.ts +45 -45
- package/src/engine/config/permission.ts +58 -58
- package/src/engine/config/plugin.ts +84 -84
- package/src/engine/config/provider.ts +111 -111
- package/src/engine/config/reference.ts +23 -23
- package/src/engine/config/server.ts +19 -19
- package/src/engine/config/skills.ts +14 -14
- package/src/engine/config/variable.ts +90 -90
- package/src/engine/control-plane/adapters/index.ts +41 -41
- package/src/engine/control-plane/adapters/worktree.ts +96 -96
- package/src/engine/control-plane/dev/README.md +19 -19
- package/src/engine/control-plane/dev/debug-workspace-plugin.ts +73 -73
- package/src/engine/control-plane/schema.ts +14 -14
- package/src/engine/control-plane/types.ts +59 -59
- package/src/engine/control-plane/util.ts +39 -39
- package/src/engine/control-plane/workspace-adapter-runtime.ts +51 -51
- package/src/engine/control-plane/workspace-context.ts +26 -26
- package/src/engine/control-plane/workspace.sql.ts +20 -20
- package/src/engine/control-plane/workspace.ts +1072 -1072
- package/src/engine/data-migration.ts +161 -161
- package/src/engine/effect/app-runtime.ts +143 -143
- package/src/engine/effect/bootstrap-runtime.ts +29 -29
- package/src/engine/effect/bridge.ts +84 -84
- package/src/engine/effect/config-service.ts +67 -67
- package/src/engine/effect/instance-ref.ts +11 -11
- package/src/engine/effect/instance-registry.ts +12 -12
- package/src/engine/effect/instance-state.ts +72 -72
- package/src/engine/effect/promise.ts +17 -17
- package/src/engine/effect/run-service.ts +47 -47
- package/src/engine/effect/runner.ts +217 -217
- package/src/engine/effect/runtime-flags.ts +74 -74
- package/src/engine/effect/service-use.ts +38 -38
- package/src/engine/env/index.ts +37 -37
- package/src/engine/event-v2-bridge.ts +89 -89
- package/src/engine/file/file/ignore.ts +81 -81
- package/src/engine/file/file/index.ts +651 -651
- package/src/engine/file/file/protected.ts +59 -59
- package/src/engine/file/file/ripgrep.ts +481 -481
- package/src/engine/file/file/watcher.ts +167 -167
- package/src/engine/file/ignore.ts +81 -81
- package/src/engine/file/index.ts +651 -651
- package/src/engine/file/protected.ts +59 -59
- package/src/engine/file/ripgrep.ts +481 -481
- package/src/engine/file/watcher.ts +167 -167
- package/src/engine/format/format/formatter.ts +404 -404
- package/src/engine/format/format/index.ts +209 -209
- package/src/engine/format/formatter.ts +404 -404
- package/src/engine/format/index.ts +209 -209
- package/src/engine/git/git/index.ts +347 -347
- package/src/engine/git/index.ts +347 -347
- package/src/engine/id/id.ts +80 -80
- package/src/engine/ide/index.ts +70 -70
- package/src/engine/image/image/image.ts +176 -176
- package/src/engine/image/image.ts +176 -176
- package/src/engine/index.ts +251 -251
- package/src/engine/installation/index.ts +327 -327
- package/src/engine/lsp/client.ts +707 -707
- package/src/engine/lsp/diagnostic.ts +29 -29
- package/src/engine/lsp/language.ts +121 -121
- package/src/engine/lsp/launch.ts +21 -21
- package/src/engine/lsp/lsp/client.ts +707 -707
- package/src/engine/lsp/lsp/diagnostic.ts +29 -29
- package/src/engine/lsp/lsp/language.ts +121 -121
- package/src/engine/lsp/lsp/launch.ts +21 -21
- package/src/engine/lsp/lsp/lsp.ts +507 -507
- package/src/engine/lsp/lsp/server.ts +2064 -2064
- package/src/engine/lsp/lsp.ts +507 -507
- package/src/engine/lsp/server.ts +2064 -2064
- package/src/engine/mcp/auth.ts +146 -146
- package/src/engine/mcp/index.ts +958 -958
- package/src/engine/mcp/mcp/auth.ts +146 -146
- package/src/engine/mcp/mcp/index.ts +958 -958
- package/src/engine/mcp/mcp/oauth-callback.ts +232 -232
- package/src/engine/mcp/mcp/oauth-provider.ts +214 -214
- package/src/engine/mcp/oauth-callback.ts +232 -232
- package/src/engine/mcp/oauth-provider.ts +214 -214
- package/src/engine/node.ts +6 -6
- package/src/engine/patch/index.ts +689 -689
- package/src/engine/patch/patch/index.ts +689 -689
- package/src/engine/permission/arity.ts +163 -163
- package/src/engine/permission/evaluate.ts +15 -15
- package/src/engine/permission/index.ts +306 -306
- package/src/engine/permission/permission/arity.ts +163 -163
- package/src/engine/permission/permission/evaluate.ts +15 -15
- package/src/engine/permission/permission/index.ts +306 -306
- package/src/engine/permission/permission/schema.ts +13 -13
- package/src/engine/permission/schema.ts +13 -13
- package/src/engine/plugin/azure.ts +26 -26
- package/src/engine/plugin/cloudflare.ts +76 -76
- package/src/engine/plugin/codex.ts +622 -622
- package/src/engine/plugin/digitalocean.ts +411 -411
- package/src/engine/plugin/github-copilot/copilot.ts +394 -394
- package/src/engine/plugin/github-copilot/models.ts +196 -196
- package/src/engine/plugin/index.ts +295 -295
- package/src/engine/plugin/install.ts +439 -439
- package/src/engine/plugin/loader.ts +216 -216
- package/src/engine/plugin/meta.ts +188 -188
- package/src/engine/plugin/shared.ts +323 -323
- package/src/engine/project/bootstrap-service.ts +9 -9
- package/src/engine/project/bootstrap.ts +75 -75
- package/src/engine/project/instance-context.ts +24 -24
- package/src/engine/project/instance-layer.ts +11 -11
- package/src/engine/project/instance-runtime.ts +16 -16
- package/src/engine/project/instance-store.ts +193 -193
- package/src/engine/project/project.sql.ts +17 -17
- package/src/engine/project/project.ts +537 -537
- package/src/engine/project/schema.ts +13 -13
- package/src/engine/project/vcs.ts +405 -405
- package/src/engine/provider/auth.ts +225 -225
- package/src/engine/provider/error.ts +204 -204
- package/src/engine/provider/model-status.ts +8 -8
- package/src/engine/provider/provider.ts +1843 -1843
- package/src/engine/provider/schema.ts +30 -30
- package/src/engine/provider/transform.ts +1376 -1376
- package/src/engine/pty/index.ts +365 -365
- package/src/engine/pty/input.ts +24 -24
- package/src/engine/pty/pty/index.ts +365 -365
- package/src/engine/pty/pty/input.ts +24 -24
- package/src/engine/pty/pty/pty.bun.ts +26 -26
- package/src/engine/pty/pty/pty.node.ts +27 -27
- package/src/engine/pty/pty/pty.ts +25 -25
- package/src/engine/pty/pty/schema.ts +14 -14
- package/src/engine/pty/pty/ticket.ts +68 -68
- package/src/engine/pty/pty.bun.ts +26 -26
- package/src/engine/pty/pty.node.ts +27 -27
- package/src/engine/pty/pty.ts +25 -25
- package/src/engine/pty/schema.ts +14 -14
- package/src/engine/pty/ticket.ts +68 -68
- package/src/engine/question/index.ts +213 -213
- package/src/engine/question/question/index.ts +213 -213
- package/src/engine/question/question/schema.ts +10 -10
- package/src/engine/question/schema.ts +10 -10
- package/src/engine/reference/reference/reference.ts +241 -241
- package/src/engine/reference/reference/repository-cache.ts +147 -147
- package/src/engine/reference/reference.ts +241 -241
- package/src/engine/reference/repository-cache.ts +147 -147
- package/src/engine/session/compaction.ts +651 -651
- package/src/engine/session/instruction.ts +238 -238
- package/src/engine/session/llm.ts +459 -459
- package/src/engine/session/message-error.ts +14 -14
- package/src/engine/session/message-v2.ts +1202 -1202
- package/src/engine/session/message.ts +146 -146
- package/src/engine/session/overflow.ts +32 -32
- package/src/engine/session/processor.ts +823 -823
- package/src/engine/session/prompt/anthropic.txt +105 -105
- package/src/engine/session/prompt/beast.txt +147 -147
- package/src/engine/session/prompt/build-switch.txt +5 -5
- package/src/engine/session/prompt/codex.txt +79 -79
- package/src/engine/session/prompt/copilot-gpt-5.txt +143 -143
- package/src/engine/session/prompt/default.txt +105 -105
- package/src/engine/session/prompt/gemini.txt +155 -155
- package/src/engine/session/prompt/gpt.txt +107 -107
- package/src/engine/session/prompt/kimi.txt +95 -95
- package/src/engine/session/prompt/max-steps.txt +15 -15
- package/src/engine/session/prompt/plan-reminder-anthropic.txt +67 -67
- package/src/engine/session/prompt/plan.txt +26 -26
- package/src/engine/session/prompt/trinity.txt +97 -97
- package/src/engine/session/prompt.ts +66 -9
- package/src/engine/session/retry.ts +200 -200
- package/src/engine/session/revert.ts +162 -162
- package/src/engine/session/run-state.ts +153 -153
- package/src/engine/session/schema.ts +26 -26
- package/src/engine/session/session.sql.ts +137 -137
- package/src/engine/session/session.ts +1011 -1011
- package/src/engine/session/status.ts +94 -94
- package/src/engine/session/summary.ts +164 -164
- package/src/engine/session/system.ts +84 -84
- package/src/engine/session/todo.ts +81 -81
- package/src/engine/share/session.ts +61 -61
- package/src/engine/share/share-next.ts +376 -376
- package/src/engine/share/share.sql.ts +13 -13
- package/src/engine/shell/shell/shell.ts +215 -215
- package/src/engine/shell/shell.ts +215 -215
- package/src/engine/skill/discovery.ts +116 -116
- package/src/engine/skill/index.ts +336 -336
- package/src/engine/skill/prompt/customize-opencode.md +377 -377
- package/src/engine/skill/skill/discovery.ts +116 -116
- package/src/engine/skill/skill/index.ts +336 -336
- package/src/engine/skill/skill/prompt/customize-opencode.md +377 -377
- package/src/engine/snapshot/index.ts +762 -762
- package/src/engine/snapshot/snapshot/index.ts +762 -762
- package/src/engine/sync/README.md +179 -179
- package/src/engine/sync/event.sql.ts +17 -17
- package/src/engine/sync/index.ts +410 -410
- package/src/engine/sync/schema.ts +11 -11
- package/src/engine/temporary.ts +33 -33
- package/src/engine/tool/apply_patch.ts +313 -313
- package/src/engine/tool/apply_patch.txt +33 -33
- package/src/engine/tool/edit.ts +711 -711
- package/src/engine/tool/edit.txt +10 -10
- package/src/engine/tool/external-directory.ts +49 -49
- package/src/engine/tool/glob.ts +103 -103
- package/src/engine/tool/glob.txt +6 -6
- package/src/engine/tool/grep.ts +156 -156
- package/src/engine/tool/grep.txt +8 -8
- package/src/engine/tool/invalid.ts +21 -21
- package/src/engine/tool/json-schema.ts +164 -164
- package/src/engine/tool/lsp.ts +113 -113
- package/src/engine/tool/lsp.txt +24 -24
- package/src/engine/tool/mcp-websearch.ts +96 -96
- package/src/engine/tool/plan-enter.txt +14 -14
- package/src/engine/tool/plan-exit.txt +13 -13
- package/src/engine/tool/plan.ts +78 -78
- package/src/engine/tool/question.ts +44 -44
- package/src/engine/tool/question.txt +10 -10
- package/src/engine/tool/read.ts +337 -337
- package/src/engine/tool/read.txt +14 -14
- package/src/engine/tool/registry.ts +472 -472
- package/src/engine/tool/repo_clone.ts +80 -80
- package/src/engine/tool/repo_clone.txt +5 -5
- package/src/engine/tool/repo_overview.ts +279 -279
- package/src/engine/tool/repo_overview.txt +4 -4
- package/src/engine/tool/schema.ts +14 -14
- package/src/engine/tool/shell/id.ts +19 -19
- package/src/engine/tool/shell/prompt.ts +295 -295
- package/src/engine/tool/shell/shell.txt +77 -77
- package/src/engine/tool/shell.ts +647 -647
- package/src/engine/tool/skill.ts +75 -75
- package/src/engine/tool/skill.txt +5 -5
- package/src/engine/tool/task.ts +337 -337
- package/src/engine/tool/task.txt +58 -58
- package/src/engine/tool/task_status.ts +179 -179
- package/src/engine/tool/task_status.txt +13 -13
- package/src/engine/tool/todo.ts +57 -57
- package/src/engine/tool/todowrite.txt +167 -167
- package/src/engine/tool/tool/apply_patch.ts +313 -313
- package/src/engine/tool/tool/apply_patch.txt +33 -33
- package/src/engine/tool/tool/edit.ts +711 -711
- package/src/engine/tool/tool/edit.txt +10 -10
- package/src/engine/tool/tool/external-directory.ts +49 -49
- package/src/engine/tool/tool/glob.ts +103 -103
- package/src/engine/tool/tool/glob.txt +6 -6
- package/src/engine/tool/tool/grep.ts +156 -156
- package/src/engine/tool/tool/grep.txt +8 -8
- package/src/engine/tool/tool/invalid.ts +21 -21
- package/src/engine/tool/tool/json-schema.ts +164 -164
- package/src/engine/tool/tool/lsp.ts +113 -113
- package/src/engine/tool/tool/lsp.txt +24 -24
- package/src/engine/tool/tool/mcp-websearch.ts +96 -96
- package/src/engine/tool/tool/plan-enter.txt +14 -14
- package/src/engine/tool/tool/plan-exit.txt +13 -13
- package/src/engine/tool/tool/plan.ts +78 -78
- package/src/engine/tool/tool/question.ts +44 -44
- package/src/engine/tool/tool/question.txt +10 -10
- package/src/engine/tool/tool/read.ts +337 -337
- package/src/engine/tool/tool/read.txt +14 -14
- package/src/engine/tool/tool/registry.ts +472 -472
- package/src/engine/tool/tool/repo_clone.ts +80 -80
- package/src/engine/tool/tool/repo_clone.txt +5 -5
- package/src/engine/tool/tool/repo_overview.ts +279 -279
- package/src/engine/tool/tool/repo_overview.txt +4 -4
- package/src/engine/tool/tool/schema.ts +14 -14
- package/src/engine/tool/tool/shell/id.ts +19 -19
- package/src/engine/tool/tool/shell/prompt.ts +295 -295
- package/src/engine/tool/tool/shell/shell.txt +77 -77
- package/src/engine/tool/tool/shell.ts +647 -647
- package/src/engine/tool/tool/skill.ts +75 -75
- package/src/engine/tool/tool/skill.txt +5 -5
- package/src/engine/tool/tool/task.ts +337 -337
- package/src/engine/tool/tool/task.txt +58 -58
- package/src/engine/tool/tool/task_status.ts +179 -179
- package/src/engine/tool/tool/task_status.txt +13 -13
- package/src/engine/tool/tool/todo.ts +57 -57
- package/src/engine/tool/tool/todowrite.txt +167 -167
- package/src/engine/tool/tool/tool.ts +164 -164
- package/src/engine/tool/tool/truncate.ts +160 -160
- package/src/engine/tool/tool/truncation-dir.ts +4 -4
- package/src/engine/tool/tool/webfetch.ts +192 -192
- package/src/engine/tool/tool/webfetch.txt +13 -13
- package/src/engine/tool/tool/websearch.ts +143 -143
- package/src/engine/tool/tool/websearch.txt +14 -14
- package/src/engine/tool/tool/write.ts +104 -104
- package/src/engine/tool/tool/write.txt +8 -8
- package/src/engine/tool/tool.ts +164 -164
- package/src/engine/tool/truncate.ts +160 -160
- package/src/engine/tool/truncation-dir.ts +4 -4
- package/src/engine/tool/webfetch.ts +192 -192
- package/src/engine/tool/webfetch.txt +13 -13
- package/src/engine/tool/websearch.ts +143 -143
- package/src/engine/tool/websearch.txt +14 -14
- package/src/engine/tool/write.ts +104 -104
- package/src/engine/tool/write.txt +8 -8
- package/src/engine/util/archive.ts +17 -17
- package/src/engine/util/bom.ts +31 -31
- package/src/engine/util/data-url.ts +9 -9
- package/src/engine/util/defer.ts +10 -10
- package/src/engine/util/effect-http-client.ts +11 -11
- package/src/engine/util/error.ts +88 -88
- package/src/engine/util/filesystem.ts +252 -252
- package/src/engine/util/format.ts +20 -20
- package/src/engine/util/iife.ts +3 -3
- package/src/engine/util/lazy.ts +20 -20
- package/src/engine/util/local-context.ts +25 -25
- package/src/engine/util/locale.ts +86 -86
- package/src/engine/util/media.ts +26 -26
- package/src/engine/util/process.ts +176 -176
- package/src/engine/util/queue.ts +32 -32
- package/src/engine/util/record.ts +3 -3
- package/src/engine/util/repository.ts +158 -158
- package/src/engine/util/rpc.ts +66 -66
- package/src/engine/util/signal.ts +12 -12
- package/src/engine/util/timeout.ts +13 -13
- package/src/engine/util/token.ts +7 -7
- package/src/engine/util/util/archive.ts +17 -17
- package/src/engine/util/util/bom.ts +31 -31
- package/src/engine/util/util/data-url.ts +9 -9
- package/src/engine/util/util/defer.ts +10 -10
- package/src/engine/util/util/effect-http-client.ts +11 -11
- package/src/engine/util/util/error.ts +88 -88
- package/src/engine/util/util/filesystem.ts +252 -252
- package/src/engine/util/util/format.ts +20 -20
- package/src/engine/util/util/iife.ts +3 -3
- package/src/engine/util/util/lazy.ts +20 -20
- package/src/engine/util/util/local-context.ts +25 -25
- package/src/engine/util/util/locale.ts +86 -86
- package/src/engine/util/util/media.ts +26 -26
- package/src/engine/util/util/process.ts +176 -176
- package/src/engine/util/util/queue.ts +32 -32
- package/src/engine/util/util/record.ts +3 -3
- package/src/engine/util/util/repository.ts +158 -158
- package/src/engine/util/util/rpc.ts +66 -66
- package/src/engine/util/util/signal.ts +12 -12
- package/src/engine/util/util/timeout.ts +13 -13
- package/src/engine/util/util/token.ts +7 -7
- package/src/engine/util/util/which.ts +14 -14
- package/src/engine/util/util/wildcard.ts +59 -59
- package/src/engine/util/which.ts +14 -14
- package/src/engine/util/wildcard.ts +59 -59
- package/src/engine/worktree/index.ts +621 -621
- package/src/server.ts +121 -158
- package/src/tui.ts +485 -502
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
-
// Migration diff utility — compares two IR snapshots and produces ALTER statements.
|
|
3
|
-
|
|
4
|
-
import * as fs from "fs";
|
|
5
|
-
|
|
6
|
-
interface Field {
|
|
7
|
-
name: string;
|
|
8
|
-
type: string;
|
|
9
|
-
nullable: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface Model {
|
|
13
|
-
name: string;
|
|
14
|
-
fields: Field[];
|
|
15
|
-
primary_key: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function diffModels(oldModels: Model[], newModels: Model[]): string[] {
|
|
19
|
-
const statements: string[] = [];
|
|
20
|
-
const oldByName = new Map(oldModels.map(m => [m.name, m]));
|
|
21
|
-
const newByName = new Map(newModels.map(m => [m.name, m]));
|
|
22
|
-
|
|
23
|
-
// New tables
|
|
24
|
-
for (const [name, model] of newByName) {
|
|
25
|
-
if (!oldByName.has(name)) {
|
|
26
|
-
const tableName = toSnake(name) + "s";
|
|
27
|
-
statements.push(`-- New table: ${tableName}`);
|
|
28
|
-
statements.push(`-- (Generated by previous migration)`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Removed tables (warn but don't auto-drop)
|
|
33
|
-
for (const [name] of oldByName) {
|
|
34
|
-
if (!newByName.has(name)) {
|
|
35
|
-
const tableName = toSnake(name) + "s";
|
|
36
|
-
statements.push(`-- WARNING: Table ${tableName} no longer in schema. Manual DROP required.`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Modified tables
|
|
41
|
-
for (const [name, newModel] of newByName) {
|
|
42
|
-
const oldModel = oldByName.get(name);
|
|
43
|
-
if (!oldModel) continue;
|
|
44
|
-
|
|
45
|
-
const tableName = toSnake(name) + "s";
|
|
46
|
-
const oldFields = new Map(oldModel.fields.map(f => [f.name, f]));
|
|
47
|
-
const newFields = new Map(newModel.fields.map(f => [f.name, f]));
|
|
48
|
-
|
|
49
|
-
// New columns (backward-compatible)
|
|
50
|
-
for (const [fname, field] of newFields) {
|
|
51
|
-
if (!oldFields.has(fname)) {
|
|
52
|
-
const sqlType = mapType(field.type);
|
|
53
|
-
const nullability = field.nullable ? "" : " NOT NULL DEFAULT (CASE WHEN false THEN NULL ELSE NULL END)";
|
|
54
|
-
statements.push(`ALTER TABLE ${tableName} ADD COLUMN ${fname} ${sqlType}${nullability};`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Removed columns (NOT auto-dropped — backward compat)
|
|
59
|
-
for (const [fname] of oldFields) {
|
|
60
|
-
if (!newFields.has(fname)) {
|
|
61
|
-
statements.push(`-- WARNING: Column ${tableName}.${fname} removed from schema. Run manually: ALTER TABLE ${tableName} DROP COLUMN ${fname};`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Type changes
|
|
66
|
-
for (const [fname, newField] of newFields) {
|
|
67
|
-
const oldField = oldFields.get(fname);
|
|
68
|
-
if (!oldField) continue;
|
|
69
|
-
if (oldField.type !== newField.type) {
|
|
70
|
-
const sqlType = mapType(newField.type);
|
|
71
|
-
statements.push(`ALTER TABLE ${tableName} ALTER COLUMN ${fname} TYPE ${sqlType};`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return statements;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function toSnake(s: string): string {
|
|
80
|
-
return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function mapType(t: string): string {
|
|
84
|
-
const map: Record<string, string> = {
|
|
85
|
-
string: "VARCHAR", uint: "BIGINT", int: "BIGINT", float: "DOUBLE PRECISION",
|
|
86
|
-
bool: "BOOLEAN", timestamp: "TIMESTAMPTZ", uuid: "UUID", bytes: "BYTEA", json: "JSONB",
|
|
87
|
-
};
|
|
88
|
-
return map[t] || "JSONB";
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (require.main === module) {
|
|
92
|
-
const oldFile = process.argv[2];
|
|
93
|
-
const newFile = process.argv[3];
|
|
94
|
-
if (!oldFile || !newFile) {
|
|
95
|
-
console.error("Usage: node migration-diff.js <old-ir.json> <new-ir.json>");
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}
|
|
98
|
-
const oldIR = JSON.parse(fs.readFileSync(oldFile, "utf-8"));
|
|
99
|
-
const newIR = JSON.parse(fs.readFileSync(newFile, "utf-8"));
|
|
100
|
-
|
|
101
|
-
const oldModels: Model[] = [];
|
|
102
|
-
const newModels: Model[] = [];
|
|
103
|
-
for (const sys of oldIR) for (const mod of sys.modules) for (const m of mod.models) oldModels.push(m);
|
|
104
|
-
for (const sys of newIR) for (const mod of sys.modules) for (const m of mod.models) newModels.push(m);
|
|
105
|
-
|
|
106
|
-
const diff = diffModels(oldModels, newModels);
|
|
107
|
-
console.log(diff.join("\n"));
|
|
108
|
-
}
|
|
1
|
+
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
+
// Migration diff utility — compares two IR snapshots and produces ALTER statements.
|
|
3
|
+
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
|
|
6
|
+
interface Field {
|
|
7
|
+
name: string;
|
|
8
|
+
type: string;
|
|
9
|
+
nullable: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Model {
|
|
13
|
+
name: string;
|
|
14
|
+
fields: Field[];
|
|
15
|
+
primary_key: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function diffModels(oldModels: Model[], newModels: Model[]): string[] {
|
|
19
|
+
const statements: string[] = [];
|
|
20
|
+
const oldByName = new Map(oldModels.map(m => [m.name, m]));
|
|
21
|
+
const newByName = new Map(newModels.map(m => [m.name, m]));
|
|
22
|
+
|
|
23
|
+
// New tables
|
|
24
|
+
for (const [name, model] of newByName) {
|
|
25
|
+
if (!oldByName.has(name)) {
|
|
26
|
+
const tableName = toSnake(name) + "s";
|
|
27
|
+
statements.push(`-- New table: ${tableName}`);
|
|
28
|
+
statements.push(`-- (Generated by previous migration)`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Removed tables (warn but don't auto-drop)
|
|
33
|
+
for (const [name] of oldByName) {
|
|
34
|
+
if (!newByName.has(name)) {
|
|
35
|
+
const tableName = toSnake(name) + "s";
|
|
36
|
+
statements.push(`-- WARNING: Table ${tableName} no longer in schema. Manual DROP required.`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Modified tables
|
|
41
|
+
for (const [name, newModel] of newByName) {
|
|
42
|
+
const oldModel = oldByName.get(name);
|
|
43
|
+
if (!oldModel) continue;
|
|
44
|
+
|
|
45
|
+
const tableName = toSnake(name) + "s";
|
|
46
|
+
const oldFields = new Map(oldModel.fields.map(f => [f.name, f]));
|
|
47
|
+
const newFields = new Map(newModel.fields.map(f => [f.name, f]));
|
|
48
|
+
|
|
49
|
+
// New columns (backward-compatible)
|
|
50
|
+
for (const [fname, field] of newFields) {
|
|
51
|
+
if (!oldFields.has(fname)) {
|
|
52
|
+
const sqlType = mapType(field.type);
|
|
53
|
+
const nullability = field.nullable ? "" : " NOT NULL DEFAULT (CASE WHEN false THEN NULL ELSE NULL END)";
|
|
54
|
+
statements.push(`ALTER TABLE ${tableName} ADD COLUMN ${fname} ${sqlType}${nullability};`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Removed columns (NOT auto-dropped — backward compat)
|
|
59
|
+
for (const [fname] of oldFields) {
|
|
60
|
+
if (!newFields.has(fname)) {
|
|
61
|
+
statements.push(`-- WARNING: Column ${tableName}.${fname} removed from schema. Run manually: ALTER TABLE ${tableName} DROP COLUMN ${fname};`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Type changes
|
|
66
|
+
for (const [fname, newField] of newFields) {
|
|
67
|
+
const oldField = oldFields.get(fname);
|
|
68
|
+
if (!oldField) continue;
|
|
69
|
+
if (oldField.type !== newField.type) {
|
|
70
|
+
const sqlType = mapType(newField.type);
|
|
71
|
+
statements.push(`ALTER TABLE ${tableName} ALTER COLUMN ${fname} TYPE ${sqlType};`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return statements;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function toSnake(s: string): string {
|
|
80
|
+
return s.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function mapType(t: string): string {
|
|
84
|
+
const map: Record<string, string> = {
|
|
85
|
+
string: "VARCHAR", uint: "BIGINT", int: "BIGINT", float: "DOUBLE PRECISION",
|
|
86
|
+
bool: "BOOLEAN", timestamp: "TIMESTAMPTZ", uuid: "UUID", bytes: "BYTEA", json: "JSONB",
|
|
87
|
+
};
|
|
88
|
+
return map[t] || "JSONB";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (require.main === module) {
|
|
92
|
+
const oldFile = process.argv[2];
|
|
93
|
+
const newFile = process.argv[3];
|
|
94
|
+
if (!oldFile || !newFile) {
|
|
95
|
+
console.error("Usage: node migration-diff.js <old-ir.json> <new-ir.json>");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const oldIR = JSON.parse(fs.readFileSync(oldFile, "utf-8"));
|
|
99
|
+
const newIR = JSON.parse(fs.readFileSync(newFile, "utf-8"));
|
|
100
|
+
|
|
101
|
+
const oldModels: Model[] = [];
|
|
102
|
+
const newModels: Model[] = [];
|
|
103
|
+
for (const sys of oldIR) for (const mod of sys.modules) for (const m of mod.models) oldModels.push(m);
|
|
104
|
+
for (const sys of newIR) for (const mod of sys.modules) for (const m of mod.models) newModels.push(m);
|
|
105
|
+
|
|
106
|
+
const diff = diffModels(oldModels, newModels);
|
|
107
|
+
console.log(diff.join("\n"));
|
|
108
|
+
}
|
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
// Generated by BoneScript compiler.
|
|
2
|
-
// Notification service — fires on event emissions.
|
|
3
|
-
// Configure NOTIFY_PROVIDER=resend|sendgrid|log (default: log)
|
|
4
|
-
// Set NOTIFY_API_KEY and NOTIFY_FROM_EMAIL in .env
|
|
5
|
-
|
|
6
|
-
import { SystemEvent } from "./events";
|
|
7
|
-
|
|
8
|
-
export type NotifyProvider = "resend" | "sendgrid" | "log";
|
|
9
|
-
|
|
10
|
-
const PROVIDER = (process.env.NOTIFY_PROVIDER || "log") as NotifyProvider;
|
|
11
|
-
const API_KEY = process.env.NOTIFY_API_KEY || "";
|
|
12
|
-
const FROM_EMAIL = process.env.NOTIFY_FROM_EMAIL || "noreply@example.com";
|
|
13
|
-
|
|
14
|
-
export interface NotifyMessage {
|
|
15
|
-
to: string;
|
|
16
|
-
subject: string;
|
|
17
|
-
body: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function sendEmail(msg: NotifyMessage): Promise<void> {
|
|
21
|
-
if (PROVIDER === "log") {
|
|
22
|
-
console.log(`[notify] ${msg.subject} → ${msg.to}`);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (PROVIDER === "resend") {
|
|
26
|
-
const res = await fetch("https://api.resend.com/emails", {
|
|
27
|
-
method: "POST",
|
|
28
|
-
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
|
|
29
|
-
body: JSON.stringify({ from: FROM_EMAIL, to: msg.to, subject: msg.subject, html: msg.body }),
|
|
30
|
-
});
|
|
31
|
-
if (!res.ok) throw new Error(`Resend error: ${res.status}`);
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (PROVIDER === "sendgrid") {
|
|
35
|
-
const res = await fetch("https://api.sendgrid.com/v3/mail/send", {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
|
|
38
|
-
body: JSON.stringify({ personalizations: [{ to: [{ email: msg.to }] }], from: { email: FROM_EMAIL }, subject: msg.subject, content: [{ type: "text/html", value: msg.body }] }),
|
|
39
|
-
});
|
|
40
|
-
if (!res.ok) throw new Error(`SendGrid error: ${res.status}`);
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Handler for AgentStarted
|
|
46
|
-
export async function notifyAgentStarted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
47
|
-
await sendEmail({
|
|
48
|
-
to: recipientEmail,
|
|
49
|
-
subject: "AgentStarted notification",
|
|
50
|
-
body: `<p>Event <strong>AgentStarted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Handler for AgentCompleted
|
|
55
|
-
export async function notifyAgentCompleted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
56
|
-
await sendEmail({
|
|
57
|
-
to: recipientEmail,
|
|
58
|
-
subject: "AgentCompleted notification",
|
|
59
|
-
body: `<p>Event <strong>AgentCompleted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Handler for AgentFailed
|
|
64
|
-
export async function notifyAgentFailed(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
65
|
-
await sendEmail({
|
|
66
|
-
to: recipientEmail,
|
|
67
|
-
subject: "AgentFailed notification",
|
|
68
|
-
body: `<p>Event <strong>AgentFailed</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Handler for ToolCallRequested
|
|
73
|
-
export async function notifyToolCallRequested(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
74
|
-
await sendEmail({
|
|
75
|
-
to: recipientEmail,
|
|
76
|
-
subject: "ToolCallRequested notification",
|
|
77
|
-
body: `<p>Event <strong>ToolCallRequested</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Handler for ToolCallCompleted
|
|
82
|
-
export async function notifyToolCallCompleted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
83
|
-
await sendEmail({
|
|
84
|
-
to: recipientEmail,
|
|
85
|
-
subject: "ToolCallCompleted notification",
|
|
86
|
-
body: `<p>Event <strong>ToolCallCompleted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Handler for PermissionRequired
|
|
91
|
-
export async function notifyPermissionRequired(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
92
|
-
await sendEmail({
|
|
93
|
-
to: recipientEmail,
|
|
94
|
-
subject: "PermissionRequired notification",
|
|
95
|
-
body: `<p>Event <strong>PermissionRequired</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function registerNotificationHandlers(eventBus: any): void {
|
|
100
|
-
// TODO: implement recipient lookup per event type
|
|
101
|
-
// eventBus.subscribe("AgentStarted", async (event: SystemEvent) => {
|
|
102
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
103
|
-
// await notifyAgentStarted(event, recipientEmail);
|
|
104
|
-
// });
|
|
105
|
-
// eventBus.subscribe("AgentCompleted", async (event: SystemEvent) => {
|
|
106
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
107
|
-
// await notifyAgentCompleted(event, recipientEmail);
|
|
108
|
-
// });
|
|
109
|
-
// eventBus.subscribe("AgentFailed", async (event: SystemEvent) => {
|
|
110
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
111
|
-
// await notifyAgentFailed(event, recipientEmail);
|
|
112
|
-
// });
|
|
113
|
-
// eventBus.subscribe("ToolCallRequested", async (event: SystemEvent) => {
|
|
114
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
115
|
-
// await notifyToolCallRequested(event, recipientEmail);
|
|
116
|
-
// });
|
|
117
|
-
// eventBus.subscribe("ToolCallCompleted", async (event: SystemEvent) => {
|
|
118
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
119
|
-
// await notifyToolCallCompleted(event, recipientEmail);
|
|
120
|
-
// });
|
|
121
|
-
// eventBus.subscribe("PermissionRequired", async (event: SystemEvent) => {
|
|
122
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
123
|
-
// await notifyPermissionRequired(event, recipientEmail);
|
|
124
|
-
// });
|
|
125
|
-
}
|
|
1
|
+
// Generated by BoneScript compiler.
|
|
2
|
+
// Notification service — fires on event emissions.
|
|
3
|
+
// Configure NOTIFY_PROVIDER=resend|sendgrid|log (default: log)
|
|
4
|
+
// Set NOTIFY_API_KEY and NOTIFY_FROM_EMAIL in .env
|
|
5
|
+
|
|
6
|
+
import { SystemEvent } from "./events";
|
|
7
|
+
|
|
8
|
+
export type NotifyProvider = "resend" | "sendgrid" | "log";
|
|
9
|
+
|
|
10
|
+
const PROVIDER = (process.env.NOTIFY_PROVIDER || "log") as NotifyProvider;
|
|
11
|
+
const API_KEY = process.env.NOTIFY_API_KEY || "";
|
|
12
|
+
const FROM_EMAIL = process.env.NOTIFY_FROM_EMAIL || "noreply@example.com";
|
|
13
|
+
|
|
14
|
+
export interface NotifyMessage {
|
|
15
|
+
to: string;
|
|
16
|
+
subject: string;
|
|
17
|
+
body: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function sendEmail(msg: NotifyMessage): Promise<void> {
|
|
21
|
+
if (PROVIDER === "log") {
|
|
22
|
+
console.log(`[notify] ${msg.subject} → ${msg.to}`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (PROVIDER === "resend") {
|
|
26
|
+
const res = await fetch("https://api.resend.com/emails", {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
|
|
29
|
+
body: JSON.stringify({ from: FROM_EMAIL, to: msg.to, subject: msg.subject, html: msg.body }),
|
|
30
|
+
});
|
|
31
|
+
if (!res.ok) throw new Error(`Resend error: ${res.status}`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (PROVIDER === "sendgrid") {
|
|
35
|
+
const res = await fetch("https://api.sendgrid.com/v3/mail/send", {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({ personalizations: [{ to: [{ email: msg.to }] }], from: { email: FROM_EMAIL }, subject: msg.subject, content: [{ type: "text/html", value: msg.body }] }),
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok) throw new Error(`SendGrid error: ${res.status}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Handler for AgentStarted
|
|
46
|
+
export async function notifyAgentStarted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
47
|
+
await sendEmail({
|
|
48
|
+
to: recipientEmail,
|
|
49
|
+
subject: "AgentStarted notification",
|
|
50
|
+
body: `<p>Event <strong>AgentStarted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handler for AgentCompleted
|
|
55
|
+
export async function notifyAgentCompleted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
56
|
+
await sendEmail({
|
|
57
|
+
to: recipientEmail,
|
|
58
|
+
subject: "AgentCompleted notification",
|
|
59
|
+
body: `<p>Event <strong>AgentCompleted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handler for AgentFailed
|
|
64
|
+
export async function notifyAgentFailed(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
65
|
+
await sendEmail({
|
|
66
|
+
to: recipientEmail,
|
|
67
|
+
subject: "AgentFailed notification",
|
|
68
|
+
body: `<p>Event <strong>AgentFailed</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Handler for ToolCallRequested
|
|
73
|
+
export async function notifyToolCallRequested(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
74
|
+
await sendEmail({
|
|
75
|
+
to: recipientEmail,
|
|
76
|
+
subject: "ToolCallRequested notification",
|
|
77
|
+
body: `<p>Event <strong>ToolCallRequested</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Handler for ToolCallCompleted
|
|
82
|
+
export async function notifyToolCallCompleted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
83
|
+
await sendEmail({
|
|
84
|
+
to: recipientEmail,
|
|
85
|
+
subject: "ToolCallCompleted notification",
|
|
86
|
+
body: `<p>Event <strong>ToolCallCompleted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Handler for PermissionRequired
|
|
91
|
+
export async function notifyPermissionRequired(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
92
|
+
await sendEmail({
|
|
93
|
+
to: recipientEmail,
|
|
94
|
+
subject: "PermissionRequired notification",
|
|
95
|
+
body: `<p>Event <strong>PermissionRequired</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function registerNotificationHandlers(eventBus: any): void {
|
|
100
|
+
// TODO: implement recipient lookup per event type
|
|
101
|
+
// eventBus.subscribe("AgentStarted", async (event: SystemEvent) => {
|
|
102
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
103
|
+
// await notifyAgentStarted(event, recipientEmail);
|
|
104
|
+
// });
|
|
105
|
+
// eventBus.subscribe("AgentCompleted", async (event: SystemEvent) => {
|
|
106
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
107
|
+
// await notifyAgentCompleted(event, recipientEmail);
|
|
108
|
+
// });
|
|
109
|
+
// eventBus.subscribe("AgentFailed", async (event: SystemEvent) => {
|
|
110
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
111
|
+
// await notifyAgentFailed(event, recipientEmail);
|
|
112
|
+
// });
|
|
113
|
+
// eventBus.subscribe("ToolCallRequested", async (event: SystemEvent) => {
|
|
114
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
115
|
+
// await notifyToolCallRequested(event, recipientEmail);
|
|
116
|
+
// });
|
|
117
|
+
// eventBus.subscribe("ToolCallCompleted", async (event: SystemEvent) => {
|
|
118
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
119
|
+
// await notifyToolCallCompleted(event, recipientEmail);
|
|
120
|
+
// });
|
|
121
|
+
// eventBus.subscribe("PermissionRequired", async (event: SystemEvent) => {
|
|
122
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
123
|
+
// await notifyPermissionRequired(event, recipientEmail);
|
|
124
|
+
// });
|
|
125
|
+
}
|
|
@@ -1,91 +1,91 @@
|
|
|
1
|
-
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
-
// Service: PlanService
|
|
3
|
-
import { Router, Request, Response } from "express";
|
|
4
|
-
import { v4 as uuid } from "uuid";
|
|
5
|
-
import { query, queryOne, execute, pool } from "../db";
|
|
6
|
-
import { eventBus } from "../events";
|
|
7
|
-
import { requireAuth, AuthContext } from "../auth";
|
|
8
|
-
import rateLimit from "express-rate-limit";
|
|
9
|
-
import { auditLog } from "../audit";
|
|
10
|
-
import { logger } from "../logger";
|
|
11
|
-
import { counter } from "../metrics";
|
|
12
|
-
import * as __algorithms from "../algorithms";
|
|
13
|
-
const { shortestPath, topologicalSort, binarySearch, bipartiteMatching, roundRobin, weightedAverage, percentile, rankBy, consistentHash } = __algorithms as any;
|
|
14
|
-
|
|
15
|
-
import { transitionPlan, PLAN_INITIAL } from "../state_machines/plan";
|
|
16
|
-
|
|
17
|
-
export const plansRouter = Router();
|
|
18
|
-
|
|
19
|
-
// Rate limiter from policy declaration
|
|
20
|
-
const __routeRateLimit = rateLimit({ windowMs: 60000, max: 200, standardHeaders: true, legacyHeaders: false });
|
|
21
|
-
|
|
22
|
-
// CREATE
|
|
23
|
-
plansRouter.post("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
24
|
-
try {
|
|
25
|
-
const id = uuid();
|
|
26
|
-
const { session_id, agent_id, task_id, steps, rationale, estimated_tokens } = req.body;
|
|
27
|
-
const state = PLAN_INITIAL;
|
|
28
|
-
const sql = `INSERT INTO plans (id, session_id, agent_id, task_id, steps, rationale, estimated_tokens, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`;
|
|
29
|
-
const rows = await query(sql, [id, session_id, agent_id, task_id, steps, rationale, estimated_tokens, state]);
|
|
30
|
-
counter("entity.created", { entity: "Plan" });
|
|
31
|
-
res.status(201).json(rows[0]);
|
|
32
|
-
} catch (e: any) {
|
|
33
|
-
res.status(400).json({ error: { code: "CREATE_FAILED", message: e.message } });
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
// READ
|
|
38
|
-
plansRouter.get("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
39
|
-
try {
|
|
40
|
-
const row = await queryOne(`SELECT * FROM plans WHERE id = $1`, [req.params.id]);
|
|
41
|
-
if (!row) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
42
|
-
res.json(row);
|
|
43
|
-
} catch (e: any) {
|
|
44
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// LIST
|
|
49
|
-
plansRouter.get("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
50
|
-
try {
|
|
51
|
-
const page = parseInt(req.query.page as string) || 1;
|
|
52
|
-
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
53
|
-
const offset = (page - 1) * pageSize;
|
|
54
|
-
const rows = await query(`SELECT * FROM plans ORDER BY created_at DESC LIMIT $1 OFFSET $2`, [pageSize, offset]);
|
|
55
|
-
const [{ count }] = await query(`SELECT COUNT(*) as count FROM plans`);
|
|
56
|
-
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
57
|
-
} catch (e: any) {
|
|
58
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// UPDATE
|
|
63
|
-
plansRouter.put("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
64
|
-
const fields = { ...req.body };
|
|
65
|
-
// State machine enforcement
|
|
66
|
-
if (fields.state !== undefined) {
|
|
67
|
-
const current = await queryOne<{ state: string }>(`SELECT state FROM plans WHERE id = $1`, [req.params.id]);
|
|
68
|
-
if (!current) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
69
|
-
// Find the trigger for this state transition
|
|
70
|
-
const trigger = `${current.state}_to_${fields.state}`;
|
|
71
|
-
const tr = transitionPlan(current.state as any, trigger);
|
|
72
|
-
if (!tr.ok) return res.status(422).json({ error: { code: "INVALID_TRANSITION", message: `Cannot transition from ${current.state} to ${fields.state}` } });
|
|
73
|
-
}
|
|
74
|
-
const sets = Object.keys(fields).map((k, i) => `${k} = $${i + 2}`).join(", ");
|
|
75
|
-
const values = Object.values(fields);
|
|
76
|
-
const sql = `UPDATE plans SET ${sets}, updated_at = NOW() WHERE id = $1 RETURNING *`;
|
|
77
|
-
const rows = await query(sql, [req.params.id, ...values]);
|
|
78
|
-
if (rows.length === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
79
|
-
res.json(rows[0]);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// DELETE
|
|
83
|
-
plansRouter.delete("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
84
|
-
try {
|
|
85
|
-
const count = await execute(`DELETE FROM plans WHERE id = $1`, [req.params.id]);
|
|
86
|
-
if (count === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
87
|
-
res.status(204).send();
|
|
88
|
-
} catch (e: any) {
|
|
89
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
90
|
-
}
|
|
91
|
-
});
|
|
1
|
+
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
+
// Service: PlanService
|
|
3
|
+
import { Router, Request, Response } from "express";
|
|
4
|
+
import { v4 as uuid } from "uuid";
|
|
5
|
+
import { query, queryOne, execute, pool } from "../db";
|
|
6
|
+
import { eventBus } from "../events";
|
|
7
|
+
import { requireAuth, AuthContext } from "../auth";
|
|
8
|
+
import rateLimit from "express-rate-limit";
|
|
9
|
+
import { auditLog } from "../audit";
|
|
10
|
+
import { logger } from "../logger";
|
|
11
|
+
import { counter } from "../metrics";
|
|
12
|
+
import * as __algorithms from "../algorithms";
|
|
13
|
+
const { shortestPath, topologicalSort, binarySearch, bipartiteMatching, roundRobin, weightedAverage, percentile, rankBy, consistentHash } = __algorithms as any;
|
|
14
|
+
|
|
15
|
+
import { transitionPlan, PLAN_INITIAL } from "../state_machines/plan";
|
|
16
|
+
|
|
17
|
+
export const plansRouter = Router();
|
|
18
|
+
|
|
19
|
+
// Rate limiter from policy declaration
|
|
20
|
+
const __routeRateLimit = rateLimit({ windowMs: 60000, max: 200, standardHeaders: true, legacyHeaders: false });
|
|
21
|
+
|
|
22
|
+
// CREATE
|
|
23
|
+
plansRouter.post("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
24
|
+
try {
|
|
25
|
+
const id = uuid();
|
|
26
|
+
const { session_id, agent_id, task_id, steps, rationale, estimated_tokens } = req.body;
|
|
27
|
+
const state = PLAN_INITIAL;
|
|
28
|
+
const sql = `INSERT INTO plans (id, session_id, agent_id, task_id, steps, rationale, estimated_tokens, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *`;
|
|
29
|
+
const rows = await query(sql, [id, session_id, agent_id, task_id, steps, rationale, estimated_tokens, state]);
|
|
30
|
+
counter("entity.created", { entity: "Plan" });
|
|
31
|
+
res.status(201).json(rows[0]);
|
|
32
|
+
} catch (e: any) {
|
|
33
|
+
res.status(400).json({ error: { code: "CREATE_FAILED", message: e.message } });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// READ
|
|
38
|
+
plansRouter.get("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
39
|
+
try {
|
|
40
|
+
const row = await queryOne(`SELECT * FROM plans WHERE id = $1`, [req.params.id]);
|
|
41
|
+
if (!row) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
42
|
+
res.json(row);
|
|
43
|
+
} catch (e: any) {
|
|
44
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// LIST
|
|
49
|
+
plansRouter.get("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
50
|
+
try {
|
|
51
|
+
const page = parseInt(req.query.page as string) || 1;
|
|
52
|
+
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
53
|
+
const offset = (page - 1) * pageSize;
|
|
54
|
+
const rows = await query(`SELECT * FROM plans ORDER BY created_at DESC LIMIT $1 OFFSET $2`, [pageSize, offset]);
|
|
55
|
+
const [{ count }] = await query(`SELECT COUNT(*) as count FROM plans`);
|
|
56
|
+
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
57
|
+
} catch (e: any) {
|
|
58
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// UPDATE
|
|
63
|
+
plansRouter.put("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
64
|
+
const fields = { ...req.body };
|
|
65
|
+
// State machine enforcement
|
|
66
|
+
if (fields.state !== undefined) {
|
|
67
|
+
const current = await queryOne<{ state: string }>(`SELECT state FROM plans WHERE id = $1`, [req.params.id]);
|
|
68
|
+
if (!current) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
69
|
+
// Find the trigger for this state transition
|
|
70
|
+
const trigger = `${current.state}_to_${fields.state}`;
|
|
71
|
+
const tr = transitionPlan(current.state as any, trigger);
|
|
72
|
+
if (!tr.ok) return res.status(422).json({ error: { code: "INVALID_TRANSITION", message: `Cannot transition from ${current.state} to ${fields.state}` } });
|
|
73
|
+
}
|
|
74
|
+
const sets = Object.keys(fields).map((k, i) => `${k} = $${i + 2}`).join(", ");
|
|
75
|
+
const values = Object.values(fields);
|
|
76
|
+
const sql = `UPDATE plans SET ${sets}, updated_at = NOW() WHERE id = $1 RETURNING *`;
|
|
77
|
+
const rows = await query(sql, [req.params.id, ...values]);
|
|
78
|
+
if (rows.length === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
79
|
+
res.json(rows[0]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// DELETE
|
|
83
|
+
plansRouter.delete("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
84
|
+
try {
|
|
85
|
+
const count = await execute(`DELETE FROM plans WHERE id = $1`, [req.params.id]);
|
|
86
|
+
if (count === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
87
|
+
res.status(204).send();
|
|
88
|
+
} catch (e: any) {
|
|
89
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
90
|
+
}
|
|
91
|
+
});
|