@bongos/core 1.18.0 → 1.18.18

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 (553) hide show
  1. package/.bongos-core.json +1740 -640
  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 +5 -3
  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 +11 -2
  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/0142-project-context-is-prose-only.md +41 -0
  27. package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
  28. package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
  29. package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
  30. package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
  31. package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
  32. package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
  33. package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
  34. package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
  35. package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
  36. package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
  37. package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
  38. package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
  39. package/docs/adr/0152-metic-task-abandonment.md +67 -0
  40. package/docs/adr/0153-sequential-chain-runner.md +51 -0
  41. package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
  42. package/docs/adr/README.md +15 -2
  43. package/docs/api/openapi.json +2648 -483
  44. package/docs/api-reference.md +73 -13
  45. package/docs/architecture.md +4 -2
  46. package/docs/branding-contract.md +3 -1
  47. package/docs/canonical-permissions.md +21 -8
  48. package/docs/file-map.md +15 -7
  49. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
  50. package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
  51. package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
  52. package/docs/onboarding/diagrams/assertions.json +4 -7
  53. package/docs/onboarding/drachmae-and-karma.md +3 -3
  54. package/docs/onboarding/primer.md +17 -16
  55. package/docs/onboarding/slash-commands.md +124 -0
  56. package/docs/recipes/builder-box-lifecycle.md +23 -0
  57. package/docs/recipes/devbox-app-release.md +14 -4
  58. package/docs/recipes/instance-first-run.md +16 -0
  59. package/docs/recipes/local-dev.md +81 -0
  60. package/docs/recipes/ops-gotchas.md +19 -1
  61. package/docs/recipes/overnight-builder.md +1 -1
  62. package/docs/recipes/packaging-the-core.md +13 -0
  63. package/docs/recipes/parallel-goal-waves.md +174 -0
  64. package/docs/recipes/ship-and-regrade.md +2 -2
  65. package/docs/recipes/standalone-live-docs.md +48 -0
  66. package/docs/recipes/upgrading-the-core.md +5 -2
  67. package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
  68. package/migrations/003_pms.sql +6 -7
  69. package/migrations/006_pms_v2.sql +3 -31
  70. package/migrations/039_newcomer_friendly_column.sql +5 -0
  71. package/migrations/102_remove_box_first_provision_approval.sql +4 -0
  72. package/migrations/core_192_github_oauth_tokens.sql +33 -0
  73. package/migrations/core_193_task_needs_rebase.sql +28 -0
  74. package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
  75. package/migrations/core_195_idea_triage_provenance.sql +57 -0
  76. package/migrations/core_196_session_reward_topup.sql +69 -0
  77. package/modules/autonomy/pollers/routine-timers.js +9 -8
  78. package/modules/builder-settings/wandering-prefs.js +61 -18
  79. package/modules/dev-box/app/README.md +73 -0
  80. package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
  81. package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
  82. package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
  83. package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
  84. package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
  85. package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
  86. package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
  87. package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
  88. package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
  89. package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
  90. package/modules/dev-box/app/assets/tray/win-off.png +0 -0
  91. package/modules/dev-box/app/assets/tray/win-on.png +0 -0
  92. package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
  93. package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
  94. package/modules/dev-box/app/build-resources/icon.png +0 -0
  95. package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
  96. package/modules/dev-box/app/electron-builder.yml +95 -0
  97. package/modules/dev-box/app/package-lock.json +5291 -0
  98. package/modules/dev-box/app/package.json +30 -0
  99. package/modules/dev-box/app/renderer/app.js +319 -0
  100. package/modules/dev-box/app/renderer/index.html +45 -0
  101. package/modules/dev-box/app/renderer/styles.css +246 -0
  102. package/modules/dev-box/app/renderer/theme.generated.css +16 -0
  103. package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
  104. package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
  105. package/modules/dev-box/app/scripts/gen-brand.js +138 -0
  106. package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
  107. package/modules/dev-box/app/scripts/gen-icons.js +286 -0
  108. package/modules/dev-box/app/scripts/vendor-client.js +23 -0
  109. package/modules/dev-box/app/src/box-controller.js +287 -0
  110. package/modules/dev-box/app/src/brand.generated.json +13 -0
  111. package/modules/dev-box/app/src/brand.js +16 -0
  112. package/modules/dev-box/app/src/config.js +19 -0
  113. package/modules/dev-box/app/src/gds-client.js +90 -0
  114. package/modules/dev-box/app/src/main.js +610 -0
  115. package/modules/dev-box/app/src/pairing.js +57 -0
  116. package/modules/dev-box/app/src/preload.js +29 -0
  117. package/modules/dev-box/app/src/session-store.js +58 -0
  118. package/modules/dev-box/app/src/ssh-setup.js +569 -0
  119. package/modules/dev-box/app/src/task-picker.js +70 -0
  120. package/modules/dev-box/app/src/tray.js +99 -0
  121. package/modules/dev-box/app/src/updater.js +55 -0
  122. package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
  123. package/modules/dev-box/app/test/unit.mjs +526 -0
  124. package/modules/dev-box/box-access.js +121 -4
  125. package/modules/dev-box/boxes.js +20 -0
  126. package/modules/dev-box/module.json +1 -1
  127. package/modules/dev-box/routes/box.js +87 -3
  128. package/modules/economy/credits.js +116 -25
  129. package/modules/economy/reward.js +8 -0
  130. package/modules/economy/streak.js +2 -1
  131. package/modules/governance/CLAUDE.md +15 -0
  132. package/modules/governance/catalog.js +419 -0
  133. package/modules/governance/config.js +174 -0
  134. package/modules/governance/db.js +125 -0
  135. package/modules/governance/migrations/governance_001_tables.sql +81 -0
  136. package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
  137. package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
  138. package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
  139. package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
  140. package/modules/governance/module.json +10 -0
  141. package/modules/governance/protected-surfaces.js +88 -0
  142. package/modules/governance/protected-surfaces.json +80 -0
  143. package/modules/governance/rank-roles.js +83 -0
  144. package/modules/governance/resolver.js +221 -0
  145. package/modules/governance/routes/governance.js +89 -0
  146. package/modules/governance/routes/role-sync.js +49 -0
  147. package/modules/governance/session-scopes.js +127 -0
  148. package/modules/governance/session-scopes.json +38 -0
  149. package/modules/hall-ui/public/atlas.css +117 -0
  150. package/modules/hall-ui/public/atlas.html +3 -114
  151. package/modules/hall-ui/public/brand-apply.js +34 -6
  152. package/modules/hall-ui/public/builders.js +187 -219
  153. package/modules/hall-ui/public/diagrams.html +2 -0
  154. package/modules/hall-ui/public/dom-utils.js +27 -0
  155. package/modules/hall-ui/public/drachmae.html +2 -0
  156. package/modules/hall-ui/public/drachmae.js +54 -1
  157. package/modules/hall-ui/public/gate.css +98 -0
  158. package/modules/hall-ui/public/gate.html +3 -95
  159. package/modules/hall-ui/public/goal-inbox.js +4 -1
  160. package/modules/hall-ui/public/goals-page.js +626 -114
  161. package/modules/hall-ui/public/goals.css +79 -1
  162. package/modules/hall-ui/public/goals.html +38 -11
  163. package/modules/hall-ui/public/hall-widgets.js +62 -52
  164. package/modules/hall-ui/public/harbor.css +123 -0
  165. package/modules/hall-ui/public/harbor.html +3 -120
  166. package/modules/hall-ui/public/index.html +11 -4
  167. package/modules/hall-ui/public/instances-panel.js +4 -1
  168. package/modules/hall-ui/public/modules.css +63 -0
  169. package/modules/hall-ui/public/modules.html +3 -60
  170. package/modules/hall-ui/public/my-projects.html +78 -0
  171. package/modules/hall-ui/public/my-projects.js +142 -0
  172. package/modules/hall-ui/public/new-project-wizard.js +7 -3
  173. package/modules/hall-ui/public/not-ready.html +2 -0
  174. package/modules/hall-ui/public/pair.css +73 -0
  175. package/modules/hall-ui/public/pair.html +3 -70
  176. package/modules/hall-ui/public/palette.js +302 -0
  177. package/modules/hall-ui/public/primer.css +13 -0
  178. package/modules/hall-ui/public/primer.html +2 -0
  179. package/modules/hall-ui/public/profile.html +2 -0
  180. package/modules/hall-ui/public/ranks.html +2 -0
  181. package/modules/hall-ui/public/roadmap.css +179 -0
  182. package/modules/hall-ui/public/roadmap.html +9 -172
  183. package/modules/hall-ui/public/roadmap.js +329 -316
  184. package/modules/hall-ui/public/scouting.html +45 -0
  185. package/modules/hall-ui/public/scouting.js +73 -0
  186. package/modules/hall-ui/public/sessions.css +16 -0
  187. package/modules/hall-ui/public/sessions.html +3 -13
  188. package/modules/hall-ui/public/settings.html +2 -0
  189. package/modules/hall-ui/public/settings.js +4 -4
  190. package/modules/hall-ui/public/shell.js +143 -18
  191. package/modules/hall-ui/public/style.css +231 -39
  192. package/modules/hall-ui/public/task-detail.js +347 -26
  193. package/modules/hall-ui/public/task.html +6 -1
  194. package/modules/hall-ui/public/watch.html +2 -0
  195. package/modules/hall-ui/public/work.html +8 -6
  196. package/modules/hall-ui/public/work.js +1 -1
  197. package/modules/ideas/inbox.js +61 -11
  198. package/modules/ideas/routes/inbox.js +23 -0
  199. package/modules/lifecycle/claim-eligibility.js +72 -0
  200. package/modules/lifecycle/db.js +519 -139
  201. package/modules/lifecycle/done-when.js +18 -3
  202. package/modules/lifecycle/github-push.js +19 -2
  203. package/modules/lifecycle/goal-advisory.js +114 -0
  204. package/modules/lifecycle/goal-authz.js +62 -0
  205. package/modules/lifecycle/lifecycle.js +9 -0
  206. package/modules/lifecycle/publish-reconciler.js +109 -6
  207. package/modules/lifecycle/routes/claims.js +68 -23
  208. package/modules/lifecycle/routes/done-when.js +110 -15
  209. package/modules/lifecycle/routes/goals.js +8 -38
  210. package/modules/lifecycle/routes/tasks.js +38 -6
  211. package/modules/lifecycle/ship-card.js +6 -0
  212. package/modules/onboarding/onboarding-state.js +1 -1
  213. package/modules/platform-identity/CLAUDE.md +15 -0
  214. package/modules/platform-identity/hub-device.js +147 -0
  215. package/modules/platform-identity/hub-keys.js +151 -0
  216. package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
  217. package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
  218. package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
  219. package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
  220. package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
  221. package/modules/platform-identity/module.json +18 -0
  222. package/modules/platform-identity/platform-identity.js +531 -0
  223. package/modules/platform-identity/pollers/code-sweep.js +43 -0
  224. package/modules/platform-identity/routes/my-projects.js +140 -0
  225. package/modules/platform-identity/routes/projects.js +107 -0
  226. package/modules/platform-identity/routes/scouting.js +35 -0
  227. package/modules/platform-identity/routes/sso.js +402 -0
  228. package/modules/platform-identity/tests/platform-identity.mjs +388 -0
  229. package/modules/platform-identity/ui/.gitkeep +0 -0
  230. package/modules/security/routes/reports.js +10 -0
  231. package/modules/sessions/db.js +166 -21
  232. package/modules/sessions/module.json +1 -1
  233. package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
  234. package/modules/sessions/routes/sessions.js +33 -0
  235. package/modules/status-ui/public/explore.html +54 -0
  236. package/modules/status-ui/public/explore.js +67 -0
  237. package/package-lock.json +2 -2
  238. package/package.json +1 -1
  239. package/public-landing/assets/anim/idle/frame_00.webp +0 -0
  240. package/public-landing/assets/anim/idle/frame_01.webp +0 -0
  241. package/public-landing/assets/anim/idle/frame_02.webp +0 -0
  242. package/public-landing/assets/anim/idle/frame_03.webp +0 -0
  243. package/public-landing/assets/anim/idle/frame_04.webp +0 -0
  244. package/public-landing/assets/anim/idle/frame_05.webp +0 -0
  245. package/public-landing/assets/anim/idle/frame_06.webp +0 -0
  246. package/public-landing/assets/anim/idle/frame_07.webp +0 -0
  247. package/public-landing/assets/anim/idle/frame_08.webp +0 -0
  248. package/public-landing/assets/anim/idle/frame_09.webp +0 -0
  249. package/public-landing/assets/anim/idle/frame_10.webp +0 -0
  250. package/public-landing/assets/anim/idle/frame_11.webp +0 -0
  251. package/public-landing/assets/anim/idle/frame_12.webp +0 -0
  252. package/public-landing/assets/anim/idle/frame_13.webp +0 -0
  253. package/public-landing/assets/anim/idle/frame_14.webp +0 -0
  254. package/public-landing/assets/anim/idle/frame_15.webp +0 -0
  255. package/public-landing/assets/anim/idle/frame_16.webp +0 -0
  256. package/public-landing/assets/anim/idle/frame_17.webp +0 -0
  257. package/public-landing/assets/anim/idle/frame_18.webp +0 -0
  258. package/public-landing/assets/anim/idle/frame_19.webp +0 -0
  259. package/public-landing/assets/anim/idle/frame_20.webp +0 -0
  260. package/public-landing/assets/anim/idle/frame_21.webp +0 -0
  261. package/public-landing/assets/anim/idle/frame_22.webp +0 -0
  262. package/public-landing/assets/anim/idle/frame_23.webp +0 -0
  263. package/public-landing/assets/anim/idle/frame_24.webp +0 -0
  264. package/public-landing/assets/anim/idle/frame_25.webp +0 -0
  265. package/public-landing/assets/anim/idle/frame_26.webp +0 -0
  266. package/public-landing/assets/anim/idle/frame_27.webp +0 -0
  267. package/public-landing/assets/anim/idle/frame_28.webp +0 -0
  268. package/public-landing/assets/anim/idle/frame_29.webp +0 -0
  269. package/public-landing/assets/anim/idle/frame_30.webp +0 -0
  270. package/public-landing/assets/anim/idle/frame_31.webp +0 -0
  271. package/public-landing/assets/anim/idle/frame_32.webp +0 -0
  272. package/public-landing/assets/anim/idle/frame_33.webp +0 -0
  273. package/public-landing/assets/anim/idle/frame_34.webp +0 -0
  274. package/public-landing/assets/anim/idle/frame_35.webp +0 -0
  275. package/public-landing/assets/anim/idle/frame_36.webp +0 -0
  276. package/public-landing/assets/anim/idle/frame_37.webp +0 -0
  277. package/public-landing/assets/anim/idle/frame_38.webp +0 -0
  278. package/public-landing/assets/anim/idle/frame_39.webp +0 -0
  279. package/public-landing/assets/anim/idle/frame_40.webp +0 -0
  280. package/public-landing/assets/anim/idle/frame_41.webp +0 -0
  281. package/public-landing/assets/anim/idle/frame_42.webp +0 -0
  282. package/public-landing/assets/anim/idle/frame_43.webp +0 -0
  283. package/public-landing/create.html +252 -62
  284. package/public-landing/gate/README.md +137 -0
  285. package/public-landing/gate/dispmaps/bar.png +0 -0
  286. package/public-landing/gate/dispmaps/flat.png +0 -0
  287. package/public-landing/gate/dispmaps/key.png +0 -0
  288. package/public-landing/gate/index.html +587 -0
  289. package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
  290. package/public-landing/gate/previews/off-the-boats.jpg +0 -0
  291. package/public-landing/gate/space.css +799 -0
  292. package/public-landing/gate/space.js +1826 -0
  293. package/public-landing/gate/sprites/enter.png +0 -0
  294. package/public-landing/gate/sprites/search.png +0 -0
  295. package/public-landing/gate/sprites/terminal-blank.png +0 -0
  296. package/public-landing/gate/sprites/tile.png +0 -0
  297. package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
  298. package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
  299. package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
  300. package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
  301. package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
  302. package/public-landing/world/assets/plates/scene-establishing.png +0 -0
  303. package/scripts/gds/abandon.js +6 -4
  304. package/scripts/gds/api.js +10 -5
  305. package/scripts/gds/api.ps1 +26 -0
  306. package/scripts/gds/api.sh +6 -0
  307. package/scripts/gds/audit-ships.js +7 -1
  308. package/scripts/gds/backfill-sessions.js +78 -18
  309. package/scripts/gds/backup.js +23 -1
  310. package/scripts/gds/box-connect-lib.js +124 -31
  311. package/scripts/gds/box-sync.js +66 -0
  312. package/scripts/gds/box.js +225 -53
  313. package/scripts/gds/cf-tunnel.js +145 -6
  314. package/scripts/gds/claim.js +34 -3
  315. package/scripts/gds/cli-lib.js +161 -21
  316. package/scripts/gds/code.js +6 -2
  317. package/scripts/gds/deploy-divergence.js +209 -0
  318. package/scripts/gds/dev-lib.js +309 -0
  319. package/scripts/gds/dev.js +322 -0
  320. package/scripts/gds/doctor.js +90 -61
  321. package/scripts/gds/fetch-art-key.js +1 -1
  322. package/scripts/gds/fetch-sound-prefs.js +2 -2
  323. package/scripts/gds/fitness.js +228 -12
  324. package/scripts/gds/gds-db-backup.service +16 -1
  325. package/scripts/gds/gds-db-offsite.service +9 -1
  326. package/scripts/gds/gen-api-client.js +1 -1
  327. package/scripts/gds/gen-api-docs.js +36 -14
  328. package/scripts/gds/gen-diagrams.js +45 -28
  329. package/scripts/gds/gen-file-map.js +2 -1
  330. package/scripts/gds/gen-freshness.js +32 -0
  331. package/scripts/gds/gen-repo-map.js +3 -2
  332. package/scripts/gds/gen-session-index.js +14 -5
  333. package/scripts/gds/hooks/pre-push.js +2 -2
  334. package/scripts/gds/init.js +60 -3
  335. package/scripts/gds/install-git-hooks.js +1 -1
  336. package/scripts/gds/key-card.js +15 -6
  337. package/scripts/gds/key-status.js +1 -1
  338. package/scripts/gds/linkify-refs.js +35 -9
  339. package/scripts/gds/lint-migrations.js +102 -0
  340. package/scripts/gds/login.js +58 -11
  341. package/scripts/gds/mirror-redact.js +5 -0
  342. package/scripts/gds/package-core.js +263 -4
  343. package/scripts/gds/paste-token.js +7 -1
  344. package/scripts/gds/preflight.js +126 -0
  345. package/scripts/gds/provision.js +268 -19
  346. package/scripts/gds/publish-manifest.js +22 -1
  347. package/scripts/gds/reauth.js +7 -3
  348. package/scripts/gds/regen-instance-docs.js +47 -0
  349. package/scripts/gds/run-unit-tests.js +42 -16
  350. package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
  351. package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
  352. package/scripts/gds/sequence.js +425 -0
  353. package/scripts/gds/session-cost.js +10 -1
  354. package/scripts/gds/setup.js +72 -5
  355. package/scripts/gds/shell.js +5 -3
  356. package/scripts/gds/ship.js +433 -59
  357. package/scripts/gds/smoke-gds.js +139 -8
  358. package/scripts/gds/start.js +171 -22
  359. package/scripts/gds/status.js +1 -1
  360. package/scripts/gds/triage.js +10 -9
  361. package/scripts/gds/upgrade.js +271 -7
  362. package/scripts/migrate.sh +10 -0
  363. package/scripts/status-mirror-sync.js +114 -84
  364. package/src/bongos/api-errors.js +1 -0
  365. package/src/bongos/auth.js +809 -107
  366. package/src/bongos/db-kernel.js +27 -0
  367. package/src/bongos/db.js +105 -0
  368. package/src/bongos/github-repos.js +93 -0
  369. package/src/bongos/module-scope-map.js +27 -1
  370. package/src/bongos/permission-path-check.js +136 -102
  371. package/src/bongos/repo-info.js +47 -11
  372. package/src/bongos/route-rank-check.js +429 -46
  373. package/src/bongos/routes/_helpers.js +12 -1
  374. package/src/bongos/routes/auth.js +312 -13
  375. package/src/bongos/routes/backup.js +58 -2
  376. package/src/bongos/routes/github.js +90 -0
  377. package/src/bongos/routes/instance.js +15 -3
  378. package/src/bongos/routes/me.js +35 -1
  379. package/src/bongos/routes.js +2 -0
  380. package/src/bongos/serve-internal.js +84 -15
  381. package/src/branding.js +49 -2
  382. package/src/instance-config.js +46 -0
  383. package/src/module-api.js +140 -1
  384. package/src/platform-server.js +86 -9
  385. package/tests/abandon_task.mjs +59 -3
  386. package/tests/api_cli_flags.mjs +53 -0
  387. package/tests/auth_page_gate.mjs +13 -0
  388. package/tests/backfill_sessions.mjs +127 -1
  389. package/tests/backup_cli.mjs +54 -0
  390. package/tests/bongos_box_connect.mjs +77 -0
  391. package/tests/box_access.mjs +130 -1
  392. package/tests/box_credential.mjs +125 -0
  393. package/tests/box_host_keys.mjs +24 -0
  394. package/tests/box_infra_resolve.mjs +149 -0
  395. package/tests/box_scope_session.mjs +6 -2
  396. package/tests/box_sync.mjs +55 -0
  397. package/tests/box_task_scope.mjs +99 -0
  398. package/tests/branding.mjs +41 -23
  399. package/tests/cf_ruleset_preflight.mjs +142 -0
  400. package/tests/cf_tunnel.mjs +37 -0
  401. package/tests/claim_gate_rebase.mjs +98 -0
  402. package/tests/clawback_confirmed_backlog.mjs +103 -0
  403. package/tests/cli_lib_formatters.mjs +20 -0
  404. package/tests/confirm_attribution.mjs +30 -46
  405. package/tests/credit_grant.mjs +198 -10
  406. package/tests/criterion_authoring_gate.mjs +272 -0
  407. package/tests/criterion_progress.mjs +33 -1
  408. package/tests/dev_lib.mjs +253 -0
  409. package/tests/devbox_artifact_gate.mjs +75 -0
  410. package/tests/devbox_dmg_backdrop.mjs +137 -0
  411. package/tests/devbox_icons.mjs +304 -0
  412. package/tests/devbox_installer_brand.mjs +232 -0
  413. package/tests/devbox_key_register.mjs +234 -0
  414. package/tests/docs_openapi_route.mjs +110 -0
  415. package/tests/doctor_hooks.mjs +141 -0
  416. package/tests/extract_json.mjs +140 -0
  417. package/tests/fitness.mjs +89 -0
  418. package/tests/gen_freshness.mjs +96 -0
  419. package/tests/github_repos_helpers.mjs +91 -0
  420. package/tests/github_token_store.mjs +121 -0
  421. package/tests/goal_advisory.mjs +251 -0
  422. package/tests/goal_criterion_confirm_ui.mjs +269 -0
  423. package/tests/goal_routes.mjs +59 -4
  424. package/tests/goal_tier.mjs +12 -3
  425. package/tests/governance_catalog.mjs +129 -0
  426. package/tests/governance_claim_eligibility.mjs +262 -0
  427. package/tests/governance_config.mjs +187 -0
  428. package/tests/governance_ownership_scope.mjs +410 -0
  429. package/tests/governance_page_gates.mjs +324 -0
  430. package/tests/governance_parity.mjs +336 -0
  431. package/tests/governance_principals.mjs +232 -0
  432. package/tests/governance_protected_surfaces.mjs +208 -0
  433. package/tests/governance_require_permission.mjs +223 -0
  434. package/tests/governance_resolver.mjs +84 -0
  435. package/tests/governance_role_sync.mjs +231 -0
  436. package/tests/governance_seed.mjs +127 -0
  437. package/tests/governance_session_scope.mjs +434 -0
  438. package/tests/governance_vanilla_boot.mjs +203 -0
  439. package/tests/grade_attribution.mjs +7 -7
  440. package/tests/hall_audit.mjs +223 -0
  441. package/tests/hall_nav.mjs +191 -0
  442. package/tests/hall_palette.mjs +206 -0
  443. package/tests/hall_signout.mjs +124 -0
  444. package/tests/hook_user_agents.mjs +10 -0
  445. package/tests/idea_triage.mjs +162 -0
  446. package/tests/idp_device_exchange.mjs +198 -0
  447. package/tests/idp_federation.mjs +100 -0
  448. package/tests/init.mjs +51 -0
  449. package/tests/instance_config.mjs +65 -0
  450. package/tests/instance_mismatch_guard.mjs +23 -6
  451. package/tests/instance_release_config.mjs +104 -0
  452. package/tests/linkify_refs.mjs +15 -2
  453. package/tests/migrations_forward_safe.mjs +86 -0
  454. package/tests/module_api.mjs +1 -1
  455. package/tests/module_contributions.mjs +55 -0
  456. package/tests/module_loader.mjs +10 -5
  457. package/tests/module_scope_active_claims.mjs +94 -0
  458. package/tests/needs_rebase.mjs +92 -0
  459. package/tests/one_active_claim_per_session.mjs +76 -0
  460. package/tests/override_attribution.mjs +10 -8
  461. package/tests/override_request_ownership.mjs +8 -4
  462. package/tests/package_core.mjs +246 -1
  463. package/tests/parse_cookie_decode.mjs +42 -0
  464. package/tests/pay_on_land.mjs +129 -0
  465. package/tests/platform_boot.mjs +100 -1
  466. package/tests/post_login_landing.mjs +42 -0
  467. package/tests/preflight_checks.mjs +72 -0
  468. package/tests/provision.mjs +289 -7
  469. package/tests/pruned_lockfile_integrity.mjs +79 -0
  470. package/tests/publish_branch_route.mjs +53 -0
  471. package/tests/publish_reconciler.mjs +187 -2
  472. package/tests/repo_info_binding.mjs +248 -0
  473. package/tests/reward_gate.mjs +11 -2
  474. package/tests/reward_mode_cost_plus_only.mjs +116 -0
  475. package/tests/reward_mode_surfacing.mjs +168 -0
  476. package/tests/route_permission_check.mjs +301 -0
  477. package/tests/route_rank_check.mjs +254 -12
  478. package/tests/route_validation.mjs +30 -0
  479. package/tests/sequence.mjs +267 -0
  480. package/tests/session_digest.mjs +44 -0
  481. package/tests/session_index.mjs +18 -6
  482. package/tests/session_records.mjs +39 -1
  483. package/tests/session_reward_on_land.mjs +381 -0
  484. package/tests/session_reward_reconcile.mjs +229 -0
  485. package/tests/ship_api_client_pathspec.mjs +100 -0
  486. package/tests/ship_base_flag.mjs +93 -0
  487. package/tests/ship_ci_deploy.mjs +140 -3
  488. package/tests/ship_upstream_deletion.mjs +57 -0
  489. package/tests/smoke_target.mjs +233 -0
  490. package/tests/start_env_guard.mjs +87 -0
  491. package/tests/start_rebase_warning.mjs +103 -0
  492. package/tests/status_mirror_sync.mjs +122 -0
  493. package/tests/stop_refcheck.mjs +19 -1
  494. package/tests/task_goal_link.mjs +15 -6
  495. package/tests/upgrade.mjs +393 -5
  496. package/tests/web_admission_status.mjs +162 -0
  497. package/tests/write_validation_gaps.mjs +110 -0
  498. package/.gitignore +0 -91
  499. package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
  500. package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
  501. package/scripts/hall-preview/fixtures/access-requests.json +0 -20
  502. package/scripts/hall-preview/fixtures/achievements.json +0 -76
  503. package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
  504. package/scripts/hall-preview/fixtures/audit-log.json +0 -68
  505. package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
  506. package/scripts/hall-preview/fixtures/box__me.json +0 -5
  507. package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
  508. package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
  509. package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
  510. package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
  511. package/scripts/hall-preview/fixtures/goals.json +0 -502
  512. package/scripts/hall-preview/fixtures/goals__25.json +0 -96
  513. package/scripts/hall-preview/fixtures/goals__26.json +0 -67
  514. package/scripts/hall-preview/fixtures/goals__3.json +0 -103
  515. package/scripts/hall-preview/fixtures/goals__35.json +0 -49
  516. package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
  517. package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
  518. package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
  519. package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
  520. package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
  521. package/scripts/hall-preview/fixtures/inbox.json +0 -330
  522. package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
  523. package/scripts/hall-preview/fixtures/instance.json +0 -124
  524. package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
  525. package/scripts/hall-preview/fixtures/me.json +0 -476
  526. package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
  527. package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
  528. package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
  529. package/scripts/hall-preview/fixtures/me__render.json +0 -5
  530. package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
  531. package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
  532. package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
  533. package/scripts/hall-preview/fixtures/override-requests.json +0 -15
  534. package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
  535. package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
  536. package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
  537. package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
  538. package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
  539. package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
  540. package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
  541. package/scripts/hall-preview/fixtures/public__grades.json +0 -50
  542. package/scripts/hall-preview/fixtures/public__progress.json +0 -124
  543. package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
  544. package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
  545. package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
  546. package/scripts/hall-preview/fixtures/security__docs.json +0 -10
  547. package/scripts/hall-preview/fixtures/security__reports.json +0 -31
  548. package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
  549. package/scripts/hall-preview/fixtures/tasks.json +0 -2420
  550. package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
  551. package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
  552. package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
  553. package/scripts/hall-preview/fixtures/versions.json +0 -89
