@bongos/core 1.18.3 → 1.18.19

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 (471) hide show
  1. package/.bongos-core.json +1576 -286
  2. package/.claude/skills/builder-box/SKILL.md +6 -0
  3. package/.claude/skills/builder-sequence/SKILL.md +97 -0
  4. package/.claude/skills/builder-ship/SKILL.md +8 -2
  5. package/.claude/skills/builder-start/SKILL.md +11 -0
  6. package/.claude/skills/builder-sync/SKILL.md +41 -0
  7. package/.claude/skills/fix-task/SKILL.md +64 -0
  8. package/.claude/skills/goal-create/SKILL.md +158 -0
  9. package/.claude/skills/goal-review/SKILL.md +3 -1
  10. package/.claude/skills/idea-triage/SKILL.md +14 -8
  11. package/.claude/skills/merge-mode/SKILL.md +2 -2
  12. package/.claude/skills/new-project/SKILL.md +1 -0
  13. package/.claude/skills/planning-session/SKILL.md +45 -18
  14. package/.env.local.example +4 -3
  15. package/README.md +4 -2
  16. package/bin/bongos.js +1 -0
  17. package/clients/bongos-client/README.md +2 -2
  18. package/clients/bongos-client/bongos-client.global.js +82 -18
  19. package/clients/bongos-client/index.cjs +82 -18
  20. package/clients/bongos-client/index.d.ts +131 -29
  21. package/clients/bongos-client/index.mjs +82 -18
  22. package/config/branding.neutral.json +6 -1
  23. package/config/governance.neutral.json +21 -0
  24. package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
  25. package/docs/adr/0090-metic-task-authoring.md +1 -1
  26. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
  27. package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
  28. package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
  29. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
  30. package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
  31. package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
  32. package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
  33. package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
  34. package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
  35. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
  36. package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
  37. package/docs/adr/0152-metic-task-abandonment.md +67 -0
  38. package/docs/adr/0153-sequential-chain-runner.md +51 -0
  39. package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
  40. package/docs/adr/README.md +10 -0
  41. package/docs/api/openapi.json +843 -17
  42. package/docs/api-reference.md +23 -10
  43. package/docs/architecture.md +4 -2
  44. package/docs/branding-contract.md +3 -1
  45. package/docs/canonical-permissions.md +21 -8
  46. package/docs/file-map.md +8 -0
  47. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
  48. package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
  49. package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
  50. package/docs/onboarding/diagrams/assertions.json +4 -7
  51. package/docs/onboarding/drachmae-and-karma.md +3 -3
  52. package/docs/onboarding/primer.md +17 -16
  53. package/docs/onboarding/slash-commands.md +124 -0
  54. package/docs/recipes/builder-box-lifecycle.md +23 -0
  55. package/docs/recipes/devbox-app-release.md +14 -4
  56. package/docs/recipes/instance-first-run.md +16 -0
  57. package/docs/recipes/local-dev.md +81 -0
  58. package/docs/recipes/ops-gotchas.md +19 -1
  59. package/docs/recipes/overnight-builder.md +1 -1
  60. package/docs/recipes/parallel-goal-waves.md +174 -0
  61. package/docs/recipes/ship-and-regrade.md +2 -2
  62. package/docs/recipes/standalone-live-docs.md +48 -0
  63. package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
  64. package/migrations/003_pms.sql +6 -7
  65. package/migrations/006_pms_v2.sql +3 -31
  66. package/migrations/core_193_task_needs_rebase.sql +28 -0
  67. package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
  68. package/migrations/core_195_idea_triage_provenance.sql +57 -0
  69. package/migrations/core_196_session_reward_topup.sql +69 -0
  70. package/modules/autonomy/pollers/routine-timers.js +9 -8
  71. package/modules/builder-settings/wandering-prefs.js +61 -18
  72. package/modules/dev-box/app/README.md +73 -0
  73. package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
  74. package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
  75. package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
  76. package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
  77. package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
  78. package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
  79. package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
  80. package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
  81. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  82. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  83. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  84. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  85. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  86. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  87. package/modules/dev-box/app/build-resources/icon.png +0 -0
  88. package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
  89. package/modules/dev-box/app/electron-builder.yml +95 -0
  90. package/modules/dev-box/app/package-lock.json +5291 -0
  91. package/modules/dev-box/app/package.json +30 -0
  92. package/modules/dev-box/app/renderer/app.js +319 -0
  93. package/modules/dev-box/app/renderer/index.html +45 -0
  94. package/modules/dev-box/app/renderer/styles.css +246 -0
  95. package/modules/dev-box/app/renderer/theme.generated.css +16 -0
  96. package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
  97. package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
  98. package/modules/dev-box/app/scripts/gen-brand.js +138 -0
  99. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
  100. package/modules/dev-box/app/scripts/gen-icons.js +286 -0
  101. package/modules/dev-box/app/scripts/vendor-client.js +23 -0
  102. package/modules/dev-box/app/src/box-controller.js +287 -0
  103. package/modules/dev-box/app/src/brand.generated.json +13 -0
  104. package/modules/dev-box/app/src/brand.js +16 -0
  105. package/modules/dev-box/app/src/config.js +19 -0
  106. package/modules/dev-box/app/src/gds-client.js +90 -0
  107. package/modules/dev-box/app/src/main.js +610 -0
  108. package/modules/dev-box/app/src/pairing.js +57 -0
  109. package/modules/dev-box/app/src/preload.js +29 -0
  110. package/modules/dev-box/app/src/session-store.js +58 -0
  111. package/modules/dev-box/app/src/ssh-setup.js +569 -0
  112. package/modules/dev-box/app/src/task-picker.js +70 -0
  113. package/modules/dev-box/app/src/tray.js +99 -0
  114. package/modules/dev-box/app/src/updater.js +55 -0
  115. package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
  116. package/modules/dev-box/app/test/unit.mjs +526 -0
  117. package/modules/dev-box/box-access.js +121 -4
  118. package/modules/dev-box/boxes.js +20 -0
  119. package/modules/dev-box/module.json +1 -1
  120. package/modules/dev-box/routes/box.js +87 -3
  121. package/modules/economy/credits.js +116 -25
  122. package/modules/economy/reward.js +8 -0
  123. package/modules/economy/streak.js +2 -1
  124. package/modules/governance/CLAUDE.md +15 -0
  125. package/modules/governance/catalog.js +419 -0
  126. package/modules/governance/config.js +174 -0
  127. package/modules/governance/db.js +125 -0
  128. package/modules/governance/migrations/governance_001_tables.sql +81 -0
  129. package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
  130. package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
  131. package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
  132. package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
  133. package/modules/governance/module.json +10 -0
  134. package/modules/governance/protected-surfaces.js +88 -0
  135. package/modules/governance/protected-surfaces.json +80 -0
  136. package/modules/governance/rank-roles.js +83 -0
  137. package/modules/governance/resolver.js +221 -0
  138. package/modules/governance/routes/governance.js +89 -0
  139. package/modules/governance/routes/role-sync.js +49 -0
  140. package/modules/governance/session-scopes.js +127 -0
  141. package/modules/governance/session-scopes.json +38 -0
  142. package/modules/hall-ui/public/atlas.css +117 -0
  143. package/modules/hall-ui/public/atlas.html +3 -114
  144. package/modules/hall-ui/public/brand-apply.js +34 -6
  145. package/modules/hall-ui/public/builders.js +187 -219
  146. package/modules/hall-ui/public/diagrams.html +2 -0
  147. package/modules/hall-ui/public/dom-utils.js +27 -0
  148. package/modules/hall-ui/public/drachmae.html +2 -0
  149. package/modules/hall-ui/public/drachmae.js +54 -1
  150. package/modules/hall-ui/public/gate.css +98 -0
  151. package/modules/hall-ui/public/gate.html +3 -95
  152. package/modules/hall-ui/public/goal-inbox.js +4 -1
  153. package/modules/hall-ui/public/goals-page.js +626 -114
  154. package/modules/hall-ui/public/goals.css +79 -1
  155. package/modules/hall-ui/public/goals.html +38 -11
  156. package/modules/hall-ui/public/hall-widgets.js +62 -52
  157. package/modules/hall-ui/public/harbor.css +123 -0
  158. package/modules/hall-ui/public/harbor.html +3 -120
  159. package/modules/hall-ui/public/index.html +11 -4
  160. package/modules/hall-ui/public/instances-panel.js +4 -1
  161. package/modules/hall-ui/public/modules.css +63 -0
  162. package/modules/hall-ui/public/modules.html +3 -60
  163. package/modules/hall-ui/public/new-project-wizard.js +7 -3
  164. package/modules/hall-ui/public/not-ready.html +2 -0
  165. package/modules/hall-ui/public/pair.css +73 -0
  166. package/modules/hall-ui/public/pair.html +3 -70
  167. package/modules/hall-ui/public/palette.js +302 -0
  168. package/modules/hall-ui/public/primer.css +13 -0
  169. package/modules/hall-ui/public/primer.html +2 -0
  170. package/modules/hall-ui/public/profile.html +2 -0
  171. package/modules/hall-ui/public/ranks.html +2 -0
  172. package/modules/hall-ui/public/roadmap.css +179 -0
  173. package/modules/hall-ui/public/roadmap.html +9 -172
  174. package/modules/hall-ui/public/roadmap.js +329 -316
  175. package/modules/hall-ui/public/sessions.css +16 -0
  176. package/modules/hall-ui/public/sessions.html +3 -13
  177. package/modules/hall-ui/public/settings.html +2 -0
  178. package/modules/hall-ui/public/settings.js +4 -4
  179. package/modules/hall-ui/public/shell.js +143 -18
  180. package/modules/hall-ui/public/style.css +231 -39
  181. package/modules/hall-ui/public/task-detail.js +347 -26
  182. package/modules/hall-ui/public/task.html +6 -1
  183. package/modules/hall-ui/public/watch.html +2 -0
  184. package/modules/hall-ui/public/work.html +8 -6
  185. package/modules/hall-ui/public/work.js +1 -1
  186. package/modules/ideas/inbox.js +61 -11
  187. package/modules/ideas/routes/inbox.js +23 -0
  188. package/modules/lifecycle/claim-eligibility.js +72 -0
  189. package/modules/lifecycle/db.js +519 -139
  190. package/modules/lifecycle/done-when.js +18 -3
  191. package/modules/lifecycle/github-push.js +19 -2
  192. package/modules/lifecycle/goal-advisory.js +114 -0
  193. package/modules/lifecycle/goal-authz.js +62 -0
  194. package/modules/lifecycle/lifecycle.js +9 -0
  195. package/modules/lifecycle/publish-reconciler.js +109 -6
  196. package/modules/lifecycle/routes/claims.js +68 -23
  197. package/modules/lifecycle/routes/done-when.js +110 -15
  198. package/modules/lifecycle/routes/goals.js +8 -38
  199. package/modules/lifecycle/routes/tasks.js +38 -6
  200. package/modules/lifecycle/ship-card.js +6 -0
  201. package/modules/onboarding/onboarding-state.js +1 -1
  202. package/modules/platform-identity/CLAUDE.md +15 -0
  203. package/modules/platform-identity/hub-device.js +147 -0
  204. package/modules/platform-identity/hub-keys.js +151 -0
  205. package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
  206. package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
  207. package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
  208. package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
  209. package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
  210. package/modules/platform-identity/module.json +18 -0
  211. package/modules/platform-identity/platform-identity.js +531 -0
  212. package/modules/platform-identity/pollers/code-sweep.js +43 -0
  213. package/modules/platform-identity/routes/my-projects.js +140 -0
  214. package/modules/platform-identity/routes/projects.js +107 -0
  215. package/modules/platform-identity/routes/scouting.js +35 -0
  216. package/modules/platform-identity/routes/sso.js +402 -0
  217. package/modules/platform-identity/tests/platform-identity.mjs +388 -0
  218. package/modules/platform-identity/ui/.gitkeep +0 -0
  219. package/modules/security/routes/reports.js +10 -0
  220. package/modules/sessions/db.js +166 -21
  221. package/modules/sessions/module.json +1 -1
  222. package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
  223. package/modules/sessions/routes/sessions.js +33 -0
  224. package/package-lock.json +2 -2
  225. package/package.json +1 -1
  226. package/public-landing/assets/anim/idle/frame_00.webp +0 -0
  227. package/public-landing/assets/anim/idle/frame_01.webp +0 -0
  228. package/public-landing/assets/anim/idle/frame_02.webp +0 -0
  229. package/public-landing/assets/anim/idle/frame_03.webp +0 -0
  230. package/public-landing/assets/anim/idle/frame_04.webp +0 -0
  231. package/public-landing/assets/anim/idle/frame_05.webp +0 -0
  232. package/public-landing/assets/anim/idle/frame_06.webp +0 -0
  233. package/public-landing/assets/anim/idle/frame_07.webp +0 -0
  234. package/public-landing/assets/anim/idle/frame_08.webp +0 -0
  235. package/public-landing/assets/anim/idle/frame_09.webp +0 -0
  236. package/public-landing/assets/anim/idle/frame_10.webp +0 -0
  237. package/public-landing/assets/anim/idle/frame_11.webp +0 -0
  238. package/public-landing/assets/anim/idle/frame_12.webp +0 -0
  239. package/public-landing/assets/anim/idle/frame_13.webp +0 -0
  240. package/public-landing/assets/anim/idle/frame_14.webp +0 -0
  241. package/public-landing/assets/anim/idle/frame_15.webp +0 -0
  242. package/public-landing/assets/anim/idle/frame_16.webp +0 -0
  243. package/public-landing/assets/anim/idle/frame_17.webp +0 -0
  244. package/public-landing/assets/anim/idle/frame_18.webp +0 -0
  245. package/public-landing/assets/anim/idle/frame_19.webp +0 -0
  246. package/public-landing/assets/anim/idle/frame_20.webp +0 -0
  247. package/public-landing/assets/anim/idle/frame_21.webp +0 -0
  248. package/public-landing/assets/anim/idle/frame_22.webp +0 -0
  249. package/public-landing/assets/anim/idle/frame_23.webp +0 -0
  250. package/public-landing/assets/anim/idle/frame_24.webp +0 -0
  251. package/public-landing/assets/anim/idle/frame_25.webp +0 -0
  252. package/public-landing/assets/anim/idle/frame_26.webp +0 -0
  253. package/public-landing/assets/anim/idle/frame_27.webp +0 -0
  254. package/public-landing/assets/anim/idle/frame_28.webp +0 -0
  255. package/public-landing/assets/anim/idle/frame_29.webp +0 -0
  256. package/public-landing/assets/anim/idle/frame_30.webp +0 -0
  257. package/public-landing/assets/anim/idle/frame_31.webp +0 -0
  258. package/public-landing/assets/anim/idle/frame_32.webp +0 -0
  259. package/public-landing/assets/anim/idle/frame_33.webp +0 -0
  260. package/public-landing/assets/anim/idle/frame_34.webp +0 -0
  261. package/public-landing/assets/anim/idle/frame_35.webp +0 -0
  262. package/public-landing/assets/anim/idle/frame_36.webp +0 -0
  263. package/public-landing/assets/anim/idle/frame_37.webp +0 -0
  264. package/public-landing/assets/anim/idle/frame_38.webp +0 -0
  265. package/public-landing/assets/anim/idle/frame_39.webp +0 -0
  266. package/public-landing/assets/anim/idle/frame_40.webp +0 -0
  267. package/public-landing/assets/anim/idle/frame_41.webp +0 -0
  268. package/public-landing/assets/anim/idle/frame_42.webp +0 -0
  269. package/public-landing/assets/anim/idle/frame_43.webp +0 -0
  270. package/public-landing/create.html +51 -58
  271. package/public-landing/gate/README.md +137 -0
  272. package/public-landing/gate/dispmaps/bar.png +0 -0
  273. package/public-landing/gate/dispmaps/flat.png +0 -0
  274. package/public-landing/gate/dispmaps/key.png +0 -0
  275. package/public-landing/gate/index.html +587 -0
  276. package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
  277. package/public-landing/gate/previews/off-the-boats.jpg +0 -0
  278. package/public-landing/gate/space.css +799 -0
  279. package/public-landing/gate/space.js +1826 -0
  280. package/public-landing/gate/sprites/enter.png +0 -0
  281. package/public-landing/gate/sprites/search.png +0 -0
  282. package/public-landing/gate/sprites/terminal-blank.png +0 -0
  283. package/public-landing/gate/sprites/tile.png +0 -0
  284. package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
  285. package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
  286. package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
  287. package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
  288. package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
  289. package/public-landing/world/assets/plates/scene-establishing.png +0 -0
  290. package/scripts/gds/abandon.js +6 -4
  291. package/scripts/gds/api.js +10 -5
  292. package/scripts/gds/api.ps1 +26 -0
  293. package/scripts/gds/api.sh +6 -0
  294. package/scripts/gds/audit-ships.js +7 -1
  295. package/scripts/gds/backfill-sessions.js +78 -18
  296. package/scripts/gds/backup.js +23 -1
  297. package/scripts/gds/box-connect-lib.js +124 -31
  298. package/scripts/gds/box-sync.js +66 -0
  299. package/scripts/gds/box.js +225 -53
  300. package/scripts/gds/cf-tunnel.js +145 -6
  301. package/scripts/gds/claim.js +34 -3
  302. package/scripts/gds/cli-lib.js +161 -27
  303. package/scripts/gds/code.js +6 -2
  304. package/scripts/gds/deploy-divergence.js +209 -0
  305. package/scripts/gds/dev-lib.js +309 -0
  306. package/scripts/gds/dev.js +322 -0
  307. package/scripts/gds/doctor.js +90 -61
  308. package/scripts/gds/fetch-art-key.js +1 -1
  309. package/scripts/gds/fetch-sound-prefs.js +2 -2
  310. package/scripts/gds/fitness.js +228 -12
  311. package/scripts/gds/gds-db-backup.service +16 -1
  312. package/scripts/gds/gds-db-offsite.service +9 -1
  313. package/scripts/gds/gen-api-client.js +1 -1
  314. package/scripts/gds/gen-api-docs.js +36 -14
  315. package/scripts/gds/gen-diagrams.js +45 -28
  316. package/scripts/gds/gen-file-map.js +2 -1
  317. package/scripts/gds/gen-freshness.js +32 -0
  318. package/scripts/gds/gen-repo-map.js +3 -2
  319. package/scripts/gds/gen-session-index.js +14 -5
  320. package/scripts/gds/hooks/pre-push.js +2 -2
  321. package/scripts/gds/init.js +60 -3
  322. package/scripts/gds/install-git-hooks.js +1 -1
  323. package/scripts/gds/key-card.js +15 -6
  324. package/scripts/gds/key-status.js +1 -1
  325. package/scripts/gds/linkify-refs.js +35 -9
  326. package/scripts/gds/login.js +16 -1
  327. package/scripts/gds/paste-token.js +7 -1
  328. package/scripts/gds/preflight.js +126 -0
  329. package/scripts/gds/provision.js +123 -12
  330. package/scripts/gds/publish-manifest.js +7 -1
  331. package/scripts/gds/reauth.js +7 -3
  332. package/scripts/gds/regen-instance-docs.js +47 -0
  333. package/scripts/gds/run-unit-tests.js +4 -2
  334. package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
  335. package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
  336. package/scripts/gds/sequence.js +425 -0
  337. package/scripts/gds/session-cost.js +10 -1
  338. package/scripts/gds/setup.js +31 -5
  339. package/scripts/gds/shell.js +5 -3
  340. package/scripts/gds/ship.js +319 -29
  341. package/scripts/gds/smoke-gds.js +139 -8
  342. package/scripts/gds/start.js +171 -22
  343. package/scripts/gds/status.js +1 -1
  344. package/scripts/gds/triage.js +10 -9
  345. package/scripts/gds/upgrade.js +124 -2
  346. package/scripts/migrate.sh +99 -14
  347. package/scripts/status-mirror-sync.js +114 -84
  348. package/src/bongos/api-errors.js +1 -0
  349. package/src/bongos/auth.js +447 -102
  350. package/src/bongos/db-kernel.js +27 -0
  351. package/src/bongos/db.js +39 -0
  352. package/src/bongos/module-scope-map.js +27 -1
  353. package/src/bongos/permission-path-check.js +136 -102
  354. package/src/bongos/repo-info.js +47 -11
  355. package/src/bongos/route-rank-check.js +429 -46
  356. package/src/bongos/routes/_helpers.js +12 -1
  357. package/src/bongos/routes/auth.js +219 -2
  358. package/src/bongos/routes/backup.js +58 -2
  359. package/src/bongos/routes/me.js +35 -1
  360. package/src/bongos/serve-internal.js +84 -15
  361. package/src/branding.js +32 -0
  362. package/src/instance-config.js +30 -0
  363. package/src/module-api.js +124 -1
  364. package/src/platform-server.js +86 -9
  365. package/tests/abandon_task.mjs +59 -3
  366. package/tests/api_cli_flags.mjs +53 -0
  367. package/tests/auth_page_gate.mjs +13 -0
  368. package/tests/backfill_sessions.mjs +127 -1
  369. package/tests/backup_cli.mjs +54 -0
  370. package/tests/bongos_box_connect.mjs +77 -0
  371. package/tests/box_access.mjs +130 -1
  372. package/tests/box_credential.mjs +125 -0
  373. package/tests/box_host_keys.mjs +24 -0
  374. package/tests/box_infra_resolve.mjs +149 -0
  375. package/tests/box_scope_session.mjs +6 -2
  376. package/tests/box_sync.mjs +55 -0
  377. package/tests/box_task_scope.mjs +99 -0
  378. package/tests/branding.mjs +12 -0
  379. package/tests/cf_ruleset_preflight.mjs +142 -0
  380. package/tests/cf_tunnel.mjs +37 -0
  381. package/tests/claim_gate_rebase.mjs +98 -0
  382. package/tests/clawback_confirmed_backlog.mjs +103 -0
  383. package/tests/cli_lib_formatters.mjs +20 -0
  384. package/tests/confirm_attribution.mjs +30 -46
  385. package/tests/credit_grant.mjs +198 -10
  386. package/tests/criterion_authoring_gate.mjs +272 -0
  387. package/tests/criterion_progress.mjs +33 -1
  388. package/tests/dev_lib.mjs +253 -0
  389. package/tests/devbox_artifact_gate.mjs +75 -0
  390. package/tests/devbox_dmg_backdrop.mjs +137 -0
  391. package/tests/devbox_icons.mjs +304 -0
  392. package/tests/devbox_installer_brand.mjs +232 -0
  393. package/tests/devbox_key_register.mjs +234 -0
  394. package/tests/docs_openapi_route.mjs +110 -0
  395. package/tests/doctor_hooks.mjs +141 -0
  396. package/tests/extract_json.mjs +140 -0
  397. package/tests/fitness.mjs +89 -0
  398. package/tests/gen_freshness.mjs +96 -0
  399. package/tests/goal_advisory.mjs +251 -0
  400. package/tests/goal_criterion_confirm_ui.mjs +269 -0
  401. package/tests/goal_routes.mjs +59 -4
  402. package/tests/goal_tier.mjs +12 -3
  403. package/tests/governance_catalog.mjs +129 -0
  404. package/tests/governance_claim_eligibility.mjs +262 -0
  405. package/tests/governance_config.mjs +187 -0
  406. package/tests/governance_ownership_scope.mjs +410 -0
  407. package/tests/governance_page_gates.mjs +324 -0
  408. package/tests/governance_parity.mjs +336 -0
  409. package/tests/governance_principals.mjs +232 -0
  410. package/tests/governance_protected_surfaces.mjs +208 -0
  411. package/tests/governance_require_permission.mjs +223 -0
  412. package/tests/governance_resolver.mjs +84 -0
  413. package/tests/governance_role_sync.mjs +231 -0
  414. package/tests/governance_seed.mjs +127 -0
  415. package/tests/governance_session_scope.mjs +434 -0
  416. package/tests/governance_vanilla_boot.mjs +203 -0
  417. package/tests/grade_attribution.mjs +7 -7
  418. package/tests/hall_audit.mjs +223 -0
  419. package/tests/hall_nav.mjs +191 -0
  420. package/tests/hall_palette.mjs +206 -0
  421. package/tests/hall_signout.mjs +124 -0
  422. package/tests/hook_user_agents.mjs +10 -0
  423. package/tests/idea_triage.mjs +162 -0
  424. package/tests/idp_device_exchange.mjs +93 -0
  425. package/tests/init.mjs +51 -0
  426. package/tests/instance_config.mjs +65 -0
  427. package/tests/instance_mismatch_guard.mjs +23 -6
  428. package/tests/instance_release_config.mjs +104 -0
  429. package/tests/linkify_refs.mjs +15 -2
  430. package/tests/migrate_root_resolution.mjs +124 -1
  431. package/tests/module_contributions.mjs +55 -0
  432. package/tests/module_loader.mjs +10 -5
  433. package/tests/module_scope_active_claims.mjs +94 -0
  434. package/tests/needs_rebase.mjs +92 -0
  435. package/tests/one_active_claim_per_session.mjs +76 -0
  436. package/tests/override_attribution.mjs +10 -8
  437. package/tests/override_request_ownership.mjs +8 -4
  438. package/tests/parse_cookie_decode.mjs +42 -0
  439. package/tests/pay_on_land.mjs +129 -0
  440. package/tests/platform_boot.mjs +100 -1
  441. package/tests/post_login_landing.mjs +42 -0
  442. package/tests/preflight_checks.mjs +72 -0
  443. package/tests/provision.mjs +132 -7
  444. package/tests/publish_branch_route.mjs +53 -0
  445. package/tests/publish_reconciler.mjs +187 -2
  446. package/tests/repo_info_binding.mjs +248 -0
  447. package/tests/reward_gate.mjs +11 -2
  448. package/tests/reward_mode_cost_plus_only.mjs +116 -0
  449. package/tests/reward_mode_surfacing.mjs +168 -0
  450. package/tests/route_permission_check.mjs +301 -0
  451. package/tests/route_rank_check.mjs +254 -12
  452. package/tests/route_validation.mjs +30 -0
  453. package/tests/sequence.mjs +267 -0
  454. package/tests/session_digest.mjs +44 -0
  455. package/tests/session_index.mjs +18 -6
  456. package/tests/session_records.mjs +39 -1
  457. package/tests/session_reward_on_land.mjs +381 -0
  458. package/tests/session_reward_reconcile.mjs +229 -0
  459. package/tests/ship_api_client_pathspec.mjs +100 -0
  460. package/tests/ship_base_flag.mjs +93 -0
  461. package/tests/ship_ci_deploy.mjs +80 -3
  462. package/tests/ship_upstream_deletion.mjs +57 -0
  463. package/tests/smoke_target.mjs +233 -0
  464. package/tests/start_env_guard.mjs +87 -0
  465. package/tests/start_rebase_warning.mjs +103 -0
  466. package/tests/status_mirror_sync.mjs +122 -0
  467. package/tests/stop_refcheck.mjs +19 -1
  468. package/tests/task_goal_link.mjs +15 -6
  469. package/tests/upgrade.mjs +139 -0
  470. package/tests/web_admission_status.mjs +162 -0
  471. package/tests/write_validation_gaps.mjs +110 -0
