@desplega.ai/agent-swarm 2.7.6 → 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.
Files changed (244) hide show
  1. package/dist/{acp-adapter-bp91d37f.js → acp-adapter-7b4vk3h5.js} +5 -4
  2. package/dist/{actions-yj0eeaqh.js → actions-3tt153af.js} +18 -18
  3. package/dist/{amp-adapter-4pg9h34q.js → amp-adapter-njpts0yr.js} +1 -1
  4. package/dist/{anthropic-messages-x4q6rfq5.js → anthropic-messages-xey2skwx.js} +7 -7
  5. package/dist/{app-909e97cr.js → app-nky4378f.js} +3 -3
  6. package/dist/{assistant-qdyb5fyy.js → assistant-jnb669pa.js} +19 -19
  7. package/dist/{azure-openai-responses-s1w5n70z.js → azure-openai-responses-26t7j9ra.js} +5 -5
  8. package/dist/{boot-reembed-fk0s9z18.js → boot-reembed-9mgvaztt.js} +1 -1
  9. package/dist/{boot-reembed-gs1rzrnh.js → boot-reembed-qs2djdej.js} +1 -1
  10. package/dist/{boot-scrub-sweep-4qfd4kfx.js → boot-scrub-sweep-yjpdj7s1.js} +3 -3
  11. package/dist/{boot-seeds-yr00k13d.js → boot-seeds-5cm6ambd.js} +4 -4
  12. package/dist/{boxd-vdmfssd9.js → boxd-nv507va8.js} +1 -1
  13. package/dist/{claude-adapter-qta1f1xn.js → claude-adapter-fn287zmm.js} +5 -4
  14. package/dist/{claude-managed-setup-sc6j4dm0.js → claude-managed-setup-wtdz2mj2.js} +1 -1
  15. package/dist/{claude-sdk-session-zgrz6yvc.js → claude-sdk-session-x91kqyhm.js} +8288 -8224
  16. package/dist/{cli-wp9sp1qb.js → cli-08bmz9z9.js} +1 -1
  17. package/dist/{cli-yy3rhsdw.js → cli-1c6tzt8g.js} +7 -7
  18. package/dist/{cli-q0k1w5zd.js → cli-35rsp8ye.js} +1 -1
  19. package/dist/{cli-xnrwazav.js → cli-3fg0bdcv.js} +1 -1
  20. package/dist/{cli-89knwags.js → cli-5b456bpf.js} +2 -2
  21. package/dist/{cli-drr5v6av.js → cli-5jnhv72d.js} +1 -1
  22. package/dist/{cli-dxae2yg7.js → cli-5zx699j9.js} +2 -2
  23. package/dist/{cli-0at8w34w.js → cli-6g0hb4cp.js} +8 -8
  24. package/dist/{cli-e3r2neck.js → cli-6pfd54vx.js} +5 -5
  25. package/dist/{cli-bsn8nhrq.js → cli-6vcp76qk.js} +3 -3
  26. package/dist/{cli-ekwks2vs.js → cli-72v799xn.js} +1 -1
  27. package/dist/cli-82j36f2m.js +45 -0
  28. package/dist/{cli-yx4kfngt.js → cli-8305gbq0.js} +29 -16
  29. package/dist/{cli-4necwtsv.js → cli-8sckt74b.js} +8 -8
  30. package/dist/{cli-vvpx3gsx.js → cli-95jzxcp3.js} +1 -1
  31. package/dist/{cli-hr2e2fft.js → cli-adeegh7d.js} +7 -7
  32. package/dist/{cli-m48g6p95.js → cli-afkqkrtw.js} +3 -3
  33. package/dist/{cli-0qatpy8q.js → cli-ayayvfg4.js} +24 -4
  34. package/dist/{cli-bqt1mptt.js → cli-az48n0nr.js} +4 -4
  35. package/dist/{cli-zm72anhg.js → cli-bfv7vdg6.js} +9 -9
  36. package/dist/{cli-hgaazk69.js → cli-caj33vcq.js} +5 -5
  37. package/dist/{cli-3ypk9vk1.js → cli-cb2a8pna.js} +1 -1
  38. package/dist/{cli-waqbxg08.js → cli-cppkf404.js} +17 -17
  39. package/dist/{cli-yn4kxs06.js → cli-ddaanqkd.js} +4 -4
  40. package/dist/{cli-386tyxxg.js → cli-e0kmphd6.js} +2 -2
  41. package/dist/{cli-54t00gt8.js → cli-e46hg0xw.js} +1 -1
  42. package/dist/{cli-jm2vfpfd.js → cli-e5bzrn01.js} +1 -1
  43. package/dist/{cli-436532ck.js → cli-excnnjg2.js} +165 -153
  44. package/dist/{cli-71ptav7x.js → cli-ferkkrg9.js} +1 -1
  45. package/dist/{cli-vpf89f34.js → cli-fmjd0t1y.js} +3 -3
  46. package/dist/{cli-pd7vagab.js → cli-fyt2g4wd.js} +3 -3
  47. package/dist/{cli-gdhpcbhf.js → cli-g08zdaec.js} +1 -1
  48. package/dist/{cli-ehq736cn.js → cli-g7s47cc5.js} +4 -4
  49. package/dist/{cli-svj5090z.js → cli-gz6q4eve.js} +3 -3
  50. package/dist/{cli-8snvgs5r.js → cli-je518txm.js} +10 -10
  51. package/dist/{cli-rmmmrjkd.js → cli-jtjtabxe.js} +1 -1
  52. package/dist/{cli-611a1294.js → cli-k0wwfqbg.js} +18 -1
  53. package/dist/{cli-es6va8jk.js → cli-k1nje3v3.js} +38 -43
  54. package/dist/{cli-p5gp8pcx.js → cli-k8196sh2.js} +6 -6
  55. package/dist/{cli-nwj0ee2w.js → cli-k899ehvh.js} +2 -2
  56. package/dist/{cli-decfb6v8.js → cli-m0da8j35.js} +23 -9
  57. package/dist/{cli-he9wchme.js → cli-mkk9rnzz.js} +4 -4
  58. package/dist/{cli-nhrvpaj7.js → cli-n6bv12jn.js} +510 -4
  59. package/dist/{cli-8bc1w0tw.js → cli-nmzhp1b5.js} +14 -12
  60. package/dist/{cli-0yv5z2pg.js → cli-p82cnnjq.js} +1 -1
  61. package/dist/{cli-c60vetmm.js → cli-pc6n7fre.js} +1 -1
  62. package/dist/{cli-xds5f77d.js → cli-pjctyea3.js} +2 -2
  63. package/dist/{cli-xbbndvjy.js → cli-pq73h5mz.js} +3 -3
  64. package/dist/{cli-aa6yxc7m.js → cli-pz4rk021.js} +1 -1
  65. package/dist/{cli-xnqgpshy.js → cli-q3tkegby.js} +1 -1
  66. package/dist/cli-qghe0h66.js +67 -0
  67. package/dist/{cli-zbbwez0r.js → cli-qh4d4tvk.js} +4 -4
  68. package/dist/{cli-w6dt9ged.js → cli-rtt8g4v9.js} +1 -1
  69. package/dist/{cli-1h3wcpbw.js → cli-snpj5zbj.js} +2 -2
  70. package/dist/{cli-a7v854rf.js → cli-tgrv9cjx.js} +263 -12
  71. package/dist/{cli-faxe6thg.js → cli-vz22fyqv.js} +186 -54
  72. package/dist/{cli-k2gzwsj2.js → cli-wk5yrfwd.js} +160 -26
  73. package/dist/{cli-shpbx5ee.js → cli-ws19768n.js} +1641 -49
  74. package/dist/{cli-70r77n04.js → cli-xae4g51r.js} +1 -1
  75. package/dist/{cli-kqdg1bsb.js → cli-yndmfxb3.js} +2 -2
  76. package/dist/{cli-bjb3z51z.js → cli-yyj3j5m4.js} +2 -2
  77. package/dist/cli.js +21 -21
  78. package/dist/{cloudflare-workers-ai-system-one-bm60fjm0.js → cloudflare-workers-ai-system-one-ef2a980q.js} +2 -2
  79. package/dist/{codex-adapter-ayd1fb6h.js → codex-adapter-cf2yxe9m.js} +3 -2
  80. package/dist/{codex-hook-9efm2x1m.js → codex-hook-a0c6g6t6.js} +1 -1
  81. package/dist/{codex-session-runner-jesa32xc.js → codex-session-runner-6vfzdgbd.js} +3 -2
  82. package/dist/{commands-hanewgf2.js → commands-t3mfy7vn.js} +3 -3
  83. package/dist/{controller-dt1n3c1q.js → controller-q7xrbaz0.js} +3 -3
  84. package/dist/{controllers-connect-xx8x64n5.js → controllers-connect-c6nm70kg.js} +19 -19
  85. package/dist/{cursor-adapter-9s4dwwdw.js → cursor-adapter-ftd81ga8.js} +1 -1
  86. package/dist/{db-3vttcbv4.js → db-dk572x25.js} +3 -3
  87. package/dist/{db-9dv0g1ab.js → db-vemtpmcc.js} +4 -2
  88. package/dist/{dispatcher-tx9hd1sv.js → dispatcher-kh7ecxh9.js} +17 -17
  89. package/dist/{dsh-adapter-007y4ejs.js → dsh-adapter-v8628r89.js} +1 -1
  90. package/dist/{e2b-we6hs6q5.js → e2b-fr12yccx.js} +1 -1
  91. package/dist/{e2b-a19d28rz.js → e2b-x6ywzak3.js} +1 -1
  92. package/dist/{easter-egg-3d-rgbrqb8s.js → easter-egg-3d-nenw4x63.js} +1 -1
  93. package/dist/{embedding-space-ny1e2940.js → embedding-space-0jepb239.js} +6 -6
  94. package/dist/{embeddings-2t386t13.js → embeddings-xxt49yxg.js} +1 -1
  95. package/dist/{execute-pksh0ceh.js → execute-1mhw6e4x.js} +1 -1
  96. package/dist/{external-channel-phgmhmd7.js → external-channel-55v12e60.js} +2 -2
  97. package/dist/{fx-adapter-fy8rr921.js → fx-adapter-bs8wqrk5.js} +6 -5
  98. package/dist/{google-generative-ai-8y3m3k4b.js → google-generative-ai-v94hr7h0.js} +5 -5
  99. package/dist/{google-vertex-w3v98n7b.js → google-vertex-g7vr6cf8.js} +5 -5
  100. package/dist/{grok-adapter-q0abvpaj.js → grok-adapter-gpjqmkcq.js} +6 -5
  101. package/dist/handlers-zxmp1ta4.js +32 -0
  102. package/dist/{heartbeat-kadyek8p.js → heartbeat-k42svnr0.js} +20 -20
  103. package/dist/{hook-9k551xnj.js → hook-114m7hap.js} +4 -3
  104. package/dist/{hook-5zs3msf6.js → hook-6nphweh0.js} +24 -9
  105. package/dist/{http-mhz9vw1f.js → http-r8cc4wz7.js} +1025 -173
  106. package/dist/index-a8phxqnk.js +37 -0
  107. package/dist/{index-vdygbq10.js → index-e3s8wmxy.js} +1 -1
  108. package/dist/{index-q361cg2f.js → index-fpk4bcd9.js} +1 -1
  109. package/dist/index-k6h00t4c.js +30 -0
  110. package/dist/{index-rvr00sg7.js → index-nh3wyqdt.js} +1017 -574
  111. package/dist/index-xrz7te8h.js +33 -0
  112. package/dist/{keepalive-w56f32cg.js → keepalive-x060nt9p.js} +3 -3
  113. package/dist/lead-956sd2yc.js +71 -0
  114. package/dist/{maintenance-7mdgxcea.js → maintenance-2xxfexhf.js} +1 -1
  115. package/dist/{mistral-conversations-4pmwj1c0.js → mistral-conversations-3gjpdb4b.js} +4 -4
  116. package/dist/{oauth-refresh-sweep-29txy9vk.js → oauth-refresh-sweep-fckc4ar5.js} +2 -2
  117. package/dist/{onboard-kpsrkarj.js → onboard-zc48j237.js} +3 -3
  118. package/dist/{openai-codex-responses-44j573nm.js → openai-codex-responses-8pbxq9h5.js} +5 -5
  119. package/dist/{openai-completions-a4gee2a8.js → openai-completions-rm00s912.js} +4 -4
  120. package/dist/{openai-decisions-w4qkrcar.js → openai-decisions-8v957r2r.js} +1 -1
  121. package/dist/{openai-responses-rbp6h5kr.js → openai-responses-agxpf96k.js} +5 -5
  122. package/dist/{opencode-adapter-j25vm3rr.js → opencode-adapter-r690h1cr.js} +4 -3
  123. package/dist/{otel-impl-6kkct7a8.js → otel-impl-r5xbh81q.js} +4 -4
  124. package/dist/{pi-mono-adapter-exhkzhn2.js → pi-mono-adapter-c7v8sdec.js} +7 -6
  125. package/dist/{pricing-refresh-n2x7jh6k.js → pricing-refresh-3pmre11v.js} +3 -3
  126. package/dist/{rbac-roles-81ypx6es.js → rbac-roles-3vbshwsb.js} +1 -1
  127. package/dist/{rbac-roles-b5htkjby.js → rbac-roles-910mmkgz.js} +2 -2
  128. package/dist/{render-v2-qn6jmpk4.js → render-v2-pxykkbab.js} +3 -3
  129. package/dist/{resume-wd30wx23.js → resume-adda0bwy.js} +6 -6
  130. package/dist/{runtime-4hsg7h60.js → runtime-fnbm7stk.js} +1 -1
  131. package/dist/{session-access-5qvfevhk.js → session-access-2fvamrdc.js} +4 -4
  132. package/dist/{session-source-backfill-n1czavbr.js → session-source-backfill-08xvv0sm.js} +2 -2
  133. package/dist/{setup-dnb56qy5.js → setup-1aqmvmh1.js} +1 -1
  134. package/dist/{typesafe-system-one-5mavm259.js → typesafe-system-one-0bmqcxfg.js} +2 -2
  135. package/dist/{virtual-modules-76xxv9fs.js → virtual-modules-d2pjk9j1.js} +5 -5
  136. package/dist/{work-objects-4n21tfkm.js → work-objects-9s0yrm5j.js} +20 -20
  137. package/dist/{worker-follow-up-77hvzxww.js → worker-follow-up-3q78fqmr.js} +17 -17
  138. package/dist/worker-y15hy08h.js +71 -0
  139. package/openapi.json +197 -4
  140. package/package.json +5 -5
  141. package/src/apps/definition.ts +6 -5
  142. package/src/be/db/page-theme-tokens.ts +12 -0
  143. package/src/be/db/tasks/read.ts +9 -1
  144. package/src/be/db/tasks/write.ts +19 -0
  145. package/src/be/db-client.ts +107 -7
  146. package/src/be/db.ts +34 -2
  147. package/src/be/migrations/269_pages_design_system.sql +23 -0
  148. package/src/be/seed/schedules-seeder.ts +0 -10
  149. package/src/be/seed-scripts/catalog/catalog-report.inline.ts +2 -0
  150. package/src/be/seed-scripts/catalog/catalog-report.ts +2 -0
  151. package/src/be/seed-scripts/catalog/memory-eval.ts +2 -0
  152. package/src/be/seed-scripts/catalog/swarm-update-check.ts +150 -0
  153. package/src/be/seed-scripts/index.ts +9 -0
  154. package/src/be/seed-skills/bundled-files.generated.json +3 -3
  155. package/src/be/swarm-config-guard.ts +32 -0
  156. package/src/be/task-auto-title-listener.ts +127 -0
  157. package/src/commands/onboard/agent-fs-version.ts +1 -1
  158. package/src/commands/profile-sync.ts +151 -16
  159. package/src/commands/runner.ts +15 -7
  160. package/src/hooks/hook.ts +20 -9
  161. package/src/http/index.ts +3 -0
  162. package/src/http/pages-public.ts +93 -129
  163. package/src/http/pages.ts +94 -21
  164. package/src/pages/browser-sdk.ts +48 -21
  165. package/src/pages/color-literals.ts +115 -0
  166. package/src/pages/page-head.ts +766 -0
  167. package/src/pages/version.ts +3 -0
  168. package/src/providers/amp-adapter.ts +1 -1
  169. package/src/providers/codex-adapter.ts +1 -0
  170. package/src/providers/codex-app-server.ts +27 -1
  171. package/src/providers/pi-mono-extension.ts +30 -15
  172. package/src/tasks/follow-up-gate.ts +318 -0
  173. package/src/tasks/worker-follow-up.ts +21 -1
  174. package/src/tests/codex-app-server.test.ts +59 -0
  175. package/src/tests/codex-gateway-route.test.ts +50 -1
  176. package/src/tests/create-page-tool.test.ts +501 -0
  177. package/src/tests/db-client-busy-retry.test.ts +81 -0
  178. package/src/tests/db-task-read-contract.test.ts +1 -0
  179. package/src/tests/db-task-write-contract.test.ts +2 -0
  180. package/src/tests/db-tasks-read.test.ts +21 -0
  181. package/src/tests/fixtures/pages/head-v1.html +56 -0
  182. package/src/tests/follow-up-gate-shadow.test.ts +513 -0
  183. package/src/tests/identity-field-budget.test.ts +1 -1
  184. package/src/tests/internal-ai/credentials.test.ts +62 -0
  185. package/src/tests/internal-ai/task-title.test.ts +283 -0
  186. package/src/tests/merge-gate-detect-changes.test.ts +145 -0
  187. package/src/tests/page-proxy.test.ts +1 -1
  188. package/src/tests/page-session-dev-cookie.test.ts +188 -0
  189. package/src/tests/pages-frame-ancestors.test.ts +28 -1
  190. package/src/tests/pages-head-v2.test.ts +534 -0
  191. package/src/tests/pages-http.test.ts +330 -0
  192. package/src/tests/pages-public-html.test.ts +43 -0
  193. package/src/tests/pages-storage.test.ts +182 -0
  194. package/src/tests/pages-versioning.test.ts +72 -0
  195. package/src/tests/profile-sync-stale-writeback.test.ts +334 -0
  196. package/src/tests/profile-sync.test.ts +11 -15
  197. package/src/tests/scheduled-task-required-params-migration.test.ts +3 -1
  198. package/src/tests/script-connections.test.ts +2 -0
  199. package/src/tests/seed-registry.test.ts +28 -6
  200. package/src/tests/seed-schedules.test.ts +61 -8
  201. package/src/tests/seed-scripts.test.ts +142 -2
  202. package/src/tests/swarm-diff.test.ts +121 -2
  203. package/src/tests/task-auto-title-config-guard.test.ts +37 -0
  204. package/src/tests/task-auto-title-listener.test.ts +165 -0
  205. package/src/tests/theme-import.test.ts +758 -0
  206. package/src/tests/themes-page-theme.test.ts +155 -0
  207. package/src/tests/themes-presets.test.ts +172 -0
  208. package/src/tests/workflow-script-principal.test.ts +2 -1
  209. package/src/themes/classics.ts +949 -0
  210. package/src/themes/import.ts +420 -0
  211. package/src/themes/page-fields.ts +40 -0
  212. package/src/themes/page-theme.ts +102 -0
  213. package/src/themes/presets.ts +561 -0
  214. package/src/themes/tokens.ts +218 -0
  215. package/src/tools/app-upsert.ts +1 -1
  216. package/src/tools/create-page.ts +118 -12
  217. package/src/tools/utils.ts +33 -0
  218. package/src/types.ts +45 -3
  219. package/src/utils/constants.ts +19 -0
  220. package/src/utils/follow-up-gate-schedule-ids.ts +13 -0
  221. package/src/utils/internal-ai/credentials.ts +146 -93
  222. package/src/utils/internal-ai/index.ts +10 -0
  223. package/src/utils/internal-ai/models.ts +18 -0
  224. package/src/utils/internal-ai/task-title.ts +282 -0
  225. package/src/utils/page-session.ts +37 -0
  226. package/templates/schedules/daily-status-report/content.md +88 -2
  227. package/templates/schedules/daily-swarm-update-check/content.md +16 -40
  228. package/templates/skills/apps/SKILL.md +1 -1
  229. package/templates/skills/apps/content.md +1 -1
  230. package/templates/skills/heartbeat-runbook/content.md +1 -1
  231. package/templates/skills/pages/config.json +1 -1
  232. package/templates/skills/pages/content.md +539 -86
  233. package/templates/skills/pages/files/examples/annotated-pr.html +21 -12
  234. package/templates/skills/pages/files/examples/multiplayer-board.html +41 -41
  235. package/templates/skills/pages/files/examples/report-page.html +125 -124
  236. package/dist/cli-2pnswgh8.js +0 -189
  237. package/dist/handlers-by3sfxyx.js +0 -32
  238. package/dist/index-4f2pvxae.js +0 -37
  239. package/dist/index-98gz7tmp.js +0 -30
  240. package/dist/index-k08z2cak.js +0 -33
  241. package/dist/lead-enq35nqp.js +0 -70
  242. package/dist/worker-gg1576j3.js +0 -70
  243. package/templates/schedules/daily-workflow-health-audit/config.json +0 -19
  244. package/templates/schedules/daily-workflow-health-audit/content.md +0 -191
