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,112 +1,112 @@
|
|
|
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 SessionCreated
|
|
46
|
-
export async function notifySessionCreated(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
47
|
-
await sendEmail({
|
|
48
|
-
to: recipientEmail,
|
|
49
|
-
subject: "SessionCreated notification",
|
|
50
|
-
body: `<p>Event <strong>SessionCreated</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Handler for SessionStateChanged
|
|
55
|
-
export async function notifySessionStateChanged(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
56
|
-
await sendEmail({
|
|
57
|
-
to: recipientEmail,
|
|
58
|
-
subject: "SessionStateChanged notification",
|
|
59
|
-
body: `<p>Event <strong>SessionStateChanged</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Handler for MessageAdded
|
|
64
|
-
export async function notifyMessageAdded(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
65
|
-
await sendEmail({
|
|
66
|
-
to: recipientEmail,
|
|
67
|
-
subject: "MessageAdded notification",
|
|
68
|
-
body: `<p>Event <strong>MessageAdded</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Handler for PartUpdated
|
|
73
|
-
export async function notifyPartUpdated(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
74
|
-
await sendEmail({
|
|
75
|
-
to: recipientEmail,
|
|
76
|
-
subject: "PartUpdated notification",
|
|
77
|
-
body: `<p>Event <strong>PartUpdated</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Handler for SessionCompacted
|
|
82
|
-
export async function notifySessionCompacted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
83
|
-
await sendEmail({
|
|
84
|
-
to: recipientEmail,
|
|
85
|
-
subject: "SessionCompacted notification",
|
|
86
|
-
body: `<p>Event <strong>SessionCompacted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function registerNotificationHandlers(eventBus: any): void {
|
|
91
|
-
// TODO: implement recipient lookup per event type
|
|
92
|
-
// eventBus.subscribe("SessionCreated", async (event: SystemEvent) => {
|
|
93
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
94
|
-
// await notifySessionCreated(event, recipientEmail);
|
|
95
|
-
// });
|
|
96
|
-
// eventBus.subscribe("SessionStateChanged", async (event: SystemEvent) => {
|
|
97
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
98
|
-
// await notifySessionStateChanged(event, recipientEmail);
|
|
99
|
-
// });
|
|
100
|
-
// eventBus.subscribe("MessageAdded", async (event: SystemEvent) => {
|
|
101
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
102
|
-
// await notifyMessageAdded(event, recipientEmail);
|
|
103
|
-
// });
|
|
104
|
-
// eventBus.subscribe("PartUpdated", async (event: SystemEvent) => {
|
|
105
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
106
|
-
// await notifyPartUpdated(event, recipientEmail);
|
|
107
|
-
// });
|
|
108
|
-
// eventBus.subscribe("SessionCompacted", async (event: SystemEvent) => {
|
|
109
|
-
// const recipientEmail = await lookupRecipient(event);
|
|
110
|
-
// await notifySessionCompacted(event, recipientEmail);
|
|
111
|
-
// });
|
|
112
|
-
}
|
|
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 SessionCreated
|
|
46
|
+
export async function notifySessionCreated(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
47
|
+
await sendEmail({
|
|
48
|
+
to: recipientEmail,
|
|
49
|
+
subject: "SessionCreated notification",
|
|
50
|
+
body: `<p>Event <strong>SessionCreated</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handler for SessionStateChanged
|
|
55
|
+
export async function notifySessionStateChanged(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
56
|
+
await sendEmail({
|
|
57
|
+
to: recipientEmail,
|
|
58
|
+
subject: "SessionStateChanged notification",
|
|
59
|
+
body: `<p>Event <strong>SessionStateChanged</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Handler for MessageAdded
|
|
64
|
+
export async function notifyMessageAdded(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
65
|
+
await sendEmail({
|
|
66
|
+
to: recipientEmail,
|
|
67
|
+
subject: "MessageAdded notification",
|
|
68
|
+
body: `<p>Event <strong>MessageAdded</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Handler for PartUpdated
|
|
73
|
+
export async function notifyPartUpdated(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
74
|
+
await sendEmail({
|
|
75
|
+
to: recipientEmail,
|
|
76
|
+
subject: "PartUpdated notification",
|
|
77
|
+
body: `<p>Event <strong>PartUpdated</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Handler for SessionCompacted
|
|
82
|
+
export async function notifySessionCompacted(event: SystemEvent, recipientEmail: string): Promise<void> {
|
|
83
|
+
await sendEmail({
|
|
84
|
+
to: recipientEmail,
|
|
85
|
+
subject: "SessionCompacted notification",
|
|
86
|
+
body: `<p>Event <strong>SessionCompacted</strong> occurred.</p><pre>${JSON.stringify(event.payload, null, 2)}</pre>`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function registerNotificationHandlers(eventBus: any): void {
|
|
91
|
+
// TODO: implement recipient lookup per event type
|
|
92
|
+
// eventBus.subscribe("SessionCreated", async (event: SystemEvent) => {
|
|
93
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
94
|
+
// await notifySessionCreated(event, recipientEmail);
|
|
95
|
+
// });
|
|
96
|
+
// eventBus.subscribe("SessionStateChanged", async (event: SystemEvent) => {
|
|
97
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
98
|
+
// await notifySessionStateChanged(event, recipientEmail);
|
|
99
|
+
// });
|
|
100
|
+
// eventBus.subscribe("MessageAdded", async (event: SystemEvent) => {
|
|
101
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
102
|
+
// await notifyMessageAdded(event, recipientEmail);
|
|
103
|
+
// });
|
|
104
|
+
// eventBus.subscribe("PartUpdated", async (event: SystemEvent) => {
|
|
105
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
106
|
+
// await notifyPartUpdated(event, recipientEmail);
|
|
107
|
+
// });
|
|
108
|
+
// eventBus.subscribe("SessionCompacted", async (event: SystemEvent) => {
|
|
109
|
+
// const recipientEmail = await lookupRecipient(event);
|
|
110
|
+
// await notifySessionCompacted(event, recipientEmail);
|
|
111
|
+
// });
|
|
112
|
+
}
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
-
// Service: MessageService
|
|
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
|
-
export const messagesRouter = Router();
|
|
16
|
-
|
|
17
|
-
// Rate limiter from policy declaration
|
|
18
|
-
const __routeRateLimit = rateLimit({ windowMs: 60000, max: 500, standardHeaders: true, legacyHeaders: false });
|
|
19
|
-
|
|
20
|
-
// CREATE
|
|
21
|
-
messagesRouter.post("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
22
|
-
try {
|
|
23
|
-
const id = uuid();
|
|
24
|
-
const { session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error } = req.body;
|
|
25
|
-
const sql = `INSERT INTO messages (id, session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *`;
|
|
26
|
-
const rows = await query(sql, [id, session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error]);
|
|
27
|
-
counter("entity.created", { entity: "Message" });
|
|
28
|
-
res.status(201).json(rows[0]);
|
|
29
|
-
} catch (e: any) {
|
|
30
|
-
res.status(400).json({ error: { code: "CREATE_FAILED", message: e.message } });
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// READ
|
|
35
|
-
messagesRouter.get("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
36
|
-
try {
|
|
37
|
-
const row = await queryOne(`SELECT * FROM messages WHERE id = $1`, [req.params.id]);
|
|
38
|
-
if (!row) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
39
|
-
res.json(row);
|
|
40
|
-
} catch (e: any) {
|
|
41
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// LIST
|
|
46
|
-
messagesRouter.get("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
47
|
-
try {
|
|
48
|
-
const page = parseInt(req.query.page as string) || 1;
|
|
49
|
-
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
50
|
-
const offset = (page - 1) * pageSize;
|
|
51
|
-
const rows = await query(`SELECT messages.*, row_to_json(session.*) as owner_session FROM messages LEFT JOIN sessions session ON messages.session_id = session.id ORDER BY messages.created_at DESC LIMIT $1 OFFSET $2`, [pageSize, offset]);
|
|
52
|
-
const [{ count }] = await query(`SELECT COUNT(*) as count FROM messages`);
|
|
53
|
-
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
54
|
-
} catch (e: any) {
|
|
55
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// UPDATE
|
|
60
|
-
messagesRouter.put("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
61
|
-
const fields = { ...req.body };
|
|
62
|
-
const sets = Object.keys(fields).map((k, i) => `${k} = $${i + 2}`).join(", ");
|
|
63
|
-
const values = Object.values(fields);
|
|
64
|
-
const sql = `UPDATE messages SET ${sets}, updated_at = NOW() WHERE id = $1 RETURNING *`;
|
|
65
|
-
const rows = await query(sql, [req.params.id, ...values]);
|
|
66
|
-
if (rows.length === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
67
|
-
res.json(rows[0]);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// DELETE
|
|
71
|
-
messagesRouter.delete("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
72
|
-
try {
|
|
73
|
-
const count = await execute(`DELETE FROM messages WHERE id = $1`, [req.params.id]);
|
|
74
|
-
if (count === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
75
|
-
res.status(204).send();
|
|
76
|
-
} catch (e: any) {
|
|
77
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// RELATION: parts (has_many Part)
|
|
82
|
-
messagesRouter.get("/:id/parts", requireAuth, async (req: Request, res: Response) => {
|
|
83
|
-
try {
|
|
84
|
-
const page = parseInt(req.query.page as string) || 1;
|
|
85
|
-
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
86
|
-
const offset = (page - 1) * pageSize;
|
|
87
|
-
const rows = await query(`SELECT * FROM parts WHERE message_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`, [req.params.id, pageSize, offset]);
|
|
88
|
-
const [{ count }] = await query(`SELECT COUNT(*) as count FROM parts WHERE message_id = $1`, [req.params.id]);
|
|
89
|
-
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
90
|
-
} catch (e: any) {
|
|
91
|
-
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
92
|
-
}
|
|
93
|
-
});
|
|
1
|
+
// Generated by BoneScript compiler. DO NOT EDIT.
|
|
2
|
+
// Service: MessageService
|
|
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
|
+
export const messagesRouter = Router();
|
|
16
|
+
|
|
17
|
+
// Rate limiter from policy declaration
|
|
18
|
+
const __routeRateLimit = rateLimit({ windowMs: 60000, max: 500, standardHeaders: true, legacyHeaders: false });
|
|
19
|
+
|
|
20
|
+
// CREATE
|
|
21
|
+
messagesRouter.post("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
22
|
+
try {
|
|
23
|
+
const id = uuid();
|
|
24
|
+
const { session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error } = req.body;
|
|
25
|
+
const sql = `INSERT INTO messages (id, session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *`;
|
|
26
|
+
const rows = await query(sql, [id, session_id, role, model_id, provider_id, tokens_input, tokens_output, cost_usd, error]);
|
|
27
|
+
counter("entity.created", { entity: "Message" });
|
|
28
|
+
res.status(201).json(rows[0]);
|
|
29
|
+
} catch (e: any) {
|
|
30
|
+
res.status(400).json({ error: { code: "CREATE_FAILED", message: e.message } });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// READ
|
|
35
|
+
messagesRouter.get("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
36
|
+
try {
|
|
37
|
+
const row = await queryOne(`SELECT * FROM messages WHERE id = $1`, [req.params.id]);
|
|
38
|
+
if (!row) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
39
|
+
res.json(row);
|
|
40
|
+
} catch (e: any) {
|
|
41
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// LIST
|
|
46
|
+
messagesRouter.get("/", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
47
|
+
try {
|
|
48
|
+
const page = parseInt(req.query.page as string) || 1;
|
|
49
|
+
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
50
|
+
const offset = (page - 1) * pageSize;
|
|
51
|
+
const rows = await query(`SELECT messages.*, row_to_json(session.*) as owner_session FROM messages LEFT JOIN sessions session ON messages.session_id = session.id ORDER BY messages.created_at DESC LIMIT $1 OFFSET $2`, [pageSize, offset]);
|
|
52
|
+
const [{ count }] = await query(`SELECT COUNT(*) as count FROM messages`);
|
|
53
|
+
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
54
|
+
} catch (e: any) {
|
|
55
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// UPDATE
|
|
60
|
+
messagesRouter.put("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
61
|
+
const fields = { ...req.body };
|
|
62
|
+
const sets = Object.keys(fields).map((k, i) => `${k} = $${i + 2}`).join(", ");
|
|
63
|
+
const values = Object.values(fields);
|
|
64
|
+
const sql = `UPDATE messages SET ${sets}, updated_at = NOW() WHERE id = $1 RETURNING *`;
|
|
65
|
+
const rows = await query(sql, [req.params.id, ...values]);
|
|
66
|
+
if (rows.length === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
67
|
+
res.json(rows[0]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// DELETE
|
|
71
|
+
messagesRouter.delete("/:id", __routeRateLimit, requireAuth, async (req: Request, res: Response) => {
|
|
72
|
+
try {
|
|
73
|
+
const count = await execute(`DELETE FROM messages WHERE id = $1`, [req.params.id]);
|
|
74
|
+
if (count === 0) return res.status(404).json({ error: { code: "NOT_FOUND", message: "Not found" } });
|
|
75
|
+
res.status(204).send();
|
|
76
|
+
} catch (e: any) {
|
|
77
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// RELATION: parts (has_many Part)
|
|
82
|
+
messagesRouter.get("/:id/parts", requireAuth, async (req: Request, res: Response) => {
|
|
83
|
+
try {
|
|
84
|
+
const page = parseInt(req.query.page as string) || 1;
|
|
85
|
+
const pageSize = Math.min(parseInt(req.query.page_size as string) || 50, 100);
|
|
86
|
+
const offset = (page - 1) * pageSize;
|
|
87
|
+
const rows = await query(`SELECT * FROM parts WHERE message_id = $1 ORDER BY created_at DESC LIMIT $2 OFFSET $3`, [req.params.id, pageSize, offset]);
|
|
88
|
+
const [{ count }] = await query(`SELECT COUNT(*) as count FROM parts WHERE message_id = $1`, [req.params.id]);
|
|
89
|
+
res.json({ items: rows, total: parseInt(count), page, page_size: pageSize });
|
|
90
|
+
} catch (e: any) {
|
|
91
|
+
res.status(500).json({ error: { code: "DB_ERROR", message: e.message } });
|
|
92
|
+
}
|
|
93
|
+
});
|