@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
package/src/http/script-runs.ts
CHANGED
|
@@ -13,10 +13,12 @@ import {
|
|
|
13
13
|
getLatestScriptRunStepTaskByContextKey,
|
|
14
14
|
getScriptRun,
|
|
15
15
|
getScriptRunByIdempotencyKey,
|
|
16
|
+
getScriptRunFollowUpGuard,
|
|
16
17
|
getScriptRunJournalStep,
|
|
17
18
|
getTaskById,
|
|
18
19
|
listScriptRunJournalSteps,
|
|
19
20
|
listScriptRuns,
|
|
21
|
+
setScriptRunFollowUpGuard,
|
|
20
22
|
updateScriptRun,
|
|
21
23
|
updateScriptRunIfNotTerminal,
|
|
22
24
|
updateScriptRunIfRunning,
|
|
@@ -24,6 +26,7 @@ import {
|
|
|
24
26
|
} from "../be/db";
|
|
25
27
|
import { explicitModelErrorForAgent } from "../be/model-validation";
|
|
26
28
|
import { refuseSourceWithSecrets } from "../be/scripts/source-secrets";
|
|
29
|
+
import { can } from "../rbac";
|
|
27
30
|
import { lintWorkflowLabels } from "../script-workflows/label-lint";
|
|
28
31
|
import { scriptRunMaxAgentTasks, scriptRunMaxSteps } from "../script-workflows/limits";
|
|
29
32
|
import {
|
|
@@ -32,6 +35,12 @@ import {
|
|
|
32
35
|
terminateScriptRunProcess,
|
|
33
36
|
} from "../script-workflows/supervisor";
|
|
34
37
|
import {
|
|
38
|
+
evaluateFollowUpRedelegation,
|
|
39
|
+
type FollowUpRedelegationBlock,
|
|
40
|
+
followUpThreadForSourceTask,
|
|
41
|
+
} from "../tasks/follow-up-redelegation-guard";
|
|
42
|
+
import {
|
|
43
|
+
type AgentTask,
|
|
35
44
|
AgentTaskStatusSchema,
|
|
36
45
|
RoutingReasonSchema,
|
|
37
46
|
ScriptRunJournalEntrySchema,
|
|
@@ -111,6 +120,8 @@ const agentTaskBodySchema = z.object({
|
|
|
111
120
|
parentTaskId: z.string().uuid().optional(),
|
|
112
121
|
requestedByUserId: z.string().optional(),
|
|
113
122
|
outputSchema: z.record(z.string(), z.unknown()).optional(),
|
|
123
|
+
/** Dispatch even when the follow-up re-delegation guard blocks it (same flag as send-task). */
|
|
124
|
+
allowRedelegation: z.boolean().optional(),
|
|
114
125
|
});
|
|
115
126
|
|
|
116
127
|
const scriptRunCreatedSchema = z.object({
|
|
@@ -298,10 +309,70 @@ const agentTaskRoute = route({
|
|
|
298
309
|
description: "Agent task created or still running",
|
|
299
310
|
schema: z.object({ taskId: z.string(), status: AgentTaskStatusSchema }),
|
|
300
311
|
},
|
|
312
|
+
403: {
|
|
313
|
+
description:
|
|
314
|
+
"Script run belongs to another agent, or the run's agent may not create a child task under parentTaskId",
|
|
315
|
+
},
|
|
301
316
|
404: { description: "Script run not found" },
|
|
317
|
+
409: { description: "Agent task failed, was cancelled, or was superseded" },
|
|
318
|
+
422: { description: "Blocked by the follow-up re-delegation guard" },
|
|
302
319
|
},
|
|
303
320
|
});
|
|
304
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Send-task's task.parent.attach decision for a `ctx.step.agentTask` step: a
|
|
324
|
+
* step inherits its parent's contextKey (its Slack or chat thread) and
|
|
325
|
+
* requester, so the run's agent needs the right to hold a child under it.
|
|
326
|
+
* Returns the 403 message, or null when allowed. A parent id with no task row
|
|
327
|
+
* passes: a step under it inherits nothing, as on send-task.
|
|
328
|
+
*/
|
|
329
|
+
async function stepParentRefusal(runAgentId: string, parentTaskId: string): Promise<string | null> {
|
|
330
|
+
const parentTask = await getTaskById(parentTaskId);
|
|
331
|
+
if (!parentTask) return null;
|
|
332
|
+
const runAgent = await getAgentById(runAgentId);
|
|
333
|
+
const decision = can({
|
|
334
|
+
principal: { kind: "agent", agentId: runAgentId, isLead: runAgent?.isLead ?? false },
|
|
335
|
+
verb: "task.parent.attach",
|
|
336
|
+
resource: {
|
|
337
|
+
kind: "task",
|
|
338
|
+
taskId: parentTask.id,
|
|
339
|
+
requestedByUserId: parentTask.requestedByUserId,
|
|
340
|
+
creatorAgentId: parentTask.creatorAgentId,
|
|
341
|
+
agentId: parentTask.agentId,
|
|
342
|
+
},
|
|
343
|
+
source: "http",
|
|
344
|
+
});
|
|
345
|
+
return decision.allow
|
|
346
|
+
? null
|
|
347
|
+
: `You don't have context for parent task ${parentTaskId}. Only its assignee, its creator, or a lead can create a child task under it.`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* The launching session's task (X-Source-Task-Id), kept only when it belongs
|
|
352
|
+
* to the launching agent so a run cannot borrow another agent's session.
|
|
353
|
+
*/
|
|
354
|
+
async function resolveRunSourceTaskId(
|
|
355
|
+
req: IncomingMessage,
|
|
356
|
+
agentId: string,
|
|
357
|
+
): Promise<string | undefined> {
|
|
358
|
+
const raw = req.headers["x-source-task-id"];
|
|
359
|
+
const sourceTaskId = Array.isArray(raw) ? raw[0] : raw;
|
|
360
|
+
if (!sourceTaskId) return undefined;
|
|
361
|
+
const task = await getTaskById(sourceTaskId);
|
|
362
|
+
return task?.agentId === agentId ? task.id : undefined;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** One `ctx.step.agentTask` dispatch: the step task, or the guard rule that blocked it. */
|
|
366
|
+
type StepDispatch =
|
|
367
|
+
| {
|
|
368
|
+
task: AgentTask;
|
|
369
|
+
/** True when this call inserted the step, false on a replay. */
|
|
370
|
+
created?: boolean;
|
|
371
|
+
blocked?: undefined;
|
|
372
|
+
override?: FollowUpRedelegationBlock["rule"];
|
|
373
|
+
}
|
|
374
|
+
| { task?: undefined; blocked: FollowUpRedelegationBlock; override?: undefined };
|
|
375
|
+
|
|
305
376
|
async function requireAgent(res: ServerResponse, agentId: string | undefined) {
|
|
306
377
|
if (!agentId) {
|
|
307
378
|
jsonError(res, "X-Agent-ID required for script runs API", 400);
|
|
@@ -408,6 +479,7 @@ export async function handleScriptRuns(
|
|
|
408
479
|
// Cap check and insert commit together: N concurrent POSTs otherwise all
|
|
409
480
|
// read cap-1 active runs and all insert, exceeding the cap.
|
|
410
481
|
const cap = scriptRunConcurrencyCap();
|
|
482
|
+
const sourceTaskId = await resolveRunSourceTaskId(req, agent.id);
|
|
411
483
|
const creation = await getDbClient().transaction(async () => {
|
|
412
484
|
if ((await countActiveScriptRuns()) >= cap) return null;
|
|
413
485
|
return await createScriptRun({
|
|
@@ -418,6 +490,7 @@ export async function handleScriptRuns(
|
|
|
418
490
|
scriptName: parsed.body.scriptName,
|
|
419
491
|
idempotencyKey: parsed.body.idempotencyKey,
|
|
420
492
|
requestedByUserId: parsed.body.requestedByUserId,
|
|
493
|
+
sourceTaskId,
|
|
421
494
|
createdBy: parsed.body.requestedByUserId,
|
|
422
495
|
});
|
|
423
496
|
});
|
|
@@ -629,9 +702,29 @@ export async function handleScriptRuns(
|
|
|
629
702
|
return true;
|
|
630
703
|
}
|
|
631
704
|
|
|
705
|
+
// Only the run's own harness dispatches its steps (it sends the run's
|
|
706
|
+
// agent id). Step tasks carry that agent as creator, so another agent
|
|
707
|
+
// must not create them.
|
|
708
|
+
if (agentId !== run.agentId) {
|
|
709
|
+
jsonError(res, "Script run belongs to another agent", 403);
|
|
710
|
+
return true;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// The requested parent, checked before any lookup or insert so a refused
|
|
714
|
+
// call creates nothing.
|
|
715
|
+
if (parsed.body.parentTaskId) {
|
|
716
|
+
const refusal = await stepParentRefusal(run.agentId, parsed.body.parentTaskId);
|
|
717
|
+
if (refusal) {
|
|
718
|
+
jsonError(res, refusal, 403);
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
632
723
|
const contextKey = `script-run:${run.id}:${parsed.body.stepKey}`;
|
|
633
724
|
let task = await getLatestScriptRunStepTaskByContextKey(contextKey);
|
|
725
|
+
let dispatchedHere = false;
|
|
634
726
|
if (!task) {
|
|
727
|
+
const taskDescription = parsed.body.template ?? parsed.body.task ?? parsed.body.stepKey;
|
|
635
728
|
const modelError = await explicitModelErrorForAgent({
|
|
636
729
|
model: parsed.body.model,
|
|
637
730
|
allowCustomModel: parsed.body.allowCustomModel,
|
|
@@ -641,10 +734,47 @@ export async function handleScriptRuns(
|
|
|
641
734
|
jsonError(res, modelError, 400);
|
|
642
735
|
return true;
|
|
643
736
|
}
|
|
737
|
+
const followUpThread = await followUpThreadForSourceTask(run.sourceTaskId);
|
|
738
|
+
// The replay lookup, the guard decision and the insert share one write
|
|
739
|
+
// transaction. It serializes this step against the run's other steps,
|
|
740
|
+
// other runs and send-task dispatches into the same thread.
|
|
741
|
+
let dispatched: StepDispatch;
|
|
644
742
|
try {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
{
|
|
743
|
+
dispatched = await getDbClient().transaction(async (): Promise<StepDispatch> => {
|
|
744
|
+
const replayed = await getLatestScriptRunStepTaskByContextKey(contextKey);
|
|
745
|
+
if (replayed) return { task: replayed };
|
|
746
|
+
|
|
747
|
+
// Follow-up re-delegation guard, as in send-task. A run is one
|
|
748
|
+
// dispatch: its first new step decides for the whole run, and every
|
|
749
|
+
// later step follows that decision. Later steps never compare against
|
|
750
|
+
// the run's own completed steps, a long run cannot use up the thread's
|
|
751
|
+
// loop cap, and parallel steps are dispatched all or none.
|
|
752
|
+
let override: FollowUpRedelegationBlock["rule"] | undefined;
|
|
753
|
+
if (followUpThread) {
|
|
754
|
+
const decision = await getScriptRunFollowUpGuard(run.id);
|
|
755
|
+
if (decision !== "passed") {
|
|
756
|
+
const blocked: FollowUpRedelegationBlock | null =
|
|
757
|
+
decision === null
|
|
758
|
+
? await evaluateFollowUpRedelegation({
|
|
759
|
+
...followUpThread,
|
|
760
|
+
creatorAgentId: run.agentId,
|
|
761
|
+
taskDescription,
|
|
762
|
+
targetAgentId: parsed.body.agentId,
|
|
763
|
+
})
|
|
764
|
+
: {
|
|
765
|
+
rule: decision,
|
|
766
|
+
message: `Blocked by the follow-up re-delegation guard (${decision} rule): an earlier step of this script run was blocked, and a run counts as one dispatch. If it must run, pass allowRedelegation: true.`,
|
|
767
|
+
};
|
|
768
|
+
if (blocked && !parsed.body.allowRedelegation) {
|
|
769
|
+
if (decision === null) await setScriptRunFollowUpGuard(run.id, blocked.rule);
|
|
770
|
+
return { blocked };
|
|
771
|
+
}
|
|
772
|
+
override = blocked?.rule;
|
|
773
|
+
await setScriptRunFollowUpGuard(run.id, "passed");
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const created = await createTaskExtended(taskDescription, {
|
|
648
778
|
agentId: parsed.body.agentId,
|
|
649
779
|
routingReason:
|
|
650
780
|
parsed.body.routingReason ?? (parsed.body.agentId ? "human_pinned" : undefined),
|
|
@@ -660,6 +790,20 @@ export async function handleScriptRuns(
|
|
|
660
790
|
offeredTo: parsed.body.offerMode ? parsed.body.agentId : undefined,
|
|
661
791
|
taskType: "script-run-step",
|
|
662
792
|
source: "mcp",
|
|
793
|
+
// Counts the run toward the launcher's follow-up loop cap.
|
|
794
|
+
creatorAgentId: run.agentId,
|
|
795
|
+
// With no parent, the step inherits the launching session's Slack
|
|
796
|
+
// thread, as a send-task from that session does.
|
|
797
|
+
sourceTaskId: run.sourceTaskId,
|
|
798
|
+
// A guarded run's steps are its dispatches into the follow-up's
|
|
799
|
+
// thread, whatever their parent, so the guard sees them there.
|
|
800
|
+
...(followUpThread
|
|
801
|
+
? {
|
|
802
|
+
slackChannelId: followUpThread.channelId,
|
|
803
|
+
slackThreadTs: followUpThread.threadTs,
|
|
804
|
+
slackUserId: followUpThread.userId,
|
|
805
|
+
}
|
|
806
|
+
: {}),
|
|
663
807
|
dir: parsed.body.dir,
|
|
664
808
|
vcsRepo: parsed.body.vcsRepo,
|
|
665
809
|
model: parsed.body.model,
|
|
@@ -667,8 +811,9 @@ export async function handleScriptRuns(
|
|
|
667
811
|
requestedByUserId: parsed.body.requestedByUserId ?? run.requestedByUserId,
|
|
668
812
|
outputSchema: parsed.body.outputSchema,
|
|
669
813
|
contextKey,
|
|
670
|
-
}
|
|
671
|
-
|
|
814
|
+
});
|
|
815
|
+
return { task: created, created: true, override };
|
|
816
|
+
});
|
|
672
817
|
} catch (error) {
|
|
673
818
|
if (error instanceof ExtensionAgentAssignmentError) {
|
|
674
819
|
jsonError(res, error.message, 400);
|
|
@@ -676,6 +821,30 @@ export async function handleScriptRuns(
|
|
|
676
821
|
}
|
|
677
822
|
throw error;
|
|
678
823
|
}
|
|
824
|
+
if (dispatched.override) {
|
|
825
|
+
console.log(
|
|
826
|
+
`[script-runs] follow-up re-delegation override: rule=${dispatched.override} runId=${run.id} creatorAgentId=${run.agentId} sourceTaskId=${run.sourceTaskId} thread=${followUpThread?.channelId}/${followUpThread?.threadTs}`,
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
if (!dispatched.task) {
|
|
830
|
+
json(res, { error: dispatched.blocked.message, rule: dispatched.blocked.rule }, 422);
|
|
831
|
+
return true;
|
|
832
|
+
}
|
|
833
|
+
task = dispatched.task;
|
|
834
|
+
dispatchedHere = dispatched.created === true;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// A replay answers from the selected step, whatever parent this call sent
|
|
838
|
+
// (or omitted), so authorize the parent the step actually holds. Every
|
|
839
|
+
// replay lookup above lands here before any output is returned. A step this
|
|
840
|
+
// call just dispatched was authorized above; refusing it now would leave
|
|
841
|
+
// the work running behind a 403.
|
|
842
|
+
if (!dispatchedHere && task.parentTaskId) {
|
|
843
|
+
const refusal = await stepParentRefusal(run.agentId, task.parentTaskId);
|
|
844
|
+
if (refusal) {
|
|
845
|
+
jsonError(res, refusal, 403);
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
679
848
|
}
|
|
680
849
|
|
|
681
850
|
const deadline = Date.now() + 30_000;
|
package/src/http/status.ts
CHANGED
|
@@ -45,6 +45,7 @@ import { getSlackConnectionState } from "../slack/connection-state";
|
|
|
45
45
|
import { isTelemetryEnabled } from "../telemetry";
|
|
46
46
|
import { type AgentCredStatus, AutomationIntegrationIdSchema, ProviderNameSchema } from "../types";
|
|
47
47
|
import { isRuntimePoolsEnabled } from "../utils/runtime-pools-flag";
|
|
48
|
+
import { resolveAppUrl } from "./config-values";
|
|
48
49
|
import { route } from "./route-def";
|
|
49
50
|
import { json, jsonError } from "./utils";
|
|
50
51
|
|
|
@@ -116,6 +117,12 @@ export const StatusIdentitySchema = z.object({
|
|
|
116
117
|
* cloud installs can be sliced server-side.
|
|
117
118
|
*/
|
|
118
119
|
org_id: z.string().nullable(),
|
|
120
|
+
/**
|
|
121
|
+
* The swarm's public dashboard URL (`APP_URL`, then `DASHBOARD_URL`, with
|
|
122
|
+
* swarm_config precedence). Null when neither is set. The dashboard reads
|
|
123
|
+
* links to it in agent output as its own. Absent on older APIs.
|
|
124
|
+
*/
|
|
125
|
+
dashboard_url: z.string().nullable().optional(),
|
|
119
126
|
});
|
|
120
127
|
export type StatusIdentity = z.infer<typeof StatusIdentitySchema>;
|
|
121
128
|
|
|
@@ -334,7 +341,7 @@ export async function rollupCredStatusForProvider(provider: string): Promise<Cre
|
|
|
334
341
|
|
|
335
342
|
// ─── Identity ────────────────────────────────────────────────────────────────
|
|
336
343
|
|
|
337
|
-
function buildIdentity(): StatusIdentity {
|
|
344
|
+
function buildIdentity(dashboardUrl: string | null): StatusIdentity {
|
|
338
345
|
const cloudRaw = process.env.SWARM_CLOUD;
|
|
339
346
|
const hideRaw = process.env.SWARM_HIDE_CLOUD_PROMO;
|
|
340
347
|
return {
|
|
@@ -345,6 +352,7 @@ function buildIdentity(): StatusIdentity {
|
|
|
345
352
|
marketing_url: process.env.SWARM_MARKETING_URL?.trim() || null,
|
|
346
353
|
hide_cloud_promo: hideRaw === "true" || hideRaw === "1",
|
|
347
354
|
org_id: process.env.SWARM_ORG_ID?.trim() || null,
|
|
355
|
+
dashboard_url: dashboardUrl,
|
|
348
356
|
};
|
|
349
357
|
}
|
|
350
358
|
|
|
@@ -759,7 +767,7 @@ export async function buildStatusPayload(): Promise<StatusResponse> {
|
|
|
759
767
|
const instance = await getInstanceFeedbackSignals();
|
|
760
768
|
return {
|
|
761
769
|
runtime_pools: { enabled: isRuntimePoolsEnabled(), supervisor: runtimeSupervisorStatus() },
|
|
762
|
-
identity: buildIdentity(),
|
|
770
|
+
identity: buildIdentity(await resolveAppUrl()),
|
|
763
771
|
setup,
|
|
764
772
|
activity: { ...activity, leads_ready: readyLeads },
|
|
765
773
|
agent_fs: {
|
package/src/http/tasks.ts
CHANGED
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
import { ensure } from "../utils/business-use";
|
|
85
85
|
import { getRequestAuth } from "../utils/request-auth-context";
|
|
86
86
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
87
|
-
import { createListTotalCache } from "./list-total-cache";
|
|
87
|
+
import { createListTotalCache, LIST_TOTAL_TTL_MS } from "./list-total-cache";
|
|
88
88
|
import {
|
|
89
89
|
agentFirstPrincipal,
|
|
90
90
|
authUserId,
|
|
@@ -224,7 +224,9 @@ const SupersedeTaskResponseSchema = z.object({
|
|
|
224
224
|
|
|
225
225
|
// ─── Route Definitions ───────────────────────────────────────────────────────
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
// The task list total scans every visible task, and only the pager shows it,
|
|
228
|
+
// so page 1 polls reuse a total younger than 15 s.
|
|
229
|
+
const taskTotals = createListTotalCache(LIST_TOTAL_TTL_MS, 15_000);
|
|
228
230
|
|
|
229
231
|
const listTasks = route({
|
|
230
232
|
method: "get",
|
package/src/pages/browser-sdk.ts
CHANGED
|
@@ -377,11 +377,23 @@ export const SWARM_UI_JS = `
|
|
|
377
377
|
closeCursorRoomIfUnused(record);
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
// Colors and fonts read the page theme tokens (designVersion 2). Each
|
|
381
|
+
// fallback is the original literal, so a designVersion 1 page, which has no
|
|
382
|
+
// tokens, renders exactly as before.
|
|
380
383
|
var SEV_COLOR = {
|
|
381
|
-
error: '#ef4444',
|
|
382
|
-
warn: '#f59e0b',
|
|
383
|
-
info: '#3b82f6',
|
|
384
|
+
error: 'var(--color-status-error-strong, #ef4444)',
|
|
385
|
+
warn: 'var(--color-status-warning-strong, #f59e0b)',
|
|
386
|
+
info: 'var(--color-status-info-strong, #3b82f6)',
|
|
384
387
|
};
|
|
388
|
+
var MUTED = 'var(--color-muted-foreground, #7c8aa6)';
|
|
389
|
+
var MONO = "var(--font-mono, 'Space Mono', ui-monospace, monospace)";
|
|
390
|
+
|
|
391
|
+
// A color at a lower alpha. Mixing with transparent keeps the color and
|
|
392
|
+
// scales its alpha, so tint('#ef4444', '13.33%') equals #ef444422 and
|
|
393
|
+
// tint('rgb(34,197,94)', '10%') equals rgba(34,197,94,0.10).
|
|
394
|
+
function tint(color, percent) {
|
|
395
|
+
return 'color-mix(in srgb, ' + color + ' ' + percent + ', transparent)';
|
|
396
|
+
}
|
|
385
397
|
|
|
386
398
|
function esc(s) {
|
|
387
399
|
return String(s == null ? '' : s)
|
|
@@ -416,7 +428,7 @@ export const SWARM_UI_JS = `
|
|
|
416
428
|
'<span class="swarm-diff-annot no-print" '
|
|
417
429
|
+ 'style="display:inline-block;margin-left:8px;padding:1px 6px;'
|
|
418
430
|
+ 'border-radius:4px;font-size:11px;font-weight:600;'
|
|
419
|
-
+ 'background:' + color + '
|
|
431
|
+
+ 'background:' + tint(color, '13.33%') + ';color:' + color + ';border:1px solid ' + tint(color, '33.33%') + ';">'
|
|
420
432
|
+ esc((ann && ann.severity ? ann.severity.toUpperCase() : 'INFO')) + ' · ' + esc(ann && ann.text || '')
|
|
421
433
|
+ '</span>'
|
|
422
434
|
);
|
|
@@ -448,12 +460,12 @@ export const SWARM_UI_JS = `
|
|
|
448
460
|
var text = line.text == null ? '' : line.text;
|
|
449
461
|
var bg, oldCell, newCell, sign;
|
|
450
462
|
if (type === 'add') {
|
|
451
|
-
bg = '
|
|
463
|
+
bg = tint('var(--color-status-success, rgb(34,197,94))', '10%');
|
|
452
464
|
oldCell = '';
|
|
453
465
|
newCell = String(newN++);
|
|
454
466
|
sign = '+';
|
|
455
467
|
} else if (type === 'del') {
|
|
456
|
-
bg = '
|
|
468
|
+
bg = tint('var(--color-status-error, rgb(239,68,68))', '10%');
|
|
457
469
|
oldCell = String(oldN++);
|
|
458
470
|
newCell = '';
|
|
459
471
|
sign = '-';
|
|
@@ -465,15 +477,17 @@ export const SWARM_UI_JS = `
|
|
|
465
477
|
}
|
|
466
478
|
|
|
467
479
|
var annHtml = '';
|
|
468
|
-
|
|
480
|
+
// Annotations name new-side lines. A deleted row has no new-side
|
|
481
|
+
// number, so only a deleted row matches on its old-side number.
|
|
482
|
+
var anns = annByLine[Number(type === 'del' ? oldCell : newCell)] || [];
|
|
469
483
|
for (var k = 0; k < anns.length; k++) annHtml += renderAnnotation(anns[k]);
|
|
470
484
|
|
|
471
485
|
rowsHtml += (
|
|
472
486
|
'<tr style="background:' + bg + ';">'
|
|
473
|
-
+ '<td class="swarm-diff-gutter" style="user-select:none;text-align:right;padding:0 8px;color
|
|
474
|
-
+ '<td class="swarm-diff-gutter" style="user-select:none;text-align:right;padding:0 8px;color
|
|
475
|
-
+ '<td class="swarm-diff-sign" style="user-select:none;text-align:center;padding:0 4px;color
|
|
476
|
-
+ '<td class="swarm-diff-code" style="padding:0 8px;white-space:pre-wrap;word-break:break-word;font-family
|
|
487
|
+
+ '<td class="swarm-diff-gutter" style="user-select:none;text-align:right;padding:0 8px;color:' + MUTED + ';font-size:12px;width:48px;">' + esc(oldCell) + '</td>'
|
|
488
|
+
+ '<td class="swarm-diff-gutter" style="user-select:none;text-align:right;padding:0 8px;color:' + MUTED + ';font-size:12px;width:48px;">' + esc(newCell) + '</td>'
|
|
489
|
+
+ '<td class="swarm-diff-sign" style="user-select:none;text-align:center;padding:0 4px;color:' + MUTED + ';font-size:12px;width:18px;">' + esc(sign) + '</td>'
|
|
490
|
+
+ '<td class="swarm-diff-code" style="padding:0 8px;white-space:pre-wrap;word-break:break-word;font-family:' + MONO + ';font-size:12px;">' + esc(text) + annHtml + '</td>'
|
|
477
491
|
+ '</tr>'
|
|
478
492
|
);
|
|
479
493
|
}
|
|
@@ -485,8 +499,8 @@ export const SWARM_UI_JS = `
|
|
|
485
499
|
);
|
|
486
500
|
|
|
487
501
|
return (
|
|
488
|
-
'<a id="' + esc(anchorId) + '" class="swarm-diff-anchor" data-hunk="' + esc(anchorSlug) + '"></a>'
|
|
489
|
-
+ '<div class="swarm-diff-hunk-header" style="padding:6px 12px;background:
|
|
502
|
+
'<a id="' + esc(anchorId) + '" class="swarm-diff-anchor" data-hunk="' + esc(anchorSlug) + '" data-new-start="' + esc(newStart) + '"></a>'
|
|
503
|
+
+ '<div class="swarm-diff-hunk-header" style="padding:6px 12px;background:' + tint('var(--color-muted-foreground, rgb(124,138,166))', '10%') + ';color:' + MUTED + ';font-family:' + MONO + ';font-size:11px;border-top:1px solid var(--swarm-border,#22304a);">'
|
|
490
504
|
+ esc(header)
|
|
491
505
|
+ '</div>'
|
|
492
506
|
+ '<table class="swarm-diff-table" style="width:100%;border-collapse:collapse;table-layout:fixed;">'
|
|
@@ -503,7 +517,7 @@ export const SWARM_UI_JS = `
|
|
|
503
517
|
|
|
504
518
|
var shaLine = '';
|
|
505
519
|
if (baseSha || headSha) {
|
|
506
|
-
shaLine = '<span class="swarm-diff-sha" style="font-family
|
|
520
|
+
shaLine = '<span class="swarm-diff-sha" style="font-family:' + MONO + ';font-size:11px;color:' + MUTED + ';">'
|
|
507
521
|
+ esc(baseSha) + ' → ' + esc(headSha)
|
|
508
522
|
+ '</span>';
|
|
509
523
|
}
|
|
@@ -515,8 +529,8 @@ export const SWARM_UI_JS = `
|
|
|
515
529
|
|
|
516
530
|
rootEl.innerHTML = (
|
|
517
531
|
'<div class="swarm-diff-root" style="border:1px solid var(--swarm-border,#22304a);border-radius:8px;background:var(--swarm-card,#121826);overflow:hidden;margin:12px 0;break-inside:avoid;">'
|
|
518
|
-
+ '<div class="swarm-diff-header" style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:rgba(59,130,246,0.10);border-bottom:1px solid var(--swarm-border,#22304a);">'
|
|
519
|
-
+ '<span class="swarm-diff-file" style="font-family
|
|
532
|
+
+ '<div class="swarm-diff-header" style="display:flex;align-items:center;justify-content:space-between;padding:10px 12px;background:var(--color-surface, rgba(59,130,246,0.10));border-bottom:1px solid var(--swarm-border,#22304a);">'
|
|
533
|
+
+ '<span class="swarm-diff-file" style="font-family:' + MONO + ';font-size:13px;font-weight:700;color:var(--swarm-text,#e6eaf2);">' + esc(file || '(untitled)') + '</span>'
|
|
520
534
|
+ shaLine
|
|
521
535
|
+ '</div>'
|
|
522
536
|
+ hunksHtml
|
|
@@ -580,21 +594,34 @@ export const SWARM_UI_JS = `
|
|
|
580
594
|
var renderJumps = function() {
|
|
581
595
|
var anchors = document.querySelectorAll('.swarm-diff-anchor[data-hunk]');
|
|
582
596
|
if (!anchors.length) {
|
|
583
|
-
self.innerHTML = '<span class="no-print" style="color
|
|
597
|
+
self.innerHTML = '<span class="no-print" style="color:' + MUTED + ';font-size:12px;">No hunks yet.</span>';
|
|
584
598
|
return;
|
|
585
599
|
}
|
|
586
|
-
var
|
|
600
|
+
var labels = [];
|
|
601
|
+
var fileCounts = new Map();
|
|
587
602
|
for (var i = 0; i < anchors.length; i++) {
|
|
588
603
|
var a = anchors[i];
|
|
589
604
|
var slug = a.getAttribute('data-hunk') || ('hunk-' + i);
|
|
590
605
|
// Hunk title = nearest preceding diff's file attribute if available.
|
|
591
606
|
var diff = a.closest && a.closest('swarm-diff');
|
|
592
607
|
var file = (diff && diff.getAttribute('file')) || slug;
|
|
593
|
-
|
|
608
|
+
labels.push(file);
|
|
609
|
+
fileCounts.set(file, (fileCounts.get(file) || 0) + 1);
|
|
610
|
+
}
|
|
611
|
+
var items = '';
|
|
612
|
+
for (var n = 0; n < anchors.length; n++) {
|
|
613
|
+
// A file with more than one hunk gets each hunk's new-side start
|
|
614
|
+
// line (src/x.ts:58), so its links differ.
|
|
615
|
+
var label = labels[n];
|
|
616
|
+
var newStart = anchors[n].getAttribute('data-new-start');
|
|
617
|
+
if (fileCounts.get(label) > 1 && newStart) label += ':' + newStart;
|
|
618
|
+
// target=_self: the page head sets <base target="_blank">, which would
|
|
619
|
+
// open these in-page anchors in a new tab.
|
|
620
|
+
items += '<li style="margin:0;padding:2px 0;"><a href="#' + esc(anchors[n].id) + '" target="_self" style="color:var(--color-primary, #3b82f6);text-decoration:none;font-family:' + MONO + ';font-size:12px;">' + esc(label) + '</a></li>';
|
|
594
621
|
}
|
|
595
622
|
self.innerHTML = (
|
|
596
|
-
'<nav class="swarm-diff-jumps no-print" style="padding:8px 12px;border:1px dashed var(--swarm-border,#22304a);border-radius:8px;background:
|
|
597
|
-
+ '<div style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color
|
|
623
|
+
'<nav class="swarm-diff-jumps no-print" style="padding:8px 12px;border:1px dashed var(--swarm-border,#22304a);border-radius:8px;background:' + tint('var(--color-muted-foreground, rgb(124,138,166))', '5%') + ';">'
|
|
624
|
+
+ '<div style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:' + MUTED + ';margin-bottom:4px;">Jump to</div>'
|
|
598
625
|
+ '<ul style="list-style:none;padding:0;margin:0;">' + items + '</ul>'
|
|
599
626
|
+ '</nav>'
|
|
600
627
|
);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hardcoded colors in an HTML page body. A design version 2 page should take
|
|
3
|
+
* every color from a theme token. A body with `COLOR_LITERAL_THRESHOLD` or more
|
|
4
|
+
* hardcoded colors gets two things: `create_page` steers its author toward
|
|
5
|
+
* tokens (`NUDGES.create_page`), and `/p/:id` serves it light also when the
|
|
6
|
+
* viewer asks for dark mode, because its hardcoded light surfaces would put
|
|
7
|
+
* dark-mode text on them.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** From this many hardcoded colors on, a page counts as hardcoded. */
|
|
11
|
+
export const COLOR_LITERAL_THRESHOLD = 8;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A `<style>` block (an unclosed one runs to the end of the body), a `style="..."`
|
|
15
|
+
* attribute, or a `class="..."` attribute. The tag's own attributes are capped at
|
|
16
|
+
* 200 characters: an unbounded `[^>]*` makes a body of many unterminated `<style`
|
|
17
|
+
* tags cost quadratic time.
|
|
18
|
+
*/
|
|
19
|
+
const STYLE_BLOCK = /<style\b[^>]{0,200}>([\s\S]*?)(?:<\/style\s*>|$)/gi;
|
|
20
|
+
const STYLE_ATTRIBUTE = /\sstyle\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
|
|
21
|
+
const CLASS_ATTRIBUTE = /\sclass\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
|
|
22
|
+
/**
|
|
23
|
+
* In style regions: `#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`, and the rgb, rgba,
|
|
24
|
+
* hsl, hsla and oklch functions.
|
|
25
|
+
*/
|
|
26
|
+
const COLOR_LITERAL = /#(?:[0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3,4})\b|\b(?:rgba?|hsla?|oklch)\(/gi;
|
|
27
|
+
/**
|
|
28
|
+
* In style regions: the `white` and `black` keywords as values, not inside a name
|
|
29
|
+
* such as `white-space`, `.white` or `--black`. Lowercase only, so a font name such
|
|
30
|
+
* as "Archivo Black" does not count.
|
|
31
|
+
*/
|
|
32
|
+
const NAMED_COLOR = /(?<![\w.#-])(?:white|black)(?![\w-])/g;
|
|
33
|
+
const PALETTE_UTILITIES = [
|
|
34
|
+
"bg",
|
|
35
|
+
"text",
|
|
36
|
+
"border",
|
|
37
|
+
"ring",
|
|
38
|
+
"outline",
|
|
39
|
+
"divide",
|
|
40
|
+
"fill",
|
|
41
|
+
"stroke",
|
|
42
|
+
"from",
|
|
43
|
+
"via",
|
|
44
|
+
"to",
|
|
45
|
+
"decoration",
|
|
46
|
+
"accent",
|
|
47
|
+
"caret",
|
|
48
|
+
"placeholder",
|
|
49
|
+
"shadow",
|
|
50
|
+
];
|
|
51
|
+
const TAILWIND_PALETTE = [
|
|
52
|
+
"slate",
|
|
53
|
+
"gray",
|
|
54
|
+
"zinc",
|
|
55
|
+
"neutral",
|
|
56
|
+
"stone",
|
|
57
|
+
"red",
|
|
58
|
+
"orange",
|
|
59
|
+
"amber",
|
|
60
|
+
"yellow",
|
|
61
|
+
"lime",
|
|
62
|
+
"green",
|
|
63
|
+
"emerald",
|
|
64
|
+
"teal",
|
|
65
|
+
"cyan",
|
|
66
|
+
"sky",
|
|
67
|
+
"blue",
|
|
68
|
+
"indigo",
|
|
69
|
+
"violet",
|
|
70
|
+
"purple",
|
|
71
|
+
"fuchsia",
|
|
72
|
+
"pink",
|
|
73
|
+
"rose",
|
|
74
|
+
];
|
|
75
|
+
/**
|
|
76
|
+
* In class attributes: Tailwind palette classes (`bg-blue-500`, `hover:text-gray-600/80`),
|
|
77
|
+
* `bg-white`, `bg-black`, `text-white`, `text-black`, and arbitrary color values
|
|
78
|
+
* (`bg-[#fff]`, `text-[rgb(0_0_0)]`, `-[hsl`, `-[oklch`).
|
|
79
|
+
*/
|
|
80
|
+
const COLOR_CLASS = new RegExp(
|
|
81
|
+
`(?<![\\w-])(?:(?:${PALETTE_UTILITIES.join("|")})-(?:${TAILWIND_PALETTE.join("|")})-\\d+|(?:bg|text)-(?:white|black))(?![\\w-])|-\\[(?:#|rgb|hsl|oklch)`,
|
|
82
|
+
"g",
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
function attributeValues(html: string, attribute: RegExp): string[] {
|
|
86
|
+
return Array.from(html.matchAll(attribute), (match) => match[1] ?? match[2] ?? "");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The values of every `class="..."` attribute in an HTML body. */
|
|
90
|
+
export function classAttributeValues(html: string): string[] {
|
|
91
|
+
return attributeValues(html, CLASS_ATTRIBUTE);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function countMatches(regions: string[], pattern: RegExp): number {
|
|
95
|
+
return regions.reduce((total, region) => total + (region.match(pattern)?.length ?? 0), 0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Counts the hardcoded colors of an HTML page body: color literals and the
|
|
100
|
+
* `white` / `black` keywords in its `<style>` blocks and `style="..."`
|
|
101
|
+
* attributes, and color classes in its `class="..."` attributes. A page on the
|
|
102
|
+
* design system should use theme tokens instead, so a high count means a theme
|
|
103
|
+
* switch will not restyle it.
|
|
104
|
+
*/
|
|
105
|
+
export function countColorLiterals(html: string): number {
|
|
106
|
+
const styles = [
|
|
107
|
+
...Array.from(html.matchAll(STYLE_BLOCK), (match) => match[1] ?? ""),
|
|
108
|
+
...attributeValues(html, STYLE_ATTRIBUTE),
|
|
109
|
+
];
|
|
110
|
+
return (
|
|
111
|
+
countMatches(styles, COLOR_LITERAL) +
|
|
112
|
+
countMatches(styles, NAMED_COLOR) +
|
|
113
|
+
countMatches(classAttributeValues(html), COLOR_CLASS)
|
|
114
|
+
);
|
|
115
|
+
}
|