@desplega.ai/agent-swarm 2.7.5 → 2.7.7
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/dist/{acp-adapter-g3ads55s.js → acp-adapter-7b4vk3h5.js} +5 -4
- package/dist/{actions-zwfykqqk.js → actions-3tt153af.js} +18 -17
- package/dist/{amp-adapter-z3s0ssdt.js → amp-adapter-njpts0yr.js} +1 -1
- package/dist/{anthropic-messages-x4q6rfq5.js → anthropic-messages-xey2skwx.js} +7 -7
- package/dist/{app-vmp4fgep.js → app-nky4378f.js} +3 -3
- package/dist/{assistant-vwde653f.js → assistant-jnb669pa.js} +24 -22
- package/dist/{azure-openai-responses-s1w5n70z.js → azure-openai-responses-26t7j9ra.js} +5 -5
- package/dist/{boot-reembed-375t7tbk.js → boot-reembed-9mgvaztt.js} +1 -1
- package/dist/{boot-reembed-gq9rcpnj.js → boot-reembed-qs2djdej.js} +1 -1
- package/dist/{boot-scrub-sweep-nd938kyf.js → boot-scrub-sweep-yjpdj7s1.js} +3 -3
- package/dist/{boot-seeds-aykx51v3.js → boot-seeds-5cm6ambd.js} +4 -4
- package/dist/{boxd-k1j26g3h.js → boxd-nv507va8.js} +5 -5
- package/dist/{claude-adapter-8j4hm099.js → claude-adapter-fn287zmm.js} +5 -4
- package/dist/{claude-managed-setup-0wyynpn1.js → claude-managed-setup-wtdz2mj2.js} +1 -1
- package/dist/{claude-sdk-session-q6wj5hmy.js → claude-sdk-session-x91kqyhm.js} +9677 -9514
- package/dist/{cli-j3jvnpe8.js → cli-08bmz9z9.js} +1 -1
- package/dist/{cli-gjr2y2xk.js → cli-0agcv1v5.js} +4 -1
- package/dist/{cli-y24sc29k.js → cli-1c6tzt8g.js} +30 -8
- package/dist/{cli-mjzynrse.js → cli-35rsp8ye.js} +1 -1
- package/dist/{cli-rpm2sgv0.js → cli-3fg0bdcv.js} +19 -2
- package/dist/{cli-nn4d8dne.js → cli-5b456bpf.js} +2 -2
- package/dist/{cli-bhjt02p8.js → cli-5jnhv72d.js} +1 -1
- package/dist/{cli-fqzx7gwa.js → cli-5zx699j9.js} +2 -2
- package/dist/{cli-hf6zt5m6.js → cli-69szn7w7.js} +17 -1
- package/dist/{cli-vqypxzh4.js → cli-6g0hb4cp.js} +8 -8
- package/dist/{cli-tqgg40ek.js → cli-6pfd54vx.js} +9 -8
- package/dist/{cli-bsn8nhrq.js → cli-6vcp76qk.js} +3 -3
- package/dist/{cli-zppwg9p9.js → cli-72v799xn.js} +1 -1
- package/dist/cli-82j36f2m.js +45 -0
- package/dist/{cli-hn9hxmz9.js → cli-8305gbq0.js} +29 -16
- package/dist/{cli-z8eh3ex8.js → cli-8sckt74b.js} +8 -8
- package/dist/{cli-bnz7a7qf.js → cli-95jzxcp3.js} +1 -1
- package/dist/{cli-0bxqnvq9.js → cli-adeegh7d.js} +29 -7
- package/dist/{cli-g61qxmge.js → cli-afkqkrtw.js} +3 -3
- package/dist/{cli-7a42nfy0.js → cli-ayayvfg4.js} +24 -4
- package/dist/{cli-bqt1mptt.js → cli-az48n0nr.js} +4 -4
- package/dist/{cli-z6jkx23q.js → cli-bfv7vdg6.js} +9 -9
- package/dist/{cli-pywf3eh5.js → cli-caj33vcq.js} +5 -5
- package/dist/{cli-5pag6rmn.js → cli-cb2a8pna.js} +1 -1
- package/dist/{cli-wvaawacd.js → cli-cppkf404.js} +5236 -72
- package/dist/{cli-mry0qzym.js → cli-ddaanqkd.js} +123 -10
- package/dist/{cli-0gey5fzy.js → cli-e0kmphd6.js} +2 -2
- package/dist/{cli-zh3fp8v2.js → cli-e46hg0xw.js} +1 -1
- package/dist/{cli-jm2vfpfd.js → cli-e5bzrn01.js} +1 -1
- package/dist/{cli-qxnf8z2z.js → cli-excnnjg2.js} +165 -153
- package/dist/{cli-71ptav7x.js → cli-ferkkrg9.js} +1 -1
- package/dist/{cli-vpf89f34.js → cli-fmjd0t1y.js} +3 -3
- package/dist/{cli-rm6hqj3z.js → cli-fyt2g4wd.js} +33 -139
- package/dist/cli-g08zdaec.js +55 -0
- package/dist/{cli-ehq736cn.js → cli-g7s47cc5.js} +4 -4
- package/dist/{cli-82ae98pz.js → cli-gz6q4eve.js} +3 -3
- package/dist/{cli-82jg7fp9.js → cli-he5nxaa8.js} +1 -1
- package/dist/{cli-rqkxrmgw.js → cli-je518txm.js} +39 -14
- package/dist/{cli-8hs41zy2.js → cli-jtjtabxe.js} +1 -1
- package/dist/{cli-611a1294.js → cli-k0wwfqbg.js} +18 -1
- package/dist/{cli-nzxr556s.js → cli-k1nje3v3.js} +38 -43
- package/dist/{cli-3h4nhjn8.js → cli-k8196sh2.js} +9 -7
- package/dist/{cli-afrrppsw.js → cli-k899ehvh.js} +2 -2
- package/dist/{cli-0731hvbw.js → cli-m0da8j35.js} +23 -9
- package/dist/cli-m2z8jagn.js +12078 -0
- package/dist/{cli-8veytvbh.js → cli-mkk9rnzz.js} +5 -5
- package/dist/{cli-7wspm5gm.js → cli-n6bv12jn.js} +528 -6
- package/dist/{cli-spknvxbq.js → cli-nmzhp1b5.js} +14 -12
- package/dist/{cli-p599f1qm.js → cli-p82cnnjq.js} +1 -1
- package/dist/{cli-xtjhfmpc.js → cli-pc6n7fre.js} +1 -1
- package/dist/{cli-vbyfwh92.js → cli-pjctyea3.js} +2 -2
- package/dist/{cli-nmbmy64z.js → cli-pq73h5mz.js} +3 -3
- package/dist/{cli-aa6yxc7m.js → cli-pz4rk021.js} +1 -1
- package/dist/{cli-7wcyk2s5.js → cli-q3tkegby.js} +1 -1
- package/dist/cli-qghe0h66.js +67 -0
- package/dist/{cli-6s7vdcta.js → cli-qh4d4tvk.js} +4 -4
- package/dist/{cli-mmwm7zbf.js → cli-rtt8g4v9.js} +1 -1
- package/dist/{cli-kg8hchyg.js → cli-sa02jsqt.js} +1 -1
- package/dist/{cli-1h3wcpbw.js → cli-snpj5zbj.js} +2 -2
- package/dist/{cli-a7v854rf.js → cli-tgrv9cjx.js} +263 -12
- package/dist/{cli-a47xy8eq.js → cli-vz22fyqv.js} +186 -54
- package/dist/{cli-1ayk1eas.js → cli-wk5yrfwd.js} +285 -42
- package/dist/{cli-1338796d.js → cli-ws19768n.js} +1755 -119
- package/dist/{cli-70r77n04.js → cli-xae4g51r.js} +1 -1
- package/dist/{cli-gf5hbmdr.js → cli-yjdgea32.js} +3 -3
- package/dist/{cli-xbkdm710.js → cli-yndmfxb3.js} +3 -3
- package/dist/{cli-rhw40jgb.js → cli-yyj3j5m4.js} +2 -2
- package/dist/cli.js +26 -25
- package/dist/{cloudflare-workers-ai-system-one-bm60fjm0.js → cloudflare-workers-ai-system-one-ef2a980q.js} +2 -2
- package/dist/{codex-adapter-q6k3gnyg.js → codex-adapter-cf2yxe9m.js} +3 -2
- package/dist/{codex-hook-9efm2x1m.js → codex-hook-a0c6g6t6.js} +1 -1
- package/dist/{codex-session-runner-3mwmk3d9.js → codex-session-runner-6vfzdgbd.js} +3 -2
- package/dist/{commands-evrenjn9.js → commands-t3mfy7vn.js} +9 -3
- package/dist/{controller-xjp8vswh.js → controller-q7xrbaz0.js} +8 -3
- package/dist/{controllers-connect-pp5jnxvc.js → controllers-connect-c6nm70kg.js} +20 -19
- package/dist/{cursor-adapter-yf47w4t0.js → cursor-adapter-ftd81ga8.js} +1 -1
- package/dist/{db-zxpw6aht.js → db-dk572x25.js} +3 -3
- package/dist/{db-rgfsh91f.js → db-vemtpmcc.js} +14 -4
- package/dist/{devtools-82fzqra8.js → devtools-qxfgbsqz.js} +1 -1
- package/dist/{dispatcher-smasgws7.js → dispatcher-kh7ecxh9.js} +17 -16
- package/dist/{docker-rrjhaqt9.js → docker-c1a3gqmf.js} +89 -22
- package/dist/{dsh-adapter-ftyy8dnp.js → dsh-adapter-v8628r89.js} +1 -1
- package/dist/{e2b-w1p0bnpm.js → e2b-fr12yccx.js} +5 -5
- package/dist/{e2b-qcaj675y.js → e2b-x6ywzak3.js} +3 -3
- package/dist/{easter-egg-3d-yyts7p16.js → easter-egg-3d-nenw4x63.js} +1 -1
- package/dist/{embedding-space-1z0mbg95.js → embedding-space-0jepb239.js} +6 -6
- package/dist/{embeddings-ygeg7tm7.js → embeddings-xxt49yxg.js} +1 -1
- package/dist/{execute-14qhqp4d.js → execute-1mhw6e4x.js} +1 -1
- package/dist/{external-channel-ttgrs3sx.js → external-channel-55v12e60.js} +2 -2
- package/dist/{fx-adapter-gt6pncj2.js → fx-adapter-bs8wqrk5.js} +6 -5
- package/dist/{google-generative-ai-yvmdxyxa.js → google-generative-ai-v94hr7h0.js} +5 -5
- package/dist/{google-vertex-jrtdh9gs.js → google-vertex-g7vr6cf8.js} +5 -5
- package/dist/{grok-adapter-sm4m5k4g.js → grok-adapter-gpjqmkcq.js} +6 -5
- package/dist/handlers-zxmp1ta4.js +32 -0
- package/dist/{heartbeat-qahz4p62.js → heartbeat-k42svnr0.js} +20 -19
- package/dist/{hook-4fd5wq5w.js → hook-114m7hap.js} +4 -3
- package/dist/{hook-kj3d398m.js → hook-6nphweh0.js} +24 -9
- package/dist/{http-1ted0j1k.js → http-r8cc4wz7.js} +1196 -211
- package/dist/index-a8phxqnk.js +37 -0
- package/dist/{index-q4b917zs.js → index-e3s8wmxy.js} +1 -1
- package/dist/{index-6rq3r5zb.js → index-fpk4bcd9.js} +1 -1
- package/dist/{index-5rk6rfzr.js → index-fvzke5kx.js} +1 -1
- package/dist/index-k6h00t4c.js +30 -0
- package/dist/{index-7v51awbn.js → index-nh3wyqdt.js} +1027 -577
- package/dist/{index-yqhz88yy.js → index-pxn30mse.js} +8 -8
- package/dist/index-xrz7te8h.js +33 -0
- package/dist/{keepalive-6cf311t5.js → keepalive-x060nt9p.js} +3 -3
- package/dist/lead-956sd2yc.js +71 -0
- package/dist/{maintenance-a4bm1bmt.js → maintenance-2xxfexhf.js} +1 -1
- package/dist/{mistral-conversations-4pmwj1c0.js → mistral-conversations-3gjpdb4b.js} +4 -4
- package/dist/{oauth-refresh-sweep-3h0dfw1k.js → oauth-refresh-sweep-fckc4ar5.js} +2 -2
- package/dist/{onboard-myn5hraa.js → onboard-zc48j237.js} +5 -5
- package/dist/{openai-codex-responses-44j573nm.js → openai-codex-responses-8pbxq9h5.js} +5 -5
- package/dist/{openai-completions-a4gee2a8.js → openai-completions-rm00s912.js} +4 -4
- package/dist/{openai-decisions-w4qkrcar.js → openai-decisions-8v957r2r.js} +1 -1
- package/dist/{openai-responses-rbp6h5kr.js → openai-responses-agxpf96k.js} +5 -5
- package/dist/{opencode-adapter-p2nkb5am.js → opencode-adapter-r690h1cr.js} +4 -3
- package/dist/{otel-impl-a1a0ef6b.js → otel-impl-r5xbh81q.js} +4 -4
- package/dist/{pi-mono-adapter-rzmpb72a.js → pi-mono-adapter-c7v8sdec.js} +7 -6
- package/dist/{pricing-refresh-83drrnxj.js → pricing-refresh-3pmre11v.js} +3 -3
- package/dist/{rbac-roles-s8y6ecb5.js → rbac-roles-3vbshwsb.js} +1 -1
- package/dist/{rbac-roles-0fb6e7pj.js → rbac-roles-910mmkgz.js} +2 -2
- package/dist/{render-v2-twmbgrz4.js → render-v2-pxykkbab.js} +3 -3
- package/dist/{resume-zfqc36xj.js → resume-adda0bwy.js} +6 -6
- package/dist/{runtime-qwggdpqr.js → runtime-fnbm7stk.js} +1 -1
- package/dist/{session-access-sc9pn9da.js → session-access-2fvamrdc.js} +4 -4
- package/dist/{session-source-backfill-qh07xr8g.js → session-source-backfill-08xvv0sm.js} +2 -2
- package/dist/{setup-4fr0m7a1.js → setup-1aqmvmh1.js} +3 -3
- package/dist/{typesafe-system-one-5mavm259.js → typesafe-system-one-0bmqcxfg.js} +2 -2
- package/dist/{virtual-modules-fh4ha15b.js → virtual-modules-d2pjk9j1.js} +5 -5
- package/dist/{work-objects-0wr8zxct.js → work-objects-9s0yrm5j.js} +20 -19
- package/dist/{worker-follow-up-ktyyazyp.js → worker-follow-up-3q78fqmr.js} +17 -16
- package/dist/worker-y15hy08h.js +71 -0
- package/openapi.json +289 -4
- package/package.json +9 -8
- package/src/apps/definition.ts +6 -5
- package/src/be/db/page-theme-tokens.ts +12 -0
- package/src/be/db/script-runs.ts +23 -0
- package/src/be/db/tasks/read.ts +131 -4
- package/src/be/db/tasks/write.ts +19 -0
- package/src/be/db-client.ts +114 -11
- package/src/be/db.ts +49 -6
- package/src/be/memory/providers/sqlite-store.ts +49 -12
- package/src/be/migrations/260_runtime_pool_cache.sql +20 -0
- package/src/be/migrations/262_session_visibility_indexes.sql +18 -0
- package/src/be/migrations/263_task_list_filter_index.sql +11 -0
- package/src/be/migrations/264_slack_thread_cover_index.sql +9 -0
- package/src/be/migrations/266_script_runs_source_task.sql +11 -0
- package/src/be/migrations/269_pages_design_system.sql +23 -0
- package/src/be/runtime-pools/cache-cleanup.ts +109 -0
- package/src/be/runtime-pools/db.ts +65 -6
- package/src/be/runtime-pools/remote-controller.ts +5 -0
- package/src/be/runtime-pools/supervisor.ts +33 -2
- package/src/be/scripts/typecheck.ts +22 -0
- package/src/be/seed/schedules-seeder.ts +0 -10
- package/src/be/seed-scripts/catalog/catalog-report.inline.ts +2 -0
- package/src/be/seed-scripts/catalog/catalog-report.ts +2 -0
- package/src/be/seed-scripts/catalog/memory-eval.ts +2 -0
- package/src/be/seed-scripts/catalog/swarm-update-check.ts +150 -0
- package/src/be/seed-scripts/catalog/task-failure-audit.ts +5 -1
- package/src/be/seed-scripts/index.ts +9 -0
- package/src/be/seed-skills/bundled-files.generated.json +3 -3
- package/src/be/swarm-config-guard.ts +32 -0
- package/src/be/task-auto-title-listener.ts +127 -0
- package/src/commands/controller.ts +4 -0
- package/src/commands/entrypoint-api-readiness.ts +74 -0
- package/src/commands/onboard/agent-fs-version.ts +1 -1
- package/src/commands/profile-sync.ts +151 -16
- package/src/commands/runner.ts +15 -7
- package/src/hooks/hook.ts +20 -9
- package/src/http/index.ts +4 -1
- package/src/http/list-total-cache.ts +14 -7
- package/src/http/memory.ts +38 -9
- package/src/http/pages-public.ts +93 -129
- package/src/http/pages.ts +94 -21
- package/src/http/script-runs.ts +174 -5
- package/src/http/status.ts +10 -2
- package/src/http/tasks.ts +4 -2
- package/src/pages/browser-sdk.ts +48 -21
- package/src/pages/color-literals.ts +115 -0
- package/src/pages/page-head.ts +766 -0
- package/src/pages/version.ts +3 -0
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +1 -0
- package/src/providers/codex-app-server.ts +27 -1
- package/src/providers/fx-adapter.ts +1 -1
- package/src/providers/pi-mono-extension.ts +30 -15
- package/src/runtime-providers/controller-protocol.ts +14 -1
- package/src/runtime-providers/controller.ts +5 -0
- package/src/runtime-providers/docker.ts +108 -23
- package/src/runtime-providers/types.ts +16 -0
- package/src/script-workflows/workflow-ctx.ts +8 -0
- package/src/scripts-runtime/types/stdlib.d.ts +22 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +22 -0
- package/src/server-user.ts +1 -0
- package/src/slack/commands.ts +5 -1
- package/src/slack/handlers.ts +37 -2
- package/src/slack/left-threads.ts +27 -4
- package/src/tasks/follow-up-gate.ts +318 -0
- package/src/tasks/follow-up-redelegation-guard.ts +155 -0
- package/src/tasks/worker-follow-up.ts +21 -1
- package/src/tests/claude-artifacts-read-script.test.ts +209 -0
- package/src/tests/codex-app-server.test.ts +59 -0
- package/src/tests/codex-gateway-route.test.ts +50 -1
- package/src/tests/create-page-tool.test.ts +501 -0
- package/src/tests/db-client-busy-retry.test.ts +81 -0
- package/src/tests/db-client.test.ts +21 -0
- package/src/tests/db-task-read-contract.test.ts +9 -2
- package/src/tests/db-task-write-contract.test.ts +7 -1
- package/src/tests/db-tasks-read.test.ts +21 -0
- package/src/tests/entrypoint-api-readiness.test.ts +416 -210
- package/src/tests/explicit-model-validation.test.ts +14 -8
- package/src/tests/fixtures/pages/head-v1.html +56 -0
- package/src/tests/follow-up-gate-shadow.test.ts +513 -0
- package/src/tests/follow-up-redelivery-guard.test.ts +432 -202
- package/src/tests/identity-field-budget.test.ts +1 -1
- package/src/tests/internal-ai/credentials.test.ts +62 -0
- package/src/tests/internal-ai/task-title.test.ts +283 -0
- package/src/tests/list-total-cache.test.ts +27 -2
- package/src/tests/memory-fts-populate.test.ts +11 -9
- package/src/tests/memory-retrieval-purge.test.ts +80 -0
- package/src/tests/merge-gate-detect-changes.test.ts +145 -0
- package/src/tests/migration-260-runtime-pool-cache.test.ts +118 -0
- package/src/tests/page-proxy.test.ts +1 -1
- package/src/tests/page-session-dev-cookie.test.ts +188 -0
- package/src/tests/pages-frame-ancestors.test.ts +28 -1
- package/src/tests/pages-head-v2.test.ts +534 -0
- package/src/tests/pages-http.test.ts +330 -0
- package/src/tests/pages-public-html.test.ts +43 -0
- package/src/tests/pages-storage.test.ts +182 -0
- package/src/tests/pages-versioning.test.ts +72 -0
- package/src/tests/profile-sync-stale-writeback.test.ts +334 -0
- package/src/tests/profile-sync.test.ts +11 -15
- package/src/tests/query-audit-plans.test.ts +27 -0
- package/src/tests/runtime-cache-cleanup.test.ts +367 -0
- package/src/tests/runtime-e2b-pools.test.ts +41 -0
- package/src/tests/runtime-pools-db.test.ts +98 -0
- package/src/tests/runtime-pools-http.test.ts +29 -0
- package/src/tests/runtime-providers-docker.test.ts +253 -0
- package/src/tests/runtime-remote-controller.test.ts +66 -2
- package/src/tests/runtime-supervisor.test.ts +66 -2
- package/src/tests/scheduled-task-required-params-migration.test.ts +3 -1
- package/src/tests/script-connections.test.ts +13 -0
- package/src/tests/script-runs-http.test.ts +684 -2
- package/src/tests/seed-registry.test.ts +28 -6
- package/src/tests/seed-schedules.test.ts +61 -8
- package/src/tests/seed-scripts.test.ts +168 -2
- package/src/tests/slack-leave-thread.test.ts +145 -5
- package/src/tests/slack-render-v2-query-plans.test.ts +24 -2
- package/src/tests/status.test.ts +11 -0
- package/src/tests/swarm-diff.test.ts +121 -2
- package/src/tests/task-auto-title-config-guard.test.ts +37 -0
- package/src/tests/task-auto-title-listener.test.ts +165 -0
- package/src/tests/tasks-readable-row.test.ts +155 -0
- package/src/tests/theme-import.test.ts +758 -0
- package/src/tests/themes-page-theme.test.ts +155 -0
- package/src/tests/themes-presets.test.ts +172 -0
- package/src/tests/workflow-script-principal.test.ts +2 -1
- package/src/themes/classics.ts +949 -0
- package/src/themes/import.ts +420 -0
- package/src/themes/page-fields.ts +40 -0
- package/src/themes/page-theme.ts +102 -0
- package/src/themes/presets.ts +561 -0
- package/src/themes/tokens.ts +218 -0
- package/src/tools/app-upsert.ts +1 -1
- package/src/tools/create-page.ts +118 -12
- package/src/tools/send-task.ts +35 -47
- package/src/tools/slack-leave-thread.ts +1 -1
- package/src/tools/task-dedup.ts +45 -21
- package/src/tools/utils.ts +33 -0
- package/src/types.ts +83 -3
- package/src/utils/constants.ts +19 -0
- package/src/utils/follow-up-gate-schedule-ids.ts +13 -0
- package/src/utils/internal-ai/credentials.ts +146 -93
- package/src/utils/internal-ai/index.ts +10 -0
- package/src/utils/internal-ai/models.ts +18 -0
- package/src/utils/internal-ai/task-title.ts +282 -0
- package/src/utils/page-session.ts +37 -0
- package/templates/schedules/daily-status-report/content.md +88 -2
- package/templates/schedules/daily-swarm-update-check/content.md +16 -40
- package/templates/skills/apps/SKILL.md +1 -1
- package/templates/skills/apps/content.md +1 -1
- package/templates/skills/composio-google-docs/content.md +10 -0
- package/templates/skills/heartbeat-runbook/content.md +1 -1
- package/templates/skills/pages/config.json +1 -1
- package/templates/skills/pages/content.md +539 -86
- package/templates/skills/pages/files/examples/annotated-pr.html +21 -12
- package/templates/skills/pages/files/examples/multiplayer-board.html +41 -41
- package/templates/skills/pages/files/examples/report-page.html +125 -124
- package/templates/skills/script-workflows/content.md +19 -1
- package/templates/skills/swarm-docs/content.md +1 -0
- package/templates/skills/swarm-scripts/SKILL.md +2 -0
- package/templates/skills/swarm-scripts/content.md +2 -0
- package/dist/cli-2pnswgh8.js +0 -189
- package/dist/cli-dznrgaep.js +0 -30
- package/dist/cli-w3hcrxht.js +0 -6985
- package/dist/handlers-vwmba1m2.js +0 -31
- package/dist/index-5r71rf98.js +0 -32
- package/dist/index-anmwxs87.js +0 -29
- package/dist/index-spp0ra5c.js +0 -36
- package/dist/lead-fjy418cw.js +0 -69
- package/dist/worker-0c5tyzqe.js +0 -69
- package/templates/schedules/daily-workflow-health-audit/config.json +0 -19
- package/templates/schedules/daily-workflow-health-audit/content.md +0 -191
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task title generation: a short display title for a task prompt.
|
|
3
|
+
*
|
|
4
|
+
* Consumer of `completeStructuredWithModel`. Walks `TASK_TITLE_MODEL_CANDIDATES`
|
|
5
|
+
* (provider order, then model order) and returns the first title a configured
|
|
6
|
+
* credential produces. Every candidate is a cheap, fast model: one title costs
|
|
7
|
+
* well under a tenth of a cent, so thousands of weekly tasks stay in cents.
|
|
8
|
+
*
|
|
9
|
+
* Worker-safe: no bun:sqlite import. The API server wires it to task creation
|
|
10
|
+
* in `src/be/task-auto-title-listener.ts`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { Type } from "typebox";
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
import { scrubSecrets } from "../secret-scrubber.js";
|
|
16
|
+
import { completeStructuredWithModel } from "./complete-structured.js";
|
|
17
|
+
import { type CredentialKind, type ResolvedCredential, resolveCredentials } from "./credentials.js";
|
|
18
|
+
import { kindForModelString } from "./models.js";
|
|
19
|
+
|
|
20
|
+
/** Longest generated title. The PATCH /api/tasks/{id}/title route allows 120. */
|
|
21
|
+
export const TASK_TITLE_MAX_CHARS = 100;
|
|
22
|
+
/** Prompts shorter than this keep the prompt itself as the display title. */
|
|
23
|
+
export const TASK_TITLE_MIN_TASK_CHARS = 48;
|
|
24
|
+
/** Prompt text sent to the model is cut here. Keeps every call small. */
|
|
25
|
+
export const TASK_TITLE_MAX_TASK_CHARS = 2000;
|
|
26
|
+
/** Whole generation, across every candidate. */
|
|
27
|
+
export const TASK_TITLE_TIMEOUT_MS = 20_000;
|
|
28
|
+
|
|
29
|
+
/** Env var that pins one model (`provider/model-id`, or a `claude -p` alias). */
|
|
30
|
+
export const TASK_TITLE_MODEL_ENV = "TASK_AUTO_TITLE_MODEL";
|
|
31
|
+
|
|
32
|
+
export interface TaskTitleCandidateGroup {
|
|
33
|
+
kind: CredentialKind;
|
|
34
|
+
/** Full model strings for this credential kind, best first. */
|
|
35
|
+
models: readonly string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Provider order, then model order within a provider. Cheapest and fastest
|
|
40
|
+
* first: pay-per-token API keys before subscription OAuth, and the `claude -p`
|
|
41
|
+
* shellout last (it spawns a full CLI process per call).
|
|
42
|
+
*
|
|
43
|
+
* Model prices (input / output, USD per million tokens, models.dev snapshot):
|
|
44
|
+
* deepseek-v4.1-flash 0.034 / 0.137 · claude-haiku-5.5 0.10 / 0.50 ·
|
|
45
|
+
* gpt-6-luna 0.10 / 0.50 · gpt-5-nano 0.05 / 0.40
|
|
46
|
+
*/
|
|
47
|
+
export const TASK_TITLE_MODEL_CANDIDATES: readonly TaskTitleCandidateGroup[] = [
|
|
48
|
+
{
|
|
49
|
+
kind: "openrouter",
|
|
50
|
+
models: [
|
|
51
|
+
"openrouter/deepseek/deepseek-v4.1-flash",
|
|
52
|
+
"openrouter/anthropic/claude-haiku-5.5",
|
|
53
|
+
"openrouter/openai/gpt-6-luna",
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
{ kind: "anthropic", models: ["anthropic/claude-haiku-5-5"] },
|
|
57
|
+
{ kind: "openai", models: ["openai/gpt-6-luna", "openai/gpt-5-nano"] },
|
|
58
|
+
{ kind: "openai-codex", models: ["openai-codex/gpt-6-luna"] },
|
|
59
|
+
{ kind: "claude-cli", models: ["haiku"] },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
export { kindForModelString };
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The candidate list for one environment. `TASK_AUTO_TITLE_MODEL` moves its
|
|
66
|
+
* provider to the front and puts the pinned model first inside it; the rest of
|
|
67
|
+
* the list stays as fallback. An unknown provider is ignored with a warning.
|
|
68
|
+
*/
|
|
69
|
+
export function buildTaskTitlePlan(
|
|
70
|
+
env: Record<string, string | undefined> = process.env,
|
|
71
|
+
): readonly TaskTitleCandidateGroup[] {
|
|
72
|
+
const pinned = env[TASK_TITLE_MODEL_ENV]?.trim();
|
|
73
|
+
if (!pinned) return TASK_TITLE_MODEL_CANDIDATES;
|
|
74
|
+
const kind = kindForModelString(pinned);
|
|
75
|
+
if (!kind) {
|
|
76
|
+
console.warn(
|
|
77
|
+
`[task-title] ${TASK_TITLE_MODEL_ENV}=${pinned} names an unsupported provider; ignored`,
|
|
78
|
+
);
|
|
79
|
+
return TASK_TITLE_MODEL_CANDIDATES;
|
|
80
|
+
}
|
|
81
|
+
const own = TASK_TITLE_MODEL_CANDIDATES.find((group) => group.kind === kind);
|
|
82
|
+
const rest = TASK_TITLE_MODEL_CANDIDATES.filter((group) => group.kind !== kind);
|
|
83
|
+
const models = [pinned, ...(own?.models ?? []).filter((model) => model !== pinned)];
|
|
84
|
+
return [{ kind, models }, ...rest];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const SIBLING_OPEN = "<sibling_tasks_in_progress>";
|
|
88
|
+
const SIBLING_CLOSE = "</sibling_tasks_in_progress>";
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Task text as the model should see it: without the sibling-awareness block
|
|
92
|
+
* the API prepends to child tasks, with runs of blank lines collapsed, and cut
|
|
93
|
+
* to `TASK_TITLE_MAX_TASK_CHARS`.
|
|
94
|
+
*/
|
|
95
|
+
export function prepareTaskTextForTitle(task: string): string {
|
|
96
|
+
let text = task;
|
|
97
|
+
if (text.startsWith(SIBLING_OPEN)) {
|
|
98
|
+
const close = text.indexOf(SIBLING_CLOSE);
|
|
99
|
+
if (close !== -1) text = text.slice(close + SIBLING_CLOSE.length);
|
|
100
|
+
}
|
|
101
|
+
text = text
|
|
102
|
+
.replace(/\r\n?/g, "\n")
|
|
103
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
104
|
+
.trim();
|
|
105
|
+
if (text.length > TASK_TITLE_MAX_TASK_CHARS) {
|
|
106
|
+
text = `${text.slice(0, TASK_TITLE_MAX_TASK_CHARS).trimEnd()} …`;
|
|
107
|
+
}
|
|
108
|
+
return text;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const WRAPPING_QUOTES: ReadonlyArray<[string, string]> = [
|
|
112
|
+
['"', '"'],
|
|
113
|
+
["'", "'"],
|
|
114
|
+
["“", "”"],
|
|
115
|
+
["‘", "’"],
|
|
116
|
+
["`", "`"],
|
|
117
|
+
["«", "»"],
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Clean a model-produced title: one line, no wrapping quotes or `Title:`
|
|
122
|
+
* prefix, no markdown emphasis, no trailing sentence punctuation, at most
|
|
123
|
+
* `TASK_TITLE_MAX_CHARS` (cut at a word boundary). Empty string when nothing
|
|
124
|
+
* usable remains.
|
|
125
|
+
*/
|
|
126
|
+
export function normalizeTaskTitle(raw: string): string {
|
|
127
|
+
let title = raw.replace(/\s+/g, " ").trim();
|
|
128
|
+
title = title.replace(/^title\s*:\s*/i, "");
|
|
129
|
+
title = title.replace(/\*\*|__|^#+\s*/g, "");
|
|
130
|
+
const stripTrailingPunctuation = () => {
|
|
131
|
+
title = title.replace(/[.!…]+$/u, "").trim();
|
|
132
|
+
};
|
|
133
|
+
// Quotes can sit inside or outside the trailing punctuation: `"Title".` and `"Title…"`.
|
|
134
|
+
stripTrailingPunctuation();
|
|
135
|
+
for (const [open, close] of WRAPPING_QUOTES) {
|
|
136
|
+
if (title.length >= 2 && title.startsWith(open) && title.endsWith(close)) {
|
|
137
|
+
title = title.slice(open.length, title.length - close.length).trim();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
stripTrailingPunctuation();
|
|
141
|
+
if (title.length > TASK_TITLE_MAX_CHARS) {
|
|
142
|
+
const cut = title.slice(0, TASK_TITLE_MAX_CHARS);
|
|
143
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
144
|
+
title = (lastSpace >= TASK_TITLE_MAX_CHARS / 2 ? cut.slice(0, lastSpace) : cut).trimEnd();
|
|
145
|
+
title = title.replace(/[,;:\-–—]+$/u, "").trimEnd();
|
|
146
|
+
}
|
|
147
|
+
return title;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export const TASK_TITLE_SYSTEM_PROMPT = [
|
|
151
|
+
"You write titles for tasks on a software team's dashboard.",
|
|
152
|
+
"Rules:",
|
|
153
|
+
"- 3 to 8 words, at most 80 characters.",
|
|
154
|
+
"- Sentence case. No trailing period. No quotes, markdown, emoji, or task ids.",
|
|
155
|
+
"- Name the concrete subject (feature, bug, repo, file, system, person), not a generic verb alone.",
|
|
156
|
+
"- Keep the language of the request.",
|
|
157
|
+
"- Ignore pasted logs, code, and context blocks; title the request itself.",
|
|
158
|
+
"Call the set_title tool with the title.",
|
|
159
|
+
].join("\n");
|
|
160
|
+
|
|
161
|
+
export const TASK_TITLE_TOOL_NAME = "set_title";
|
|
162
|
+
|
|
163
|
+
const TaskTitleZodSchema = z.object({ title: z.string().trim().min(1).max(200) });
|
|
164
|
+
const TaskTitleToolSchema = Type.Object({
|
|
165
|
+
title: Type.String({ minLength: 1, maxLength: 200, description: "The task title." }),
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
export interface GenerateTaskTitleOptions {
|
|
169
|
+
/** Full task prompt as stored on the task. */
|
|
170
|
+
task: string;
|
|
171
|
+
/** Credential lookup env. Defaults to `process.env`. */
|
|
172
|
+
env?: Record<string, string | undefined>;
|
|
173
|
+
/** Optional loopback context for the codex OAuth probe (see `resolveCredentials`). */
|
|
174
|
+
apiUrl?: string;
|
|
175
|
+
apiKey?: string;
|
|
176
|
+
signal?: AbortSignal;
|
|
177
|
+
/** Diagnostic tag forwarded to `completeStructured` logs. */
|
|
178
|
+
callerTag?: string;
|
|
179
|
+
// Test injection points:
|
|
180
|
+
_resolveCredentials?: typeof resolveCredentials;
|
|
181
|
+
_completeStructured?: typeof completeStructuredWithModel;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export type GenerateTaskTitleResult =
|
|
185
|
+
| { ok: true; title: string; model: string; kind: CredentialKind }
|
|
186
|
+
| { ok: false; reason: "short-task" | "no-credentials" | "all-models-failed" };
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Generate a title for `task`. Never throws: a provider error moves on to the
|
|
190
|
+
* next candidate, and exhausting the list returns `{ ok: false }`.
|
|
191
|
+
*/
|
|
192
|
+
export async function generateTaskTitle(
|
|
193
|
+
opts: GenerateTaskTitleOptions,
|
|
194
|
+
): Promise<GenerateTaskTitleResult> {
|
|
195
|
+
const text = prepareTaskTextForTitle(opts.task);
|
|
196
|
+
if (text.length < TASK_TITLE_MIN_TASK_CHARS) return { ok: false, reason: "short-task" };
|
|
197
|
+
|
|
198
|
+
const env = opts.env ?? process.env;
|
|
199
|
+
const resolve = opts._resolveCredentials ?? resolveCredentials;
|
|
200
|
+
const complete = opts._completeStructured ?? completeStructuredWithModel;
|
|
201
|
+
const callerTag = opts.callerTag ?? "task-title";
|
|
202
|
+
const plan = buildTaskTitlePlan(env);
|
|
203
|
+
|
|
204
|
+
// One lookup per kind, on demand, so the codex OAuth probe (an HTTP call
|
|
205
|
+
// that can rotate a refresh token) runs only when its turn comes.
|
|
206
|
+
const credentialCache = new Map<CredentialKind, ResolvedCredential | null>();
|
|
207
|
+
const credentialFor = async (kind: CredentialKind): Promise<ResolvedCredential | null> => {
|
|
208
|
+
const cached = credentialCache.get(kind);
|
|
209
|
+
if (cached !== undefined) return cached;
|
|
210
|
+
const [cred] = await resolve({
|
|
211
|
+
env,
|
|
212
|
+
apiUrl: opts.apiUrl,
|
|
213
|
+
apiKey: opts.apiKey,
|
|
214
|
+
callerTag,
|
|
215
|
+
kinds: [kind],
|
|
216
|
+
limit: 1,
|
|
217
|
+
});
|
|
218
|
+
credentialCache.set(kind, cred ?? null);
|
|
219
|
+
return cred ?? null;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
let sawCredential = false;
|
|
223
|
+
for (const group of plan) {
|
|
224
|
+
if (opts.signal?.aborted) break;
|
|
225
|
+
const cred = await credentialFor(group.kind);
|
|
226
|
+
if (!cred) continue;
|
|
227
|
+
sawCredential = true;
|
|
228
|
+
for (const model of group.models) {
|
|
229
|
+
if (opts.signal?.aborted) break;
|
|
230
|
+
const title = await attemptTitle(complete, {
|
|
231
|
+
cred,
|
|
232
|
+
model,
|
|
233
|
+
text,
|
|
234
|
+
env,
|
|
235
|
+
callerTag,
|
|
236
|
+
signal: opts.signal,
|
|
237
|
+
});
|
|
238
|
+
if (title) return { ok: true, title, model, kind: cred.kind };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { ok: false, reason: sawCredential ? "all-models-failed" : "no-credentials" };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
interface TitleAttempt {
|
|
245
|
+
cred: ResolvedCredential;
|
|
246
|
+
model: string;
|
|
247
|
+
text: string;
|
|
248
|
+
env: Record<string, string | undefined>;
|
|
249
|
+
callerTag: string;
|
|
250
|
+
signal?: AbortSignal;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** One model call. `completeStructuredWithModel` swallows provider errors; a throw here is still just a miss. */
|
|
254
|
+
async function attemptTitle(
|
|
255
|
+
complete: typeof completeStructuredWithModel,
|
|
256
|
+
attempt: TitleAttempt,
|
|
257
|
+
): Promise<string> {
|
|
258
|
+
try {
|
|
259
|
+
const result = await complete({
|
|
260
|
+
zodSchema: TaskTitleZodSchema,
|
|
261
|
+
toolSchema: TaskTitleToolSchema,
|
|
262
|
+
toolName: TASK_TITLE_TOOL_NAME,
|
|
263
|
+
toolDescription: "Record the title for this task.",
|
|
264
|
+
systemPrompt: TASK_TITLE_SYSTEM_PROMPT,
|
|
265
|
+
userPrompt: `Task request:\n\n${attempt.text}`,
|
|
266
|
+
env: attempt.env,
|
|
267
|
+
retries: 1,
|
|
268
|
+
signal: attempt.signal,
|
|
269
|
+
callerTag: `${attempt.callerTag}:${attempt.model}`,
|
|
270
|
+
_credentialOverride: { ...attempt.cred, modelDefault: attempt.model },
|
|
271
|
+
});
|
|
272
|
+
return result ? normalizeTaskTitle(result.data.title) : "";
|
|
273
|
+
} catch (error) {
|
|
274
|
+
// Provider errors can echo request fragments; scrub before logging.
|
|
275
|
+
console.error(
|
|
276
|
+
scrubSecrets(
|
|
277
|
+
`[task-title] ${attempt.model} threw: ${error instanceof Error ? error.message : String(error)}`,
|
|
278
|
+
),
|
|
279
|
+
);
|
|
280
|
+
return "";
|
|
281
|
+
}
|
|
282
|
+
}
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
*/
|
|
28
28
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
29
29
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
30
|
+
import type { IncomingHttpHeaders } from "node:http";
|
|
30
31
|
import path from "node:path";
|
|
32
|
+
import { isDevOrTestNodeEnv } from "./node-env";
|
|
31
33
|
|
|
32
34
|
const ENV_SECRET = "PAGE_SESSION_SECRET";
|
|
33
35
|
const ENV_SECRET_FILE = "PAGE_SESSION_SECRET_FILE";
|
|
@@ -336,6 +338,41 @@ export async function extractAndVerifyCookie(
|
|
|
336
338
|
*/
|
|
337
339
|
const PAGE_SESSION_TTL_SECONDS = 3600;
|
|
338
340
|
|
|
341
|
+
const LOCAL_DEV_HOSTNAMES = new Set(["localhost", "127.0.0.1"]);
|
|
342
|
+
|
|
343
|
+
/** True only for a parsed `http:` URL whose hostname is exactly a loopback dev name. */
|
|
344
|
+
function isLocalHttpUrl(value: string): boolean {
|
|
345
|
+
try {
|
|
346
|
+
const url = new URL(value);
|
|
347
|
+
return url.protocol === "http:" && LOCAL_DEV_HOSTNAMES.has(url.hostname);
|
|
348
|
+
} catch {
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Decide the `dev` flag for `issuePageSessionCookie`. Shared by the launch
|
|
355
|
+
* endpoint (`src/http/pages.ts`) and the password flow on `/p/:id`
|
|
356
|
+
* (`src/http/pages-public.ts`) so both issue the same cookie.
|
|
357
|
+
*
|
|
358
|
+
* Fails closed: only an explicit development or test NODE_ENV can soften the
|
|
359
|
+
* cookie. Deployed images leave NODE_ENV unset and get `SameSite=None; Secure`.
|
|
360
|
+
* In dev, the request must come from `http://localhost` or `http://127.0.0.1`
|
|
361
|
+
* (parsed, so `http://localhost.evil.example` does not match). Without an
|
|
362
|
+
* Origin, the Host header decides; a missing Host counts as local.
|
|
363
|
+
* Anything else, including portless `https://*.localhost`, keeps
|
|
364
|
+
* `SameSite=None; Secure` so the cookie travels on cross-site fetches.
|
|
365
|
+
* Chrome treats localhost as a secure context, so Secure also works over http.
|
|
366
|
+
*/
|
|
367
|
+
export function isLocalDevPageRequest(req: { headers: IncomingHttpHeaders }): boolean {
|
|
368
|
+
if (!isDevOrTestNodeEnv()) return false;
|
|
369
|
+
const origin = req.headers.origin ?? "";
|
|
370
|
+
if (origin !== "") return isLocalHttpUrl(origin);
|
|
371
|
+
const host = req.headers.host;
|
|
372
|
+
if (!host) return true;
|
|
373
|
+
return isLocalHttpUrl(`http://${host}`);
|
|
374
|
+
}
|
|
375
|
+
|
|
339
376
|
/**
|
|
340
377
|
* Mint a signed page-session token + build the `Set-Cookie` header value for
|
|
341
378
|
* `pageId`. Shared by the bearer-authed launch endpoint (`src/http/pages.ts`)
|
|
@@ -27,7 +27,93 @@ You are Lead. Produce one digest covering workflows, schedule runs, agents, task
|
|
|
27
27
|
Call `GET $MCP_BASE_URL/status` and read `status.automations`. List every automation whose state is `needs_setup`, its missing parameters/integrations, and its `fixUrl`. This is the first digest section and the first failure classification; it is setup work, not an automation failure.
|
|
28
28
|
|
|
29
29
|
### 1B. Workflows and schedules
|
|
30
|
-
Run
|
|
30
|
+
Run these six failure-mode queries with `db-query`:
|
|
31
|
+
|
|
32
|
+
**1.** Hard-failed workflow runs (last 24h)
|
|
33
|
+
|
|
34
|
+
```sql
|
|
35
|
+
SELECT wr.id, w.name AS workflowName, wr.status,
|
|
36
|
+
wr.finishedAt, wr.lastUpdatedAt,
|
|
37
|
+
SUBSTR(COALESCE(wr.error, ''), 1, 220) AS errSnippet
|
|
38
|
+
FROM workflow_runs wr
|
|
39
|
+
JOIN workflows w ON w.id = wr.workflowId
|
|
40
|
+
WHERE wr.status = 'failed'
|
|
41
|
+
AND datetime(COALESCE(wr.finishedAt, wr.lastUpdatedAt, wr.startedAt)) > datetime('now', '-24 hours')
|
|
42
|
+
ORDER BY wr.lastUpdatedAt DESC;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**2.** Hard-failed schedule-spawned tasks (last 24h)
|
|
46
|
+
|
|
47
|
+
```sql
|
|
48
|
+
SELECT t.id, s.name AS scheduleName, t.status,
|
|
49
|
+
SUBSTR(COALESCE(t.failureReason, ''), 1, 220) AS reasonSnippet,
|
|
50
|
+
SUBSTR(COALESCE(t.output, ''), 1, 220) AS outSnippet,
|
|
51
|
+
t.lastUpdatedAt
|
|
52
|
+
FROM agent_tasks t
|
|
53
|
+
LEFT JOIN scheduled_tasks s ON s.id = t.scheduleId
|
|
54
|
+
WHERE t.status = 'failed'
|
|
55
|
+
AND t.scheduleId IS NOT NULL
|
|
56
|
+
AND datetime(t.lastUpdatedAt) > datetime('now', '-24 hours')
|
|
57
|
+
ORDER BY t.lastUpdatedAt DESC;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**3.** Halted >24h workflow runs (silent stuck)
|
|
61
|
+
|
|
62
|
+
```sql
|
|
63
|
+
SELECT wr.id, w.name AS workflowName, wr.status, wr.lastUpdatedAt
|
|
64
|
+
FROM workflow_runs wr
|
|
65
|
+
JOIN workflows w ON w.id = wr.workflowId
|
|
66
|
+
WHERE wr.status IN ('running', 'waiting')
|
|
67
|
+
AND datetime(wr.lastUpdatedAt) < datetime('now', '-24 hours')
|
|
68
|
+
ORDER BY wr.lastUpdatedAt ASC;
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**4.** Silent: schedule-spawned task completed with empty/sentinel output
|
|
72
|
+
|
|
73
|
+
```sql
|
|
74
|
+
SELECT t.id, s.name AS scheduleName, t.status,
|
|
75
|
+
SUBSTR(COALESCE(t.output, ''), 1, 220) AS outSnippet,
|
|
76
|
+
LENGTH(TRIM(COALESCE(t.output, ''))) AS outLen,
|
|
77
|
+
t.lastUpdatedAt
|
|
78
|
+
FROM agent_tasks t
|
|
79
|
+
LEFT JOIN scheduled_tasks s ON s.id = t.scheduleId
|
|
80
|
+
WHERE t.status = 'completed'
|
|
81
|
+
AND t.scheduleId IS NOT NULL
|
|
82
|
+
AND datetime(t.lastUpdatedAt) > datetime('now', '-24 hours')
|
|
83
|
+
AND (
|
|
84
|
+
t.output IS NULL
|
|
85
|
+
OR TRIM(t.output) = ''
|
|
86
|
+
OR TRIM(t.output) = '⚡ Running shell command'
|
|
87
|
+
OR LENGTH(TRIM(t.output)) < 10
|
|
88
|
+
)
|
|
89
|
+
ORDER BY t.lastUpdatedAt DESC;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**5.** Cron didn't fire (nextRunAt in the past)
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
SELECT s.id, s.name, s.cronExpression, s.lastRunAt, s.nextRunAt, s.consecutiveErrors,
|
|
96
|
+
SUBSTR(COALESCE(s.lastErrorMessage, ''), 1, 220) AS lastErrSnippet
|
|
97
|
+
FROM scheduled_tasks s
|
|
98
|
+
WHERE s.enabled = 1
|
|
99
|
+
AND s.scheduleType = 'recurring'
|
|
100
|
+
AND s.nextRunAt IS NOT NULL
|
|
101
|
+
AND datetime(s.nextRunAt) < datetime('now', '-1 hour')
|
|
102
|
+
ORDER BY s.nextRunAt ASC;
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**6.** Schedules with consecutive errors (defensive)
|
|
106
|
+
|
|
107
|
+
```sql
|
|
108
|
+
SELECT s.id, s.name, s.cronExpression, s.consecutiveErrors, s.lastErrorAt,
|
|
109
|
+
SUBSTR(COALESCE(s.lastErrorMessage, ''), 1, 220) AS lastErrSnippet
|
|
110
|
+
FROM scheduled_tasks s
|
|
111
|
+
WHERE s.enabled = 1
|
|
112
|
+
AND s.consecutiveErrors >= 3
|
|
113
|
+
ORDER BY s.consecutiveErrors DESC;
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Plus:
|
|
31
117
|
- Enabled/disabled counts: `SELECT enabled, COUNT(*) FROM scheduled_tasks GROUP BY enabled` and the workflow equivalent.
|
|
32
118
|
- 7-day rollup, not just 24h: repeat the hard-failure and cron-didn't-fire queries with a `-7 days` window for a weekly trend line.
|
|
33
119
|
|
|
@@ -87,7 +173,7 @@ More than 3 qualify ⇒ post the 3 that matter and put the rest in the task outp
|
|
|
87
173
|
`store-progress` with `status: "completed"`. **This is where the detail goes** — every count from Phase 1, the per-class failure breakdown, and the Slack message ts. The Slack post is the headline; the task output is the record. Cutting the post does not mean cutting the work.
|
|
88
174
|
|
|
89
175
|
## Anti-patterns
|
|
90
|
-
- ❌ Modifying anything — this schedule reports, it doesn't fix (that's `daily-
|
|
176
|
+
- ❌ Modifying anything — this schedule reports, it doesn't fix (that's `daily-compounding-reflection` for agent/skill/memory evolution).
|
|
91
177
|
- ❌ Folding the unclassified-failure bucket into "real defect" to make the number look more actionable than it is.
|
|
92
178
|
- ❌ Narrating a zero. The all-clear line already covers `needs_setup` and integrations; only a non-verified integration or a real `needs_setup` automation earns its own line.
|
|
93
179
|
- ❌ Exceeding 600 characters, or posting more than one message.
|
|
@@ -2,48 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Zero-config auto-update watchdog: compares the swarm's own running version against the latest published GitHub release of `desplega-ai/agent-swarm`, and flags the operator when an upgrade is available. No placeholders and no integration required — every install gets this by default.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```json
|
|
8
|
-
{"cron":"0 9 * * *","timezone":"UTC","agentRole":"lead","enabled":true}
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Scheduled Task
|
|
12
|
-
|
|
13
|
-
This schedule runs by default. It needs no repository clone and no integration — it only reads its own task metadata and calls the public GitHub API.
|
|
14
|
-
|
|
15
|
-
Task Type: Daily Agent-Swarm Update Check
|
|
16
|
-
|
|
17
|
-
You are Lead. Determine whether a newer `desplega-ai/agent-swarm` release is published than the version currently running on this install, and tell the operator if so.
|
|
18
|
-
|
|
19
|
-
## Phase 1 — Determine the running version
|
|
5
|
+
This is a script schedule: each fire runs the global `swarm-update-check` script directly, with no agent task in between. The script:
|
|
20
6
|
|
|
21
|
-
|
|
7
|
+
1. Reads the running version from the API server's own `/health` route.
|
|
8
|
+
2. Fetches `https://api.github.com/repos/desplega-ai/agent-swarm/releases/latest` once and reads `tag_name` and `html_url`.
|
|
9
|
+
3. Compares the two as numeric `major.minor.patch`, never as strings (`"1.9.0" < "1.10.0"` is false as strings).
|
|
10
|
+
4. Only when the latest release is newer, sends the lead one task to post the notice to its configured admin delivery channel (the in-app fallback if none is configured).
|
|
22
11
|
|
|
23
|
-
|
|
12
|
+
Up to date, a missing running version (reported as `unknown`, never as up to date) and an unreachable GitHub API all end the run without any agent task. A failed GitHub call is reported once and never retried in a loop. The check never attempts the upgrade; `weekly-harness-upgrade-check` is the separate routine that bumps pinned harness versions inside the repo.
|
|
24
13
|
|
|
25
|
-
##
|
|
14
|
+
## Schedule
|
|
26
15
|
|
|
27
|
-
```
|
|
28
|
-
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"cron": "0 9 * * *",
|
|
19
|
+
"timezone": "UTC",
|
|
20
|
+
"enabled": true,
|
|
21
|
+
"targetType": "script",
|
|
22
|
+
"scriptName": "swarm-update-check",
|
|
23
|
+
"scriptArgs": {}
|
|
24
|
+
}
|
|
29
25
|
```
|
|
30
|
-
|
|
31
|
-
Read `.tag_name` (strip a leading `v` if present) and `.html_url`. If the request fails (network, rate limit, non-200), complete with `output`: `"Could not reach GitHub releases API: <error>"` and stop — do not retry in a loop.
|
|
32
|
-
|
|
33
|
-
## Phase 3 — Compare and act
|
|
34
|
-
|
|
35
|
-
Compare the two versions as dotted numeric triples (major.minor.patch) — never as plain strings (`"1.9.0" < "1.10.0"` is false as strings).
|
|
36
|
-
|
|
37
|
-
- **Latest <= running:** complete with `output`: `"Up to date: running <running>, latest published <latest>."` No further action.
|
|
38
|
-
- **Latest > running:** raise it for the operator:
|
|
39
|
-
1. Post a short message to your configured admin delivery channel (or the in-app fallback if none is configured) naming the running version, the new version, and the release URL.
|
|
40
|
-
2. Complete `store-progress` with `status: "completed"` and `output`: `"Update available: running <running>, latest <latest> — <releaseUrl>"`.
|
|
41
|
-
|
|
42
|
-
Do not attempt the upgrade yourself — this schedule only detects and reports. `weekly-harness-upgrade-check` is the separate routine that bumps pinned harness versions inside the repo; this schedule is about the agent-swarm release itself.
|
|
43
|
-
|
|
44
|
-
## Anti-patterns
|
|
45
|
-
|
|
46
|
-
- ❌ Cloning the repo or reading `package.json` from disk — this schedule must work on any install, including ones where the API pod has no repo checkout.
|
|
47
|
-
- ❌ String-comparing versions.
|
|
48
|
-
- ❌ Treating a missing `swarmVersion` as "no update available" — it's "unknown", say so explicitly.
|
|
49
|
-
- ❌ Retrying a failed GitHub API call in a loop.
|
|
@@ -133,7 +133,7 @@ Use `{ "$state": "/user/<field>" }` on a page for the read-only current-user bin
|
|
|
133
133
|
|
|
134
134
|
### Theming
|
|
135
135
|
|
|
136
|
-
An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas
|
|
136
|
+
An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas: a lowercase slug validated by shape only. The preset catalog ships with the dashboard and lives in `src/themes/presets.ts` and `src/themes/classics.ts`. Update this list and the `app-upsert` tool description when it changes. Current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, `paper` (the warm editorial paper look), and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette: hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
|
|
137
137
|
|
|
138
138
|
Viewers can override the preset per app from the app's settings drawer; the override rides the reserved `$theme` key of the user-config values (accepted on every app, even without a declared `userConfig` schema, and never visible at `/user/...`). A present override always beats the definition's `theme` — even an unrecognized one, which degrades to the dashboard theme — so treat `theme` as the app's default styling, not a guarantee.
|
|
139
139
|
|
|
@@ -128,7 +128,7 @@ Use `{ "$state": "/user/<field>" }` on a page for the read-only current-user bin
|
|
|
128
128
|
|
|
129
129
|
### Theming
|
|
130
130
|
|
|
131
|
-
An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas
|
|
131
|
+
An optional top-level `"theme"` sets the preset the dashboard applies to the app's rendered canvas: a lowercase slug validated by shape only. The preset catalog ships with the dashboard and lives in `src/themes/presets.ts` and `src/themes/classics.ts`. Update this list and the `app-upsert` tool description when it changes. Current ids: `hive` (the stock look), the accent/field presets `meadow`, `iris`, `rose`, `cobalt`, `ember`, `carbon`, `paper` (the warm editorial paper look), and the classic editor/platform presets `github`, `vscode`, `material`, `solarized`, `tokyo`, `monokai`, `gruvbox`, `catppuccin`. Action and destructive tones are never themed; status tones are themed ONLY by the classic presets (their identity includes a status palette: hue semantics stay fixed, success reads green and error reads red everywhere). An id the viewer's dashboard build does not know degrades to the dashboard's own theme, so unknown slugs are safe but pointless. Omit `theme` to inherit whatever theme the viewer runs; `"hive"` is an explicit reset to the stock look even inside a themed dashboard.
|
|
132
132
|
|
|
133
133
|
Viewers can override the preset per app from the app's settings drawer; the override rides the reserved `$theme` key of the user-config values (accepted on every app, even without a declared `userConfig` schema, and never visible at `/user/...`). A present override always beats the definition's `theme` — even an unrecognized one, which degrades to the dashboard theme — so treat `theme` as the app's default styling, not a guarantee.
|
|
134
134
|
|
|
@@ -80,6 +80,16 @@ Google Drive export, then preserve or reconstruct the structure explicitly.
|
|
|
80
80
|
There is no `GET_DOCUMENT_MARKDOWN` tool; markdown exists on create/update, not
|
|
81
81
|
on read.
|
|
82
82
|
|
|
83
|
+
## Comments
|
|
84
|
+
|
|
85
|
+
Doc comments are a Drive feature, not a Docs one: there is no `GOOGLEDOCS_*`
|
|
86
|
+
comment slug. List them with `GOOGLEDRIVE_LIST_COMMENTS` (replies:
|
|
87
|
+
`GOOGLEDRIVE_LIST_REPLIES`) from the `googledrive` toolkit, so resolve the
|
|
88
|
+
user's `googledrive` connected account instead of their `googledocs` one.
|
|
89
|
+
Listing only works when the Drive read scopes are authorized on that account.
|
|
90
|
+
`GOOGLEDRIVE_CREATE_COMMENT` and the update/delete tools are write actions,
|
|
91
|
+
only on explicit request.
|
|
92
|
+
|
|
83
93
|
## Gotchas
|
|
84
94
|
|
|
85
95
|
- Search returns Drive metadata, not document content — do a second
|
|
@@ -35,7 +35,7 @@ Two kinds of sections:
|
|
|
35
35
|
|
|
36
36
|
0. Quiet check. Take the fast path when three things hold: every failed, stalled or reboot-interrupted task in the system status was already named in the previous heartbeat-checklist task's output (newest completed one via `get-tasks`); no mention has gone unanswered since the last heartbeat; and no tracked item in the task's runbook snapshot is at or past its date. On the fast path, run the two step 3 scripts. If they report nothing the previous heartbeat had not already triaged, complete with exactly one line, `Quiet. Same as <previousTaskId>: <N> failures (triaged), schedule-health <M>/<total>, controls ok.`, and skip steps 1, 2 and 4-7. A longer quiet output is a defect: no failure-set recap, no per-script bullets. Anything new means continue at step 1.
|
|
37
37
|
1. Read the latest runbook. The snapshot in the task may be stale.
|
|
38
|
-
2. Prune first. Check every tracked item against its lift trigger. Remove resolved, stale, and past-date items. A trigger tied to a pull request ("lift when #N merges") fires silently: read the state of every PR a trigger names. Merged means the lift fired, so act on it now. Closed without merge means the item is dead, so drop it.
|
|
38
|
+
2. Prune first. Check every tracked item against its lift trigger. Remove resolved, stale, and past-date items. A trigger tied to a pull request ("lift when #N merges") fires silently: read the state of every PR a trigger names. Merged means the lift fired, so act on it now. Closed without merge means the item is dead, so drop it. A PR's `mergeable` field reads `null` while the host is still computing it: `null` is unknown, never clean, so re-read until a value comes back and never treat it as a cleared blocker or as ready to merge.
|
|
39
39
|
3. Run the seeded scripts: `script-run` with name `schedule-health`, then `task-failure-audit`, both with `args: { days: 1, publishPage: false }`. They report failing schedules and failure clusters. Check any other standing order in the runbook yourself.
|
|
40
40
|
4. Read the system status and the script results for stalled tasks, idle workers next to open work, and anomalies.
|
|
41
41
|
5. Reboot-interrupted failures: the failure reason "Auto-failed by reboot sweep: worker session not found after server restart" means a restart cut the task off. For each one: `get-task-details` on the task, confirm a retry task tagged `reboot-retry` exists and moves, recreate the task when no retry exists and the work is still needed. Heartbeat and triage tasks get no retry. A worker crash outside a restart ("worker session not found" or "worker session heartbeat is stale" from the stall sweep) normally leaves a `superseded` task with a `resume` child instead; check that the child moves. None of these are "expected cleanup".
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"displayName": "Pages",
|
|
5
5
|
"slug": "pages",
|
|
6
6
|
"title": "Pages",
|
|
7
|
-
"description": "Publish human-readable task outputs as DB-backed shareable pages (HTML or JSON) via `create_page
|
|
7
|
+
"description": "Publish human-readable task outputs as DB-backed shareable pages (HTML or JSON) via `create_page`, with no server and no tunnel. Covers auth modes, share URLs, versioning, the injected browser SDK, the `<swarm-diff>` web component, print/PDF export, and limits. Also covers the swarm design system every page should use: theme tokens, `swarm-*` primitives, Tailwind v4 utilities, theme presets, dark mode, and the minimalist taste and report-density rules.",
|
|
8
8
|
"version": "2.0.0",
|
|
9
9
|
"category": "skills",
|
|
10
10
|
"placeholders": [],
|