@@ -0,0 +1,302 @@
1
+ // palette.js — the hall's jump palette (task 2178). Ctrl/Cmd-K, or the top-bar
2
+ // slot shell.js renders inert until this file loads.
3
+ //
4
+ // Dependency-free like shell.js: it runs on pages that load neither dom-utils.js
5
+ // nor hall-kit.js, so it defines its own helpers and reads the DOM shell.js has
6
+ // already drawn. OTBKit owns pagers/filters/tabs/rails — a modal command palette
7
+ // is none of those, so it is built here rather than bent out of a kit primitive.
8
+ //
9
+ // Progressive enhancement is the contract: a page that does not load palette.js
10
+ // keeps a hidden slot and no key handler, and nothing in shell.js calls in here.
11
+ //
12
+ // The index is CLIENT-SIDE ONLY (no new server surface, task 2178 scope):
13
+ // 1. Pages — read live from the sidebar shell.js rendered, so rank + module
14
+ // gating come for free and can never drift from the nav. A hidden nav item
15
+ // is a hidden destination. (Cosmetic only; the server still gates each page.)
16
+ // 2. Sections — the sub-destinations of the three pages that have them. These
17
+ // cannot be read from another page's DOM, so they are declared below and
18
+ // held to the real ids by tests/hall_palette.mjs.
19
+ // 3. Records — id syntax: `1234`, `g 12`, `b 7`, `i 42`.
20
+ // Full-text search over tasks/docs is phase 2 — it needs a server surface.
21
+ (function () {
22
+ 'use strict';
23
+
24
+ var PALETTE_ID = 'jump-palette';
25
+ var MAX_RESULTS = 40;
26
+
27
+ // Sub-destinations, grouped by the nav item that owns them. `gate` names the
28
+ // element whose visibility decides whether the group is offered — the nav item
29
+ // itself for pages, the profile chip for Settings (which is not a nav item).
30
+ // Anchors must stay in step with their source of truth; the test asserts it:
31
+ // standing → builders.js STANDING_GROUPS (+ shell.js VIEW_ALIASES)
32
+ // work → work.js makeTabs ids
33
+ // settings → settings.js RAIL_GROUPS
34
+ var SECTIONS = [
35
+ { parent: 'Standing', gate: 'nav-standing', items: [
36
+ { label: 'Work', href: '/#standing-work' },
37
+ { label: 'Karma', href: '/#standing-karma' },
38
+ { label: 'Progress', href: '/#standing-progress' },
39
+ { label: 'Achievements', href: '/#standing-achievements' },
40
+ ] },
41
+ { parent: 'Tasks', gate: 'nav-work', items: [
42
+ { label: 'Ready', href: '/work#ready' },
43
+ { label: 'In Progress', href: '/work#in-progress' },
44
+ { label: 'Backlog', href: '/work#backlog' },
45
+ { label: 'Completed', href: '/work#completed' },
46
+ ] },
47
+ { parent: 'Settings', gate: 'shell-user', items: [
48
+ { label: 'Account', href: '/settings#account' },
49
+ { label: 'Access', href: '/settings#access' },
50
+ // settings.js builds this panel only when the dev-box module is on, so the
51
+ // jump must carry the same condition or it lands on a panel that isn't there.
52
+ { label: 'Dev box', href: '/settings#devbox', module: 'dev-box' },
53
+ { label: 'Extensions', href: '/settings#extensions' },
54
+ { label: 'Preferences', href: '/settings#preferences' },
55
+ { label: 'Sound', href: '/settings#sound' },
56
+ ] },
57
+ ];
58
+
59
+ // id syntax → destination. `overlay: true` marks an overlay hash: those resolve
60
+ // in place when the page carries task-detail.js, and otherwise route via the index.
61
+ var SYNTAX = [
62
+ { re: /^(\d+)$/, hint: 'task', href: function (n) { return '/task/' + n; } },
63
+ { re: /^g\s*(\d+)$/i, hint: 'goal', href: function (n) { return '/goals#/goal/' + n; } },
64
+ { re: /^b\s*(\d+)$/i, hint: 'blocker', href: function (n) { return '#/blocker/' + n; }, overlay: true },
65
+ { re: /^i\s*(\d+)$/i, hint: 'idea', href: function (n) { return '#/idea/' + n; }, overlay: true },
66
+ ];
67
+
68
+ var isMac = /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent || '');
69
+ var root = null; // the overlay element, built on first open
70
+ var input = null;
71
+ var listEl = null;
72
+ var results = [];
73
+ var cursor = 0;
74
+ var lastFocus = null;
75
+
76
+ function esc(s) {
77
+ return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
78
+ return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
79
+ });
80
+ }
81
+ function visible(id) {
82
+ var el = document.getElementById(id);
83
+ return !!(el && !el.hidden);
84
+ }
85
+ // Same contract as shell.js moduleOn: an unknown key is treated as ON, so a
86
+ // core instance that publishes no module map keeps every destination.
87
+ function moduleOn(name) {
88
+ var m = window.__MODULES__;
89
+ if (!m || !m.enabled || !(name in m.enabled)) return true;
90
+ return m.enabled[name] === true;
91
+ }
92
+
93
+ // Pages, straight from the rendered sidebar. Skips the external API-docs link's
94
+ // target rewrite by reading the href attribute as authored.
95
+ //
96
+ // Re-read per keystroke rather than cached at open(): on a non-index page
97
+ // shell.js settles gating ASYNCHRONOUSLY (its /me probe), so a cache taken when
98
+ // the palette opened could offer pages the builder cannot see, or hide ones they
99
+ // can. The nav is ~18 nodes — correctness is worth the query.
100
+ function pageEntries() {
101
+ var out = [];
102
+ document.querySelectorAll('#app-sidebar .nav-item').forEach(function (a) {
103
+ if (a.hidden) return;
104
+ var label = (a.querySelector('.nav-item__label') || {}).textContent || '';
105
+ if (!label) return;
106
+ out.push({
107
+ label: label.trim(),
108
+ group: 'Pages',
109
+ href: a.getAttribute('href') || '/',
110
+ external: a.target === '_blank',
111
+ });
112
+ });
113
+ return out;
114
+ }
115
+
116
+ function sectionEntries() {
117
+ var out = [];
118
+ SECTIONS.forEach(function (s) {
119
+ if (!visible(s.gate)) return;
120
+ s.items.forEach(function (it) {
121
+ if (it.module && !moduleOn(it.module)) return;
122
+ out.push({ label: it.label, group: s.parent, href: it.href });
123
+ });
124
+ });
125
+ return out;
126
+ }
127
+
128
+ // Subsequence match — "stw" finds "Standing › Work". Returns a score (lower is
129
+ // better) or -1. A prefix hit on the label outranks a scattered match.
130
+ function score(entry, q) {
131
+ if (!q) return 0;
132
+ var hay = (entry.group + ' ' + entry.label).toLowerCase();
133
+ var label = entry.label.toLowerCase();
134
+ if (label.indexOf(q) === 0) return 0;
135
+ if (label.indexOf(q) > 0) return 1;
136
+ if (hay.indexOf(q) >= 0) return 2;
137
+ var i = 0;
138
+ for (var c = 0; c < hay.length && i < q.length; c++) if (hay[c] === q[i]) i++;
139
+ return i === q.length ? 3 : -1;
140
+ }
141
+
142
+ function recordEntry(q) {
143
+ for (var i = 0; i < SYNTAX.length; i++) {
144
+ var m = q.match(SYNTAX[i].re);
145
+ if (!m) continue;
146
+ var n = m[1];
147
+ return {
148
+ label: SYNTAX[i].hint.charAt(0).toUpperCase() + SYNTAX[i].hint.slice(1) + ' ' + n,
149
+ group: 'Go to',
150
+ href: SYNTAX[i].href(n),
151
+ overlay: !!SYNTAX[i].overlay,
152
+ };
153
+ }
154
+ return null;
155
+ }
156
+
157
+ function compute(q) {
158
+ var query = String(q || '').trim().toLowerCase();
159
+ var rec = recordEntry(query);
160
+ var pool = pageEntries().concat(sectionEntries());
161
+ var scored = [];
162
+ pool.forEach(function (e) {
163
+ var s = score(e, query);
164
+ if (s >= 0) scored.push({ e: e, s: s });
165
+ });
166
+ scored.sort(function (a, b) { return a.s - b.s; });
167
+ var list = scored.slice(0, MAX_RESULTS).map(function (x) { return x.e; });
168
+ return rec ? [rec].concat(list) : list;
169
+ }
170
+
171
+ function render() {
172
+ if (!results.length) {
173
+ listEl.innerHTML = '<li class="palette__empty" role="presentation">No match. Try a page name, or an id like <kbd>1234</kbd>, <kbd>g 12</kbd>, <kbd>b 7</kbd>, <kbd>i 42</kbd>.</li>';
174
+ return;
175
+ }
176
+ listEl.innerHTML = results.map(function (e, i) {
177
+ return '<li class="palette__item' + (i === cursor ? ' palette__item--active' : '') + '"' +
178
+ ' role="option" id="palette-opt-' + i + '" aria-selected="' + (i === cursor ? 'true' : 'false') + '" data-i="' + i + '">' +
179
+ '<span class="palette__group">' + esc(e.group) + '</span>' +
180
+ '<span class="palette__label">' + esc(e.label) + '</span>' +
181
+ (e.external ? '<span class="palette__hint">opens a new tab</span>' : '') +
182
+ '</li>';
183
+ }).join('');
184
+ var active = listEl.querySelector('.palette__item--active');
185
+ if (active && active.scrollIntoView) active.scrollIntoView({ block: 'nearest' });
186
+ input.setAttribute('aria-activedescendant', results.length ? 'palette-opt-' + cursor : '');
187
+ }
188
+
189
+ function move(delta) {
190
+ if (!results.length) return;
191
+ cursor = (cursor + delta + results.length) % results.length;
192
+ render();
193
+ }
194
+
195
+ function choose() {
196
+ var e = results[cursor];
197
+ if (!e) return;
198
+ close();
199
+ if (e.external) { window.open(e.href, '_blank', 'noopener'); return; }
200
+ // An overlay hash resolves in place where task-detail.js is loaded; elsewhere
201
+ // it has no listener, so route through the index which always carries it.
202
+ if (e.overlay) {
203
+ if (window.OTBTaskDetail) window.location.hash = e.href;
204
+ else window.location.assign('/' + e.href);
205
+ return;
206
+ }
207
+ window.location.assign(e.href);
208
+ }
209
+
210
+ function build() {
211
+ root = document.createElement('div');
212
+ root.className = 'palette';
213
+ root.id = PALETTE_ID;
214
+ root.hidden = true;
215
+ root.innerHTML =
216
+ '<div class="palette__scrim" data-close="1"></div>' +
217
+ '<div class="palette__panel" role="dialog" aria-modal="true" aria-label="Jump to">' +
218
+ '<input class="palette__input" id="palette-input" type="text" autocomplete="off" spellcheck="false"' +
219
+ ' role="combobox" aria-expanded="true" aria-controls="palette-list"' +
220
+ ' placeholder="Jump to a page, section, or id…">' +
221
+ '<ul class="palette__list" id="palette-list" role="listbox" aria-label="Results"></ul>' +
222
+ '</div>';
223
+ document.body.appendChild(root);
224
+ input = root.querySelector('#palette-input');
225
+ listEl = root.querySelector('#palette-list');
226
+
227
+ input.addEventListener('input', function () {
228
+ results = compute(input.value);
229
+ cursor = 0;
230
+ render();
231
+ });
232
+ listEl.addEventListener('click', function (ev) {
233
+ var li = ev.target.closest ? ev.target.closest('[data-i]') : null;
234
+ if (!li) return;
235
+ cursor = Number(li.dataset.i) || 0;
236
+ choose();
237
+ });
238
+ root.addEventListener('mousedown', function (ev) {
239
+ if (ev.target && ev.target.dataset && ev.target.dataset.close) close();
240
+ });
241
+ // Focus trap: the panel holds exactly one focusable control, so keeping focus
242
+ // on the input is the whole trap.
243
+ root.addEventListener('keydown', function (ev) {
244
+ if (ev.key === 'Tab') { ev.preventDefault(); input.focus(); }
245
+ });
246
+ }
247
+
248
+ function isOpen() { return !!(root && !root.hidden); }
249
+
250
+ function open() {
251
+ if (!root) build();
252
+ if (isOpen()) return;
253
+ lastFocus = document.activeElement;
254
+ root.hidden = false;
255
+ document.documentElement.classList.add('palette-open');
256
+ input.value = '';
257
+ results = compute('');
258
+ cursor = 0;
259
+ render();
260
+ input.focus();
261
+ }
262
+
263
+ function close() {
264
+ if (!isOpen()) return;
265
+ root.hidden = true;
266
+ document.documentElement.classList.remove('palette-open');
267
+ if (lastFocus && lastFocus.focus) lastFocus.focus();
268
+ lastFocus = null;
269
+ }
270
+
271
+ // Don't steal the key from a field the builder is typing in.
272
+ function inTextField(el) {
273
+ if (!el) return false;
274
+ var tag = (el.tagName || '').toLowerCase();
275
+ return tag === 'input' || tag === 'textarea' || tag === 'select' || el.isContentEditable;
276
+ }
277
+
278
+ document.addEventListener('keydown', function (ev) {
279
+ if ((ev.ctrlKey || ev.metaKey) && (ev.key === 'k' || ev.key === 'K')) {
280
+ if (inTextField(ev.target) && !isOpen()) return;
281
+ ev.preventDefault();
282
+ if (isOpen()) close(); else open();
283
+ return;
284
+ }
285
+ if (!isOpen()) return;
286
+ if (ev.key === 'Escape') { ev.preventDefault(); close(); return; }
287
+ if (ev.key === 'ArrowDown') { ev.preventDefault(); move(1); return; }
288
+ if (ev.key === 'ArrowUp') { ev.preventDefault(); move(-1); return; }
289
+ if (ev.key === 'Enter') { ev.preventDefault(); choose(); }
290
+ });
291
+
292
+ // Reveal the slot shell.js left inert, and label it for this platform.
293
+ var slot = document.getElementById('topbar-jump');
294
+ if (slot) {
295
+ slot.hidden = false;
296
+ slot.addEventListener('click', open);
297
+ var kbd = document.getElementById('topbar-jump-kbd');
298
+ if (kbd) kbd.textContent = isMac ? '⌘K' : 'Ctrl K';
299
+ }
300
+
301
+ window.OTBPalette = { open: open, close: close, isOpen: isOpen, compute: compute };
302
+ })();
@@ -401,4 +401,17 @@ body.primer-body { background: var(--bg); }
401
401
  .primer-article h2 {
402
402
  font-size: 1.25rem;
403
403
  }