@@ -0,0 +1,45 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Scouting — cross-project builders</title>
7
+ <style>
8
+ :root {
9
+ --bg: #fff7ed; --card: #ffffff; --ink: #2a1f17; --ink-soft: #6b5d52;
10
+ --rule: #fed7aa; --accent: #ea580c;
11
+ }
12
+ * { box-sizing: border-box; }
13
+ body {
14
+ margin: 0; padding: 2.5rem 1.25rem 4rem; background: var(--bg); color: var(--ink);
15
+ font-family: "Quicksand", system-ui, -apple-system, "Segoe UI", sans-serif; line-height: 1.5;
16
+ }
17
+ .wrap { max-width: 960px; margin: 0 auto; }
18
+ a.home { color: var(--accent); text-decoration: none; font-size: .9rem; }
19
+ h1 { font-size: 1.9rem; margin: .4rem 0 .3rem; }
20
+ .sub { color: var(--ink-soft); margin: 0 0 1.75rem; }
21
+ .badge { display: inline-block; font-size: .7rem; text-transform: uppercase; letter-spacing: .06em;
22
+ background: var(--accent); color: #fff; border-radius: 999px; padding: .12rem .6rem; vertical-align: middle; }
23
+ table { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--rule); border-radius: 12px; overflow: hidden; }
24
+ th, td { text-align: left; padding: .6rem .8rem; border-bottom: 1px solid var(--rule); font-size: .92rem; }
25
+ th { color: var(--ink-soft); font-weight: 600; }
26
+ td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
27
+ tr:last-child td { border-bottom: none; }
28
+ .who { font-weight: 600; }
29
+ .note { color: var(--ink-soft); padding: 2.5rem 1rem; text-align: center; }
30
+ .scroll { overflow-x: auto; }
31
+ @media (prefers-color-scheme: dark) {
32
+ :root { --bg: #1a1410; --card: #241c16; --ink: #f5ece3; --ink-soft: #b9a998; --rule: #4a3728; }
33
+ }
34
+ </style>
35
+ </head>
36
+ <body>
37
+ <div class="wrap">
38
+ <a class="home" href="/builders">← Back to the hall</a>
39
+ <h1>Scouting <span class="badge">Archon only</span></h1>
40
+ <p class="sub">Builders active across all hosted projects — an internal talent view. Descriptive only; it grants no authority anywhere.</p>
41
+ <div id="body" class="note">Loading…</div>
42
+ </div>
43
+ <script src="/scouting.js"></script>
44
+ </body>
45
+ </html>
@@ -0,0 +1,73 @@
1
+ // scouting.js — the internal Archon-only cross-project scouting view (ADR 0141 §4,
2
+ // task #1002114). Fetches /api/gds/scouting (Archon-gated server-side) and renders a
3
+ // ranked table. A non-Archon gets a 403 and sees the Archon-only notice — the data
4
+ // endpoint's rank gate is the real protection ("NOT shown to builders"). All network
5
+ // values are rendered via textContent — never innerHTML.
6
+ (function () {
7
+ 'use strict';
8
+ var body = document.getElementById('body');
9
+
10
+ function el(tag, cls) { var e = document.createElement(tag); if (cls) e.className = cls; return e; }
11
+ function td(text, cls) { var c = el('td', cls); c.textContent = text; return c; }
12
+
13
+ function fmtRecency(iso) {
14
+ if (!iso) return '—';
15
+ var t = Date.parse(iso);
16
+ if (isNaN(t)) return '—';
17
+ var days = Math.floor((Date.now() - t) / 86400000);
18
+ if (days <= 0) return 'today';
19
+ if (days === 1) return '1 day ago';
20
+ if (days < 30) return days + ' days ago';
21
+ return Math.floor(days / 30) + ' mo ago';
22
+ }
23
+
24
+ function render(builders) {
25
+ body.className = '';
26
+ body.textContent = '';
27
+ if (!builders || builders.length === 0) {
28
+ body.className = 'note';
29
+ body.textContent = 'No cross-project activity reported yet.';
30
+ return;
31
+ }
32
+ var scroll = el('div', 'scroll');
33
+ var table = el('table');
34
+ var thead = el('thead');
35
+ var hr = el('tr');
36
+ [['Builder', ''], ['Projects', 'num'], ['Credits', 'num'], ['Ships', 'num'], ['Karma', 'num'], ['Disciplines', ''], ['Last active', '']]
37
+ .forEach(function (h) { var th = el('th', h[1]); th.textContent = h[0]; hr.appendChild(th); });
38
+ thead.appendChild(hr); table.appendChild(thead);
39
+ var tbody = el('tbody');
40
+ builders.forEach(function (b) {
41
+ var tr = el('tr');
42
+ var who = el('td');
43
+ var name = el('span', 'who');
44
+ name.textContent = b.github_login || b.display_name || ('#' + b.github_id);
45
+ who.appendChild(name);
46
+ tr.appendChild(who);
47
+ tr.appendChild(td(String(b.project_count != null ? b.project_count : '—'), 'num'));
48
+ tr.appendChild(td(String(b.total_credits != null ? b.total_credits : 0), 'num'));
49
+ tr.appendChild(td(String(b.total_tasks_shipped != null ? b.total_tasks_shipped : 0), 'num'));
50
+ tr.appendChild(td(String(b.total_karma != null ? b.total_karma : 0), 'num'));
51
+ tr.appendChild(td(Array.isArray(b.disciplines) ? b.disciplines.join(', ') : '—'));
52
+ tr.appendChild(td(fmtRecency(b.last_active)));
53
+ tbody.appendChild(tr);
54
+ });
55
+ table.appendChild(tbody);
56
+ scroll.appendChild(table);
57
+ body.appendChild(scroll);
58
+ }
59
+
60
+ fetch('/api/gds/scouting', { headers: { Accept: 'application/json' } })
61
+ .then(function (r) {
62
+ if (r.status === 403 || r.status === 401) { throw { archon: true }; }
63
+ if (!r.ok) throw new Error('http ' + r.status);
64
+ return r.json();
65
+ })
66
+ .then(function (data) { render(data && data.builders); })
67
+ .catch(function (e) {
68
+ body.className = 'note';
69
+ body.textContent = (e && e.archon)
70
+ ? 'This view is Archon-only.'
71
+ : 'Couldn’t load the scouting view right now.';
72
+ });
73
+ }());
@@ -0,0 +1,16 @@
1
+ /* sessions.css — Page-local styles for the Session log 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
+ /* Page-local styles for the session log — small additions on top of the
7
+ shared .ledger / .stat-row components in style.css. */
8
+ .ledger-table-wrap { overflow-x: auto; margin-top: 6px; }
9
+ table.ledger th, table.ledger td { white-space: nowrap; }
10
+ .ledger td.warn { color: var(--danger); font-weight: 600; }
11
+ .ledger-sid {
12
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
13
+ font-size: 12.5px;
14
+ color: var(--info);
15
+ }
16
+ .ledger-rank { font-size: 12px; color: var(--ink-faint); }
@@ -10,19 +10,7 @@
10
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
12
12
  <link rel="stylesheet" href="/builders/style.css?v=2026-06-04-sessions">
13
- <style>
14
- /* Page-local styles for the session log — small additions on top of the
15
- shared .ledger / .stat-row components in style.css. */
16
- .ledger-table-wrap { overflow-x: auto; margin-top: 6px; }
17
- table.ledger th, table.ledger td { white-space: nowrap; }
18
- .ledger td.warn { color: var(--danger); font-weight: 600; }
19
- .ledger-sid {
20
- font-family: ui-monospace, "SF Mono", Menlo, monospace;
21
- font-size: 12.5px;
22
- color: var(--info);
23
- }
24
- .ledger-rank { font-size: 12px; color: var(--ink-faint); }
25
- </style>
13
+ <link rel="stylesheet" href="/builders/sessions.css">
26
14
  </head>
27
15
  <body data-page="sessions" data-page-title="Sessions">
28
16
 
@@ -83,6 +71,8 @@
83
71
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
84
72
  chrome exists before the page script runs. -->
85
73
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
74
+ <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
75
+ <script src="/builders/palette.js" defer></script>
86
76
  <!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
87
77
  <script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
88
78
  <script src="/builders/task-detail.js?v=2026-07-03-taskdetail"></script>
@@ -298,6 +298,8 @@
298
298
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
299
299
  chrome exists before the page scripts run. -->
300
300
  <script src="/builders/shell.js?v=2026-07-02-shell1"></script>
301
+ <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
302
+ <script src="/builders/palette.js" defer></script>
301
303
  <!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
302
304
  <script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
303
305
  <!-- shared component kit (window.OTBKit) — section rail (task 2166). -->
@@ -58,7 +58,7 @@
58
58
  ? data.allowed_models
59
59
  : ['opus', 'sonnet', 'haiku', 'script'];
60
60
  if (rows.length === 0) {
61
- body.innerHTML = '<tr><td colspan="3" class="voices-empty">No skills registered.</td></tr>';
61
+ body.innerHTML = `<tr><td colspan="3">${window.OTBKit.emptyStateHtml('No skills registered.')}</td></tr>`;
62
62
  return;
63
63
  }
64
64
  body.innerHTML = rows.map((row) => {
@@ -139,7 +139,7 @@
139
139
  if (!wrap) return;
140
140
  const rows = Array.isArray(data?.effective) ? data.effective : [];
141
141
  if (rows.length === 0) {
142
- wrap.innerHTML = '<p class="voices-empty">No sounds registered.</p>';
142
+ wrap.innerHTML = window.OTBKit.emptyStateHtml('No sounds registered.');
143
143
  return;
144
144
  }
145
145
  wrap.innerHTML = rows.map((row) => {
@@ -284,7 +284,7 @@
284
284
  if (!wrap) return;
285
285
  const rows = Array.isArray(data?.effective) ? data.effective : [];
286
286
  if (rows.length === 0) {
287
- wrap.innerHTML = '<p class="voices-empty">No event sounds registered.</p>';
287
+ wrap.innerHTML = window.OTBKit.emptyStateHtml('No event sounds registered.');
288
288
  return;
289
289
  }
290
290
  wrap.innerHTML = rows.map((row) => {
@@ -402,7 +402,7 @@
402
402
  const eff = typeof data?.effective_level === 'number' ? data.effective_level : null;
403
403
  const def = typeof data?.default_level === 'number' ? data.default_level : null;
404
404
  if (levels.length === 0) {
405
- wrap.innerHTML = '<p class="voices-empty">No levels registered.</p>';
405
+ wrap.innerHTML = window.OTBKit.emptyStateHtml('No levels registered.');
406
406
  return;
407
407
  }
408
408
  wrap.innerHTML = levels.map((lv) => {
@@ -13,9 +13,10 @@
13
13
  // (#app-sidebar / #app-topbar / #app-foot) every hall page carries;
14
14
  // - rank-gate nav items COSMETICALLY (server-side page gates remain the real
15
15
  // access control — serve-internal.js requireArchonPage etc.);
16
- // - on the index (body[data-page="home"]) route the four views (#home,
17
- // #standing, #achievements, #leaderboard). The `#/task|idea|blocker/N`
18
- // deep-link hashes belong to builders.js and are deliberately ignored here;
16
+ // - on the index (body[data-page="home"]) route the three views (#home,
17
+ // #standing, #leaderboard) plus the #achievements alias into Standing. The
18
+ // `#/task|idea|blocker/N` deep-link hashes belong to builders.js and are
19
+ // deliberately ignored here;
19
20
  // - expose window.OTBShell.applyAccess(...) so builders.js (index) or the
20
21
  // shell's own /api/bongos/me probe (other pages) can settle gated nav state.
21
22
  (function () {
@@ -29,7 +30,23 @@
29
30
  var brand = window.__BRANDING__ || {};
30
31
  var PAGE = (document.body && document.body.dataset.page) || '';
31
32
  var IS_INDEX = PAGE === 'home';
32
- var VIEWS = ['home', 'standing', 'achievements', 'leaderboard'];
33
+ var VIEWS = ['home', 'standing', 'leaderboard'];
34
+ // task 2174: #achievements retired as a view — the achievements grid folded
35
+ // into Standing's Achievements rail section; task 2175 then retired its nav
36
+ // entry. Old links (bookmarks, the stat tiles) keep working: the hash resolves
37
+ // to its host view and, after the view is shown, scrolls to the section anchor.
38
+ // task 2178: each Standing rail section is addressable too, so the jump palette
39
+ // (and any link) can land on one directly. Without an alias entry `#standing-work`
40
+ // is an unknown hash and route() deliberately leaves the current view alone —
41
+ // the section would never be reachable from another page. Keys mirror
42
+ // builders.js STANDING_GROUPS; tests/hall_palette.mjs holds them in step.
43
+ var VIEW_ALIASES = {
44
+ achievements: { view: 'standing', anchor: 'standing-achievements' },
45
+ 'standing-work': { view: 'standing', anchor: 'standing-work' },
46
+ 'standing-karma': { view: 'standing', anchor: 'standing-karma' },
47
+ 'standing-progress': { view: 'standing', anchor: 'standing-progress' },
48
+ 'standing-achievements': { view: 'standing', anchor: 'standing-achievements' },
49
+ };
33
50
  // builders.js owns these hashes (deep-link overlay) — never route them.
34
51
  var DEEPLINK_RE = /^#\/(task|idea|blocker)\/(\d+)$/;
35
52
 
@@ -60,7 +77,6 @@
60
77
  profile: '<rect x="2.5" y="4" width="13" height="10" rx="1.5"/><circle cx="6.3" cy="8" r="1.6"/><path d="M4.1 12c.3-1.1 1.1-1.7 2.2-1.7s1.9.6 2.2 1.7"/><path d="M10.4 7.5h3M10.4 10.3h3"/>',
61
78
  goals: '<circle cx="9" cy="9" r="6.5"/><circle cx="9" cy="9" r="3.5"/><circle cx="9" cy="9" r="0.8" fill="currentColor"/>',
62
79
  roadmap: '<path d="M3 15.5V3.5l4 2 4-2 4 2v10l-4-2-4 2-4-2Z"/><path d="M7 3.5v10M11 5.5v10"/>',
63
- achievements: '<circle cx="9" cy="7" r="4.5"/><path d="M6.2 10.8 5 15.5l4-2 4 2-1.2-4.7"/>',
64
80
  leaderboard: '<path d="M3.5 15.5v-6M9 15.5V3.5m5.5 12v-9"/>',
65
81
  docs: '<path d="M4 3.5h7l3 3v10H4v-13Z"/><path d="M11 3.5v3h3"/>',
66
82
  settings: '<circle cx="9" cy="9" r="2.5"/><path d="M9 2.5v2m0 9v2M2.5 9h2m9 0h2M4.4 4.4l1.4 1.4m6.4 6.4 1.4 1.4m0-9.2-1.4 1.4M5.8 12.2l-1.4 1.4"/>',
@@ -81,16 +97,30 @@
81
97
  // current (mirrors the old #hall-nav-work rule, task #833)
82
98
  // archon — rank === 'archon'
83
99
  // `view` marks an index view (hash-routed); `module` gates on window.__MODULES__.
100
+ // task 2175: grouped by AUDIENCE of the data, so the sidebar reads in coherent
101
+ // runs instead of one long list — the project (unlabeled), You, Community,
102
+ // Docs, Archon. A group's `gate` must match its most permissive item's, or the
103
+ // head renders over nothing.
84
104
  var NAV = [
85
105
  { group: '', items: [
86
106
  { id: 'home', label: 'Home', icon: 'home', href: '/', view: 'home', gate: 'always' },
87
- // task 1966: Work is visible to ANY signed-in builder (incl. newcomer Xenos).
88
- // Claimability is controlled per-task, not by hiding the page — every row
89
- // carries a rank tag and the server enforces requires_rank on the claim. This
90
- // reverses task #833's newcomer hide (the 'work' gate below is now unused).
91
- { id: 'work', label: 'Work', icon: 'work', href: '/work', gate: 'signed' },
92
107
  { id: 'roadmap', label: 'Roadmap', icon: 'roadmap', href: '/roadmap', gate: 'member' },
93
108
  { id: 'goals', label: 'Goals', icon: 'goals', href: '/goals', gate: 'member' },
109
+ // task 1966: Tasks (the board formerly labelled "Work") is visible to ANY
110
+ // signed-in builder (incl. newcomer Xenos). Claimability is controlled
111
+ // per-task, not by hiding the page — every row carries a rank tag and the
112
+ // server enforces requires_rank on the claim. This reverses task #833's
113
+ // newcomer hide (the 'work' gate below is now unused).
114
+ // task 1002425: relabelled Work → Tasks and moved below Roadmap/Goals. The
115
+ // id ('work') and href ('/work') are deliberately UNCHANGED so deep links,
116
+ // active-nav detection (#nav-work), the 'work' gate case, and the server
117
+ // page-gate all keep working — only the visible label and order change.
118
+ { id: 'work', label: 'Tasks', icon: 'work', href: '/work', gate: 'signed' },
119
+ ] },
120
+ // Your own numbers. task 2174 folded Achievements into Standing and this task
121
+ // retires its nav entry; VIEW_ALIASES still routes #achievements here, so old
122
+ // bookmarks and the stat tiles keep landing on the section.
123
+ { group: 'You', gate: 'signed', items: [
94
124
  { id: 'standing', label: 'Standing', icon: 'standing', href: '/#standing', view: 'standing', gate: 'signed' },
95
125
  // task 1467: the viewable, shareable builder profile. The nav link points at
96
126
  // the viewer's OWN profile (profile.js defaults to self when no ?id=). gate is
@@ -98,15 +128,24 @@
98
128
  // /profile?id=N from the leaderboard); 'signed' just means "show this 'my
99
129
  // profile' shortcut once you're signed in".
100
130
  { id: 'profile', label: 'Profile', icon: 'profile', href: '/profile', gate: 'signed' },
101
- { id: 'achievements', label: 'Achievements', icon: 'achievements', href: '/#achievements', view: 'achievements', gate: 'member' },
131
+ ] },
132
+ { group: 'Community', gate: 'member', items: [
102
133
  { id: 'leaderboard', label: 'Leaderboard', icon: 'leaderboard', href: '/#leaderboard', view: 'leaderboard', gate: 'member' },
103
134
  ] },
104
135
  { group: 'Docs', gate: 'signed', items: [
105
136
  { id: 'primer', label: 'Primer', icon: 'docs', href: '/primer', gate: 'member' },
137
+ { id: 'ranks', label: 'Ranks', icon: 'docs', href: '/ranks', gate: 'signed' },
138
+ // task 2175: /drachmae had no nav entry at all — reachable only from prose
139
+ // links since task 2174 moved the bounty rate card onto it. It is reference
140
+ // material (the reward schedule + how karma differs), so it belongs in Docs,
141
+ // not on personal Standing. Labelled for the TOPIC rather than the instance's
142
+ // currency: the page covers karma too, which is not currency, and "Economy"
143
+ // stays right whatever `branding.currency.label` is set to. Page is public
144
+ // like /ranks — 'signed' is the same cosmetic "show it once you're in".
145
+ { id: 'economy', label: 'Economy', icon: 'docs', href: '/drachmae', gate: 'signed' },
106
146
  { id: 'diagrams', label: 'Diagrams', icon: 'docs', href: '/diagrams', gate: 'member' },
107
147
  { id: 'atlas', label: 'Repo Atlas', icon: 'docs', href: '/atlas', gate: 'member' },
108
148
  { id: 'modules', label: 'Modules', icon: 'docs', href: '/modules', gate: 'member' },
109
- { id: 'ranks', label: 'Ranks', icon: 'docs', href: '/ranks', gate: 'signed' },
110
149
  // The rendered OpenAPI reference lives on the APEX (/docs), not this builders
111
150
  // subdomain — external so the rewrite shim doesn't turn it into /builders/docs.
112
151
  { id: 'apidocs', label: 'API docs', icon: 'docs', href: '/docs', gate: 'signed', external: true },
@@ -119,11 +158,13 @@
119
158
  ] },
120
159
  ];
121
160
 
122
- // ---------- nav group collapse (labeled groups only — Docs, Archon) ----------
161
+ // ---------- nav group collapse (labeled groups only) ----------
123
162
  // Mirrors the THEME_KEY localStorage pattern: per-group collapsed state,
124
163
  // survives reloads and carries across every hall page (shell.js runs on all
125
164
  // of them). Only labeled groups get a toggle — the unlabeled main group
126
- // (Home/Work/Roadmap/…) is core nav and always stays expanded.
165
+ // (Home/Roadmap/Goals/Tasks) is core nav and always stays expanded. Keys are
166
+ // the lowercased group label, so a regroup renames the key and a group reverts
167
+ // to expanded once — acceptable for a cosmetic preference.
127
168
  var NAV_COLLAPSE_KEY = 'hall-nav-collapsed';
128
169
 
129
170
  function collapsedGroups() {
@@ -152,6 +193,9 @@
152
193
  // builders./status. subdomain). Derived from the current host so it's correct
153
194
  // on any instance (amazonprimea.com, cloudbongos.com, localhost).
154
195
  var APEX_ORIGIN = window.location.origin.replace('://builders.', '://').replace('://status.', '://');
196
+ // Instance product/world name for the "back to home" wayfinding link — same
197
+ // source renderFoot() uses, so the core carries no hardcoded identity.
198
+ var platformName = (brand.identity && (brand.identity.productName || brand.identity.worldName)) || 'projects';
155
199
  var groups = NAV.map(function (g) {
156
200
  var groupId = g.group ? g.group.toLowerCase() : '';
157
201
  var collapsible = !!g.group;
@@ -189,6 +233,15 @@
189
233
  '<span class="shell-user__meta"><span class="shell-user__name" id="shell-user-name"></span>' +
190
234
  '<span class="shell-user__rank" id="shell-user-rank"></span></span>' +
191
235
  '</a>' +
236
+ // Wayfinding back to the platform's public home (the orbs gate on
237
+ // cloudbongos), where a builder can browse the OTHER projects. Kept core-
238
+ // neutral: the label is the instance's product/world name (as renderFoot
239
+ // does) and the href is the derived apex origin — no instance identity
240
+ // hardcoded. Ungated (shown signed-in or out) — it's a way out, not a
241
+ // gated action. Sits by Sign out (bottom-left) per the owner's call.
242
+ '<a class="shell-home" id="shell-home" href="' + esc(APEX_ORIGIN + '/') + '" title="Back to ' + esc(platformName) + ' — browse projects">' +
243
+ '<svg class="nav-icon" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.5 4 5.5 9l5 5"/><path d="M5.5 9H14"/></svg>' +
244
+ '<span class="nav-item__label">' + esc(platformName) + '</span></a>' +
192
245
  '<a class="shell-signout" id="logout-link" href="/api/bongos/auth/logout" title="Sign out">' + icon('signout') + '<span class="nav-item__label">Sign out</span></a>' +
193
246
  '</div>';
194
247
  var nameEl = document.getElementById('brand-name');
@@ -206,6 +259,15 @@
206
259
  '</button>' +
207
260
  '<h2 class="topbar-title" id="topbar-title"></h2>' +
208
261
  '<div class="topbar-side"><span class="topbar-note" id="welcome-line"></span>' +
262
+ // task 2178: the jump-palette slot. Rendered inert + hidden — palette.js
263
+ // reveals and wires it when the page loads it. A page without palette.js
264
+ // therefore shows no slot and runs no palette code (progressive
265
+ // enhancement): the shell never calls into it, so nothing can throw.
266
+ '<button class="topbar-jump" id="topbar-jump" type="button" hidden aria-label="Jump to a page or record">' +
267
+ '<svg viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="8" cy="8" r="4.5"/><path d="M11.5 11.5 15 15"/></svg>' +
268
+ '<span class="topbar-jump__label">Jump to…</span>' +
269
+ '<kbd class="topbar-jump__kbd" id="topbar-jump-kbd"></kbd>' +
270
+ '</button>' +
209
271
  '<button class="zoom-toggle" id="zoom-toggle" type="button" aria-label="Text size"></button>' +
210
272
  '<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Switch theme"></button></div>';
211
273
  var t = document.getElementById('topbar-title');
@@ -358,10 +420,14 @@
358
420
 
359
421
  var currentView = 'home';
360
422
 
423
+ // → { view, anchor } for a routable hash, else null. An aliased hash resolves
424
+ // to its host view plus the in-view anchor to scroll to once it is shown.
361
425
  function viewFromHash(hash) {
362
426
  if (!hash || DEEPLINK_RE.test(hash)) return null;
363
427
  var name = hash.replace(/^#\/?/, '');
364
- return VIEWS.indexOf(name) !== -1 ? name : null;
428
+ if (VIEWS.indexOf(name) !== -1) return { view: name, anchor: null };
429
+ var alias = VIEW_ALIASES[name];
430
+ return alias ? { view: alias.view, anchor: alias.anchor } : null;
365
431
  }
366
432
 
367
433
  function setView(name, opts) {
@@ -384,12 +450,30 @@
384
450
  }
385
451
 
386
452
  function route(opts) {
387
- var v = viewFromHash(window.location.hash);
388
- if (v) setView(v, opts);
389
- else if (!window.location.hash || window.location.hash === '#') setView('home', opts);
453
+ var target = viewFromHash(window.location.hash);
454
+ if (target) {
455
+ // An aliased hash owns its scroll position, so suppress setView's
456
+ // scroll-to-top and land on the section instead.
457
+ setView(target.view, target.anchor ? { scroll: false } : opts);
458
+ if (target.anchor) scrollToAnchor(target.anchor);
459
+ } else if (!window.location.hash || window.location.hash === '#') {
460
+ setView('home', opts);
461
+ }
390
462
  // unknown hashes (deep-links, legacy anchors) leave the current view alone.
391
463
  }
392
464
 
465
+ // The anchor is stamped by builders.js when it mounts the hall widgets, which
466
+ // can land after the first route() call — retry on the next frame so a cold
467
+ // load of an aliased hash still arrives at the section.
468
+ function scrollToAnchor(id) {
469
+ var el = document.getElementById(id);
470
+ if (el) { el.scrollIntoView(); return; }
471
+ window.requestAnimationFrame(function () {
472
+ var late = document.getElementById(id);
473
+ if (late) late.scrollIntoView();
474
+ });
475
+ }
476
+
393
477
  // ---------- drawer (≤768px) ----------
394
478
 
395
479
  function openDrawer() {
@@ -407,6 +491,35 @@
407
491
  if (btn) btn.setAttribute('aria-expanded', 'false');
408
492
  }
409
493
 
494
+ // Sign out. The /api/bongos/auth/logout endpoint is POST + cookie-gated, so a
495
+ // plain-anchor GET navigation (what the sidebar/footer sign-out links do on
496
+ // their own) just 404s: the session is never revoked, the still-valid cookie
497
+ // signs the builder back in on the next page, and — because the POST handler
498
+ // is the ONLY place seams.emit('builder.logout') fires — the federated
499
+ // single-logout to the hub never happens either (ADR 0144 / task 1002238).
500
+ // shell.js draws the sign-out control on EVERY hall page, so this handler must
501
+ // live here, not only on the index (builders.js used to own it alone). Convert
502
+ // the click into the real POST, then bounce home.
503
+ function doLogout() {
504
+ var finish = function () {
505
+ // Mirror the SERVER logout (src/bongos/routes/auth.js): expire BOTH the
506
+ // current gds_session and the legacy pms_session, each in BOTH the
507
+ // host-only form and the apex-scoped Domain=.<apex> form (#726 — the
508
+ // session cookie is apex-scoped on production hosts so it crosses
509
+ // subdomains; a Max-Age=0 only matches the cookie whose Domain attribute
510
+ // it names, so the host-only expire alone leaves the apex cookie live).
511
+ var apex = location.hostname.split('.').slice(-2).join('.');
512
+ ['gds_session', 'pms_session'].forEach(function (name) {
513
+ document.cookie = name + '=; Max-Age=0; path=/';
514
+ document.cookie = name + '=; Max-Age=0; path=/; Domain=.' + apex;
515
+ });
516
+ window.location.assign('/');
517
+ };
518
+ // Best-effort: whether the POST succeeds, fails, or the network drops, still
519
+ // clear the client cookies and bounce (finish runs on both settle paths).
520
+ api.request('POST', '/api/bongos/auth/logout').then(finish, finish);
521
+ }
522
+
410
523
  function wire() {
411
524
  var menu = document.getElementById('topbar-menu');
412
525
  if (menu) menu.addEventListener('click', function () {
@@ -441,6 +554,18 @@
441
554
  document.addEventListener('keydown', function (e) {
442
555
  if (e.key === 'Escape') closeDrawer();
443
556
  });
557
+ // Sign-out: delegated so it catches BOTH the sidebar (#logout-link) and the
558
+ // footer sign-out anchors on every page, plus any future one. Any anchor
559
+ // pointing at the logout endpoint is intercepted and turned into the real
560
+ // POST (see doLogout) instead of a dead GET navigation.
561
+ document.addEventListener('click', function (e) {
562
+ var a = e.target.closest && e.target.closest('a');
563
+ if (!a) return;
564
+ if (/\/auth\/logout\/?$/.test(a.getAttribute('href') || '')) {
565
+ e.preventDefault();
566
+ doLogout();
567
+ }
568
+ });
444
569
  }
445
570
 
446
571
  // Non-index pages: probe /api/bongos/me for cosmetic nav gating (the index's