@@ -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 + '22;color:' + color + ';border:1px solid ' + color + '55;">'
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 = 'rgba(34,197,94,0.10)';
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 = 'rgba(239,68,68,0.10)';
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
- var anns = annByLine[Number(newCell)] || annByLine[Number(oldCell)] || [];
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:#7c8aa6;font-size:12px;width:48px;">' + esc(oldCell) + '</td>'
474
- + '<td class="swarm-diff-gutter" style="user-select:none;text-align:right;padding:0 8px;color:#7c8aa6;font-size:12px;width:48px;">' + esc(newCell) + '</td>'
475
- + '<td class="swarm-diff-sign" style="user-select:none;text-align:center;padding:0 4px;color:#7c8aa6;font-size:12px;width:18px;">' + esc(sign) + '</td>'
476
- + '<td class="swarm-diff-code" style="padding:0 8px;white-space:pre-wrap;word-break:break-word;font-family:\\'Space Mono\\',ui-monospace,monospace;font-size:12px;">' + esc(text) + annHtml + '</td>'
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:rgba(124,138,166,0.10);color:#7c8aa6;font-family:\\'Space Mono\\',ui-monospace,monospace;font-size:11px;border-top:1px solid var(--swarm-border,#22304a);">'
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:\\'Space Mono\\',ui-monospace,monospace;font-size:11px;color:#7c8aa6;">'
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:\\'Space Mono\\',ui-monospace,monospace;font-size:13px;font-weight:700;color:var(--swarm-text,#e6eaf2);">' + esc(file || '(untitled)') + '</span>'
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:#7c8aa6;font-size:12px;">No hunks yet.</span>';
597
+ self.innerHTML = '<span class="no-print" style="color:' + MUTED + ';font-size:12px;">No hunks yet.</span>';
584
598
  return;
585
599
  }
586
- var items = '';
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
- items += '<li style="margin:0;padding:2px 0;"><a href="#' + esc(a.id) + '" style="color:#3b82f6;text-decoration:none;font-family:\\'Space Mono\\',ui-monospace,monospace;font-size:12px;">' + esc(file) + '</a></li>';
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:rgba(124,138,166,0.05);">'
597
- + '<div style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:#7c8aa6;margin-bottom:4px;">Jump to</div>'
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
+ }