@bongos/core 1.23.22 → 1.24.1

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 (424) hide show
  1. package/.bongos-core.json +902 -407
  2. package/.claude/skills/blocker-review/SKILL.md +9 -1
  3. package/.claude/skills/blocker-solve/SKILL.md +1 -1
  4. package/.claude/skills/builder-claim/SKILL.md +1 -1
  5. package/.claude/skills/builder-reauth/SKILL.md +1 -1
  6. package/.claude/skills/builder-redteam/SKILL.md +1 -1
  7. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  8. package/.claude/skills/builder-setup/SKILL.md +1 -1
  9. package/.claude/skills/builder-ship/SKILL.md +1 -1
  10. package/.claude/skills/collab-review/SKILL.md +5 -2
  11. package/.claude/skills/design/SKILL.md +1 -1
  12. package/.claude/skills/goal-create/SKILL.md +2 -2
  13. package/.claude/skills/grade-recover/SKILL.md +1 -1
  14. package/.claude/skills/merge-mode/SKILL.md +1 -1
  15. package/.claude/skills/owner-review/SKILL.md +1 -1
  16. package/.claude/skills/planning-session/SKILL.md +11 -11
  17. package/.claude/skills/read-session-export/SKILL.md +1 -1
  18. package/.claude/skills/recall/SKILL.md +1 -1
  19. package/.claude/skills/scan-before-install/SKILL.md +1 -1
  20. package/.claude/skills/session-handoff/SKILL.md +1 -1
  21. package/.claude/skills/strand-fix/SKILL.md +13 -0
  22. package/.claude/skills/worktree-clean/SKILL.md +1 -1
  23. package/AGENTS.md +15 -0
  24. package/GEMINI.md +5 -0
  25. package/clients/bongos-client/README.md +1 -1
  26. package/clients/bongos-client/bongos-client.global.js +90 -0
  27. package/clients/bongos-client/index.cjs +90 -0
  28. package/clients/bongos-client/index.d.ts +149 -4
  29. package/clients/bongos-client/index.mjs +90 -0
  30. package/docs/adr/0054-session-token-reward-cost-plus.md +3 -1
  31. package/docs/adr/0055-server-mediated-branch-publish.md +1 -1
  32. package/docs/adr/0393-a-platform-account-is-a-person-and-github-is-one-way-in.md +37 -0
  33. package/docs/adr/0394-market-watch-searches-through-the-messages-api-on-the-projects-key-and-runs-from-its-own-poller.md +102 -0
  34. package/docs/adr/0395-a-task-says-what-it-needs-and-lists-show-only-what-you-can-do.md +36 -0
  35. package/docs/adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md +41 -0
  36. package/docs/adr/README.md +5 -1
  37. package/docs/api/openapi.json +8555 -5876
  38. package/docs/api-reference.md +63 -10
  39. package/docs/architecture.md +37 -1
  40. package/docs/canonical-permissions.md +1 -1
  41. package/docs/copy-inventory.md +420 -337
  42. package/docs/copy-registry.json +1321 -500
  43. package/docs/file-map.md +1 -0
  44. package/docs/module-api-changelog.md +5 -0
  45. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +3 -3
  46. package/docs/onboarding/diagrams/README.md +1 -1
  47. package/docs/onboarding/drachmae-and-karma.md +15 -15
  48. package/docs/onboarding/primer.md +2 -2
  49. package/docs/page-inventory.json +55 -6
  50. package/docs/page-readings.json +1185 -1011
  51. package/docs/recipes/google-sign-in.md +60 -0
  52. package/docs/recipes/ops-gotchas.md +1 -1
  53. package/migrations/core_282_builders_lower_login_idx.sql +33 -0
  54. package/migrations/core_283_claimable_ignores_page_markers.sql +53 -0
  55. package/migrations/core_283_payout_approvals.sql +183 -0
  56. package/migrations/core_284_payout_gates.sql +179 -0
  57. package/migrations/core_285_task_needs.sql +74 -0
  58. package/modules/ai-studio/billing.js +67 -0
  59. package/modules/ai-studio/context.js +29 -0
  60. package/modules/ai-studio/db.js +172 -0
  61. package/modules/ai-studio/gemini.js +75 -0
  62. package/modules/ai-studio/generate.js +119 -0
  63. package/modules/ai-studio/keys.js +73 -0
  64. package/modules/ai-studio/migrations/ai_studio_001_keys.sql +22 -0
  65. package/modules/ai-studio/migrations/ai_studio_002_ledger.sql +48 -0
  66. package/modules/ai-studio/migrations/ai_studio_003_requests.sql +55 -0
  67. package/modules/ai-studio/openrouter.js +90 -0
  68. package/modules/ai-studio/payments.js +105 -0
  69. package/modules/ai-studio/pricing.js +92 -0
  70. package/modules/ai-studio/routes/ai-studio.js +235 -5
  71. package/modules/ai-studio/studio.js +121 -0
  72. package/modules/autonomy/fence.js +64 -1
  73. package/modules/builder-settings/builder-needs.js +27 -1
  74. package/modules/copy-desk/routes/copy-desk.js +5 -0
  75. package/modules/economy/achievements.js +22 -10
  76. package/modules/economy/cost-classify.js +9 -0
  77. package/modules/economy/cost-write-guard.js +52 -0
  78. package/modules/economy/cost.js +2 -1
  79. package/modules/economy/credits.js +18 -15
  80. package/modules/economy/goal-reward.js +161 -0
  81. package/modules/economy/reward.js +4 -0
  82. package/modules/economy/routes/cost.js +33 -7
  83. package/modules/government/catalog.js +6 -0
  84. package/modules/government/db.js +34 -0
  85. package/modules/government/docket.js +36 -0
  86. package/modules/government/migrations/government_035_payout_approve.sql +29 -0
  87. package/modules/government/pollers/board-expiry.js +108 -20
  88. package/modules/government/protected-surfaces.json +1 -0
  89. package/modules/government/routes/government.js +22 -0
  90. package/modules/government/routing.js +39 -5
  91. package/modules/government/waiting.js +74 -0
  92. package/modules/hall-ui/public/ai-studio-lib.js +268 -0
  93. package/modules/hall-ui/public/ai-studio.css +193 -0
  94. package/modules/hall-ui/public/ai-studio.html +98 -0
  95. package/modules/hall-ui/public/ai-studio.js +556 -0
  96. package/modules/hall-ui/public/ai-studio.states.json +94 -0
  97. package/modules/hall-ui/public/blockers-by-person.js +156 -0
  98. package/modules/hall-ui/public/blockers-lib.js +15 -1
  99. package/modules/hall-ui/public/blockers.html +8 -0
  100. package/modules/hall-ui/public/blockers.js +1 -1
  101. package/modules/hall-ui/public/claim-action.js +3 -0
  102. package/modules/hall-ui/public/collab.html +12 -0
  103. package/modules/hall-ui/public/craft-mode.js +4 -1
  104. package/modules/hall-ui/public/criterion-uat-ui.js +4 -1
  105. package/modules/hall-ui/public/drachmae.html +1 -1
  106. package/modules/hall-ui/public/genesis/r5-life-1-primordial-sea.jpg +0 -0
  107. package/modules/hall-ui/public/genesis/r5-life-2-first-cells-cut.webp +0 -0
  108. package/modules/hall-ui/public/genesis/r5-life-2-first-cells.jpg +0 -0
  109. package/modules/hall-ui/public/genesis/r5-life-3-genome-cut.webp +0 -0
  110. package/modules/hall-ui/public/genesis/r5-life-3-genome.jpg +0 -0
  111. package/modules/hall-ui/public/genesis/r5-life-4-membrane-cut.webp +0 -0
  112. package/modules/hall-ui/public/genesis/r5-life-4-membrane.jpg +0 -0
  113. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system-cut.webp +0 -0
  114. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system.jpg +0 -0
  115. package/modules/hall-ui/public/goal-inbox.js +1 -1
  116. package/modules/hall-ui/public/goals-render.js +4 -0
  117. package/modules/hall-ui/public/goals.html +8 -0
  118. package/modules/hall-ui/public/gov-living.js +6 -2
  119. package/modules/hall-ui/public/hall-ask.css +5 -0
  120. package/modules/hall-ui/public/hall-ask.js +39 -3
  121. package/modules/hall-ui/public/notes-panel.css +20 -0
  122. package/modules/hall-ui/public/notes-panel.js +146 -0
  123. package/modules/hall-ui/public/project-settings.html +1 -1
  124. package/modules/hall-ui/public/project-settings.js +7 -5
  125. package/modules/hall-ui/public/settings-ai-keys.js +124 -0
  126. package/modules/hall-ui/public/settings.html +15 -0
  127. package/modules/hall-ui/public/street-deck.js +12 -3
  128. package/modules/hall-ui/public/studio.css +90 -8
  129. package/modules/hall-ui/public/studio.html +39 -10
  130. package/modules/hall-ui/public/studio.js +148 -18
  131. package/modules/hall-ui/public/task.html +2 -0
  132. package/modules/hall-ui/public/task.js +4 -0
  133. package/modules/hall-ui/public/tweak-editor.js +12 -3
  134. package/modules/hall-ui/public/welcome-boot.css +42 -6
  135. package/modules/hall-ui/public/welcome-boot.js +20 -6
  136. package/modules/hall-ui/public/work.js +20 -0
  137. package/modules/hall-ui/records/ai-studio.md +36 -0
  138. package/modules/hall-ui/records/blockers-people.md +24 -0
  139. package/modules/lifecycle/db-claims.js +32 -4
  140. package/modules/lifecycle/db-goals.js +18 -5
  141. package/modules/lifecycle/db-tasks.js +15 -6
  142. package/modules/lifecycle/done-when.js +23 -1
  143. package/modules/lifecycle/lifecycle.js +5 -0
  144. package/modules/lifecycle/migrations/lifecycle_017_notes.sql +46 -0
  145. package/modules/lifecycle/module.json +2 -1
  146. package/modules/lifecycle/notes.js +219 -0
  147. package/modules/lifecycle/page-notice.js +124 -0
  148. package/modules/lifecycle/page-tweak-artist.js +18 -1
  149. package/modules/lifecycle/publish-reconciler.js +67 -20
  150. package/modules/lifecycle/routes/claims.js +5 -2
  151. package/modules/lifecycle/routes/goals.js +3 -1
  152. package/modules/lifecycle/routes/notes.js +91 -0
  153. package/modules/lifecycle/routes/project-settings.js +43 -35
  154. package/modules/lifecycle/routes/task-route-helpers.js +21 -0
  155. package/modules/lifecycle/routes/task-write-routes.js +21 -3
  156. package/modules/lifecycle/routes/tasks.js +12 -12
  157. package/modules/lifecycle/task-needs-gate.js +70 -0
  158. package/modules/market-watch/CLAUDE.md +15 -0
  159. package/modules/market-watch/db.js +340 -0
  160. package/modules/market-watch/key.js +58 -0
  161. package/modules/market-watch/migrations/market_watch_001_tables.sql +249 -0
  162. package/modules/market-watch/migrations/market_watch_002_run.sql +46 -0
  163. package/modules/market-watch/module.json +26 -0
  164. package/modules/market-watch/pollers/hub-seed.js +54 -0
  165. package/modules/market-watch/pollers/weekly-run.js +100 -0
  166. package/modules/market-watch/research.js +350 -0
  167. package/modules/market-watch/run.js +245 -0
  168. package/modules/market-watch/seed/market-data.json +38 -0
  169. package/modules/market-watch/seed/partners-data.json +497 -0
  170. package/modules/market-watch/seed.js +252 -0
  171. package/modules/market-watch/store.js +230 -0
  172. package/modules/memory/routes/memory.js +14 -2
  173. package/modules/memory/routes/search.js +8 -2
  174. package/modules/platform-identity/account-logins.js +192 -0
  175. package/modules/platform-identity/migrations/platform_identity_034_account_logins.sql +96 -0
  176. package/modules/platform-identity/platform-identity.js +5 -4
  177. package/modules/platform-identity/routes/my-projects.js +6 -0
  178. package/modules/platform-identity/routes/profile.js +18 -0
  179. package/modules/platform-identity/routes/public-profile.js +10 -1
  180. package/modules/platform-identity/routes/sso.js +26 -1
  181. package/modules/platform-identity/tests/platform-identity.mjs +2 -1
  182. package/modules/provisioning/credential-preflight.js +13 -3
  183. package/modules/provisioning/pollers/app-liveness.js +25 -5
  184. package/modules/provisioning/routes/provisioning.js +1 -1
  185. package/modules/provisioning/starter-bundles.js +6 -2
  186. package/modules/public-landing/public/account.html +10 -2
  187. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg +0 -0
  188. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
  189. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
  190. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +1 -1
  191. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp +0 -0
  192. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp.json +1 -1
  193. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg +0 -0
  194. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
  195. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
  196. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +1 -1
  197. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg +0 -0
  198. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
  199. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
  200. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +1 -1
  201. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp +0 -0
  202. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp.json +1 -1
  203. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp +0 -0
  204. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp.json +1 -1
  205. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp +0 -0
  206. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp.json +1 -1
  207. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp +0 -0
  208. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp.json +1 -1
  209. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp +0 -0
  210. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp.json +1 -1
  211. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp +0 -0
  212. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp.json +1 -1
  213. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg +0 -0
  214. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg.json +1 -1
  215. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg +0 -0
  216. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg.json +1 -1
  217. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg +0 -0
  218. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg.json +1 -1
  219. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg +0 -0
  220. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg.json +1 -1
  221. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp +0 -0
  222. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp.json +1 -1
  223. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg +0 -0
  224. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg.json +1 -1
  225. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp +0 -0
  226. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp.json +1 -1
  227. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg +0 -0
  228. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg.json +1 -1
  229. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp +0 -0
  230. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp.json +1 -1
  231. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg +0 -0
  232. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg.json +1 -1
  233. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp +0 -0
  234. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp.json +1 -1
  235. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg +0 -0
  236. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg.json +1 -1
  237. package/modules/public-landing/public/community.html +1 -1
  238. package/modules/public-landing/public/connections.html +2 -2
  239. package/modules/public-landing/public/guild.html +1 -1
  240. package/modules/public-landing/public/invitations.html +2 -2
  241. package/modules/public-landing/public/projects.html +5 -5
  242. package/modules/raise/views/nda.html +2 -0
  243. package/modules/specialities/db.js +32 -1
  244. package/modules/specialities/routes/specialities.js +10 -6
  245. package/modules/status-ui/public/index.html +1 -1
  246. package/package-lock.json +2 -2
  247. package/package.json +1 -1
  248. package/release-notes.json +220 -0
  249. package/scripts/bongos/autobongos-tweak-lane.js +46 -1
  250. package/scripts/bongos/backfill-subagent-rewards.js +2 -2
  251. package/scripts/bongos/claim.js +22 -1
  252. package/scripts/bongos/db-backup-nightly.sh +29 -0
  253. package/scripts/bongos/deploy-divergence.js +7 -0
  254. package/scripts/bongos/doc-cli-guard.js +6 -0
  255. package/scripts/bongos/fitness.js +3 -2
  256. package/scripts/bongos/gen-diagrams.js +3 -3
  257. package/scripts/bongos/lib.sh +4 -5
  258. package/scripts/bongos/migration-namespace.js +13 -1
  259. package/scripts/bongos/plain-cards.js +4 -0
  260. package/scripts/bongos/provision-github-setup.js +3 -1
  261. package/scripts/bongos/provision-units.js +6 -1
  262. package/scripts/bongos/publish-manifest.js +3 -0
  263. package/scripts/bongos/release.js +2 -0
  264. package/scripts/bongos/run-unit-tests.js +268 -82
  265. package/scripts/bongos/seed-tasks.example.json +56 -0
  266. package/scripts/bongos/seed-tasks.js +222 -0
  267. package/scripts/bongos/seed-verify-criteria.js +1 -2
  268. package/scripts/bongos/ship-finish.js +2 -0
  269. package/scripts/bongos/ship-resume.js +2 -0
  270. package/scripts/bongos/strand-lease.js +250 -0
  271. package/scripts/bongos/strand-watch.js +26 -5
  272. package/scripts/bongos/version-literal-guard.js +2 -2
  273. package/scripts/discord/post.js +4 -3
  274. package/scripts/gds/seed-tasks.js +7 -0
  275. package/scripts/gds/{build-bongos.js → strand-lease.js} +3 -3
  276. package/scripts/hall-preview/server.js +21 -0
  277. package/src/bongos/auth-config.js +29 -1
  278. package/src/bongos/auth-discord.js +3 -3
  279. package/src/bongos/auth-github.js +3 -6
  280. package/src/bongos/auth-google.js +217 -0
  281. package/src/bongos/device-approval.js +140 -0
  282. package/src/bongos/llm-pricing.js +17 -1
  283. package/src/bongos/metrics.js +48 -2
  284. package/src/bongos/middleware/rate-limit.js +30 -11
  285. package/src/bongos/module-scope-map.js +12 -1
  286. package/src/bongos/optimizer.js +15 -1
  287. package/src/bongos/payout-approvals.js +342 -0
  288. package/src/bongos/payout-gates.js +364 -0
  289. package/src/bongos/prelaunch-gate.js +7 -9
  290. package/src/bongos/prelaunch-switch.js +20 -0
  291. package/src/bongos/route-rank-check.js +3 -0
  292. package/src/bongos/routes/auth-google.js +246 -0
  293. package/src/bongos/routes/auth.js +38 -1
  294. package/src/bongos/routes/backup.js +33 -9
  295. package/src/bongos/routes/builders.js +57 -30
  296. package/src/bongos/routes/github.js +9 -0
  297. package/src/bongos/routes/me.js +18 -0
  298. package/src/bongos/routes/my-payouts.js +133 -0
  299. package/src/bongos/routes/payout-approvals.js +312 -0
  300. package/src/bongos/routes/payout-gates.js +179 -0
  301. package/src/bongos/routes.js +15 -1
  302. package/src/bongos/secret-box.js +18 -3
  303. package/src/bongos/serve-internal.js +47 -19
  304. package/src/bongos/sign-in-pages.js +138 -0
  305. package/src/bongos/task-needs.js +146 -0
  306. package/src/bongos-downloads.js +18 -1
  307. package/src/instance-config.js +28 -0
  308. package/src/module-api.js +14 -1
  309. package/tests/account_logins.mjs +326 -0
  310. package/tests/account_logins_db.mjs +161 -0
  311. package/tests/ai_studio_billing.mjs +253 -0
  312. package/tests/ai_studio_generate.mjs +282 -0
  313. package/tests/ai_studio_keys.mjs +159 -0
  314. package/tests/ai_studio_requests.mjs +319 -0
  315. package/tests/auth_backchannel_logout_route.mjs +201 -0
  316. package/tests/auto_satisfy_criteria.mjs +10 -1
  317. package/tests/autobongos_tweak_lane.mjs +144 -0
  318. package/tests/autobongos_tweak_pin_identity.mjs +137 -0
  319. package/tests/backfill_subagent_rewards.mjs +17 -1
  320. package/tests/backup_trigger_lock.mjs +119 -0
  321. package/tests/blockers_people.mjs +198 -0
  322. package/tests/bounded_rate_maps.mjs +184 -0
  323. package/tests/claimable_blocker_status.mjs +1 -1
  324. package/tests/claims_batch_routes.mjs +421 -0
  325. package/tests/config_read_cache.mjs +171 -0
  326. package/tests/copy_desk_page_editor.mjs +12 -0
  327. package/tests/cost_write_guard.mjs +200 -0
  328. package/tests/craft_achievements.mjs +33 -10
  329. package/tests/criterion_goal_attach.mjs +1 -1
  330. package/tests/db_backup_nightly.mjs +73 -1
  331. package/tests/deploy_divergence_line.mjs +7 -0
  332. package/tests/effective_visibility_predicate.mjs +12 -0
  333. package/tests/fitness.mjs +19 -0
  334. package/tests/fixtures/seed-tasks/bongos-v1-idea-routing.json +256 -0
  335. package/tests/fixtures/seed-tasks/bv1-profiles.json +592 -0
  336. package/tests/fixtures/seed-tasks/bv2-ideator-surface.json +373 -0
  337. package/tests/fixtures/seed-tasks/fake-api.mjs +80 -0
  338. package/tests/github_one_trip.mjs +34 -0
  339. package/tests/github_repo_visibility.mjs +20 -0
  340. package/tests/goal_achievement.mjs +30 -1
  341. package/tests/goal_achievement_reward.mjs +205 -0
  342. package/tests/goal_sort_staleness.mjs +2 -1
  343. package/tests/goal_tier.mjs +11 -1
  344. package/tests/google_fonts_nonblocking.mjs +84 -0
  345. package/tests/google_sign_in.mjs +401 -0
  346. package/tests/government_board_expiry.mjs +94 -0
  347. package/tests/government_protected_surfaces.mjs +1 -1
  348. package/tests/government_routes.mjs +1 -1
  349. package/tests/hall_ai_studio.mjs +347 -0
  350. package/tests/hall_page_gate_map.mjs +3 -0
  351. package/tests/hall_studio_home.mjs +61 -2
  352. package/tests/home_attention_cards.mjs +1 -1
  353. package/tests/human_signal.mjs +141 -0
  354. package/tests/install_script_reader.mjs +51 -0
  355. package/tests/integration_fixture_ids.mjs +82 -0
  356. package/tests/invite_expiry_db.mjs +13 -1
  357. package/tests/lib_sh_resolution.mjs +0 -4
  358. package/tests/market_watch_data.mjs +244 -0
  359. package/tests/market_watch_data_db.mjs +308 -0
  360. package/tests/market_watch_module.mjs +114 -0
  361. package/tests/market_watch_run.mjs +503 -0
  362. package/tests/metrics.mjs +124 -0
  363. package/tests/migration_namespace.mjs +14 -0
  364. package/tests/module_api.mjs +2 -0
  365. package/tests/module_loader.mjs +1 -1
  366. package/tests/notes.mjs +182 -0
  367. package/tests/own_scope_guard.mjs +5 -0
  368. package/tests/page_tweak_marker_sql.mjs +76 -0
  369. package/tests/page_tweak_no_block.mjs +135 -0
  370. package/tests/page_tweak_notice.mjs +103 -0
  371. package/tests/payout_approvals.mjs +253 -0
  372. package/tests/payout_approvals_db.mjs +106 -0
  373. package/tests/payout_gates.mjs +322 -0
  374. package/tests/payout_gates_db.mjs +113 -0
  375. package/tests/planning_session_skill.mjs +13 -3
  376. package/tests/project_settings_page.mjs +29 -5
  377. package/tests/project_settings_spend_cap_route.mjs +235 -0
  378. package/tests/promotion_sweep.mjs +29 -1
  379. package/tests/provision.mjs +3 -2
  380. package/tests/provisioning_app_status.mjs +18 -0
  381. package/tests/provisioning_credential_preflight.mjs +53 -0
  382. package/tests/provisioning_env_manifest_edit_delete.mjs +223 -0
  383. package/tests/publish_reconciler_overlap.mjs +60 -0
  384. package/tests/rank_change_broadcast_port.mjs +151 -0
  385. package/tests/seed_tasks.mjs +176 -0
  386. package/tests/seed_verify_criteria.mjs +2 -6
  387. package/tests/site_classified_once.mjs +142 -0
  388. package/tests/speciality_db_shape.mjs +23 -0
  389. package/tests/speciality_session_skills.mjs +48 -2
  390. package/tests/strand_lease.mjs +249 -0
  391. package/tests/strand_watch.mjs +10 -0
  392. package/tests/task_criteria_routes.mjs +275 -0
  393. package/tests/task_criteria_unlink_db.mjs +123 -0
  394. package/tests/task_needs.mjs +233 -0
  395. package/tests/task_needs_db.mjs +110 -0
  396. package/tests/unit_runner_serial.mjs +266 -43
  397. package/tests/version_literals.mjs +5 -7
  398. package/tests/welcome_boot.mjs +16 -5
  399. package/tests/welcome_boot_browser.mjs +36 -4
  400. package/docs/recipes/bongos-cli-release.md +0 -66
  401. package/scripts/bongos/backfill-disciplines.js +0 -144
  402. package/scripts/bongos/backfill-session-earnings.js +0 -123
  403. package/scripts/bongos/backfill-session-types.js +0 -87
  404. package/scripts/bongos/build-bongos.js +0 -94
  405. package/scripts/bongos/cleanup-orphans.js +0 -74
  406. package/scripts/bongos/seed-bongos-v1-idea-routing-tasks.js +0 -152
  407. package/scripts/bongos/seed-bv1-profiles-tasks.js +0 -135
  408. package/scripts/bongos/seed-bv2-ideator-surface-tasks.js +0 -390
  409. package/scripts/bongos/smoke-batch-claim.sh +0 -238
  410. package/scripts/bongos/smoke-batch-release.sh +0 -316
  411. package/scripts/bongos/smoke-claim-consistency.sh +0 -222
  412. package/scripts/bongos/smoke-dependencies.sh +0 -143
  413. package/scripts/gds/backfill-disciplines.js +0 -7
  414. package/scripts/gds/backfill-session-earnings.js +0 -7
  415. package/scripts/gds/backfill-session-types.js +0 -7
  416. package/scripts/gds/cleanup-orphans.js +0 -7
  417. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +0 -6
  418. package/scripts/gds/seed-bv1-profiles-tasks.js +0 -6
  419. package/scripts/gds/seed-bv2-ideator-surface-tasks.js +0 -6
  420. package/scripts/gds/smoke-batch-claim.sh +0 -8
  421. package/scripts/gds/smoke-batch-release.sh +0 -8
  422. package/scripts/gds/smoke-claim-consistency.sh +0 -8
  423. package/scripts/gds/smoke-dependencies.sh +0 -8
  424. package/tests/smoke_dependencies_witness.mjs +0 -46