404
+ /* A markdown table's column count is fixed by the source, so its min-content
405
+ width outruns a phone (measured: 79px of page overflow on /drachmae). Give
406
+ the table its own horizontal scroller instead of letting it drag the page
407
+ sideways — the .section-rail / .kit-tabs strips already set that precedent.
408
+ `display: block` is what makes the table box a scrollport; the rows still
409
+ lay out through the anonymous table box inside it. Nothing here is sticky,
410
+ so this costs no header behaviour. */
411
+ .primer-article table {
412
+ display: block;
413
+ width: max-content;
414
+ max-width: 100%;
415
+ overflow-x: auto;
416
+ }
404
417
  }
@@ -78,6 +78,8 @@
78
78
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
79
79
 
80
80
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
81
+ <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
82
+ <script src="/builders/palette.js" defer></script>
81
83
  <script src="/builders/primer.js?v=2026-05-29-primer-1" defer></script>
82
84
  <script src="/builders/diagram-viewer.js?v=2026-06-14-diagviewer-1" defer></script>
83
85
  <script src="/builders/copy-on-click.js?v=2026-06-01-copy-1" defer></script>
@@ -78,6 +78,8 @@
78
78
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
79
79
  chrome exists before the page script runs. -->
80
80
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
81
+ <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
82
+ <script src="/builders/palette.js" defer></script>
81
83
  <!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
