@desplega.ai/agent-swarm 2.5.4 → 2.7.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/README.md +4 -2
- package/dist/{acp-adapter-ek38cwsv.js → acp-adapter-ma1js5n7.js} +9 -9
- package/dist/{actions-92mepq03.js → actions-1vhmtvg9.js} +21 -21
- package/dist/{amp-adapter-9gaxg015.js → amp-adapter-sxqqvmdk.js} +4 -4
- package/dist/{app-ctn8gsgx.js → app-mwx1d5a9.js} +3 -3
- package/dist/{assistant-zyr5kz47.js → assistant-yx1p6g82.js} +30 -26
- package/dist/{boot-reembed-w75maga2.js → boot-reembed-5h37a2c2.js} +1 -1
- package/dist/{boot-reembed-dwzfttdr.js → boot-reembed-7h78vmvv.js} +2 -1
- package/dist/{boot-scrub-sweep-e9kq43kf.js → boot-scrub-sweep-8mawd4gw.js} +4 -4
- package/dist/{boot-seeds-x28v3fhb.js → boot-seeds-ca84dhnn.js} +4 -4
- package/dist/{claude-adapter-f0afqnne.js → claude-adapter-wqt4hfkq.js} +9 -9
- package/dist/{claude-managed-adapter-x81a7r65.js → claude-managed-adapter-6fjqtr2z.js} +2 -2
- package/dist/{claude-managed-setup-bqzwjd9x.js → claude-managed-setup-rqv98sea.js} +10 -3
- package/dist/{claude-sdk-session-7b7whkaq.js → claude-sdk-session-f29f3b2x.js} +11 -11
- package/dist/{cli-sxgtf5fw.js → cli-07q03xm2.js} +1 -1
- package/dist/{cli-kxpfx2xr.js → cli-0z1xjzwa.js} +2 -2
- package/dist/{cli-g9vd9ece.js → cli-1hhbzkbb.js} +14 -16
- package/dist/{cli-qqzmjxkf.js → cli-1m9x8dr5.js} +11 -6
- package/dist/{cli-jbnn4vxb.js → cli-2pvzmas1.js} +3 -3
- package/dist/{cli-x77gen2p.js → cli-2y7v133v.js} +7 -7
- package/dist/{cli-dew6x255.js → cli-39aet655.js} +2 -2
- package/dist/{cli-g1cw7xtt.js → cli-39rrw8yp.js} +1 -1
- package/dist/{cli-jb30dzvk.js → cli-48gxjmcz.js} +530 -190
- package/dist/{cli-pzatvw94.js → cli-54sj64fc.js} +2 -2
- package/dist/{cli-bvpgr9ny.js → cli-60sty27p.js} +5 -5
- package/dist/{cli-asq5ydm4.js → cli-6a9qfa8b.js} +411 -69
- package/dist/{cli-277c31dw.js → cli-6mgdba42.js} +225 -3
- package/dist/{cli-19202kew.js → cli-6srv653c.js} +5 -5
- package/dist/{cli-n4c8e3s5.js → cli-708wdy32.js} +1 -1
- package/dist/{cli-pasyvjmm.js → cli-737pyqxr.js} +1 -1
- package/dist/{cli-6x9ma5w5.js → cli-803188pb.js} +1 -1
- package/dist/{cli-hh5we352.js → cli-86ehn4s5.js} +7 -7
- package/dist/{cli-9s05422w.js → cli-8mbc9za9.js} +1 -1
- package/dist/{cli-ff1tm9n9.js → cli-8wmj18cz.js} +1 -1
- package/dist/{cli-1r5ad7j5.js → cli-9gsm2rzp.js} +12 -12
- package/dist/{cli-mz9afxxf.js → cli-9pshx6rd.js} +17 -3
- package/dist/{cli-s682zgqz.js → cli-a6ds2epe.js} +1 -1
- package/dist/{cli-6a1xg1p7.js → cli-a89zdqz9.js} +2 -2
- package/dist/{cli-03vpq45j.js → cli-ay40dnj3.js} +2 -2
- package/dist/{cli-tsma7p8v.js → cli-aypd09nf.js} +2 -2
- package/dist/{cli-ethgy7ha.js → cli-b3yzyc57.js} +2 -2
- package/dist/{cli-bn0rewsy.js → cli-c081bj3b.js} +2 -2
- package/dist/{cli-mmhj8vd7.js → cli-c668vvcf.js} +11 -2
- package/dist/{cli-sbwsxvtd.js → cli-d20qvpr2.js} +2 -2
- package/dist/{cli-c952c7ac.js → cli-e1595bgx.js} +3 -3
- package/dist/{cli-621ce7kw.js → cli-f12mr20z.js} +3 -3
- package/dist/{cli-dqygeeh5.js → cli-f1e0ptjj.js} +10 -1
- package/dist/{cli-xzfq4at3.js → cli-f4dbh7a5.js} +16 -12
- package/dist/{cli-ha9rmwgq.js → cli-fb8m699c.js} +2 -2
- package/dist/{cli-5bnsc0e1.js → cli-gsfk58nw.js} +5 -5
- package/dist/cli-gt4h8cxw.js +895 -0
- package/dist/{cli-nwyw3zhg.js → cli-gxee0bqa.js} +1 -1
- package/dist/{cli-25n3mv5d.js → cli-h5jeg46p.js} +6 -6
- package/dist/{cli-gn5af0x5.js → cli-he9gbdx0.js} +62 -12
- package/dist/{cli-gbfxp48k.js → cli-j0ppywdr.js} +42 -35
- package/dist/{cli-k4tjsdx9.js → cli-j3y0x2n4.js} +277 -199
- package/dist/{cli-7p4jxgtt.js → cli-j9bpmykh.js} +75 -27
- package/dist/{cli-dabehxhp.js → cli-kt907da6.js} +1 -1
- package/dist/{cli-wx2nj19m.js → cli-kv7sbc2c.js} +6 -6
- package/dist/{cli-abs8ndtr.js → cli-m30k9777.js} +26 -26
- package/dist/{cli-cz5nmdxt.js → cli-m5e802r7.js} +2 -2
- package/dist/{cli-0shx9j93.js → cli-pfk92eqz.js} +2 -2
- package/dist/{cli-xtrz6bzs.js → cli-ptfq202x.js} +5 -3
- package/dist/{cli-6n8axjv1.js → cli-qj442fws.js} +2 -2
- package/dist/{cli-c61mbdds.js → cli-rd5m70gj.js} +4 -4
- package/dist/{cli-eftzyh9y.js → cli-s09j9vp5.js} +2 -2
- package/dist/{cli-m4ecdxvz.js → cli-s0mgx214.js} +7 -7
- package/dist/{cli-wghjkr0e.js → cli-sgqm2582.js} +10 -7
- package/dist/{cli-2655k16q.js → cli-sjctjr48.js} +2 -2
- package/dist/{cli-nzfnt2gs.js → cli-tf1n0r0b.js} +1 -1
- package/dist/{cli-x0f2v69c.js → cli-twctnkng.js} +12 -7
- package/dist/{cli-j6rktc91.js → cli-v6shg7na.js} +1 -1
- package/dist/{cli-gx4rm0qx.js → cli-vz78s5wm.js} +1 -1
- package/dist/{cli-gwhjmh8g.js → cli-wqr7cea4.js} +5 -5
- package/dist/{cli-e42vss7b.js → cli-x37r7qwf.js} +16 -8
- package/dist/{cli-4b2z6n0m.js → cli-yd2nreqw.js} +17 -8
- package/dist/{cli-64mh9mf3.js → cli-ymjpkxgn.js} +69 -17
- package/dist/{cli-5kqnemen.js → cli-yvy48785.js} +1 -1
- package/dist/{cli-9j129brq.js → cli-yxbsmx56.js} +6 -6
- package/dist/cli.js +22 -20
- package/dist/{codex-adapter-wch12q99.js → codex-adapter-zk59x2zh.js} +7 -7
- package/dist/{codex-hook-brpnycn5.js → codex-hook-xyjhvxwd.js} +1 -1
- package/dist/{codex-login-rn7c5gxt.js → codex-login-8cg0vhf2.js} +1 -1
- package/dist/{codex-session-runner-41pfcr95.js → codex-session-runner-kh6s4j3n.js} +8 -8
- package/dist/{commands-9849dkj6.js → commands-68et1qv2.js} +2 -2
- package/dist/{controller-ja0sd95p.js → controller-fyrbnzg4.js} +4 -4
- package/dist/{controllers-connect-xp05dj6x.js → controllers-connect-nep9h2xv.js} +23 -23
- package/dist/{cursor-adapter-623qxqew.js → cursor-adapter-yss3pg7t.js} +2 -2
- package/dist/{db-w759qmx0.js → db-28gjyvxj.js} +4 -2
- package/dist/{db-47vj40dy.js → db-8ftwvzba.js} +3 -3
- package/dist/{devin-adapter-4ycy4vrf.js → devin-adapter-byen2cxt.js} +1 -1
- package/dist/{dispatcher-7b8e4z2j.js → dispatcher-hayexmkr.js} +20 -20
- package/dist/{docker-s84hjs91.js → docker-fdzyewpz.js} +2 -2
- package/dist/{dsh-adapter-2ezw3xea.js → dsh-adapter-46wawff9.js} +2 -2
- package/dist/{e2b-9gkdhm3c.js → e2b-222hsajc.js} +2 -2
- package/dist/{e2b-cjtf8k1z.js → e2b-fn3zacvt.js} +2 -2
- package/dist/{easter-egg-3d-e4qv8dxj.js → easter-egg-3d-8d1e0h4m.js} +1 -1
- package/dist/{event-bus-3z78ep5n.js → event-bus-pghg8hqy.js} +1 -1
- package/dist/{execute-0xpz8950.js → execute-cjrfxfnm.js} +1 -1
- package/dist/{external-channel-e2s028da.js → external-channel-xbmxcg09.js} +2 -2
- package/dist/{grok-adapter-ys7gaqee.js → grok-adapter-ag4wks2a.js} +10 -10
- package/dist/handlers-tzmevqb5.js +41 -0
- package/dist/{heartbeat-w3mntghj.js → heartbeat-psfvcgwp.js} +23 -23
- package/dist/{hook-g7kvv6x9.js → hook-8pz04697.js} +6 -6
- package/dist/{hook-3jjywnpb.js → hook-cyq4mryn.js} +8 -8
- package/dist/{http-tkp7d4kb.js → http-haj1nd6k.js} +921 -169
- package/dist/{index-q7m26kvs.js → index-jwt2bj6f.js} +265 -97
- package/dist/{index-3n8m9ea2.js → index-q52f47pe.js} +1 -1
- package/dist/{index-31ceyf42.js → index-syvhnvtw.js} +1 -1
- package/dist/index-y1ajx04a.js +43 -0
- package/dist/{index-1ef1myq2.js → index-z5h22pes.js} +20 -20
- package/dist/{index-xdaahthb.js → index-zyq8ct52.js} +20 -20
- package/dist/{keepalive-v4ta8wgg.js → keepalive-xdvsamvj.js} +4 -4
- package/dist/lead-hqg57kdp.js +79 -0
- package/dist/{maintenance-84n1ex21.js → maintenance-4y2xzh3a.js} +1 -1
- package/dist/{oauth-refresh-sweep-vjnnandw.js → oauth-refresh-sweep-jd4r7zbs.js} +9 -4
- package/dist/{onboard-sfmpe4np.js → onboard-18447q9q.js} +6 -6
- package/dist/{opencode-adapter-jmpst4q4.js → opencode-adapter-26b2frdf.js} +7 -7
- package/dist/{otel-impl-v6cc0zve.js → otel-impl-f9tgr8yw.js} +2 -2
- package/dist/{pi-mono-adapter-fk8fkcf6.js → pi-mono-adapter-qn6qbga1.js} +38 -17
- package/dist/{pricing-refresh-fsk1e1zc.js → pricing-refresh-dw2tgb53.js} +3 -3
- package/dist/{rbac-roles-prmkdnkw.js → rbac-roles-aygm2760.js} +2 -2
- package/dist/{rbac-roles-zxmxqa39.js → rbac-roles-s4nwj2m3.js} +1 -1
- package/dist/render-v2-yfvdfr0x.js +16 -0
- package/dist/{resume-frdtgfa0.js → resume-1bmvjbf3.js} +9 -9
- package/dist/{runtime-bt5pkpm1.js → runtime-f7tpzedy.js} +1 -1
- package/dist/{session-access-fpez4y5q.js → session-access-r5garej6.js} +4 -4
- package/dist/session-source-backfill-424wzv0r.js +110 -0
- package/dist/{setup-mq6m3m8q.js → setup-8tygvxkq.js} +1 -1
- package/dist/{virtual-modules-mnfbh5mr.js → virtual-modules-xsw323b3.js} +2 -2
- package/dist/{work-objects-kfahhjsq.js → work-objects-ggnghpgf.js} +23 -23
- package/dist/worker-sqjd1nqf.js +79 -0
- package/dist/{x-pbpezr0s.js → x-wxrzvzx8.js} +2 -2
- package/openapi.json +1324 -14
- package/package.json +5 -3
- package/src/assets/source-key.ts +95 -0
- package/src/be/automation-preflight.ts +2 -0
- package/src/be/db/api-keys.ts +89 -0
- package/src/be/db/session-labels.ts +28 -0
- package/src/be/db/session-moves.ts +5 -6
- package/src/be/db/session-tree.ts +153 -14
- package/src/be/db/tasks/read.ts +11 -0
- package/src/be/db/tasks/write.ts +6 -1
- package/src/be/db/workflow-runs.ts +219 -6
- package/src/be/db-retention.ts +61 -6
- package/src/be/db.ts +135 -132
- package/src/be/memory/providers/openai-embedding.ts +5 -1
- package/src/be/memory/task-learning.ts +155 -0
- package/src/be/migrations/244_api_key_validation.sql +4 -0
- package/src/be/migrations/245_script_executor.sql +3 -0
- package/src/be/oauth-refresh-sweep.ts +2 -1
- package/src/be/onboarding.ts +4 -0
- package/src/be/scripts/boot-reembed.ts +2 -0
- package/src/be/scripts/db.ts +14 -4
- package/src/be/scripts/embeddings.ts +2 -0
- package/src/be/scripts/run-saved.ts +1 -0
- package/src/be/scripts/typecheck.ts +10 -4
- package/src/be/seed-skills/index.ts +7 -0
- package/src/be/session-source-backfill.ts +163 -0
- package/src/be/swarm-config-guard.ts +1 -0
- package/src/comb/review-batch.ts +28 -1
- package/src/comb/templates.ts +7 -2
- package/src/commands/claude-managed-setup.ts +7 -1
- package/src/commands/credential-refresh.ts +76 -1
- package/src/commands/credential-wait.ts +2 -2
- package/src/commands/onboard/compose-generator.ts +5 -3
- package/src/commands/provider-credentials.ts +212 -171
- package/src/commands/runner.ts +25 -4
- package/src/extensions/apply-task-create.ts +8 -1
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +5 -0
- package/src/heartbeat/heartbeat.ts +14 -1
- package/src/heartbeat/script-runner-probe.ts +47 -0
- package/src/http/all-routes.ts +2 -0
- package/src/http/api-keys.ts +77 -9
- package/src/http/assets.ts +15 -0
- package/src/http/codex-oauth-accounts.ts +191 -0
- package/src/http/comb.ts +15 -2
- package/src/http/config.ts +1 -1
- package/src/http/core.ts +6 -0
- package/src/http/fleet-benchmark.ts +5 -2
- package/src/http/idempotency-key.ts +1 -1
- package/src/http/index.ts +14 -3
- package/src/http/integrations.ts +5 -1
- package/src/http/kv.ts +8 -3
- package/src/http/onboarding.ts +6 -1
- package/src/http/pages-public.ts +38 -5
- package/src/http/pool-keys.ts +354 -0
- package/src/http/scripts.ts +27 -0
- package/src/http/sessions.ts +37 -12
- package/src/http/stats.ts +1 -0
- package/src/http/status.ts +26 -12
- package/src/http/tasks.ts +3 -0
- package/src/http/used-by.ts +7 -2
- package/src/http/workflows.ts +88 -9
- package/src/http/x.ts +5 -0
- package/src/integrations/chat-sdk/inbound.ts +27 -0
- package/src/kv-reserved-namespaces.ts +19 -0
- package/src/prompts/base-prompt.ts +21 -1
- package/src/prompts/session-templates.ts +17 -3
- package/src/providers/acp-targets.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/claude-adapter.ts +5 -1
- package/src/providers/claude-managed-adapter.ts +16 -9
- package/src/providers/codex-adapter.ts +71 -11
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/providers/pi-mono-adapter.ts +41 -11
- package/src/scheduler/scheduler.ts +5 -3
- package/src/scripts-runtime/eval-harness.ts +8 -1
- package/src/scripts-runtime/executors/native.ts +22 -16
- package/src/scripts-runtime/executors/quickjs-prelude.ts +103 -1
- package/src/scripts-runtime/executors/quickjs-runner.ts +2 -1
- package/src/scripts-runtime/executors/quickjs.ts +7 -0
- package/src/scripts-runtime/executors/registry.ts +32 -0
- package/src/scripts-runtime/executors/types.ts +7 -0
- package/src/scripts-runtime/host-validated-args.ts +133 -0
- package/src/scripts-runtime/loader.ts +30 -3
- package/src/scripts-runtime/swarm-sdk.ts +16 -3
- package/src/scripts-runtime/types/stdlib.d.ts +10 -2
- package/src/scripts-runtime/types/swarm-extension.d.ts +17 -8
- package/src/scripts-runtime/types/swarm-sdk.d.ts +10 -2
- package/src/slack/assistant.ts +7 -0
- package/src/slack/channel-labels.ts +74 -0
- package/src/slack/handlers.ts +8 -0
- package/src/slack/inbound-files.ts +5 -2
- package/src/slack/thread-buffer.ts +4 -0
- package/src/tasks/sibling-awareness.ts +12 -3
- package/src/telemetry-context.ts +5 -6
- package/src/telemetry-identity.ts +3 -3
- package/src/tests/api-key-status-by-suffix.test.ts +242 -0
- package/src/tests/api-keys-validation.test.ts +170 -0
- package/src/tests/base-prompt.test.ts +70 -2
- package/src/tests/claude-managed-adapter.test.ts +46 -0
- package/src/tests/claude-routes-e2e.test.ts +7 -2
- package/src/tests/codex-credential-pools.test.ts +120 -0
- package/src/tests/codex-gateway-route.test.ts +165 -0
- package/src/tests/codex-oauth-accounts.test.ts +357 -0
- package/src/tests/comb-review-batch.test.ts +63 -2
- package/src/tests/community-linear-delivery-loop.test.ts +2099 -0
- package/src/tests/config-pool-keys.test.ts +533 -0
- package/src/tests/credential-check.test.ts +294 -4
- package/src/tests/credential-refresh.test.ts +172 -1
- package/src/tests/db-retention.test.ts +9 -3
- package/src/tests/db-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +1 -3
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/docs-index.test.ts +135 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/extensions-pre-task.test.ts +53 -1
- package/src/tests/fetch-resolved-env.test.ts +16 -2
- package/src/tests/fixtures/extensions/record-task-create/hooks.ts +9 -0
- package/src/tests/fixtures/extensions/record-task-create/manifest.json +7 -0
- package/src/tests/fleet-benchmark.test.ts +8 -0
- package/src/tests/get-workflow-run-tool.test.ts +98 -0
- package/src/tests/heartbeat-checklist.test.ts +89 -0
- package/src/tests/heartbeat-script-runner-probe.test.ts +83 -0
- package/src/tests/integrations-http.test.ts +32 -2
- package/src/tests/internal-ai/complete-structured.test.ts +37 -1
- package/src/tests/internal-ai/credentials.test.ts +23 -0
- package/src/tests/kv-http.test.ts +32 -0
- package/src/tests/kv-tool.test.ts +25 -0
- package/src/tests/multi-runtime-registration.test.ts +12 -12
- package/src/tests/oauth-refresh-sweep.test.ts +34 -1
- package/src/tests/onboard-compose.test.ts +20 -0
- package/src/tests/onboarding.test.ts +108 -1
- package/src/tests/openai-embedding-credentials.test.ts +35 -0
- package/src/tests/opencode-adapter.test.ts +2 -1
- package/src/tests/openrouter-attribution-call-sites.test.ts +2 -2
- package/src/tests/org-website.test.ts +36 -0
- package/src/tests/pages-frame-ancestors.test.ts +162 -0
- package/src/tests/pi-codemode.test.ts +2 -1
- package/src/tests/pi-mono-adapter.test.ts +54 -0
- package/src/tests/pi-native-mcp.test.ts +13 -1
- package/src/tests/pi-tool-exposure.test.ts +8 -8
- package/src/tests/probe-tool-schema-tokens.test.ts +144 -0
- package/src/tests/prompt-template-session.test.ts +4 -3
- package/src/tests/provider-key-probes.test.ts +181 -0
- package/src/tests/rbac-e2e-helpers.test.ts +88 -1
- package/src/tests/rbac-e2e-helpers.ts +36 -11
- package/src/tests/request-composition-derive.test.ts +329 -0
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/script-executor-conformance.test.ts +36 -1
- package/src/tests/script-executor-quickjs-pool.test.ts +50 -0
- package/src/tests/script-executor-quickjs.test.ts +140 -0
- package/src/tests/script-host-validated-args-native.test.ts +196 -0
- package/src/tests/script-per-script-executor.test.ts +415 -0
- package/src/tests/script-runs-retention.test.ts +212 -0
- package/src/tests/scripts-external-api.test.ts +45 -0
- package/src/tests/sdk-allowlist.test.ts +42 -2
- package/src/tests/self-improvement.test.ts +4 -4
- package/src/tests/session-source-backfill.test.ts +429 -0
- package/src/tests/session-source-keys.test.ts +236 -0
- package/src/tests/session-source-labels.test.ts +419 -0
- package/src/tests/sessions-detail-batch.test.ts +2 -0
- package/src/tests/sessions-move.test.ts +131 -0
- package/src/tests/sessions-tree.test.ts +299 -2
- package/src/tests/slack-inbound-files.test.ts +103 -23
- package/src/tests/status.test.ts +101 -18
- package/src/tests/store-progress-learning.test.ts +288 -0
- package/src/tests/tasks-workflow-run-filter.test.ts +146 -0
- package/src/tests/test-net.ts +31 -0
- package/src/tests/transcription.test.ts +8 -0
- package/src/tests/ui-logs-parser.test.ts +180 -0
- package/src/tests/used-by-route.test.ts +11 -0
- package/src/tests/workflow-cascade-cancel.test.ts +172 -0
- package/src/tests/workflow-engine-v2.test.ts +116 -1
- package/src/tests/workflow-http-v2.test.ts +131 -0
- package/src/tests/workflow-mcp-trigger-schema.test.ts +209 -0
- package/src/tests/workflow-run-finished-event.test.ts +263 -0
- package/src/tests/workflow-step-order.test.ts +92 -0
- package/src/tests/workflow-sub-workflow.test.ts +30 -0
- package/src/tests/workflow-swarm-script.test.ts +34 -0
- package/src/tools/get-tasks.ts +8 -0
- package/src/tools/kv/kv-read-auth.ts +4 -2
- package/src/tools/script-common.ts +1 -0
- package/src/tools/script-run.ts +7 -0
- package/src/tools/script-upsert.ts +7 -0
- package/src/tools/store-progress.ts +67 -1
- package/src/tools/task-action.ts +1 -1
- package/src/tools/workflows/get-workflow-run.ts +14 -4
- package/src/tools/workflows/trigger-workflow.ts +104 -10
- package/src/types.ts +36 -1
- package/src/utils/company-profile.ts +51 -1
- package/src/utils/credentials.ts +10 -4
- package/src/utils/internal-ai/complete-structured.ts +5 -0
- package/src/utils/internal-ai/credentials.ts +4 -3
- package/src/utils/provider-key-probes.ts +328 -0
- package/src/utils/transcription.ts +4 -1
- package/src/workflows/engine.ts +18 -16
- package/src/workflows/executors/sub-workflow.ts +8 -1
- package/src/workflows/executors/swarm-script.ts +5 -0
- package/src/workflows/foreach-driver.ts +5 -11
- package/src/workflows/node-timeout.ts +30 -0
- package/templates/ai-toolbox.manifest.json +2 -2
- package/templates/community/linear-delivery-loop/PLAYBOOK.md +323 -0
- package/templates/community/linear-delivery-loop/README.md +38 -0
- package/templates/community/linear-delivery-loop/config.example.json +31 -0
- package/templates/community/linear-delivery-loop/lead-prompt.md +34 -0
- package/templates/community/linear-delivery-loop/schedule.json +10 -0
- package/templates/community/linear-delivery-loop/scripts/linear-delivery-setup.ts +148 -0
- package/templates/community/linear-delivery-loop/scripts/linear-delivery-tick.ts +1781 -0
- package/templates/skills/researching/content.md +2 -0
- package/templates/skills/swarm-docs/config.json +14 -0
- package/templates/skills/swarm-docs/content.md +144 -0
- package/templates/skills/swarm-scripts/SKILL.md +1 -0
- package/templates/skills/swarm-scripts/content.md +1 -0
- package/dist/cli-7421jzsw.js +0 -84
- package/dist/cli-e45e4m6b.js +0 -413
- package/dist/cli-zw88zjba.js +0 -307
- package/dist/handlers-wy1dr6ja.js +0 -41
- package/dist/index-nmm79qgr.js +0 -43
- package/dist/lead-sawnyqxk.js +0 -79
- package/dist/render-v2-pjwxvnkw.js +0 -12
- package/dist/worker-v5e5rxj3.js +0 -79
|
@@ -1,12 +1,161 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
TERMINAL_TASK_STATUSES,
|
|
3
|
+
type WorkflowRun,
|
|
4
|
+
type WorkflowRunStatus,
|
|
5
|
+
type WorkflowRunStep,
|
|
6
|
+
type WorkflowRunStepSlim,
|
|
7
|
+
type WorkflowRunStepStatus,
|
|
8
|
+
type WorkflowRunSummary,
|
|
9
|
+
} from "../../types";
|
|
2
10
|
import { scrubSecrets } from "../../utils/secret-scrubber";
|
|
11
|
+
import { normalizeDate, normalizeDateRequired } from "../date-utils";
|
|
3
12
|
import { scrubJsonValue } from "../scrub-json";
|
|
13
|
+
import { defineWorkflowPayload, type WorkflowPayloadView } from "../workflow-replay";
|
|
4
14
|
import { getDbClient } from "./runtime";
|
|
5
15
|
|
|
6
16
|
// Parent/child links between workflow runs (migration 203): a `sub-workflow`
|
|
7
17
|
// step starts a child run that records the step in `parentStepId`, and the
|
|
8
18
|
// step's `retryCount` at that time in `parentStepAttempt` (migration 240).
|
|
9
19
|
|
|
20
|
+
export type WorkflowRunRow = {
|
|
21
|
+
id: string;
|
|
22
|
+
workflowId: string;
|
|
23
|
+
status: string;
|
|
24
|
+
triggerType: string;
|
|
25
|
+
triggerData: string | null;
|
|
26
|
+
/** Absent from list rows: see `WORKFLOW_RUN_SUMMARY_COLUMNS`. */
|
|
27
|
+
context?: string | null;
|
|
28
|
+
/** Sealed exact `context` (migration 201). Absent from list rows. */
|
|
29
|
+
context_replay?: string | null;
|
|
30
|
+
error: string | null;
|
|
31
|
+
created_by: string | null;
|
|
32
|
+
startedAt: string;
|
|
33
|
+
lastUpdatedAt: string;
|
|
34
|
+
finishedAt: string | null;
|
|
35
|
+
/** The `sub-workflow` step that started this run (migration 203). */
|
|
36
|
+
parentStepId?: string | null;
|
|
37
|
+
/** That step's attempt (`retryCount`) when it started this run (migration 240). */
|
|
38
|
+
parentStepAttempt?: number | null;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `view` picks the `context` copy: `replay` (default) is the exact sealed value
|
|
43
|
+
* the engine resumes from; `display` is the scrubbed column for API, MCP and UI
|
|
44
|
+
* responses. See `src/be/workflow-replay.ts`.
|
|
45
|
+
*/
|
|
46
|
+
export function rowToWorkflowRun(
|
|
47
|
+
row: WorkflowRunRow,
|
|
48
|
+
view: WorkflowPayloadView = "replay",
|
|
49
|
+
): WorkflowRun {
|
|
50
|
+
const run: WorkflowRun = {
|
|
51
|
+
id: row.id,
|
|
52
|
+
workflowId: row.workflowId,
|
|
53
|
+
status: row.status as WorkflowRunStatus,
|
|
54
|
+
triggerData: row.triggerData ? JSON.parse(row.triggerData) : undefined,
|
|
55
|
+
context: undefined,
|
|
56
|
+
error: row.error ?? undefined,
|
|
57
|
+
createdBy: row.created_by ?? undefined,
|
|
58
|
+
startedAt: normalizeDateRequired(row.startedAt),
|
|
59
|
+
lastUpdatedAt: normalizeDateRequired(row.lastUpdatedAt),
|
|
60
|
+
finishedAt: normalizeDate(row.finishedAt) ?? undefined,
|
|
61
|
+
parentStepId: row.parentStepId ?? undefined,
|
|
62
|
+
parentStepAttempt: row.parentStepId ? (row.parentStepAttempt ?? 0) : undefined,
|
|
63
|
+
};
|
|
64
|
+
return defineWorkflowPayload(run, "context", row.context, row.context_replay, view, {
|
|
65
|
+
runId: row.id,
|
|
66
|
+
target: "its context",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Everything but `context`. `triggerData` stays: it is small, and stored
|
|
71
|
+
// scripts read it off list rows (dedupe by trigger, failure reports). The
|
|
72
|
+
// parent link and attempt stay so a list row identifies a child's invocation.
|
|
73
|
+
export const WORKFLOW_RUN_SUMMARY_COLUMNS =
|
|
74
|
+
"id, workflowId, status, triggerType, triggerData, error, created_by, startedAt, lastUpdatedAt, finishedAt, parentStepId, parentStepAttempt";
|
|
75
|
+
|
|
76
|
+
export type WorkflowRunStepRow = {
|
|
77
|
+
id: string;
|
|
78
|
+
runId: string;
|
|
79
|
+
nodeId: string;
|
|
80
|
+
nodeType: string;
|
|
81
|
+
status: string;
|
|
82
|
+
/** Absent from slim rows: see `WORKFLOW_RUN_STEP_SLIM_COLUMNS`. */
|
|
83
|
+
input?: string | null;
|
|
84
|
+
output: string | null;
|
|
85
|
+
/** Sealed exact `output` (migration 201). Absent from slim rows. */
|
|
86
|
+
output_replay?: string | null;
|
|
87
|
+
error: string | null;
|
|
88
|
+
startedAt: string;
|
|
89
|
+
finishedAt: string | null;
|
|
90
|
+
retryCount: number;
|
|
91
|
+
maxRetries: number;
|
|
92
|
+
nextRetryAt: string | null;
|
|
93
|
+
idempotencyKey: string | null;
|
|
94
|
+
diagnostics: string | null;
|
|
95
|
+
nextPort: string | null;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** `view` picks the `output` copy, as in `rowToWorkflowRun`. */
|
|
99
|
+
export function rowToWorkflowRunStep(
|
|
100
|
+
row: WorkflowRunStepRow,
|
|
101
|
+
view: WorkflowPayloadView = "replay",
|
|
102
|
+
): WorkflowRunStep {
|
|
103
|
+
const step: WorkflowRunStep = {
|
|
104
|
+
id: row.id,
|
|
105
|
+
runId: row.runId,
|
|
106
|
+
nodeId: row.nodeId,
|
|
107
|
+
nodeType: row.nodeType,
|
|
108
|
+
status: row.status as WorkflowRunStepStatus,
|
|
109
|
+
input: row.input ? JSON.parse(row.input) : undefined,
|
|
110
|
+
output: undefined,
|
|
111
|
+
error: row.error ?? undefined,
|
|
112
|
+
startedAt: normalizeDateRequired(row.startedAt),
|
|
113
|
+
finishedAt: normalizeDate(row.finishedAt) ?? undefined,
|
|
114
|
+
retryCount: row.retryCount,
|
|
115
|
+
maxRetries: row.maxRetries,
|
|
116
|
+
nextRetryAt: normalizeDate(row.nextRetryAt) ?? undefined,
|
|
117
|
+
idempotencyKey: row.idempotencyKey ?? undefined,
|
|
118
|
+
diagnostics: row.diagnostics ?? undefined,
|
|
119
|
+
nextPort: row.nextPort ?? undefined,
|
|
120
|
+
};
|
|
121
|
+
return defineWorkflowPayload(step, "output", row.output, row.output_replay, view, {
|
|
122
|
+
runId: row.runId,
|
|
123
|
+
target: `the output of step ${row.id} (node ${row.nodeId})`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Everything but `input` (a context snapshot per step, so loops grow it with
|
|
128
|
+
// every iteration) and `output_replay` (the display view never opens it).
|
|
129
|
+
const WORKFLOW_RUN_STEP_SLIM_COLUMNS =
|
|
130
|
+
"id, runId, nodeId, nodeType, status, output, error, startedAt, finishedAt, retryCount, maxRetries, nextRetryAt, idempotencyKey, diagnostics, nextPort";
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* `getWorkflowRun` without `context`, in the display view. Backs
|
|
134
|
+
* `GET /api/workflow-runs/{id}?fields=slim`: the large column is neither read
|
|
135
|
+
* nor parsed.
|
|
136
|
+
*/
|
|
137
|
+
export async function getWorkflowRunSummary(id: string): Promise<WorkflowRunSummary | null> {
|
|
138
|
+
const row = await getDbClient().get<WorkflowRunRow>(
|
|
139
|
+
`SELECT ${WORKFLOW_RUN_SUMMARY_COLUMNS} FROM workflow_runs WHERE id = ?`,
|
|
140
|
+
[id],
|
|
141
|
+
);
|
|
142
|
+
return row ? rowToWorkflowRun(row, "display") : null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* `getWorkflowRunStepsByRunId` without `input`, in the display view. Same
|
|
147
|
+
* order, including the rowid tie-break for steps that share `startedAt`.
|
|
148
|
+
*/
|
|
149
|
+
export async function getWorkflowRunStepsSlimByRunId(
|
|
150
|
+
runId: string,
|
|
151
|
+
): Promise<WorkflowRunStepSlim[]> {
|
|
152
|
+
const rows = await getDbClient().query<WorkflowRunStepRow>(
|
|
153
|
+
`SELECT ${WORKFLOW_RUN_STEP_SLIM_COLUMNS} FROM workflow_run_steps WHERE runId = ? ORDER BY startedAt ASC, rowid ASC`,
|
|
154
|
+
[runId],
|
|
155
|
+
);
|
|
156
|
+
return rows.map((row) => rowToWorkflowRunStep(row, "display"));
|
|
157
|
+
}
|
|
158
|
+
|
|
10
159
|
const TERMINAL_STATUSES = new Set<WorkflowRunStatus>([
|
|
11
160
|
"completed",
|
|
12
161
|
"failed",
|
|
@@ -242,6 +391,39 @@ export async function workflowRunTreeHasOpenWork(runIds: string[]): Promise<bool
|
|
|
242
391
|
return open;
|
|
243
392
|
}
|
|
244
393
|
|
|
394
|
+
export type WorkflowRunTree = {
|
|
395
|
+
rootRunId: string;
|
|
396
|
+
/** Root first, in `getWorkflowRunTreeIds` order. List rows: no `context`. */
|
|
397
|
+
runs: WorkflowRun[];
|
|
398
|
+
hasOpenWork: boolean;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* The run and every run below it, with whether any of them still has open
|
|
403
|
+
* work (see `workflowRunTreeHasOpenWork`). One read transaction, so `runs` and
|
|
404
|
+
* `hasOpenWork` come from the same snapshot. Null when the root is missing.
|
|
405
|
+
* Throws WorkflowRunTreeError on a cycle or a chain past the depth bound.
|
|
406
|
+
*/
|
|
407
|
+
export async function getWorkflowRunTree(rootRunId: string): Promise<WorkflowRunTree | null> {
|
|
408
|
+
return getDbClient().transaction(
|
|
409
|
+
async () => {
|
|
410
|
+
if ((await getWorkflowRunStatus(rootRunId)) === null) return null;
|
|
411
|
+
const ids = await getWorkflowRunTreeIds(rootRunId);
|
|
412
|
+
const byId = new Map<string, WorkflowRun>();
|
|
413
|
+
await forEachChunk(ids, async (chunk, placeholders) => {
|
|
414
|
+
const rows = await getDbClient().query<WorkflowRunRow>(
|
|
415
|
+
`SELECT ${WORKFLOW_RUN_SUMMARY_COLUMNS} FROM workflow_runs WHERE id IN (${placeholders})`,
|
|
416
|
+
chunk,
|
|
417
|
+
);
|
|
418
|
+
for (const row of rows) byId.set(row.id, rowToWorkflowRun(row, "display"));
|
|
419
|
+
});
|
|
420
|
+
const runs = ids.flatMap((id) => byId.get(id) ?? []);
|
|
421
|
+
return { rootRunId, runs, hasOpenWork: await workflowRunTreeHasOpenWork(ids) };
|
|
422
|
+
},
|
|
423
|
+
{ readOnly: true },
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
245
427
|
/**
|
|
246
428
|
* Cancel the pending, running and waiting steps of the given runs. The
|
|
247
429
|
* migration-140 trigger closes each cancelled step's pending approval.
|
|
@@ -283,7 +465,8 @@ export async function disarmWorkflowTreeRetries(
|
|
|
283
465
|
/**
|
|
284
466
|
* Mark the given runs that are still running or waiting `cancelled`, without
|
|
285
467
|
* the per-run `workflow.child.finished` wake-up: it is for runs whose parent
|
|
286
|
-
* step the same cancel closes.
|
|
468
|
+
* step the same cancel closes. Each run it cancels still emits
|
|
469
|
+
* `workflow.run.finished`. A terminal run keeps its status and reason.
|
|
287
470
|
*/
|
|
288
471
|
export async function cancelLiveWorkflowTreeRuns(
|
|
289
472
|
runIds: string[],
|
|
@@ -291,12 +474,14 @@ export async function cancelLiveWorkflowTreeRuns(
|
|
|
291
474
|
finishedAt: string,
|
|
292
475
|
): Promise<void> {
|
|
293
476
|
await forEachChunk(runIds, async (chunk, placeholders) => {
|
|
294
|
-
await getDbClient().
|
|
477
|
+
const cancelled = await getDbClient().query<{ id: string; workflowId: string }>(
|
|
295
478
|
`UPDATE workflow_runs
|
|
296
479
|
SET status = 'cancelled', error = ?, finishedAt = ?, lastUpdatedAt = ?
|
|
297
|
-
WHERE id IN (${placeholders}) AND status IN ('running', 'waiting')
|
|
480
|
+
WHERE id IN (${placeholders}) AND status IN ('running', 'waiting')
|
|
481
|
+
RETURNING id, workflowId`,
|
|
298
482
|
[scrubSecrets(reason), finishedAt, finishedAt, ...chunk],
|
|
299
483
|
);
|
|
484
|
+
for (const run of cancelled) emitRunFinished(run.id, run.workflowId, "cancelled");
|
|
300
485
|
});
|
|
301
486
|
}
|
|
302
487
|
|
|
@@ -461,14 +646,42 @@ export function emitChildRunFinished(
|
|
|
461
646
|
}
|
|
462
647
|
|
|
463
648
|
function emitAfterCommit(childRunId: string, parentStepId: string): void {
|
|
649
|
+
emitBusEventAfterCommit("workflow.child.finished", { childRunId, parentStepId });
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/** Bus event every run emits once when it turns terminal. */
|
|
653
|
+
export const WORKFLOW_RUN_FINISHED_EVENT = "workflow.run.finished";
|
|
654
|
+
|
|
655
|
+
export function isTerminalWorkflowRunStatus(status: WorkflowRunStatus): boolean {
|
|
656
|
+
return TERMINAL_STATUSES.has(status);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Announce after commit that a run turned terminal, top-level and child runs
|
|
661
|
+
* alike, so an event-mode `wait` can resume when any run ends. Callers emit
|
|
662
|
+
* only when a live run (running or waiting) turns terminal, never on a later
|
|
663
|
+
* update of a run that is already terminal. The id is `runId`, never `workflowRunId` or
|
|
664
|
+
* `_runId`: those would put the finished run in the waiting run's own `run`
|
|
665
|
+
* scope, so waiters use scope `global` and filter on `runId`.
|
|
666
|
+
*/
|
|
667
|
+
export function emitRunFinished(
|
|
668
|
+
runId: string,
|
|
669
|
+
workflowId: string,
|
|
670
|
+
status: WorkflowRunStatus,
|
|
671
|
+
): void {
|
|
672
|
+
if (!TERMINAL_STATUSES.has(status)) return;
|
|
673
|
+
emitBusEventAfterCommit(WORKFLOW_RUN_FINISHED_EVENT, { runId, workflowId, status });
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function emitBusEventAfterCommit(event: string, payload: Record<string, unknown>): void {
|
|
464
677
|
getDbClient().afterCommit(() => {
|
|
465
678
|
import("../../workflows/event-bus")
|
|
466
679
|
.then(({ workflowEventBus }) => {
|
|
467
|
-
workflowEventBus.emit(
|
|
680
|
+
workflowEventBus.emit(event, payload);
|
|
468
681
|
})
|
|
469
682
|
.catch((err) =>
|
|
470
683
|
console.error(
|
|
471
|
-
|
|
684
|
+
`[db] ${event} event not emitted:`,
|
|
472
685
|
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
473
686
|
),
|
|
474
687
|
);
|
package/src/be/db-retention.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import type { Attributes, DbRetentionSweepMetric, SpanStatus, SwarmSpan } from "../otel";
|
|
3
3
|
import { recordDbRetentionStatement, recordDbRetentionSweep, startSpan, withSpan } from "../otel";
|
|
4
|
+
import { TERMINAL_SCRIPT_RUN_STATUSES } from "../types";
|
|
4
5
|
import { isEnvFlagEnabled } from "../utils/env-flag";
|
|
5
6
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
6
7
|
import { getDbClient } from "./db";
|
|
@@ -23,7 +24,11 @@ const YIELD_MS = 25;
|
|
|
23
24
|
*
|
|
24
25
|
* Two policies exist:
|
|
25
26
|
* - `age`: the env value is a number of days; rows whose `timeColumn` is older
|
|
26
|
-
* than that horizon are deleted.
|
|
27
|
+
* than that horizon are deleted. Optional narrowing: `terminalStatuses`
|
|
28
|
+
* deletes only rows whose `statusColumn` is in that list, `keepWhenSet`
|
|
29
|
+
* keeps every row where that column is non-NULL, and
|
|
30
|
+
* `cutoffFormat: "sqliteDatetime"` compares against a `YYYY-MM-DD HH:MM:SS`
|
|
31
|
+
* cutoff for a column that mixes that format with ISO strings.
|
|
27
32
|
* - `keepLatest`: the env value is a count; within each `partitionBy` group,
|
|
28
33
|
* only the newest `rankBy` rows are kept. The newest row of a group is
|
|
29
34
|
* never deleted, because the smallest accepted count is 1.
|
|
@@ -65,6 +70,29 @@ export const DB_RETENTION_TABLES = [
|
|
|
65
70
|
initialBatchSize: 50,
|
|
66
71
|
maxBatchSize: 100,
|
|
67
72
|
},
|
|
73
|
+
{
|
|
74
|
+
// Every inline script run stores its full source, args and output. Only
|
|
75
|
+
// terminal runs are eligible: a running or paused durable run must survive
|
|
76
|
+
// to be resumed. Runs with an idempotencyKey are kept, so a retried launch
|
|
77
|
+
// still gets its 409 instead of executing twice. The status filter, the
|
|
78
|
+
// time range and the key exclusion all resolve on indexes
|
|
79
|
+
// (idx_script_runs_status_startedAt, idx_script_runs_idempotencyKey).
|
|
80
|
+
// Workflow runs write `datetime('now')` (space separator) while inline runs
|
|
81
|
+
// write ISO strings, hence the sqliteDatetime cutoff. script_run_journal
|
|
82
|
+
// rows go with their run through ON DELETE CASCADE on idx_srj_runId.
|
|
83
|
+
// Rows average ~30 KB and reach ~1.3 MB, so batches stay small.
|
|
84
|
+
table: "script_runs",
|
|
85
|
+
policy: "age",
|
|
86
|
+
timeColumn: "startedAt",
|
|
87
|
+
cutoffFormat: "sqliteDatetime",
|
|
88
|
+
statusColumn: "status",
|
|
89
|
+
terminalStatuses: TERMINAL_SCRIPT_RUN_STATUSES,
|
|
90
|
+
keepWhenSet: "idempotencyKey",
|
|
91
|
+
envKey: "SCRIPT_RUNS_RETENTION_DAYS",
|
|
92
|
+
metricsKey: "scriptRuns",
|
|
93
|
+
initialBatchSize: 100,
|
|
94
|
+
maxBatchSize: 500,
|
|
95
|
+
},
|
|
68
96
|
] as const satisfies ReadonlyArray<
|
|
69
97
|
{
|
|
70
98
|
table: string;
|
|
@@ -73,7 +101,14 @@ export const DB_RETENTION_TABLES = [
|
|
|
73
101
|
initialBatchSize?: number;
|
|
74
102
|
maxBatchSize?: number;
|
|
75
103
|
} & (
|
|
76
|
-
| {
|
|
104
|
+
| {
|
|
105
|
+
policy: "age";
|
|
106
|
+
timeColumn: string;
|
|
107
|
+
cutoffFormat?: "sqliteDatetime";
|
|
108
|
+
statusColumn?: string;
|
|
109
|
+
terminalStatuses?: readonly string[];
|
|
110
|
+
keepWhenSet?: string;
|
|
111
|
+
}
|
|
77
112
|
| { policy: "keepLatest"; partitionBy: string; rankBy: string }
|
|
78
113
|
)
|
|
79
114
|
>;
|
|
@@ -326,13 +361,33 @@ export function sweepStatements(table: RetentionTable, value: number, now: Date)
|
|
|
326
361
|
params: [value],
|
|
327
362
|
};
|
|
328
363
|
}
|
|
329
|
-
const
|
|
364
|
+
const iso = new Date(now.getTime() - value * DAY_MS).toISOString();
|
|
365
|
+
// Text comparison of the two formats: ' ' sorts before 'T', so against a
|
|
366
|
+
// space-separated cutoff an ISO row on the cutoff's own date is kept, never
|
|
367
|
+
// deleted early. It is swept on the next day's ticks instead.
|
|
368
|
+
const cutoff = "cutoffFormat" in table ? `${iso.slice(0, 10)} ${iso.slice(11, 19)}` : iso;
|
|
369
|
+
const conditions: string[] = [];
|
|
370
|
+
const params: Array<string | number> = [];
|
|
371
|
+
if ("terminalStatuses" in table) {
|
|
372
|
+
conditions.push(
|
|
373
|
+
`${table.statusColumn} IN (${table.terminalStatuses.map(() => "?").join(", ")})`,
|
|
374
|
+
);
|
|
375
|
+
params.push(...table.terminalStatuses);
|
|
376
|
+
}
|
|
377
|
+
conditions.push(`${table.timeColumn} < ?`);
|
|
378
|
+
params.push(cutoff);
|
|
379
|
+
if ("keepWhenSet" in table) {
|
|
380
|
+
conditions.push(
|
|
381
|
+
`rowid NOT IN (SELECT rowid FROM ${table.table} WHERE ${table.keepWhenSet} IS NOT NULL)`,
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
const where = conditions.join(" AND ");
|
|
330
385
|
return {
|
|
331
|
-
backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${
|
|
386
|
+
backlogSql: `SELECT COUNT(*) AS n FROM ${table.table} WHERE ${where}`,
|
|
332
387
|
deleteSql: `DELETE FROM ${table.table} WHERE rowid IN (
|
|
333
|
-
SELECT rowid FROM ${table.table} WHERE ${
|
|
388
|
+
SELECT rowid FROM ${table.table} WHERE ${where} ORDER BY ${table.timeColumn} LIMIT ?
|
|
334
389
|
)`,
|
|
335
|
-
params
|
|
390
|
+
params,
|
|
336
391
|
};
|
|
337
392
|
}
|
|
338
393
|
|