@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.
- package/dist/{acp-adapter-bp91d37f.js → acp-adapter-7b4vk3h5.js} +5 -4
- package/dist/{actions-yj0eeaqh.js → actions-3tt153af.js} +18 -18
- package/dist/{amp-adapter-4pg9h34q.js → amp-adapter-njpts0yr.js} +1 -1
- package/dist/{anthropic-messages-x4q6rfq5.js → anthropic-messages-xey2skwx.js} +7 -7
- package/dist/{app-909e97cr.js → app-nky4378f.js} +3 -3
- package/dist/{assistant-qdyb5fyy.js → assistant-jnb669pa.js} +19 -19
- package/dist/{azure-openai-responses-s1w5n70z.js → azure-openai-responses-26t7j9ra.js} +5 -5
- package/dist/{boot-reembed-fk0s9z18.js → boot-reembed-9mgvaztt.js} +1 -1
- package/dist/{boot-reembed-gs1rzrnh.js → boot-reembed-qs2djdej.js} +1 -1
- package/dist/{boot-scrub-sweep-4qfd4kfx.js → boot-scrub-sweep-yjpdj7s1.js} +3 -3
- package/dist/{boot-seeds-yr00k13d.js → boot-seeds-5cm6ambd.js} +4 -4
- package/dist/{boxd-vdmfssd9.js → boxd-nv507va8.js} +1 -1
- package/dist/{claude-adapter-qta1f1xn.js → claude-adapter-fn287zmm.js} +5 -4
- package/dist/{claude-managed-setup-sc6j4dm0.js → claude-managed-setup-wtdz2mj2.js} +1 -1
- package/dist/{claude-sdk-session-zgrz6yvc.js → claude-sdk-session-x91kqyhm.js} +8288 -8224
- package/dist/{cli-wp9sp1qb.js → cli-08bmz9z9.js} +1 -1
- package/dist/{cli-yy3rhsdw.js → cli-1c6tzt8g.js} +7 -7
- package/dist/{cli-q0k1w5zd.js → cli-35rsp8ye.js} +1 -1
- package/dist/{cli-xnrwazav.js → cli-3fg0bdcv.js} +1 -1
- package/dist/{cli-89knwags.js → cli-5b456bpf.js} +2 -2
- package/dist/{cli-drr5v6av.js → cli-5jnhv72d.js} +1 -1
- package/dist/{cli-dxae2yg7.js → cli-5zx699j9.js} +2 -2
- package/dist/{cli-0at8w34w.js → cli-6g0hb4cp.js} +8 -8
- package/dist/{cli-e3r2neck.js → cli-6pfd54vx.js} +5 -5
- package/dist/{cli-bsn8nhrq.js → cli-6vcp76qk.js} +3 -3
- package/dist/{cli-ekwks2vs.js → cli-72v799xn.js} +1 -1
- package/dist/cli-82j36f2m.js +45 -0
- package/dist/{cli-yx4kfngt.js → cli-8305gbq0.js} +29 -16
- package/dist/{cli-4necwtsv.js → cli-8sckt74b.js} +8 -8
- package/dist/{cli-vvpx3gsx.js → cli-95jzxcp3.js} +1 -1
- package/dist/{cli-hr2e2fft.js → cli-adeegh7d.js} +7 -7
- package/dist/{cli-m48g6p95.js → cli-afkqkrtw.js} +3 -3
- package/dist/{cli-0qatpy8q.js → cli-ayayvfg4.js} +24 -4
- package/dist/{cli-bqt1mptt.js → cli-az48n0nr.js} +4 -4
- package/dist/{cli-zm72anhg.js → cli-bfv7vdg6.js} +9 -9
- package/dist/{cli-hgaazk69.js → cli-caj33vcq.js} +5 -5
- package/dist/{cli-3ypk9vk1.js → cli-cb2a8pna.js} +1 -1
- package/dist/{cli-waqbxg08.js → cli-cppkf404.js} +17 -17
- package/dist/{cli-yn4kxs06.js → cli-ddaanqkd.js} +4 -4
- package/dist/{cli-386tyxxg.js → cli-e0kmphd6.js} +2 -2
- package/dist/{cli-54t00gt8.js → cli-e46hg0xw.js} +1 -1
- package/dist/{cli-jm2vfpfd.js → cli-e5bzrn01.js} +1 -1
- package/dist/{cli-436532ck.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-pd7vagab.js → cli-fyt2g4wd.js} +3 -3
- package/dist/{cli-gdhpcbhf.js → cli-g08zdaec.js} +1 -1
- package/dist/{cli-ehq736cn.js → cli-g7s47cc5.js} +4 -4
- package/dist/{cli-svj5090z.js → cli-gz6q4eve.js} +3 -3
- package/dist/{cli-8snvgs5r.js → cli-je518txm.js} +10 -10
- package/dist/{cli-rmmmrjkd.js → cli-jtjtabxe.js} +1 -1
- package/dist/{cli-611a1294.js → cli-k0wwfqbg.js} +18 -1
- package/dist/{cli-es6va8jk.js → cli-k1nje3v3.js} +38 -43
- package/dist/{cli-p5gp8pcx.js → cli-k8196sh2.js} +6 -6
- package/dist/{cli-nwj0ee2w.js → cli-k899ehvh.js} +2 -2
- package/dist/{cli-decfb6v8.js → cli-m0da8j35.js} +23 -9
- package/dist/{cli-he9wchme.js → cli-mkk9rnzz.js} +4 -4
- package/dist/{cli-nhrvpaj7.js → cli-n6bv12jn.js} +510 -4
- package/dist/{cli-8bc1w0tw.js → cli-nmzhp1b5.js} +14 -12
- package/dist/{cli-0yv5z2pg.js → cli-p82cnnjq.js} +1 -1
- package/dist/{cli-c60vetmm.js → cli-pc6n7fre.js} +1 -1
- package/dist/{cli-xds5f77d.js → cli-pjctyea3.js} +2 -2
- package/dist/{cli-xbbndvjy.js → cli-pq73h5mz.js} +3 -3
- package/dist/{cli-aa6yxc7m.js → cli-pz4rk021.js} +1 -1
- package/dist/{cli-xnqgpshy.js → cli-q3tkegby.js} +1 -1
- package/dist/cli-qghe0h66.js +67 -0
- package/dist/{cli-zbbwez0r.js → cli-qh4d4tvk.js} +4 -4
- package/dist/{cli-w6dt9ged.js → cli-rtt8g4v9.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-faxe6thg.js → cli-vz22fyqv.js} +186 -54
- package/dist/{cli-k2gzwsj2.js → cli-wk5yrfwd.js} +160 -26
- package/dist/{cli-shpbx5ee.js → cli-ws19768n.js} +1641 -49
- package/dist/{cli-70r77n04.js → cli-xae4g51r.js} +1 -1
- package/dist/{cli-kqdg1bsb.js → cli-yndmfxb3.js} +2 -2
- package/dist/{cli-bjb3z51z.js → cli-yyj3j5m4.js} +2 -2
- package/dist/cli.js +21 -21
- package/dist/{cloudflare-workers-ai-system-one-bm60fjm0.js → cloudflare-workers-ai-system-one-ef2a980q.js} +2 -2
- package/dist/{codex-adapter-ayd1fb6h.js → codex-adapter-cf2yxe9m.js} +3 -2
- package/dist/{codex-hook-9efm2x1m.js → codex-hook-a0c6g6t6.js} +1 -1
- package/dist/{codex-session-runner-jesa32xc.js → codex-session-runner-6vfzdgbd.js} +3 -2
- package/dist/{commands-hanewgf2.js → commands-t3mfy7vn.js} +3 -3
- package/dist/{controller-dt1n3c1q.js → controller-q7xrbaz0.js} +3 -3
- package/dist/{controllers-connect-xx8x64n5.js → controllers-connect-c6nm70kg.js} +19 -19
- package/dist/{cursor-adapter-9s4dwwdw.js → cursor-adapter-ftd81ga8.js} +1 -1
- package/dist/{db-3vttcbv4.js → db-dk572x25.js} +3 -3
- package/dist/{db-9dv0g1ab.js → db-vemtpmcc.js} +4 -2
- package/dist/{dispatcher-tx9hd1sv.js → dispatcher-kh7ecxh9.js} +17 -17
- package/dist/{dsh-adapter-007y4ejs.js → dsh-adapter-v8628r89.js} +1 -1
- package/dist/{e2b-we6hs6q5.js → e2b-fr12yccx.js} +1 -1
- package/dist/{e2b-a19d28rz.js → e2b-x6ywzak3.js} +1 -1
- package/dist/{easter-egg-3d-rgbrqb8s.js → easter-egg-3d-nenw4x63.js} +1 -1
- package/dist/{embedding-space-ny1e2940.js → embedding-space-0jepb239.js} +6 -6
- package/dist/{embeddings-2t386t13.js → embeddings-xxt49yxg.js} +1 -1
- package/dist/{execute-pksh0ceh.js → execute-1mhw6e4x.js} +1 -1
- package/dist/{external-channel-phgmhmd7.js → external-channel-55v12e60.js} +2 -2
- package/dist/{fx-adapter-fy8rr921.js → fx-adapter-bs8wqrk5.js} +6 -5
- package/dist/{google-generative-ai-8y3m3k4b.js → google-generative-ai-v94hr7h0.js} +5 -5
- package/dist/{google-vertex-w3v98n7b.js → google-vertex-g7vr6cf8.js} +5 -5
- package/dist/{grok-adapter-q0abvpaj.js → grok-adapter-gpjqmkcq.js} +6 -5
- package/dist/handlers-zxmp1ta4.js +32 -0
- package/dist/{heartbeat-kadyek8p.js → heartbeat-k42svnr0.js} +20 -20
- package/dist/{hook-9k551xnj.js → hook-114m7hap.js} +4 -3
- package/dist/{hook-5zs3msf6.js → hook-6nphweh0.js} +24 -9
- package/dist/{http-mhz9vw1f.js → http-r8cc4wz7.js} +1025 -173
- package/dist/index-a8phxqnk.js +37 -0
- package/dist/{index-vdygbq10.js → index-e3s8wmxy.js} +1 -1
- package/dist/{index-q361cg2f.js → index-fpk4bcd9.js} +1 -1
- package/dist/index-k6h00t4c.js +30 -0
- package/dist/{index-rvr00sg7.js → index-nh3wyqdt.js} +1017 -574
- package/dist/index-xrz7te8h.js +33 -0
- package/dist/{keepalive-w56f32cg.js → keepalive-x060nt9p.js} +3 -3
- package/dist/lead-956sd2yc.js +71 -0
- package/dist/{maintenance-7mdgxcea.js → maintenance-2xxfexhf.js} +1 -1
- package/dist/{mistral-conversations-4pmwj1c0.js → mistral-conversations-3gjpdb4b.js} +4 -4
- package/dist/{oauth-refresh-sweep-29txy9vk.js → oauth-refresh-sweep-fckc4ar5.js} +2 -2
- package/dist/{onboard-kpsrkarj.js → onboard-zc48j237.js} +3 -3
- 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-j25vm3rr.js → opencode-adapter-r690h1cr.js} +4 -3
- package/dist/{otel-impl-6kkct7a8.js → otel-impl-r5xbh81q.js} +4 -4
- package/dist/{pi-mono-adapter-exhkzhn2.js → pi-mono-adapter-c7v8sdec.js} +7 -6
- package/dist/{pricing-refresh-n2x7jh6k.js → pricing-refresh-3pmre11v.js} +3 -3
- package/dist/{rbac-roles-81ypx6es.js → rbac-roles-3vbshwsb.js} +1 -1
- package/dist/{rbac-roles-b5htkjby.js → rbac-roles-910mmkgz.js} +2 -2
- package/dist/{render-v2-qn6jmpk4.js → render-v2-pxykkbab.js} +3 -3
- package/dist/{resume-wd30wx23.js → resume-adda0bwy.js} +6 -6
- package/dist/{runtime-4hsg7h60.js → runtime-fnbm7stk.js} +1 -1
- package/dist/{session-access-5qvfevhk.js → session-access-2fvamrdc.js} +4 -4
- package/dist/{session-source-backfill-n1czavbr.js → session-source-backfill-08xvv0sm.js} +2 -2
- package/dist/{setup-dnb56qy5.js → setup-1aqmvmh1.js} +1 -1
- package/dist/{typesafe-system-one-5mavm259.js → typesafe-system-one-0bmqcxfg.js} +2 -2
- package/dist/{virtual-modules-76xxv9fs.js → virtual-modules-d2pjk9j1.js} +5 -5
- package/dist/{work-objects-4n21tfkm.js → work-objects-9s0yrm5j.js} +20 -20
- package/dist/{worker-follow-up-77hvzxww.js → worker-follow-up-3q78fqmr.js} +17 -17
- package/dist/worker-y15hy08h.js +71 -0
- package/openapi.json +197 -4
- package/package.json +5 -5
- package/src/apps/definition.ts +6 -5
- package/src/be/db/page-theme-tokens.ts +12 -0
- package/src/be/db/tasks/read.ts +9 -1
- package/src/be/db/tasks/write.ts +19 -0
- package/src/be/db-client.ts +107 -7
- package/src/be/db.ts +34 -2
- package/src/be/migrations/269_pages_design_system.sql +23 -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/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/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 +3 -0
- package/src/http/pages-public.ts +93 -129
- package/src/http/pages.ts +94 -21
- 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/pi-mono-extension.ts +30 -15
- package/src/tasks/follow-up-gate.ts +318 -0
- package/src/tasks/worker-follow-up.ts +21 -1
- 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-task-read-contract.test.ts +1 -0
- package/src/tests/db-task-write-contract.test.ts +2 -0
- package/src/tests/db-tasks-read.test.ts +21 -0
- package/src/tests/fixtures/pages/head-v1.html +56 -0
- package/src/tests/follow-up-gate-shadow.test.ts +513 -0
- 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/merge-gate-detect-changes.test.ts +145 -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/scheduled-task-required-params-migration.test.ts +3 -1
- package/src/tests/script-connections.test.ts +2 -0
- 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 +142 -2
- 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/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/utils.ts +33 -0
- package/src/types.ts +45 -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/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/dist/cli-2pnswgh8.js +0 -189
- package/dist/handlers-by3sfxyx.js +0 -32
- package/dist/index-4f2pvxae.js +0 -37
- package/dist/index-98gz7tmp.js +0 -30
- package/dist/index-k08z2cak.js +0 -33
- package/dist/lead-enq35nqp.js +0 -70
- package/dist/worker-gg1576j3.js +0 -70
- 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,766 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `<head>` that `/p/:id` injects into an HTML page, one per design
|
|
3
|
+
* version (`page.designVersion`):
|
|
4
|
+
*
|
|
5
|
+
* - 1: `PAGE_HEAD_V1`, the original head. Frozen.
|
|
6
|
+
* - 2: `buildPageHeadV2()`, the swarm design system: theme tokens (see
|
|
7
|
+
* `src/themes/page-theme.ts`), element defaults and `swarm-*` primitives in
|
|
8
|
+
* cascade layers, and the pinned Tailwind v4 browser build.
|
|
9
|
+
*/
|
|
10
|
+
import { type ResolvedPageTheme, renderPageThemeCss } from "../themes/page-theme";
|
|
11
|
+
import { PAGE_THEME_TOKENS } from "../themes/tokens";
|
|
12
|
+
|
|
13
|
+
/** Query param: the viewer's dashboard preset id. Read by design version 2 only. */
|
|
14
|
+
export const PAGE_THEME_PARAM = "__swarm-theme";
|
|
15
|
+
/** Query param: `dark` renders the dark tokens. Read by design version 2 only. */
|
|
16
|
+
export const PAGE_MODE_PARAM = "__swarm-mode";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Design version 1, FROZEN: never change it. Pages with designVersion 1 must
|
|
20
|
+
* keep rendering as they did when they were written. Design changes go to
|
|
21
|
+
* `buildPageHeadV2` (or to a new design version).
|
|
22
|
+
*
|
|
23
|
+
* Default `<head>` injection: `<base>` so links escape the iframe, Tailwind
|
|
24
|
+
* Play CDN so agent pages can use utility classes out of the box, Space
|
|
25
|
+
* Grotesk / Space Mono fonts to match the swarm SPA, a small reset that
|
|
26
|
+
* makes pages theme-aware (light by default) so an agent who writes zero CSS
|
|
27
|
+
* still gets a presentable page, and finally the Browser SDK so
|
|
28
|
+
* `window.swarmSdk` works.
|
|
29
|
+
*
|
|
30
|
+
* Agent-provided styles can override these defaults. Tailwind utilities stay
|
|
31
|
+
* available, but its Preflight reset is disabled to preserve browser heading,
|
|
32
|
+
* margin, and list styles.
|
|
33
|
+
*/
|
|
34
|
+
export const PAGE_HEAD_V1 = `<base target="_blank">
|
|
35
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
36
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
37
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
38
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
39
|
+
<script>
|
|
40
|
+
if (window.tailwind) {
|
|
41
|
+
window.tailwind.config = { corePlugins: { preflight: false } };
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
<style>
|
|
45
|
+
*, ::before, ::after { box-sizing: border-box; border: 0 solid #e5e7eb; }
|
|
46
|
+
hr { border-top-width: 1px; }
|
|
47
|
+
img, video { display: block; max-width: 100%; height: auto; }
|
|
48
|
+
button, input, optgroup, select, textarea, ::file-selector-button { font: inherit; }
|
|
49
|
+
:root {
|
|
50
|
+
color-scheme: light;
|
|
51
|
+
--swarm-bg: #fbfbfa;
|
|
52
|
+
--swarm-card: #ffffff;
|
|
53
|
+
--swarm-border: #e5e7eb;
|
|
54
|
+
--swarm-text: #111827;
|
|
55
|
+
--swarm-muted: #6b7280;
|
|
56
|
+
--swarm-primary: #3b82f6;
|
|
57
|
+
}
|
|
58
|
+
html, body { background: var(--swarm-bg); color: var(--swarm-text); }
|
|
59
|
+
body {
|
|
60
|
+
font-family: "Space Grotesk", system-ui, sans-serif;
|
|
61
|
+
margin: 0;
|
|
62
|
+
padding: 24px;
|
|
63
|
+
line-height: 1.5;
|
|
64
|
+
}
|
|
65
|
+
code, pre, kbd, samp { font-family: "Space Mono", ui-monospace, monospace; }
|
|
66
|
+
a { color: var(--swarm-primary); }
|
|
67
|
+
::selection { background: var(--swarm-primary); color: #fff; }
|
|
68
|
+
@media print {
|
|
69
|
+
/* Override theme variables so built-in primitives (swarm-diff, swarm-card)
|
|
70
|
+
that read var(--swarm-card) / var(--swarm-border) etc. inline-styled
|
|
71
|
+
backgrounds also flip to light. Without this, diff cards stay dark navy
|
|
72
|
+
on print. */
|
|
73
|
+
:root {
|
|
74
|
+
--swarm-bg: #ffffff;
|
|
75
|
+
--swarm-card: #ffffff;
|
|
76
|
+
--swarm-border: #cccccc;
|
|
77
|
+
--swarm-text: #000000;
|
|
78
|
+
--swarm-muted: #555555;
|
|
79
|
+
}
|
|
80
|
+
html, body { background: white !important; color: black !important; }
|
|
81
|
+
a { color: black !important; text-decoration: underline; }
|
|
82
|
+
/* Hide any swarm chrome the agent (or built-in primitives) tagged with
|
|
83
|
+
.no-print. Use this class on annotation badges, jump-list nav, anything
|
|
84
|
+
that shouldn't appear in the PDF export. */
|
|
85
|
+
.no-print { display: none !important; }
|
|
86
|
+
/* Avoid page-break inside cards / diff blocks. */
|
|
87
|
+
.swarm-card, swarm-diff { break-inside: avoid; }
|
|
88
|
+
}
|
|
89
|
+
</style>`;
|
|
90
|
+
|
|
91
|
+
// ─── Design version 2 ───────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
/** Pinned Tailwind v4 browser build. Bump the version and the hash together. */
|
|
94
|
+
const TAILWIND_BROWSER_SRC =
|
|
95
|
+
"https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3/dist/index.global.js";
|
|
96
|
+
const TAILWIND_BROWSER_INTEGRITY =
|
|
97
|
+
"sha384-2ql948lIdLcGEE0/qxNiudyTjgauA3RDJERu5xW75kFCvSl5a9odyQYCb6tEjnmB";
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* `<base target="_blank">` would open an in-page `#id` link in a new tab. On
|
|
101
|
+
* click (capture phase, so before page handlers), this gives such a link
|
|
102
|
+
* `target="_self"` when it has no target. `setAttribute` also works on SVG
|
|
103
|
+
* links.
|
|
104
|
+
*/
|
|
105
|
+
const IN_PAGE_LINK_SCRIPT = `<script>document.addEventListener("click", function (event) {
|
|
106
|
+
var link = event.target && event.target.closest && event.target.closest('a[href^="#"]:not([target])');
|
|
107
|
+
if (link) link.setAttribute("target", "_self");
|
|
108
|
+
}, true);</script>`;
|
|
109
|
+
|
|
110
|
+
const FONT_LINKS = `<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
111
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
112
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">`;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* The Tailwind source. Theme and utilities only: Preflight stays off, so the
|
|
116
|
+
* element defaults below survive. `inline reference` maps each token utility
|
|
117
|
+
* (`bg-primary`, `rounded-xl`, `font-mono`) to `var(<token>)` and emits no
|
|
118
|
+
* variable of its own, so the unlayered theme CSS stays the one source.
|
|
119
|
+
*/
|
|
120
|
+
const TAILWIND_SOURCE = [
|
|
121
|
+
'@import "tailwindcss/theme" layer(theme);',
|
|
122
|
+
'@import "tailwindcss/utilities" layer(utilities);',
|
|
123
|
+
"@custom-variant dark (&:where(.dark, .dark *));",
|
|
124
|
+
"@theme inline reference {",
|
|
125
|
+
...PAGE_THEME_TOKENS.map((token) => ` ${token}: var(${token});`),
|
|
126
|
+
"}",
|
|
127
|
+
].join("\n");
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Adds the Tailwind source as a `text/tailwindcss` style element at run time
|
|
131
|
+
* (see `buildPageHeadV2`, item 6). The source is a JSON string with `<`
|
|
132
|
+
* escaped, so it cannot close the script.
|
|
133
|
+
*/
|
|
134
|
+
const TAILWIND_SOURCE_SCRIPT = `<script>(function () {
|
|
135
|
+
var style = document.createElement("style");
|
|
136
|
+
style.type = "text/tailwindcss";
|
|
137
|
+
style.textContent = ${JSON.stringify(TAILWIND_SOURCE).replace(/</g, "\\u003c")};
|
|
138
|
+
document.head.appendChild(style);
|
|
139
|
+
})();</script>`;
|
|
140
|
+
|
|
141
|
+
// One look, two selectors each: the plain element (`@layer base`) and the
|
|
142
|
+
// primitive class (`@layer components`). Both are 36px tall, like the
|
|
143
|
+
// dashboard controls. Only `background-color` is set, so the select arrow
|
|
144
|
+
// (a background image) survives. The base font reset for controls puts its
|
|
145
|
+
// elements in `:where()`, so its zero specificity lets these looks win by
|
|
146
|
+
// source order (a pseudo-element cannot go inside `:where()`).
|
|
147
|
+
const CONTROL_LOOK = `min-width: 0;
|
|
148
|
+
padding: 7px 12px;
|
|
149
|
+
font-size: 14px;
|
|
150
|
+
line-height: 20px;
|
|
151
|
+
color: var(--color-foreground);
|
|
152
|
+
background-color: var(--color-card);
|
|
153
|
+
border: 1px solid var(--color-input);
|
|
154
|
+
border-radius: var(--radius-md);
|
|
155
|
+
transition: border-color 150ms, box-shadow 150ms;`;
|
|
156
|
+
|
|
157
|
+
const BUTTON_LOOK = `display: inline-flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
gap: 8px;
|
|
161
|
+
padding: 7px 14px;
|
|
162
|
+
font-size: 14px;
|
|
163
|
+
font-weight: 500;
|
|
164
|
+
line-height: 20px;
|
|
165
|
+
color: var(--color-foreground);
|
|
166
|
+
background-color: var(--color-card);
|
|
167
|
+
border: 1px solid var(--color-input);
|
|
168
|
+
border-radius: var(--radius-md);
|
|
169
|
+
text-decoration: none;
|
|
170
|
+
white-space: nowrap;
|
|
171
|
+
cursor: pointer;
|
|
172
|
+
transition: color 150ms, background-color 150ms, border-color 150ms, box-shadow 150ms;`;
|
|
173
|
+
|
|
174
|
+
const FOCUS_RING = `outline: none;
|
|
175
|
+
border-color: var(--color-ring);
|
|
176
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--color-ring) 60%, transparent);`;
|
|
177
|
+
|
|
178
|
+
const TEXT_CONTROLS = `:where(input:not([type="checkbox"], [type="radio"], [type="range"], [type="color"], [type="file"], [type="button"], [type="submit"], [type="reset"], [type="image"], [type="hidden"]), select, textarea)`;
|
|
179
|
+
const BUTTON_CONTROLS = `:where(button, input[type="button"], input[type="submit"], input[type="reset"])`;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* The edge shadow of `.swarm-table-wrap`. The wrap paints it at each side with
|
|
183
|
+
* `background-attachment: scroll`, and covers it with card-colored gradients
|
|
184
|
+
* that scroll with the table (`local`). A side shows its shadow only when
|
|
185
|
+
* columns are hidden past it.
|
|
186
|
+
*/
|
|
187
|
+
const EDGE_SHADOW = "color-mix(in oklab, var(--color-foreground) 14%, transparent)";
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The status tones of `.swarm-badge`, `.swarm-callout` and `.swarm-metric`
|
|
191
|
+
* (`data-tone`). Each sets a soft color and a text-safe strong color.
|
|
192
|
+
*/
|
|
193
|
+
const TONES: ReadonlyArray<readonly [tone: string, soft: string, strong: string]> = [
|
|
194
|
+
["neutral", "--color-status-neutral", "--color-status-neutral-strong"],
|
|
195
|
+
["primary", "--color-primary", "--color-primary"],
|
|
196
|
+
...["success", "warning", "error", "info", "pending", "paused", "active"].map(
|
|
197
|
+
(tone) => [tone, `--color-status-${tone}`, `--color-status-${tone}-strong`] as const,
|
|
198
|
+
),
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
const TONE_RULES = TONES.map(
|
|
202
|
+
([tone, soft, strong]) =>
|
|
203
|
+
` :is(.swarm-badge, .swarm-callout, .swarm-metric)[data-tone="${tone}"] {\n --swarm-tone: var(${soft});\n --swarm-tone-strong: var(${strong});\n }`,
|
|
204
|
+
).join("\n");
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Element defaults (`@layer base`), primitives (`@layer components`) and the
|
|
208
|
+
* print rules (unlayered). Every color is a theme token. Taste bar: the Hive
|
|
209
|
+
* dashboard (`apps/ui/DESIGN.md`): quiet chrome, whitespace and uppercase
|
|
210
|
+
* micro-labels for separation, two-tier borders, soft pills, one accent, no
|
|
211
|
+
* shadows.
|
|
212
|
+
*/
|
|
213
|
+
const PAGE_DESIGN_CSS = `@layer base {
|
|
214
|
+
*, ::before, ::after, ::backdrop, ::file-selector-button {
|
|
215
|
+
box-sizing: border-box;
|
|
216
|
+
border: 0 solid var(--color-border);
|
|
217
|
+
}
|
|
218
|
+
html {
|
|
219
|
+
color: var(--color-foreground);
|
|
220
|
+
-webkit-text-size-adjust: 100%;
|
|
221
|
+
text-size-adjust: 100%;
|
|
222
|
+
tab-size: 4;
|
|
223
|
+
}
|
|
224
|
+
body {
|
|
225
|
+
margin: 0;
|
|
226
|
+
padding: 24px;
|
|
227
|
+
background-color: var(--color-background);
|
|
228
|
+
color: var(--color-foreground);
|
|
229
|
+
font-family: var(--font-sans), ui-sans-serif, system-ui, sans-serif;
|
|
230
|
+
font-size: 15px;
|
|
231
|
+
line-height: 1.55;
|
|
232
|
+
-webkit-font-smoothing: antialiased;
|
|
233
|
+
-moz-osx-font-smoothing: grayscale;
|
|
234
|
+
}
|
|
235
|
+
@media (max-width: 640px) {
|
|
236
|
+
body { padding: 16px; }
|
|
237
|
+
}
|
|
238
|
+
:focus-visible {
|
|
239
|
+
outline: 2px solid var(--color-ring);
|
|
240
|
+
outline-offset: 2px;
|
|
241
|
+
}
|
|
242
|
+
h1, h2, h3, h4, h5, h6 {
|
|
243
|
+
margin: 0;
|
|
244
|
+
font-weight: 600;
|
|
245
|
+
text-wrap: balance;
|
|
246
|
+
}
|
|
247
|
+
h1 { margin: 0 0 12px; font-size: 30px; line-height: 1.2; letter-spacing: -0.02em; }
|
|
248
|
+
h2 { margin: 40px 0 12px; font-size: 20px; line-height: 1.3; letter-spacing: -0.015em; }
|
|
249
|
+
h3 { margin: 28px 0 8px; font-size: 16px; line-height: 1.4; letter-spacing: -0.01em; }
|
|
250
|
+
h4 { margin: 24px 0 6px; font-size: 15px; line-height: 1.45; }
|
|
251
|
+
h5, h6 { margin: 20px 0 6px; font-size: 13px; line-height: 1.45; }
|
|
252
|
+
p { margin: 0 0 12px; text-wrap: pretty; }
|
|
253
|
+
ul, ol { margin: 0 0 12px; padding-left: 1.5em; }
|
|
254
|
+
li { margin: 4px 0; }
|
|
255
|
+
li > ul, li > ol { margin: 4px 0 0; }
|
|
256
|
+
li::marker { color: var(--color-muted-foreground); }
|
|
257
|
+
dl, figure, blockquote, pre, table, details, fieldset, form { margin: 0 0 16px; }
|
|
258
|
+
dt { font-weight: 500; }
|
|
259
|
+
dd { margin: 0 0 8px; }
|
|
260
|
+
:where(h1, h2, h3, h4, h5, h6):first-child { margin-top: 0; }
|
|
261
|
+
:where(p, ul, ol, dl, dd, figure, blockquote, pre, table, details, fieldset, form):last-child { margin-bottom: 0; }
|
|
262
|
+
a {
|
|
263
|
+
color: var(--color-primary);
|
|
264
|
+
text-decoration-line: underline;
|
|
265
|
+
text-decoration-thickness: 1px;
|
|
266
|
+
text-decoration-color: color-mix(in oklab, currentColor 35%, transparent);
|
|
267
|
+
text-underline-offset: 3px;
|
|
268
|
+
}
|
|
269
|
+
a:hover { text-decoration-color: currentColor; }
|
|
270
|
+
hr {
|
|
271
|
+
height: 0;
|
|
272
|
+
margin: 32px 0;
|
|
273
|
+
color: inherit;
|
|
274
|
+
border-top: 1px solid var(--color-border-subtle);
|
|
275
|
+
}
|
|
276
|
+
b, strong { font-weight: 600; }
|
|
277
|
+
mark {
|
|
278
|
+
padding: 0 2px;
|
|
279
|
+
color: inherit;
|
|
280
|
+
background-color: color-mix(in oklab, var(--color-status-pending) 35%, transparent);
|
|
281
|
+
border-radius: 2px;
|
|
282
|
+
}
|
|
283
|
+
code, kbd, samp, pre {
|
|
284
|
+
font-family: var(--font-mono), ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
285
|
+
font-size: 0.85em;
|
|
286
|
+
}
|
|
287
|
+
code {
|
|
288
|
+
padding: 0.1em 0.35em;
|
|
289
|
+
background-color: var(--color-muted);
|
|
290
|
+
border-radius: var(--radius-sm);
|
|
291
|
+
-webkit-box-decoration-break: clone;
|
|
292
|
+
box-decoration-break: clone;
|
|
293
|
+
}
|
|
294
|
+
kbd {
|
|
295
|
+
padding: 0.05em 0.4em;
|
|
296
|
+
background-color: var(--color-card);
|
|
297
|
+
border: 1px solid var(--color-border);
|
|
298
|
+
border-bottom-width: 2px;
|
|
299
|
+
border-radius: var(--radius-sm);
|
|
300
|
+
}
|
|
301
|
+
pre {
|
|
302
|
+
padding: 12px 14px;
|
|
303
|
+
overflow: auto;
|
|
304
|
+
line-height: 1.6;
|
|
305
|
+
background-color: var(--color-surface);
|
|
306
|
+
border: 1px solid var(--color-border);
|
|
307
|
+
border-radius: var(--radius-lg);
|
|
308
|
+
}
|
|
309
|
+
pre code {
|
|
310
|
+
padding: 0;
|
|
311
|
+
font-size: inherit;
|
|
312
|
+
background-color: transparent;
|
|
313
|
+
border-radius: 0;
|
|
314
|
+
}
|
|
315
|
+
blockquote {
|
|
316
|
+
padding: 2px 0 2px 16px;
|
|
317
|
+
color: var(--color-muted-foreground);
|
|
318
|
+
border-left: 2px solid var(--color-border);
|
|
319
|
+
}
|
|
320
|
+
summary {
|
|
321
|
+
cursor: pointer;
|
|
322
|
+
font-weight: 500;
|
|
323
|
+
}
|
|
324
|
+
summary::marker { color: var(--color-muted-foreground); }
|
|
325
|
+
details[open] > summary { margin-bottom: 8px; }
|
|
326
|
+
img, video {
|
|
327
|
+
display: block;
|
|
328
|
+
max-width: 100%;
|
|
329
|
+
height: auto;
|
|
330
|
+
}
|
|
331
|
+
figcaption {
|
|
332
|
+
margin-top: 8px;
|
|
333
|
+
font-size: 13px;
|
|
334
|
+
color: var(--color-muted-foreground);
|
|
335
|
+
}
|
|
336
|
+
table {
|
|
337
|
+
width: 100%;
|
|
338
|
+
border-collapse: collapse;
|
|
339
|
+
font-size: 14px;
|
|
340
|
+
font-variant-numeric: tabular-nums;
|
|
341
|
+
}
|
|
342
|
+
caption {
|
|
343
|
+
padding-bottom: 8px;
|
|
344
|
+
font-size: 13px;
|
|
345
|
+
text-align: left;
|
|
346
|
+
color: var(--color-muted-foreground);
|
|
347
|
+
}
|
|
348
|
+
th, td {
|
|
349
|
+
padding: 8px 12px;
|
|
350
|
+
text-align: left;
|
|
351
|
+
vertical-align: middle;
|
|
352
|
+
border-bottom: 1px solid var(--color-border-subtle);
|
|
353
|
+
}
|
|
354
|
+
th {
|
|
355
|
+
font-size: 11px;
|
|
356
|
+
font-weight: 500;
|
|
357
|
+
line-height: 1.45;
|
|
358
|
+
letter-spacing: 0.05em;
|
|
359
|
+
text-transform: uppercase;
|
|
360
|
+
vertical-align: bottom;
|
|
361
|
+
color: var(--color-muted-foreground);
|
|
362
|
+
border-bottom-color: var(--color-border);
|
|
363
|
+
}
|
|
364
|
+
th[scope="row"] {
|
|
365
|
+
font-size: inherit;
|
|
366
|
+
letter-spacing: normal;
|
|
367
|
+
text-transform: none;
|
|
368
|
+
vertical-align: middle;
|
|
369
|
+
color: inherit;
|
|
370
|
+
border-bottom-color: var(--color-border-subtle);
|
|
371
|
+
}
|
|
372
|
+
tfoot :is(td, th) {
|
|
373
|
+
font-weight: 600;
|
|
374
|
+
border-top: 1px solid var(--color-border);
|
|
375
|
+
}
|
|
376
|
+
tbody:has(+ tfoot) > tr:last-child > :is(td, th) { border-bottom-color: var(--color-border); }
|
|
377
|
+
:where(button, input, optgroup, select, textarea), ::file-selector-button {
|
|
378
|
+
font: inherit;
|
|
379
|
+
font-feature-settings: inherit;
|
|
380
|
+
font-variation-settings: inherit;
|
|
381
|
+
letter-spacing: inherit;
|
|
382
|
+
color: inherit;
|
|
383
|
+
}
|
|
384
|
+
${TEXT_CONTROLS} {
|
|
385
|
+
${CONTROL_LOOK}
|
|
386
|
+
}
|
|
387
|
+
${TEXT_CONTROLS}:focus-visible {
|
|
388
|
+
${FOCUS_RING}
|
|
389
|
+
}
|
|
390
|
+
:where(input, select, textarea)::placeholder {
|
|
391
|
+
color: var(--color-muted-foreground);
|
|
392
|
+
opacity: 1;
|
|
393
|
+
}
|
|
394
|
+
:where(input, select, textarea, button):disabled {
|
|
395
|
+
cursor: not-allowed;
|
|
396
|
+
opacity: 0.5;
|
|
397
|
+
}
|
|
398
|
+
:where(input, select, textarea)[aria-invalid="true"] { border-color: var(--color-destructive); }
|
|
399
|
+
textarea {
|
|
400
|
+
min-height: 80px;
|
|
401
|
+
line-height: 1.5;
|
|
402
|
+
resize: vertical;
|
|
403
|
+
}
|
|
404
|
+
select:not([multiple], [size]) {
|
|
405
|
+
appearance: none;
|
|
406
|
+
padding-right: 32px;
|
|
407
|
+
background-image:
|
|
408
|
+
linear-gradient(45deg, transparent 50%, var(--color-muted-foreground) 50%),
|
|
409
|
+
linear-gradient(135deg, var(--color-muted-foreground) 50%, transparent 50%);
|
|
410
|
+
background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
|
|
411
|
+
background-size: 5px 5px;
|
|
412
|
+
background-repeat: no-repeat;
|
|
413
|
+
}
|
|
414
|
+
${BUTTON_CONTROLS} {
|
|
415
|
+
${BUTTON_LOOK}
|
|
416
|
+
}
|
|
417
|
+
${BUTTON_CONTROLS}:hover:not(:disabled) {
|
|
418
|
+
color: var(--color-accent-foreground);
|
|
419
|
+
background-color: var(--color-accent);
|
|
420
|
+
}
|
|
421
|
+
${BUTTON_CONTROLS}:focus-visible {
|
|
422
|
+
${FOCUS_RING}
|
|
423
|
+
}
|
|
424
|
+
::file-selector-button {
|
|
425
|
+
margin-right: 12px;
|
|
426
|
+
padding: 4px 10px;
|
|
427
|
+
font-size: 13px;
|
|
428
|
+
font-weight: 500;
|
|
429
|
+
color: var(--color-foreground);
|
|
430
|
+
background-color: var(--color-card);
|
|
431
|
+
border: 1px solid var(--color-input);
|
|
432
|
+
border-radius: var(--radius-sm);
|
|
433
|
+
cursor: pointer;
|
|
434
|
+
}
|
|
435
|
+
input[type="checkbox"], input[type="radio"], input[type="range"], progress {
|
|
436
|
+
accent-color: var(--color-primary);
|
|
437
|
+
}
|
|
438
|
+
fieldset {
|
|
439
|
+
min-width: 0;
|
|
440
|
+
padding: 12px 16px 16px;
|
|
441
|
+
border: 1px solid var(--color-border);
|
|
442
|
+
border-radius: var(--radius-lg);
|
|
443
|
+
}
|
|
444
|
+
legend {
|
|
445
|
+
padding: 0 6px;
|
|
446
|
+
font-size: 13px;
|
|
447
|
+
font-weight: 500;
|
|
448
|
+
color: var(--color-muted-foreground);
|
|
449
|
+
}
|
|
450
|
+
label:has(input, select, textarea), label[for] { cursor: pointer; }
|
|
451
|
+
::selection {
|
|
452
|
+
color: var(--color-primary-foreground);
|
|
453
|
+
background-color: var(--color-primary);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@layer components {
|
|
458
|
+
.swarm-page {
|
|
459
|
+
max-width: 1120px;
|
|
460
|
+
margin-inline: auto;
|
|
461
|
+
padding-block: 8px 24px;
|
|
462
|
+
}
|
|
463
|
+
.swarm-eyebrow {
|
|
464
|
+
margin: 0 0 8px;
|
|
465
|
+
font-size: 11px;
|
|
466
|
+
font-weight: 500;
|
|
467
|
+
line-height: 1.45;
|
|
468
|
+
letter-spacing: 0.08em;
|
|
469
|
+
text-transform: uppercase;
|
|
470
|
+
color: var(--color-muted-foreground);
|
|
471
|
+
}
|
|
472
|
+
.swarm-lede {
|
|
473
|
+
max-width: 68ch;
|
|
474
|
+
margin: 0 0 16px;
|
|
475
|
+
font-size: 17px;
|
|
476
|
+
line-height: 1.55;
|
|
477
|
+
color: var(--color-muted-foreground);
|
|
478
|
+
text-wrap: pretty;
|
|
479
|
+
}
|
|
480
|
+
.swarm-section { margin-block: 40px; }
|
|
481
|
+
.swarm-section:last-child { margin-bottom: 0; }
|
|
482
|
+
.swarm-section > :first-child { margin-top: 0; }
|
|
483
|
+
|
|
484
|
+
.swarm-metrics {
|
|
485
|
+
display: grid;
|
|
486
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, 148px), 1fr));
|
|
487
|
+
gap: 12px;
|
|
488
|
+
margin: 24px 0;
|
|
489
|
+
}
|
|
490
|
+
.swarm-metric {
|
|
491
|
+
display: flex;
|
|
492
|
+
flex-direction: column;
|
|
493
|
+
gap: 4px;
|
|
494
|
+
min-width: 0;
|
|
495
|
+
padding: 14px 16px;
|
|
496
|
+
color: var(--color-card-foreground);
|
|
497
|
+
background-color: var(--color-card);
|
|
498
|
+
border: 1px solid var(--color-border);
|
|
499
|
+
border-radius: var(--radius-xl);
|
|
500
|
+
}
|
|
501
|
+
.swarm-metric-value {
|
|
502
|
+
font-size: 26px;
|
|
503
|
+
font-weight: 600;
|
|
504
|
+
line-height: 1.15;
|
|
505
|
+
letter-spacing: -0.02em;
|
|
506
|
+
font-variant-numeric: tabular-nums;
|
|
507
|
+
overflow-wrap: anywhere;
|
|
508
|
+
}
|
|
509
|
+
.swarm-metric[data-tone] .swarm-metric-value { color: var(--swarm-tone-strong); }
|
|
510
|
+
.swarm-metric-label {
|
|
511
|
+
font-size: 12px;
|
|
512
|
+
line-height: 1.45;
|
|
513
|
+
color: var(--color-muted-foreground);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.swarm-panel, .swarm-card {
|
|
517
|
+
padding: 20px;
|
|
518
|
+
color: var(--color-card-foreground);
|
|
519
|
+
background-color: var(--color-card);
|
|
520
|
+
border: 1px solid var(--color-border);
|
|
521
|
+
border-radius: var(--radius-xl);
|
|
522
|
+
}
|
|
523
|
+
:is(.swarm-panel, .swarm-card) > :first-child { margin-top: 0; }
|
|
524
|
+
:is(.swarm-panel, .swarm-card) > :last-child { margin-bottom: 0; }
|
|
525
|
+
|
|
526
|
+
.swarm-badge {
|
|
527
|
+
--swarm-tone: var(--color-status-neutral);
|
|
528
|
+
--swarm-tone-strong: var(--color-status-neutral-strong);
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
align-items: center;
|
|
531
|
+
gap: 6px;
|
|
532
|
+
height: 22px;
|
|
533
|
+
padding: 0 8px;
|
|
534
|
+
font-size: 12px;
|
|
535
|
+
font-weight: 500;
|
|
536
|
+
line-height: 1;
|
|
537
|
+
white-space: nowrap;
|
|
538
|
+
vertical-align: middle;
|
|
539
|
+
color: var(--swarm-tone-strong);
|
|
540
|
+
background-color: color-mix(in oklab, var(--swarm-tone) 16%, transparent);
|
|
541
|
+
border: 1px solid color-mix(in oklab, var(--swarm-tone) 28%, transparent);
|
|
542
|
+
border-radius: 999px;
|
|
543
|
+
}
|
|
544
|
+
.swarm-badge[data-dot]::before {
|
|
545
|
+
content: "";
|
|
546
|
+
flex: none;
|
|
547
|
+
width: 6px;
|
|
548
|
+
height: 6px;
|
|
549
|
+
background: var(--swarm-dot, currentColor);
|
|
550
|
+
border-radius: 999px;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
.swarm-table-wrap {
|
|
554
|
+
max-height: min(70vh, 720px);
|
|
555
|
+
margin: 0 0 16px;
|
|
556
|
+
overflow: auto;
|
|
557
|
+
background:
|
|
558
|
+
linear-gradient(to right, var(--color-card) 30%, transparent) left / 40px 100% no-repeat local,
|
|
559
|
+
linear-gradient(to left, var(--color-card) 30%, transparent) right / 40px 100% no-repeat local,
|
|
560
|
+
linear-gradient(to right, ${EDGE_SHADOW}, transparent) left / 14px 100% no-repeat scroll,
|
|
561
|
+
linear-gradient(to left, ${EDGE_SHADOW}, transparent) right / 14px 100% no-repeat scroll,
|
|
562
|
+
var(--color-card);
|
|
563
|
+
border: 1px solid var(--color-border);
|
|
564
|
+
border-radius: var(--radius-xl);
|
|
565
|
+
}
|
|
566
|
+
.swarm-table-wrap:last-child { margin-bottom: 0; }
|
|
567
|
+
.swarm-table-wrap > table { margin: 0; }
|
|
568
|
+
.swarm-table {
|
|
569
|
+
width: 100%;
|
|
570
|
+
border-collapse: separate;
|
|
571
|
+
border-spacing: 0;
|
|
572
|
+
font-size: 13px;
|
|
573
|
+
line-height: 1.45;
|
|
574
|
+
font-variant-numeric: tabular-nums;
|
|
575
|
+
}
|
|
576
|
+
.swarm-table :is(th, td) { padding: 8px 12px; }
|
|
577
|
+
.swarm-table thead th {
|
|
578
|
+
position: sticky;
|
|
579
|
+
top: 0;
|
|
580
|
+
z-index: 1;
|
|
581
|
+
padding-block: 10px 8px;
|
|
582
|
+
white-space: nowrap;
|
|
583
|
+
background-color: var(--color-card);
|
|
584
|
+
}
|
|
585
|
+
.swarm-table tbody tr:hover > :is(td, th) { background-color: color-mix(in oklab, var(--color-accent) 70%, transparent); }
|
|
586
|
+
.swarm-table-wrap > .swarm-table > :last-child > tr:last-child > :is(td, th) { border-bottom: 0; }
|
|
587
|
+
:is(td, th).num {
|
|
588
|
+
text-align: right;
|
|
589
|
+
white-space: nowrap;
|
|
590
|
+
font-variant-numeric: tabular-nums;
|
|
591
|
+
}
|
|
592
|
+
:is(td, th).nowrap { white-space: nowrap; }
|
|
593
|
+
.swarm-diff-root :is(table, th, td) { margin: 0; border: 0; }
|
|
594
|
+
|
|
595
|
+
.swarm-button {
|
|
596
|
+
${BUTTON_LOOK}
|
|
597
|
+
}
|
|
598
|
+
.swarm-button:hover {
|
|
599
|
+
color: var(--color-accent-foreground);
|
|
600
|
+
background-color: var(--color-accent);
|
|
601
|
+
}
|
|
602
|
+
.swarm-button[data-variant="primary"] {
|
|
603
|
+
color: var(--color-primary-foreground);
|
|
604
|
+
background-color: var(--color-primary);
|
|
605
|
+
border-color: transparent;
|
|
606
|
+
}
|
|
607
|
+
.swarm-button[data-variant="primary"]:hover {
|
|
608
|
+
color: var(--color-primary-foreground);
|
|
609
|
+
background-color: color-mix(in oklab, var(--color-primary) 90%, transparent);
|
|
610
|
+
}
|
|
611
|
+
.swarm-button[data-variant="ghost"] {
|
|
612
|
+
background-color: transparent;
|
|
613
|
+
border-color: transparent;
|
|
614
|
+
}
|
|
615
|
+
.swarm-button[data-variant="ghost"]:hover { background-color: var(--color-accent); }
|
|
616
|
+
.swarm-button:focus-visible {
|
|
617
|
+
${FOCUS_RING}
|
|
618
|
+
}
|
|
619
|
+
.swarm-button:is(:disabled, [aria-disabled="true"]) {
|
|
620
|
+
opacity: 0.5;
|
|
621
|
+
pointer-events: none;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.swarm-input {
|
|
625
|
+
${CONTROL_LOOK}
|
|
626
|
+
}
|
|
627
|
+
.swarm-input:focus-visible {
|
|
628
|
+
${FOCUS_RING}
|
|
629
|
+
}
|
|
630
|
+
select.swarm-input:not([multiple], [size]) { padding-right: 32px; }
|
|
631
|
+
|
|
632
|
+
.swarm-toolbar {
|
|
633
|
+
display: flex;
|
|
634
|
+
flex-wrap: wrap;
|
|
635
|
+
align-items: center;
|
|
636
|
+
gap: 8px;
|
|
637
|
+
margin: 0 0 12px;
|
|
638
|
+
}
|
|
639
|
+
.swarm-toolbar > :is(input[type="search"], input[type="text"], input:not([type])) { flex: 1 1 260px; }
|
|
640
|
+
|
|
641
|
+
.swarm-segmented {
|
|
642
|
+
display: inline-flex;
|
|
643
|
+
align-items: center;
|
|
644
|
+
gap: 2px;
|
|
645
|
+
height: 36px;
|
|
646
|
+
padding: 2px;
|
|
647
|
+
vertical-align: middle;
|
|
648
|
+
background-color: color-mix(in oklab, var(--color-muted) 40%, transparent);
|
|
649
|
+
border: 1px solid var(--color-border);
|
|
650
|
+
border-radius: var(--radius-md);
|
|
651
|
+
}
|
|
652
|
+
.swarm-segmented > :is(button, a) {
|
|
653
|
+
display: inline-flex;
|
|
654
|
+
align-items: center;
|
|
655
|
+
justify-content: center;
|
|
656
|
+
gap: 6px;
|
|
657
|
+
height: 100%;
|
|
658
|
+
padding: 0 12px;
|
|
659
|
+
font-size: 12px;
|
|
660
|
+
font-weight: 500;
|
|
661
|
+
line-height: 1;
|
|
662
|
+
white-space: nowrap;
|
|
663
|
+
text-decoration: none;
|
|
664
|
+
color: var(--color-muted-foreground);
|
|
665
|
+
background-color: transparent;
|
|
666
|
+
border: 0;
|
|
667
|
+
border-radius: calc(var(--radius-md) - 3px);
|
|
668
|
+
box-shadow: none;
|
|
669
|
+
cursor: pointer;
|
|
670
|
+
transition: color 150ms, background-color 150ms;
|
|
671
|
+
}
|
|
672
|
+
.swarm-segmented > :is(button, a):hover {
|
|
673
|
+
color: var(--color-foreground);
|
|
674
|
+
background-color: transparent;
|
|
675
|
+
}
|
|
676
|
+
.swarm-segmented > :is([aria-pressed="true"], [data-active]:not([data-active="false"])) {
|
|
677
|
+
color: var(--color-primary-foreground);
|
|
678
|
+
background-color: var(--color-primary);
|
|
679
|
+
}
|
|
680
|
+
.swarm-segmented > :is(button, a):focus-visible {
|
|
681
|
+
outline: none;
|
|
682
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--color-ring) 60%, transparent);
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.swarm-callout {
|
|
686
|
+
--swarm-tone: var(--color-status-info);
|
|
687
|
+
--swarm-tone-strong: var(--color-status-info-strong);
|
|
688
|
+
margin: 0 0 12px;
|
|
689
|
+
padding: 12px 16px;
|
|
690
|
+
color: var(--color-foreground);
|
|
691
|
+
background-color: color-mix(in oklab, var(--swarm-tone) 12%, transparent);
|
|
692
|
+
border: 1px solid color-mix(in oklab, var(--swarm-tone) 40%, transparent);
|
|
693
|
+
border-radius: var(--radius-lg);
|
|
694
|
+
}
|
|
695
|
+
.swarm-callout:last-child { margin-bottom: 0; }
|
|
696
|
+
.swarm-callout > :first-child { margin-top: 0; }
|
|
697
|
+
.swarm-callout > :last-child { margin-bottom: 0; }
|
|
698
|
+
|
|
699
|
+
.swarm-kv {
|
|
700
|
+
display: grid;
|
|
701
|
+
grid-template-columns: minmax(96px, max-content) minmax(0, 1fr);
|
|
702
|
+
gap: 8px 20px;
|
|
703
|
+
margin: 0 0 16px;
|
|
704
|
+
font-size: 14px;
|
|
705
|
+
}
|
|
706
|
+
.swarm-kv:last-child { margin-bottom: 0; }
|
|
707
|
+
.swarm-kv > dt {
|
|
708
|
+
font-weight: 400;
|
|
709
|
+
color: var(--color-muted-foreground);
|
|
710
|
+
}
|
|
711
|
+
.swarm-kv > dd {
|
|
712
|
+
min-width: 0;
|
|
713
|
+
margin: 0;
|
|
714
|
+
overflow-wrap: anywhere;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
${TONE_RULES}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
@media print {
|
|
721
|
+
html, body { background: white !important; color: black !important; }
|
|
722
|
+
a:not(.swarm-button) { color: black !important; text-decoration: underline; }
|
|
723
|
+
.no-print { display: none !important; }
|
|
724
|
+
.swarm-panel, .swarm-card, swarm-diff, .swarm-metric { break-inside: avoid; }
|
|
725
|
+
.swarm-table-wrap { max-height: none; overflow: visible; }
|
|
726
|
+
.swarm-table { font-size: 12px; }
|
|
727
|
+
.swarm-table :is(th, td):not(.num) { white-space: normal; }
|
|
728
|
+
.swarm-table thead th { position: static; }
|
|
729
|
+
tfoot { display: table-row-group; }
|
|
730
|
+
}`;
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* The design version 2 head. Order matters:
|
|
734
|
+
* 1. `<base>` so links escape the iframe, and the click handler that keeps
|
|
735
|
+
* in-page `#id` links in the page.
|
|
736
|
+
* 2. The layer order statement, as the FIRST style element: layers rank by
|
|
737
|
+
* first mention, so base < components < Tailwind utilities, whatever order
|
|
738
|
+
* the sheets load in. Unlayered CSS (the theme, the page's own styles)
|
|
739
|
+
* beats every layer.
|
|
740
|
+
* 3. Fonts. 4. Theme tokens (unlayered). 5. Element defaults and primitives.
|
|
741
|
+
* 6. The Tailwind source, before the script, so the first compile already
|
|
742
|
+
* skips Preflight. A script creates its `text/tailwindcss` style element:
|
|
743
|
+
* the browser preload scanner reads `@import` in any `<style>` in the
|
|
744
|
+
* markup, whatever its type, and would fetch `tailwindcss/theme` relative
|
|
745
|
+
* to the page. 7. The pinned Tailwind script (SRI).
|
|
746
|
+
* 8. In dark mode, the `.dark` class, set before the body renders.
|
|
747
|
+
*/
|
|
748
|
+
export function buildPageHeadV2({
|
|
749
|
+
theme,
|
|
750
|
+
mode,
|
|
751
|
+
}: {
|
|
752
|
+
theme: ResolvedPageTheme;
|
|
753
|
+
mode: "light" | "dark";
|
|
754
|
+
}): string {
|
|
755
|
+
return [
|
|
756
|
+
'<base target="_blank">',
|
|
757
|
+
IN_PAGE_LINK_SCRIPT,
|
|
758
|
+
"<style>@layer properties, theme, base, components, utilities;</style>",
|
|
759
|
+
FONT_LINKS,
|
|
760
|
+
`<style id="swarm-theme">\n${renderPageThemeCss(theme)}\n</style>`,
|
|
761
|
+
`<style id="swarm-design">\n${PAGE_DESIGN_CSS}\n</style>`,
|
|
762
|
+
TAILWIND_SOURCE_SCRIPT,
|
|
763
|
+
`<script src="${TAILWIND_BROWSER_SRC}" integrity="${TAILWIND_BROWSER_INTEGRITY}" crossorigin="anonymous"></script>`,
|
|
764
|
+
...(mode === "dark" ? ['<script>document.documentElement.classList.add("dark")</script>'] : []),
|
|
765
|
+
].join("\n");
|
|
766
|
+
}
|