@@ -1,144 +0,0 @@
1
- #!/usr/bin/env node
2
- // scripts/bongos/backfill-disciplines.js — task 1002988: give every role-less task a craft.
3
- //
4
- // WHY THIS EXISTS SEPARATELY FROM THE MIGRATION. core_247 narrows
5
- // tasks_discipline_check to {engineer, artist, ideator, ui} and carries a
6
- // last-resort `UPDATE ... SET discipline='engineer'` so a fresh install can never
7
- // be blocked on a human remembering to run a script. But that net is a blunt
8
- // guess. The real classification is classifyTaskDiscipline() — a JS heuristic over
9
- // title + description + touches that SQL cannot express — so the good pass runs
10
- // here, first, and the migration only catches what is left.
11
- //
12
- // Run this BEFORE deploying core_247. Order matters: rows this script resolves keep
13
- // a reasoned craft; rows it does not are parked on 'engineer' by the migration.
14
- //
15
- // USAGE
16
- // node scripts/bongos/backfill-disciplines.js # dry run — the spot-check list
17
- // node scripts/bongos/backfill-disciplines.js --apply # commit the PATCHes
18
- // node scripts/bongos/backfill-disciplines.js --sample 40 # widen the printed sample
19
- //
20
- // The dry run is the default on purpose: the task required a spot-check list for the
21
- // owner BEFORE anything was applied, and 1,189 rows is not a diff anyone reviews in
22
- // their head.
23
-
24
- 'use strict';
25
-
26
- const { cliClient, requireSession } = require('./cli-lib');
27
- const { resolveWriteDiscipline, WRITABLE_DISCIPLINES } = require('../../modules/lifecycle/task-classifier.js');
28
-
29
- // Rows whose title marks them as test debris. The classifier already skips these
30
- // (they are not real work), but they still carry 'unclassified' and therefore still
31
- // violate the narrowed constraint — so they must be resolved, not skipped, or the
32
- // migration's net silently becomes the thing that handles 164 rows.
33
- const SMOKE_RE = /__smoke__/;
34
-
35
- // The fallback for anything the heuristic refuses. Stated as a constant with its
36
- // reasoning rather than inlined, because this value is a GUESS and every report
37
- // below labels it as one.
38
- const FALLBACK = 'engineer';
39
-
40
- function classify(task) {
41
- const resolved = resolveWriteDiscipline({
42
- title: task.title, description: task.description, touches: task.touches,
43
- });
44
- if (resolved.discipline) {
45
- return { discipline: resolved.discipline, reasoned: true, confidence: resolved.confidence ?? null };
46
- }
47
- return { discipline: FALLBACK, reasoned: false, confidence: null };
48
- }
49
-
50
- const { sleep } = require('../../src/sleep'); // the one shared sleep (task 1004893)
51
-
52
- // PATCH one row, WAITING OUT the per-session rate limit rather than counting it as a
53
- // failure. The first run of this backfill treated a 429 as a failed row and stopped
54
- // having written 120 of 1,189 — the limiter was doing its job and the script was
55
- // reading "slow down" as "no". The server tells us how long to wait; honour it.
56
- // Re-running is safe either way: the query only returns rows still unclassified.
57
- async function patchWithBackoff(api, id, discipline, maxAttempts = 6) {
58
- for (let attempt = 1; ; attempt += 1) {
59
- const res = await api.tasks.patchTasksId({ id, body: { discipline } });
60
- if (res.status !== 429 || attempt >= maxAttempts) return res;
61
- const retryAfter = Number(res.data?.error?.details?.retry_after_seconds);
62
- const waitMs = (Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter : 2 ** attempt) * 1000;
63
- console.log(` rate limited — waiting ${Math.round(waitMs / 1000)}s (attempt ${attempt}/${maxAttempts - 1})`);
64
- await sleep(waitMs + 500);
65
- }
66
- }
67
-
68
- async function main() {
69
- const args = process.argv.slice(2);
70
- const apply = args.includes('--apply');
71
- const sampleIdx = args.indexOf('--sample');
72
- const sampleSize = sampleIdx >= 0 ? Number(args[sampleIdx + 1]) || 20 : 20;
73
-
74
- await requireSession();
75
- const api = await cliClient();
76
-
77
- const r = await api.tasks.getTasks({ query: { discipline: 'unclassified' } });
78
- if (!r.ok) {
79
- console.error(`failed to read tasks (${r.status}):`, r.data);
80
- process.exit(1);
81
- }
82
- const tasks = r.data?.tasks || [];
83
- if (!tasks.length) {
84
- console.log('Nothing to do — no task carries discipline=unclassified.');
85
- return;
86
- }
87
-
88
- const plan = tasks.map((t) => ({ task: t, ...classify(t), smoke: SMOKE_RE.test(t.title || '') }));
89
- const reasoned = plan.filter((p) => p.reasoned);
90
- const guessed = plan.filter((p) => !p.reasoned);
91
- const byDiscipline = {};
92
- for (const p of plan) byDiscipline[p.discipline] = (byDiscipline[p.discipline] || 0) + 1;
93
-
94
- console.log(`\n${apply ? 'Applying' : 'DRY RUN —'} discipline backfill over ${plan.length} role-less task(s)\n`);
95
- console.log(' Resolved by the classifier (a reasoned answer):');
96
- for (const [d, n] of Object.entries(byDiscipline).sort((a, b) => b[1] - a[1])) {
97
- const reasonedN = reasoned.filter((p) => p.discipline === d).length;
98
- console.log(` ${d.padEnd(12)} ${String(reasonedN).padStart(5)}`);
99
- }
100
- console.log(`\n BEST GUESS (classifier refused → ${FALLBACK}): ${guessed.length}`);
101
- console.log(` of which __smoke__ test debris: ${guessed.filter((p) => p.smoke).length}`);
102
- console.log(' These are NOT determined answers. A later reader must not treat');
103
- console.log(' them as evidence that anyone classified the row (owner decision 2026-09-17).\n');
104
-
105
- console.log(` Spot-check sample — reasoned (first ${sampleSize}):`);
106
- for (const p of reasoned.slice(0, sampleSize)) {
107
- console.log(` ${p.discipline.padEnd(9)} ${p.confidence != null ? `(${p.confidence.toFixed(2)})` : ' '} ${String(p.task.title).slice(0, 72)}`);
108
- }
109
- console.log(`\n Spot-check sample — GUESSED (first ${sampleSize}):`);
110
- for (const p of guessed.filter((x) => !x.smoke).slice(0, sampleSize)) {
111
- console.log(` ${p.discipline.padEnd(9)} ${String(p.task.title).slice(0, 72)}`);
112
- }
113
-
114
- if (!apply) {
115
- console.log(`\nDry run — nothing was written. Re-run with --apply to commit.\n`);
116
- return;
117
- }
118
-
119
- let ok = 0;
120
- const failures = [];
121
- for (const p of plan) {
122
- const res = await patchWithBackoff(api, p.task.id, p.discipline);
123
- if (res.ok) ok += 1;
124
- else failures.push({ id: p.task.id, status: res.status, detail: JSON.stringify(res.data).slice(0, 160) });
125
- if (ok % 100 === 0 && res.ok) console.log(` … ${ok}/${plan.length}`);
126
- }
127
- console.log(`\nApplied: ${ok}/${plan.length}`);
128
- if (failures.length) {
129
- console.log(`Failed: ${failures.length}`);
130
- for (const f of failures.slice(0, 20)) console.log(` #${f.id} → ${f.status} ${f.detail}`);
131
- process.exitCode = 1;
132
- }
133
- // Report the residue against the same query, so the number quoted afterwards is
134
- // measured rather than assumed.
135
- const after = await api.tasks.getTasks({ query: { discipline: 'unclassified' } });
136
- const left = after.ok ? (after.data?.tasks || []).length : null;
137
- console.log(`Remaining unclassified: ${left == null ? '(re-read failed)' : left}`);
138
- }
139
-
140
- if (require.main === module) {
141
- main().catch((e) => { console.error(e && e.message ? e.message : e); process.exit(1); });
142
- }
143
-
144
- module.exports = { classify, FALLBACK, SMOKE_RE };
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // scripts/bongos/backfill-session-earnings.js — repair the historical
5
- // `session_records.drachmae_earned` mirror (task 1003634).
6
- //
7
- // WHAT THIS IS, and what it emphatically is NOT. It moves NO money. It writes no
8
- // `credit_log` row, mints nothing, and cannot change any builder's balance. It
9
- // rewrites ONE display column to agree with the ledger that already exists. That
10
- // makes it categorically unlike its neighbours here (backfill-task-rewards.js,
11
- // backfill-subagent-rewards.js), which mint credits and carry an ADR 0097 /
12
- // ADR 0173 safety model to match. Read this one as a data repair.
13
- //
14
- // WHY IT IS NEEDED. `drachmae_earned` means "the credit_log delta attributable to
15
- // this session" (migration 062), but the only thing that ever wrote it summed
16
- // rows keyed on `task_id`. The cost-plus session reward (ADR 0054) keys on
17
- // `session_id` and leaves `task_id` NULL on purpose, because it pays for the
18
- // session's real token spend rather than for any one task in it. So the mirror
19
- // could not see it. Under reward mode `cost-plus-only` (ADR 0146 — this
20
- // instance's standing choice) that reward is the ONLY stream that pays, so the
21
- // column read 0 for essentially every session, and the hall told builders they
22
- // had earned nothing for work they had genuinely been paid for. A builder
23
- // reported it as missing pay; the pay was never missing, this number was.
24
- //
25
- // WHY THE LIVE FIX DOES NOT COVER HISTORY. The code fix re-derives the figure
26
- // whenever a reward books, and all three pay-on-land triggers now funnel through
27
- // that. But none of them revisits a session that is already paid in full — the
28
- // state-based sweep explicitly skips any session that already has a
29
- // `session.token_reward` row. So already-paid history never self-heals, which is
30
- // precisely the history a builder looks at. Hence a one-shot pass.
31
- //
32
- // SAFETY. DRY-RUN BY DEFAULT: with no flags it prints the plan and writes
33
- // nothing. `--apply` performs the UPDATEs. Idempotent by construction — every
34
- // row is SET to a value derived wholly from current ledger state, so re-running
35
- // lands on the same numbers, and a row already correct is skipped and reported
36
- // as such. `--builder N` scopes the pass to one builder (useful for verifying on
37
- // a single account before the full sweep).
38
- //
39
- // Run: node scripts/bongos/backfill-session-earnings.js [--builder N] [--limit N]
40
- // node scripts/bongos/backfill-session-earnings.js --apply
41
-
42
- const path = require('node:path');
43
-
44
- const credits = require('../../modules/economy/credits');
45
- const { arg, hasFlag } = require('./cli-lib');
46
-
47
- const REPO_ROOT = path.resolve(__dirname, '..', '..');
48
-
49
- function loadPool() {
50
- const { pool } = require(path.join(REPO_ROOT, 'src/bongos/pool'));
51
- return pool;
52
- }
53
-
54
- async function main() {
55
- const apply = hasFlag('--apply');
56
- const builderArg = arg('--builder');
57
- const limitArg = Number(arg('--limit'));
58
- const limit = Number.isFinite(limitArg) && limitArg > 0 ? Math.trunc(limitArg) : null;
59
-
60
- const pool = loadPool();
61
- const client = await pool.connect();
62
- let changed = 0;
63
- let alreadyCorrect = 0;
64
- let scanned = 0;
65
- let deltaTotal = 0;
66
- const examples = [];
67
-
68
- try {
69
- const params = [];
70
- let where = 'WHERE sr.session_id IS NOT NULL';
71
- if (builderArg) { params.push(builderArg); where += ` AND sr.builder_id = $${params.length}`; }
72
- let sql = `SELECT sr.session_id, sr.builder_id, sr.task_ids, sr.drachmae_earned,
73
- b.github_login
74
- FROM session_records sr
75
- JOIN builders b ON b.id = sr.builder_id
76
- ${where}
77
- ORDER BY sr.uploaded_at DESC`;
78
- if (limit) { params.push(limit); sql += ` LIMIT $${params.length}`; }
79
-
80
- const { rows } = await client.query(sql, params);
81
- scanned = rows.length;
82
-
83
- for (const r of rows) {
84
- const ids = Array.isArray(r.task_ids)
85
- ? r.task_ids.map((n) => Number(n)).filter(Number.isFinite)
86
- : [];
87
- // The same two-key sum the live path uses — one definition, so a repaired
88
- // row and a freshly-synced row can never disagree.
89
- const truth = await credits.sumSessionEarnings(client, r.builder_id, ids, r.session_id);
90
- const was = Number(r.drachmae_earned) || 0;
91
- if (truth === was) { alreadyCorrect++; continue; }
92
- changed++;
93
- deltaTotal += (truth - was);
94
- if (examples.length < 15) {
95
- examples.push(` ${String(r.github_login).padEnd(18)} ${r.session_id.slice(0, 8)} ${was} → ${truth}`);
96
- }
97
- if (apply) {
98
- await client.query(
99
- `UPDATE session_records SET drachmae_earned = $3
100
- WHERE session_id = $1 AND builder_id = $2`,
101
- [r.session_id, r.builder_id, truth]
102
- );
103
- }
104
- }
105
- } finally {
106
- client.release();
107
- await pool.end().catch(() => {});
108
- }
109
-
110
- console.log(`\nsession-earnings backfill — ${apply ? 'APPLIED' : 'DRY RUN (no writes)'}`);
111
- console.log(` sessions scanned ${scanned}`);
112
- console.log(` already correct ${alreadyCorrect}`);
113
- console.log(` ${apply ? 'repaired' : 'would repair'}${apply ? ' ' : ' '}${changed}`);
114
- console.log(` net mirror change ${deltaTotal >= 0 ? '+' : ''}${deltaTotal} drachmae of DISPLAY (no money moved)`);
115
- if (examples.length > 0) {
116
- console.log(`\n sample rows:\n${examples.join('\n')}`);
117
- }
118
- if (!apply && changed > 0) {
119
- console.log(`\n re-run with --apply to write these.`);
120
- }
121
- }
122
-
123
- main().catch((err) => { console.error(err); process.exit(1); });
@@ -1,87 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // scripts/bongos/backfill-session-types.js — classify the sessions that predate the
5
- // classifier (task 1003975, from idea 1001033).
6
- //
7
- // WHAT THIS IS, and what it is NOT. It writes ONE column, `session_records.session_type`,
8
- // and only where that column is NULL. It moves no money, books no reward, touches
9
- // no `task_ids` and creates no attribution. That separation is deliberate and it
10
- // is the lesson this module already paid for once: the attribution sweep had to be
11
- // windowed because it ran on the same tick as a payout and would have minted a mass
12
- // retroactive payment nobody authorised (see the warning in modules/sessions/CLAUDE.md).
13
- // A sweep that both labels and pays is the wrong shape whatever its intent, so this
14
- // one cannot pay even in principle — db.setSessionType writes that column alone.
15
- //
16
- // WHY IT IS NEEDED. The upload path classifies every session from now on, but the
17
- // corpus is ~4,600 rows old and none of them carry a verdict. Without this pass the
18
- // ledger's new filter would only ever see today's sessions, which is exactly the
19
- // half of the corpus nobody needs help reading.
20
- //
21
- // SAFETY. DRY-RUN BY DEFAULT: with no flags it classifies in memory, prints the
22
- // distribution it WOULD write, and writes nothing. `--apply` performs the UPDATEs.
23
- // Idempotent by construction: the verdict is a pure function of the row's own
24
- // stored digest, so a re-run lands on the same answer, and a row that already has
25
- // a type is never revisited (the query selects `WHERE session_type IS NULL`).
26
- // `--limit N` bounds one pass so the first apply can be small and checked.
27
- //
28
- // Run: node scripts/bongos/backfill-session-types.js [--limit N]
29
- // node scripts/bongos/backfill-session-types.js --apply
30
-
31
- const { classifySession, SESSION_TYPES } = require('../../modules/sessions/session-type');
32
- const db = require('../../modules/sessions/db');
33
- const { arg, hasFlag } = require('./cli-lib');
34
-
35
- const BATCH = 500;
36
-
37
- async function main() {
38
- const apply = hasFlag('--apply');
39
- const limitArg = Number(arg('--limit'));
40
- const cap = Number.isFinite(limitArg) && limitArg > 0 ? Math.trunc(limitArg) : Infinity;
41
-
42
- const tally = Object.fromEntries(SESSION_TYPES.map((t) => [t, 0]));
43
- let scanned = 0;
44
- let written = 0;
45
-
46
- // Paged rather than one big SELECT: `detail` is a jsonb per row and the corpus
47
- // is the largest table this module owns, so pulling it whole would hold the
48
- // entire transcript corpus in memory at once for no gain.
49
- for (;;) {
50
- const room = Math.min(BATCH, cap - scanned);
51
- if (room <= 0) break;
52
- const rows = await db.unclassifiedSessions(room);
53
- if (rows.length === 0) break;
54
- for (const row of rows) {
55
- const type = classifySession({ detail: row.detail, metrics: row.metrics });
56
- tally[type] = (tally[type] || 0) + 1;
57
- scanned++;
58
- if (apply) written += await db.setSessionType(row.id, type);
59
- }
60
- // A dry run never writes, so the same unclassified page comes back forever.
61
- // One page is enough to show the shape; say so rather than looping.
62
- if (!apply) break;
63
- }
64
-
65
- console.log(`\nsession-type backfill — ${apply ? 'APPLIED' : 'DRY RUN (no writes)'}`);
66
- console.log(` rows classified ${scanned}`);
67
- if (apply) console.log(` rows written ${written}`);
68
- console.log(` distribution:`);
69
- for (const t of SESSION_TYPES) {
70
- const n = tally[t] || 0;
71
- const pct = scanned ? ` (${Math.round((n / scanned) * 100)}%)` : '';
72
- console.log(` ${t.padEnd(14)} ${String(n).padStart(6)}${pct}`);
73
- }
74
-
75
- if (apply) {
76
- console.log(`\n corpus now:`);
77
- for (const r of await db.sessionTypeCounts()) {
78
- console.log(` ${String(r.type).padEnd(14)} ${String(r.n).padStart(6)}`);
79
- }
80
- } else if (scanned > 0) {
81
- console.log(`\n dry run reads one page of ${BATCH}; re-run with --apply to write and walk the whole corpus.`);
82
- }
83
- }
84
-
85
- main()
86
- .then(() => process.exit(0))
87
- .catch((err) => { console.error(err); process.exit(1); });
@@ -1,94 +0,0 @@
1
- #!/usr/bin/env node
2
- // scripts/bongos/build-bongos.js — compile the standalone `bongos` CLI binaries
3
- // (GDS-V4 · V4.R81 · task 1248). CI (.github/workflows/build-bongos-cli.yml) runs
4
- // this; a maintainer can run it locally too.
5
- //
6
- // Uses `bun build --compile`, which CROSS-compiles every target from a single
7
- // host (mac arm64/x64, linux x64/arm64, windows x64) — no per-OS runner matrix.
8
- // The binary is fully self-contained: no Node, no repo needed at runtime. The
9
- // on-ramp verbs (login/box/shell/code/init/reauth) are bundled + dispatched
10
- // in-process by bin/bongos.js (its COMPILED branch); work verbs print how to get
11
- // a real environment.
12
- //
13
- // node scripts/bongos/build-bongos.js # all targets → dist/
14
- // node scripts/bongos/build-bongos.js --target mac-arm64
15
- // node scripts/bongos/build-bongos.js --outdir /tmp/out
16
- //
17
- // Output filenames match config/bongos-cli.json's `assets` exactly (so the
18
- // /downloads/bongos redirects resolve after `gh release create`). Version comes
19
- // from that same config — the single source of truth for a release.
20
-
21
- 'use strict';
22
-
23
- const fs = require('node:fs');
24
- const path = require('node:path');
25
- const { spawnSync } = require('node:child_process');
26
- const { arg } = require('./cli-lib');
27
-
28
- const REPO_ROOT = path.join(__dirname, '..', '..');
29
- const ENTRY = path.join(REPO_ROOT, 'bin', 'bongos.js');
30
- const cfg = require(path.join(REPO_ROOT, 'config', 'bongos-cli.json'));
31
- const VERSION = cfg.version;
32
-
33
- // target key (matches config assets) → { bunTarget, asset filename }
34
- const TARGETS = {
35
- 'mac-arm64': { bun: 'bun-darwin-arm64', file: cfg.assets['mac-arm64'] },
36
- 'mac-x64': { bun: 'bun-darwin-x64', file: cfg.assets['mac-x64'] },
37
- 'linux-x64': { bun: 'bun-linux-x64', file: cfg.assets['linux-x64'] },
38
- 'linux-arm64': { bun: 'bun-linux-arm64', file: cfg.assets['linux-arm64'] },
39
- 'win-x64': { bun: 'bun-windows-x64', file: cfg.assets['win-x64'] },
40
- };
41
-
42
- function bunPresent() {
43
- const r = spawnSync('bun', ['--version'], { encoding: 'utf8', shell: process.platform === 'win32' });
44
- return !!r && !r.error && r.status === 0;
45
- }
46
-
47
- function build(one, outDir) {
48
- const t = TARGETS[one];
49
- if (!t) throw new Error(`unknown target "${one}" (known: ${Object.keys(TARGETS).join(', ')})`);
50
- if (!t.file) throw new Error(`config/bongos-cli.json has no asset for target "${one}"`);
51
- const outfile = path.join(outDir, t.file);
52
- console.log(` building ${one} → ${path.relative(REPO_ROOT, outfile)} (${t.bun})`);
53
- const r = spawnSync(
54
- 'bun',
55
- ['build', '--compile', `--target=${t.bun}`, ENTRY, '--outfile', outfile],
56
- { stdio: 'inherit', cwd: REPO_ROOT, shell: process.platform === 'win32' }
57
- );
58
- if (!r || r.error || r.status !== 0) {
59
- throw new Error(`bun build failed for ${one}${r && r.error ? `: ${r.error.message}` : ` (exit ${r ? r.status : '?'})`}`);
60
- }
61
- return outfile;
62
- }
63
-
64
- function main() {
65
- if (!bunPresent()) {
66
- console.error('✖ `bun` is required to compile the standalone binary but was not found.');
67
- console.error(' Install it (https://bun.sh) — e.g. `curl -fsSL https://bun.sh/install | bash` —');
68
- console.error(' or in CI use the oven-sh/setup-bun action. Then re-run.');
69
- process.exit(1);
70
- }
71
- const outDir = arg('--outdir') || path.join(REPO_ROOT, 'dist');
72
- fs.mkdirSync(outDir, { recursive: true });
73
- const only = arg('--target');
74
- const targets = only ? [only] : Object.keys(TARGETS);
75
-
76
- console.log(`bongos build — version ${VERSION}, ${targets.length} target(s) → ${path.relative(REPO_ROOT, outDir) || '.'}`);
77
- const built = [];
78
- for (const t of targets) built.push(build(t, outDir));
79
-
80
- console.log(`\n✓ Built ${built.length} binary(ies):`);
81
- for (const f of built) {
82
- let size = '';
83
- try { size = ` (${(fs.statSync(f).size / 1e6).toFixed(1)} MB)`; } catch { /* ignore */ }
84
- console.log(` ${path.relative(REPO_ROOT, f)}${size}`);
85
- }
86
- console.log('\nNext: publish these as assets on a `v' + VERSION + '` release of the public releases repo');
87
- console.log('(config/bongos-cli.json → releases_repo). See docs/recipes/bongos-cli-release.md.');
88
- }
89
-
90
- if (require.main === module) {
91
- try { main(); } catch (e) { console.error(`✖ ${e.message}`); process.exit(1); }
92
- }
93
-
94
- module.exports = { TARGETS, VERSION };
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env node
2
- // Mark an orphan task as 'abandoned' with an audit value_summary.
3
- //
4
- // Used when a task has been superseded by a different task (e.g. reclassified
5
- // into a different version, replaced by a follow-up with full scope) and
6
- // should stop inflating the version's total_count.
7
- //
8
- // Refuses to abandon anything but a 'backlog' task — once a task has been
9
- // claimed, confirmed, or shipped, abandoning it would corrupt the audit
10
- // trail. Use a real lifecycle transition instead.
11
- //
12
- // Usage:
13
- // node scripts/bongos/cleanup-orphans.js <task-id> --reason "Superseded by #48 (P6)"
14
- //
15
- // Audit log (one-shot abandonments via this script):
16
- // - #12 (2026-05-10) — placeholder for 'themed /builders web UI'; superseded
17
- // by P6 (#48). Original task was carried over from
18
- // PMS-V1 reclassification and never picked up.
19
- //
20
- // When adding a new orphan, append a line to the audit log above so a future
21
- // reader can answer "why was this abandoned" without spelunking the DB.
22
-
23
- const { pool } = require('../../src/bongos/pool');
24
- const { arg } = require('./cli-lib');
25
-
26
-
27
- async function main() {
28
- const args = process.argv.slice(2);
29
- const taskId = Number(args[0]);
30
- const reason = arg('--reason', args);
31
- if (!Number.isFinite(taskId) || !reason) {
32
- console.error('usage: node scripts/bongos/cleanup-orphans.js <task-id> --reason "<text>"');
33
- process.exit(2);
34
- }
35
-
36
- const { rows: before } = await pool.query(
37
- `SELECT id, title, status, version_id FROM tasks WHERE id = $1`,
38
- [taskId]
39
- );
40
- if (before.length === 0) {
41
- console.error(`Task #${taskId} not found.`);
42
- process.exit(1);
43
- }
44
- const task = before[0];
45
- if (task.status !== 'backlog') {
46
- console.error(`Refusing: task #${taskId} status is '${task.status}', not 'backlog'.`);
47
- console.error('Abandoning a non-backlog task would corrupt the audit trail.');
48
- console.error('Use a real lifecycle transition instead.');
49
- process.exit(1);
50
- }
51
-
52
- console.log(`Before: #${task.id} [${task.version_id}] ${task.status} — ${task.title}`);
53
-
54
- const { rows: after } = await pool.query(
55
- `UPDATE tasks
56
- SET status = 'abandoned',
57
- value_summary = $2,
58
- updated_at = now()
59
- WHERE id = $1 AND status = 'backlog'
60
- RETURNING id, status, value_summary`,
61
- [taskId, reason]
62
- );
63
- if (after.length === 0) {
64
- console.error('UPDATE matched 0 rows — race with concurrent change?');
65
- process.exit(1);
66
- }
67
- console.log(`After: #${after[0].id} ${after[0].status} — ${after[0].value_summary}`);
68
- await pool.end();
69
- }
70
-
71
- main().catch((err) => {
72
- console.error('fatal:', err);
73
- process.exit(1);
74
- });