82
84
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
83
85
  <script src="/builders/profile.js?v=2026-06-14-domutils"></script>
@@ -62,6 +62,8 @@
62
62
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
63
63
  chrome exists before the page script runs. -->
64
64
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
65
+ <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
66
+ <script src="/builders/palette.js" defer></script>
65
67
  <!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
66
68
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
67
69
  <script src="/builders/ranks.js?v=2026-06-14-domutils"></script>
@@ -0,0 +1,179 @@
1
+ /* roadmap.css — Page-local styles for the Roadmap page.
2
+ Lifted verbatim out of the page's inline <style> block (task 1002176);
3
+ the ?v= cache-bust is stamped automatically from this file's content hash
4
+ at boot (src/asset-version.js). */
5
+
6
+ /* Roadmap — the "Command deck" (task 1002426, owner-approved redesign from the
7
+ mockup review). Replaces the old flat stack of version progress bars +
8
+ nested goal/criteria disclosures with: a program-level hero, then versions
9
+ GROUPED BY their real status (planning=Staged · building=In flight ·
10
+ frozen=Parked · shipped=Shipped), and a SUMMARIZED goal layer per version
11
+ (status bar + only the goals active right now, full list on the Goals page).
12
+
13
+ Every class is `rm-`prefixed so nothing collides with the shared hall
14
+ stylesheet, and only THREE derived helper tokens are added here — the pack
15
+ tokens + light/dark theming stay owned by style.css + themeMarkup (the
16
+ theming contract). The helpers derive via color-mix on pack tokens, so they
17
+ re-derive automatically when the theme flips. */
18
+ :root {
19
+ --rm-plan: color-mix(in srgb, var(--ink) 16%, var(--bg));
20
+ --rm-terra-weak: color-mix(in srgb, var(--terracotta) 13%, var(--bg-card));
21
+ --rm-shadow-soft: 0 1px 2px color-mix(in srgb, var(--ink) 8%, transparent);
22
+ }
23
+
24
+ .rm-num { font-variant-numeric: tabular-nums; }
25
+
26
+ /* ---- shared atoms ---- */
27
+ .rm-chip { display:inline-flex; align-items:center; gap:5px; font-size:10.5px; font-weight:600;
28
+ letter-spacing:.05em; text-transform:uppercase; padding:3px 8px; border-radius:999px; white-space:nowrap; }
29
+ .rm-chip .rm-sq { width:7px; height:7px; border-radius:2px; }
30
+ .rm-chip--product { background:var(--accent-weak); color:var(--accent-text); }
31
+ .rm-chip--product .rm-sq { background:var(--accent); }
32
+ .rm-chip--internal { background:var(--info-weak); color:color-mix(in srgb, var(--sea) 78%, var(--ink)); }
33
+ .rm-chip--internal .rm-sq { background:var(--sea); }
34
+ .rm-chip--dogfood { background:var(--rm-terra-weak); color:color-mix(in srgb, var(--terracotta) 82%, var(--ink)); }
35
+ .rm-chip--dogfood .rm-sq { background:var(--terracotta); }
36
+
37
+ .rm-phase { display:inline-flex; align-items:center; gap:6px; font-size:11px; font-weight:600;
38
+ padding:3px 9px; border-radius:999px; white-space:nowrap; border:1px solid transparent; }
39
+ .rm-phase .rm-pd { width:6px; height:6px; border-radius:50%; }
40
+ .rm-phase--building { background:var(--ok-weak); color:var(--ok); }
41
+ .rm-phase--building .rm-pd { background:var(--ok); }
42
+ .rm-phase--planning { background:var(--accent-weak); color:var(--accent-text);
43
+ border-color:color-mix(in srgb, var(--accent) 22%, var(--border)); }
44
+ .rm-phase--planning .rm-pd { background:transparent; box-shadow:inset 0 0 0 1.5px var(--accent); }
45
+ .rm-phase--frozen { background:var(--surface-2); color:var(--ink-soft); border-color:var(--border); }
46
+ .rm-phase--frozen .rm-pd { background:var(--ink-faint); }
47
+
48
+ /* lifecycle segmented bar (shipped / confirmed / completed / remaining) */
49
+ .rm-lbar { display:flex; height:9px; border-radius:999px; overflow:hidden;
50
+ background:var(--rule-soft); border:1px solid var(--border); }
51
+ .rm-lbar__s { height:100%; }
52
+ .rm-lbar__s--sh { background:var(--ok); }
53
+ .rm-lbar__s--co { background:var(--info); }
54
+ .rm-lbar__s--cm { background:var(--warn); opacity:.62; }
55
+
56
+ /* progress ring (conic-gradient — no SVG path authoring) */
57
+ .rm-ring { --p:0; --rc:var(--accent); position:relative; flex:none; width:60px; height:60px;
58
+ border-radius:50%; display:grid; place-items:center;
59
+ background:conic-gradient(var(--rc) calc(var(--p)*3.6deg), var(--rule-soft) 0); }
60
+ .rm-ring::after { content:""; position:absolute; inset:6px; border-radius:50%; background:var(--surface); }
61
+ .rm-ring b { position:relative; z-index:1; font-size:15px; font-weight:700; font-variant-numeric:tabular-nums; letter-spacing:-.02em; }
62
+ .rm-ring b i { font-style:normal; font-size:9.5px; font-weight:600; color:var(--ink-faint); }
63
+
64
+ /* goal-status bar (segmented by goal COUNT: achieved / in progress / not started) */
65
+ .rm-gbar { display:flex; height:8px; border-radius:999px; overflow:hidden;
66
+ background:var(--rule-soft); border:1px solid var(--border); }
67
+ .rm-gbar__s { height:100%; }
68
+ .rm-gbar__s--ach { background:var(--ok); }
69
+ .rm-gbar__s--prog { background:var(--accent); }
70
+ .rm-gbar__s--plan { background:var(--rm-plan); }
71
+
72
+ /* ---- program hero ---- */
73
+ .rm-hero { background:linear-gradient(135deg, color-mix(in srgb, var(--accent) 7%, var(--bg-card)), var(--bg-card) 62%);
74
+ border:1px solid var(--border); border-radius:var(--radius); padding:20px 22px; margin-bottom:22px; box-shadow:var(--rm-shadow-soft); }
75
+ .rm-hero__top { display:grid; grid-template-columns:auto 1fr; gap:26px; align-items:center; }
76
+ .rm-big { display:flex; align-items:baseline; gap:3px; }
77
+ .rm-big .n { font-size:52px; font-weight:700; line-height:.95; letter-spacing:-.03em; font-variant-numeric:tabular-nums; }
78
+ .rm-big .u { font-size:18px; font-weight:600; color:var(--ink-faint); }
79
+ .rm-lab { font-size:11px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-faint); margin-top:7px; max-width:16ch; }
80
+ .rm-hbar { height:15px; }
81
+ .rm-stats { display:flex; flex-wrap:wrap; gap:9px 24px; margin-top:14px; }
82
+ .rm-stat { display:flex; flex-direction:column; gap:1px; }
83
+ .rm-stat .v { font-size:18px; font-weight:700; font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
84
+ .rm-stat .k { font-size:11px; color:var(--ink-faint); font-weight:500; }
85
+ .rm-stat .v.sh { color:var(--ok); } .rm-stat .v.co { color:var(--info); } .rm-stat .v.cm { color:var(--warn); }
86
+ .rm-hgoals { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin-top:16px; padding-top:15px; border-top:1px solid var(--border); }
87
+ .rm-hgoals .glab { font-size:11px; font-weight:600; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-faint); }
88
+ .rm-hgoals .rm-gbar { width:200px; max-width:44vw; }
89
+ .rm-hgoals .gleg { font-size:12.5px; color:var(--ink-soft); }
90
+ .rm-hgoals .gleg b { color:var(--ink); font-variant-numeric:tabular-nums; }
91
+
92
+ /* ---- section rhythm ---- */
93
+ .rm-sec { margin-top:26px; }
94
+ .rm-sec__h { display:flex; align-items:center; gap:10px; margin:0 2px 13px; }
95
+ .rm-sec__dot { width:8px; height:8px; border-radius:50%; }
96
+ .rm-sec__dot--flight { background:var(--ok); }
97
+ .rm-sec__dot--staged { background:var(--accent); }
98
+ .rm-sec__dot--parked { background:var(--ink-faint); }
99
+ .rm-sec__dot--shipped { background:var(--sea); }
100
+ .rm-sec__t { font-size:12.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; }
101
+ .rm-sec__n { font-size:11.5px; color:var(--ink-faint); font-variant-numeric:tabular-nums;
102
+ background:var(--surface-2); border:1px solid var(--border); border-radius:999px; padding:1px 8px; }
103
+ .rm-sec__rule { flex:1; height:1px; background:var(--border); }
104
+
105
+ /* ---- version cards ---- */
106
+ .rm-grid { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
107
+ .rm-card { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius); padding:17px; box-shadow:var(--rm-shadow-soft); }
108
+ .rm-card--feat { grid-column:1 / -1; }
109
+ .rm-card--parked { background:var(--surface-2); }
110
+ .rm-card--staged { border-style:dashed; background:color-mix(in srgb, var(--accent) 3%, var(--surface)); }
111
+ .rm-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
112
+ .rm-name { font-size:16px; font-weight:700; letter-spacing:-.01em; margin:9px 0 0; }
113
+ .rm-id { font-size:11px; font-weight:700; letter-spacing:.04em; color:var(--ink-faint); font-variant-numeric:tabular-nums; }
114
+ .rm-desc { font-size:12.5px; color:var(--ink-soft); margin:7px 0 0; }
115
+ .rm-desc--clamp { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
116
+ .rm-cardprog { margin-top:14px; }
117
+ .rm-count { display:flex; justify-content:space-between; gap:10px; font-size:12px; color:var(--ink-soft); margin-bottom:6px; }
118
+ .rm-count b { color:var(--ink); font-variant-numeric:tabular-nums; }
119
+ .rm-featgrid { display:grid; grid-template-columns:1.05fr 1fr; gap:22px; align-items:start; }
120
+ .rm-featgrid__l { min-width:0; }
121
+ .rm-feat-top { display:flex; align-items:flex-start; gap:16px; }
122
+ .rm-feat-top .rt { flex:1; min-width:0; }
123
+
124
+ /* ---- goals block ---- */
125
+ .rm-goals { min-width:0; }
126
+ .rm-goals__frame { background:var(--surface-2); border:1px solid var(--border); border-radius:var(--radius-sm); padding:14px; }
127
+ .rm-goals__h { display:flex; align-items:baseline; justify-content:space-between; gap:8px; margin-bottom:10px; }
128
+ .rm-goals__h .t { font-size:11px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color:var(--ink-faint); }
129
+ .rm-goals__h .n { font-size:12px; color:var(--ink-soft); font-variant-numeric:tabular-nums; }
130
+ .rm-gdist { display:flex; gap:12px; flex-wrap:wrap; margin-top:9px; font-size:12px; color:var(--ink-soft); }
131
+ .rm-gdist span { display:inline-flex; align-items:center; gap:6px; }
132
+ .rm-gdist i { width:9px; height:9px; border-radius:2px; }
133
+ .rm-gdist i.rm-ach { background:var(--ok); } .rm-gdist i.rm-prog { background:var(--accent); } .rm-gdist i.rm-plan { background:var(--rm-plan); }
134
+ .rm-gdist b { color:var(--ink); font-variant-numeric:tabular-nums; }
135
+ .rm-ginp { margin-top:14px; }
136
+ .rm-ginp__cap { font-size:11px; font-weight:600; letter-spacing:.04em; text-transform:uppercase; color:var(--ink-faint); margin-bottom:2px; }
137
+ .rm-goal { display:flex; align-items:center; gap:10px; padding:7px 0; }
138
+ .rm-goal + .rm-goal { border-top:1px solid var(--rule-soft); }
139
+ .rm-goal__dot { flex:none; width:8px; height:8px; border-radius:50%; background:var(--accent); }
140
+ .rm-goal__t { flex:1; min-width:0; font-size:13px; font-weight:500; color:var(--ink); text-decoration:none;
141
+ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
142
+ a.rm-goal__t:hover { color:var(--accent-text); text-decoration:underline; }
143
+ .rm-goal__ready { flex:none; font-size:9.5px; font-weight:700; letter-spacing:.04em; text-transform:uppercase;
144
+ color:var(--ok); background:var(--ok-weak); padding:2px 6px; border-radius:999px; }
145
+ .rm-goal__meter { flex:none; width:70px; height:5px; border-radius:999px; background:var(--rule-soft); overflow:hidden; }
146
+ .rm-goal__meter i { display:block; height:100%; background:var(--accent); }
147
+ .rm-goal__n { flex:none; font-size:11.5px; color:var(--ink-soft); font-variant-numeric:tabular-nums; min-width:28px; text-align:right; }
148
+ .rm-goal__seed { flex:none; font-size:11px; color:var(--ink-faint); }
149
+ .rm-gmore { display:inline-flex; align-items:center; gap:6px; margin-top:12px; font-size:12.5px; font-weight:600; color:var(--accent-text); text-decoration:none; }
150
+ .rm-gmore:hover { text-decoration:underline; }
151
+ .rm-gmore svg { width:13px; height:13px; }
152
+ .rm-gnone { font-size:12.5px; color:var(--ink-faint); margin:2px 0 0; }
153
+
154
+ /* parked note + staged state */
155
+ .rm-parknote { display:flex; gap:9px; font-size:12.5px; color:var(--ink-soft); background:var(--surface);
156
+ border:1px solid var(--border); border-radius:var(--radius-sm); padding:10px 12px; margin-top:13px; }
157
+ .rm-parknote svg { flex:none; width:15px; height:15px; margin-top:1px; color:var(--ink-faint); }
158
+ .rm-staged-state { display:flex; align-items:center; gap:11px; margin-top:15px; padding:12px 14px;
159
+ border:1px dashed var(--border-strong); border-radius:var(--radius-sm); }
160
+ .rm-staged-state svg { flex:none; width:18px; height:18px; color:var(--accent); }
161
+ .rm-staged-state .s1 { font-size:13px; font-weight:600; color:var(--ink); }
162
+ .rm-staged-state .s2 { font-size:12px; color:var(--ink-soft); margin-top:1px; }
163
+ .rm-staged-state .s2 b { color:var(--ink); font-variant-numeric:tabular-nums; }
164
+
165
+ /* shipped strip */
166
+ .rm-shipstrip { display:flex; flex-wrap:wrap; gap:10px; }
167
+ .rm-shippill { display:flex; align-items:center; gap:11px; background:var(--surface); border:1px solid var(--border);
168
+ border-radius:999px; padding:8px 15px 8px 10px; box-shadow:var(--rm-shadow-soft); text-decoration:none; }
169
+ .rm-shippill:hover { border-color:var(--border-strong); }
170
+ .rm-shippill .ok { width:20px; height:20px; border-radius:50%; background:var(--ok-weak); color:var(--ok);
171
+ display:grid; place-items:center; font-size:11px; }
172
+ .rm-shippill .nm { font-size:12.5px; font-weight:700; color:var(--ink); }
173
+ .rm-shippill .mt { font-size:11px; color:var(--ink-faint); font-variant-numeric:tabular-nums; }
174
+
175
+ @media (max-width:820px) {
176
+ .rm-grid { grid-template-columns:1fr; }
177
+ .rm-featgrid { grid-template-columns:1fr; }
178
+ .rm-hero__top { grid-template-columns:1fr; gap:14px; }
179
+ }