@bongos/core 1.21.174 → 1.21.176

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 (1744) hide show
  1. package/.bongos-core.json +3565 -1515
  2. package/.claude/skills/ask-for-help/SKILL.md +4 -4
  3. package/.claude/skills/backlog-review/SKILL.md +1 -1
  4. package/.claude/skills/blocker-review/SKILL.md +2 -2
  5. package/.claude/skills/blocker-solve/SKILL.md +4 -4
  6. package/.claude/skills/bongos-feedback/SKILL.md +1 -1
  7. package/.claude/skills/bug-triage/SKILL.md +8 -8
  8. package/.claude/skills/builder-backup/SKILL.md +3 -3
  9. package/.claude/skills/builder-claim/SKILL.md +5 -5
  10. package/.claude/skills/builder-cost/SKILL.md +5 -5
  11. package/.claude/skills/builder-end/SKILL.md +6 -6
  12. package/.claude/skills/builder-exit/SKILL.md +2 -2
  13. package/.claude/skills/builder-key/SKILL.md +6 -6
  14. package/.claude/skills/builder-reauth/SKILL.md +4 -4
  15. package/.claude/skills/builder-redteam/SKILL.md +3 -3
  16. package/.claude/skills/builder-release/SKILL.md +3 -3
  17. package/.claude/skills/builder-sequence/SKILL.md +8 -8
  18. package/.claude/skills/builder-setup/SKILL.md +4 -4
  19. package/.claude/skills/builder-ship/SKILL.md +7 -7
  20. package/.claude/skills/builder-stage/SKILL.md +8 -8
  21. package/.claude/skills/builder-start/SKILL.md +4 -4
  22. package/.claude/skills/collab-review/SKILL.md +5 -5
  23. package/.claude/skills/design/SKILL.md +6 -4
  24. package/.claude/skills/design-sync/SKILL.md +3 -3
  25. package/.claude/skills/figma-design-sync/SKILL.md +4 -4
  26. package/.claude/skills/fix-task/SKILL.md +8 -8
  27. package/.claude/skills/goal-close/SKILL.md +9 -9
  28. package/.claude/skills/goal-create/SKILL.md +18 -18
  29. package/.claude/skills/grade-recover/SKILL.md +8 -8
  30. package/.claude/skills/grade-sweep/SKILL.md +15 -15
  31. package/.claude/skills/idea-triage/SKILL.md +15 -15
  32. package/.claude/skills/merge-mode/SKILL.md +14 -14
  33. package/.claude/skills/new-project/SKILL.md +5 -5
  34. package/.claude/skills/owner-review/SKILL.md +1 -1
  35. package/.claude/skills/planning-session/SKILL.md +14 -14
  36. package/.claude/skills/priority-session/SKILL.md +6 -6
  37. package/.claude/skills/read-session-export/SKILL.md +3 -3
  38. package/.claude/skills/recall/SKILL.md +7 -7
  39. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  40. package/.claude/skills/session-handoff/SKILL.md +1 -1
  41. package/.claude/skills/ship-check/SKILL.md +3 -3
  42. package/.claude/skills/status/SKILL.md +3 -3
  43. package/.claude/skills/strand-fix/SKILL.md +6 -6
  44. package/.claude/skills/worktree-clean/SKILL.md +4 -4
  45. package/.gitattributes +12 -32
  46. package/GOVERNMENT.md +1 -1
  47. package/README.md +8 -8
  48. package/bin/bongos.js +23 -23
  49. package/clients/bongos-client/README.md +2 -2
  50. package/clients/bongos-client/bongos-client.global.js +22 -4
  51. package/clients/bongos-client/index.cjs +22 -4
  52. package/clients/bongos-client/index.d.ts +33 -4
  53. package/clients/bongos-client/index.mjs +21 -3
  54. package/config/branding.neutral.json +1 -1
  55. package/config/design-tokens.schema.json +1 -1
  56. package/config/modules.neutral.json +1 -3
  57. package/docs/adr/0029-status-page-outage-resilience.md +6 -6
  58. package/docs/adr/0227-a-task-network-map-is-refused-the-goal-graph-is-the-map.md +1 -1
  59. package/docs/adr/0294-cli-sessions-do-not-expire.md +1 -1
  60. package/docs/adr/0383-sessions-end-after-ten-idle-days.md +35 -0
  61. package/docs/adr/0384-the-raise-page-is-a-hub-module-builders-edit-in-place.md +31 -0
  62. package/docs/adr/README.md +2 -0
  63. package/docs/api/openapi.json +606 -44
  64. package/docs/api-reference.md +25 -12
  65. package/docs/architecture.md +8 -7
  66. package/docs/canonical-permissions.md +3 -3
  67. package/docs/copy-inventory.md +1389 -1437
  68. package/docs/copy-registry.json +2160 -2634
  69. package/docs/design/demonolith-plan.md +6 -6
  70. package/docs/design/modular-architecture/00-research-report.md +1 -1
  71. package/docs/design/project-startup-direction.md +2 -2
  72. package/docs/design/projects-hub-direction-v2.md +1 -1
  73. package/docs/design/reviews/hall-v2/README.md +2 -2
  74. package/docs/design/vanilla-hall-ui-redesign-scope.md +1 -1
  75. package/docs/file-map.md +89 -88
  76. package/docs/handoff-template.md +4 -4
  77. package/docs/module-api-changelog.md +6 -2
  78. package/docs/modules-contract.md +8 -7
  79. package/docs/onboarding/diagrams/01-task-lifecycle.mmd +1 -1
  80. package/docs/onboarding/diagrams/02-rank-ladder.mmd +1 -1
  81. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +1 -1
  82. package/docs/onboarding/diagrams/04-architecture.mmd +1 -1
  83. package/docs/onboarding/diagrams/05-versioning.mmd +1 -1
  84. package/docs/onboarding/diagrams/README.md +2 -2
  85. package/docs/onboarding/diagrams/assertions.json +2 -2
  86. package/docs/onboarding/slash-commands.md +2 -2
  87. package/docs/packs/artist.md +4 -4
  88. package/docs/packs/engineer.md +11 -10
  89. package/docs/packs/ideator.md +7 -7
  90. package/docs/page-inventory.json +25 -1
  91. package/docs/page-readings.json +4388 -4602
  92. package/docs/recipes/README.md +1 -1
  93. package/docs/recipes/audit-replay.md +4 -4
  94. package/docs/recipes/autobongos-windows-host.md +6 -6
  95. package/docs/recipes/bongos-cli-release.md +2 -2
  96. package/docs/recipes/claude-design-loop.md +7 -7
  97. package/docs/recipes/core-release-pipeline.md +19 -19
  98. package/docs/recipes/failed-ship-recovery-proof.md +2 -2
  99. package/docs/recipes/figma-design-loop.md +6 -6
  100. package/docs/recipes/gds-db-backup.md +9 -9
  101. package/docs/recipes/instance-deploy.md +3 -3
  102. package/docs/recipes/instance-first-run.md +1 -1
  103. package/docs/recipes/multi-builder-merge.md +2 -2
  104. package/docs/recipes/ops-gotchas.md +10 -9
  105. package/docs/recipes/packaging-the-core.md +6 -6
  106. package/docs/recipes/parallel-goal-waves.md +4 -4
  107. package/docs/recipes/private-npm-distribution.md +9 -9
  108. package/docs/recipes/redteam-patrol.md +5 -5
  109. package/docs/recipes/render-pilot.md +2 -2
  110. package/docs/recipes/reranking-a-goals-board.md +2 -2
  111. package/docs/recipes/search-index-ingestion.md +5 -5
  112. package/docs/recipes/self-host.md +1 -1
  113. package/docs/recipes/ship-and-regrade.md +4 -4
  114. package/docs/recipes/staging-environment.md +1 -1
  115. package/docs/recipes/standalone-live-docs.md +1 -1
  116. package/docs/recipes/ui-look-before-you-ship.md +2 -2
  117. package/docs/recipes/upgrading-the-core.md +11 -11
  118. package/docs/recipes/windows-builders.md +18 -18
  119. package/docs/research/llm-model-agnostic-and-cheaper-grader.md +6 -6
  120. package/docs/research/task-network-map-readability.md +3 -3
  121. package/migrations/core_278_builder_tester_tag.sql +18 -0
  122. package/migrations/core_279_bongos_shipper_new_scripts_path.sql +13 -0
  123. package/modules/agents/lib/answer-hold.js +1 -1
  124. package/modules/agents/lib/gate.js +1 -1
  125. package/modules/agents/lib/validate.js +1 -1
  126. package/modules/autonomy/gauge.js +1 -1
  127. package/modules/autonomy/governor-docket.js +2 -2
  128. package/modules/autonomy/pollers/routine-timers.js +3 -3
  129. package/modules/autonomy/routes/autonomy.js +3 -3
  130. package/modules/builder-settings/interaction-prefs.js +1 -1
  131. package/modules/builder-settings/render-prefs.js +1 -1
  132. package/modules/builder-settings/routes/settings.js +1 -1
  133. package/modules/builder-settings/skill-prefs.js +2 -2
  134. package/modules/builder-settings/wandering-prefs.js +2 -2
  135. package/modules/copy-desk/module.json +2 -2
  136. package/modules/copy-desk/page-data.js +5 -5
  137. package/modules/copy-desk/page-decisions.js +13 -1
  138. package/modules/copy-desk/proposals.js +4 -4
  139. package/modules/copy-desk/registry.js +2 -2
  140. package/modules/copy-desk/routes/copy-desk-release.js +119 -0
  141. package/modules/copy-desk/routes/copy-desk.js +3 -12
  142. package/modules/copy-desk/skills/tweak/SKILL.md +12 -12
  143. package/modules/copy-desk/tests/copy_flags.mjs +1 -1
  144. package/modules/copy-desk/tests/copy_no_cms.mjs +7 -3
  145. package/modules/copy-desk/tests/copy_proposals.mjs +2 -2
  146. package/modules/copy-desk/tests/copy_queue.mjs +1 -1
  147. package/modules/design-styles/skills/README.md +4 -4
  148. package/modules/design-styles/skills/imagegen-frontend-mobile/SKILL.md +1 -1
  149. package/modules/design-styles/skills/imagegen-frontend-web/SKILL.md +1 -1
  150. package/modules/discord/bug-attachments.js +1 -1
  151. package/modules/discord/ship-broadcast.js +1 -1
  152. package/modules/economy/achievements.js +49 -7
  153. package/modules/economy/cost-classify.js +6 -6
  154. package/modules/economy/cost-report.js +1 -1
  155. package/modules/economy/cost.js +1 -1
  156. package/modules/economy/credits.js +2 -1
  157. package/modules/economy/idea-size.js +2 -2
  158. package/modules/economy/reward.js +2 -0
  159. package/modules/economy/routes/cost.js +1 -1
  160. package/modules/economy/streak.js +43 -4
  161. package/modules/government/asks.js +1 -1
  162. package/modules/government/board.js +19 -2
  163. package/modules/government/catalog.js +3 -0
  164. package/modules/government/migrations/government_033_idea_vote.sql +46 -0
  165. package/modules/government/protected-surfaces.json +48 -47
  166. package/modules/government/recommendations.js +6 -2
  167. package/modules/government/routes/government.js +1 -1
  168. package/modules/grading/generated-provenance.js +13 -5
  169. package/modules/grading/grade-engine.js +1 -1
  170. package/modules/grading/grader-rubric.json +1 -1
  171. package/modules/grading/grader-score.js +1 -1
  172. package/modules/grading/grader-workers/index.js +1 -1
  173. package/modules/grading/grader.js +1 -1
  174. package/modules/grading/routes/grade.js +1 -1
  175. package/modules/hall-ui/public/atlas.html +5 -7
  176. package/modules/hall-ui/public/atlas.js +1 -1
  177. package/modules/hall-ui/public/atlas.states.json +1 -1
  178. package/modules/hall-ui/public/blockers.css +9 -0
  179. package/modules/hall-ui/public/blockers.html +6 -4
  180. package/modules/hall-ui/public/blockers.js +39 -27
  181. package/modules/hall-ui/public/board-room.css +5 -12
  182. package/modules/hall-ui/public/board-room.html +6 -6
  183. package/modules/hall-ui/public/board-room.js +41 -23
  184. package/modules/hall-ui/public/board-room.states.json +1 -1
  185. package/modules/hall-ui/public/brand-apply.js +1 -1
  186. package/modules/hall-ui/public/brand-holes.js +1 -1
  187. package/modules/hall-ui/public/builders.js +40 -86
  188. package/modules/hall-ui/public/city-decide.js +18 -4
  189. package/modules/hall-ui/public/city.html +1 -1
  190. package/modules/hall-ui/public/collab.html +1 -1
  191. package/modules/hall-ui/public/commands.html +6 -9
  192. package/modules/hall-ui/public/copy-desk.html +1 -1
  193. package/modules/hall-ui/public/copy-desk.js +2 -2
  194. package/modules/hall-ui/public/craft-mode.js +4 -0
  195. package/modules/hall-ui/public/deploy.html +6 -2
  196. package/modules/hall-ui/public/deploy.js +21 -13
  197. package/modules/hall-ui/public/diagrams.css +1 -1
  198. package/modules/hall-ui/public/diagrams.html +5 -8
  199. package/modules/hall-ui/public/diagrams.states.json +1 -1
  200. package/modules/hall-ui/public/drachmae.html +3 -7
  201. package/modules/hall-ui/public/fleet.html +3 -2
  202. package/modules/hall-ui/public/fleet.js +0 -4
  203. package/modules/hall-ui/public/gate.html +7 -7
  204. package/modules/hall-ui/public/gate.js +58 -77
  205. package/modules/hall-ui/public/goal-inbox.js +69 -86
  206. package/modules/hall-ui/public/goal-map.html +1 -1
  207. package/modules/hall-ui/public/goals-page.js +5 -5
  208. package/modules/hall-ui/public/goals-render.js +10 -11
  209. package/modules/hall-ui/public/goals.css +10 -0
  210. package/modules/hall-ui/public/goals.html +14 -7
  211. package/modules/hall-ui/public/government.html +3 -5
  212. package/modules/hall-ui/public/government.js +1 -5
  213. package/modules/hall-ui/public/hall-ask.css +57 -0
  214. package/modules/hall-ui/public/hall-ask.js +50 -0
  215. package/modules/hall-ui/public/hall-render.js +117 -57
  216. package/modules/hall-ui/public/hall-widgets.js +11 -11
  217. package/modules/hall-ui/public/idea.html +1 -1
  218. package/modules/hall-ui/public/ideas.html +3 -1
  219. package/modules/hall-ui/public/ideas.js +1 -0
  220. package/modules/hall-ui/public/index.html +15 -6
  221. package/modules/hall-ui/public/index.states.json +1 -1
  222. package/modules/hall-ui/public/mine-lens.js +1 -1
  223. package/modules/hall-ui/public/modules.html +7 -10
  224. package/modules/hall-ui/public/modules.js +0 -2
  225. package/modules/hall-ui/public/my-agents.html +1 -1
  226. package/modules/hall-ui/public/palette.js +5 -5
  227. package/modules/hall-ui/public/primer.html +4 -9
  228. package/modules/hall-ui/public/profile-connections.js +10 -2
  229. package/modules/hall-ui/public/profile-roles.js +3 -10
  230. package/modules/hall-ui/public/profile.html +12 -10
  231. package/modules/hall-ui/public/profile.js +13 -17
  232. package/modules/hall-ui/public/project-settings.html +3 -4
  233. package/modules/hall-ui/public/project-settings.js +0 -3
  234. package/modules/hall-ui/public/ranks.html +5 -11
  235. package/modules/hall-ui/public/ranks.js +6 -8
  236. package/modules/hall-ui/public/roadmap.css +0 -2
  237. package/modules/hall-ui/public/roadmap.html +1 -1
  238. package/modules/hall-ui/public/roadmap.js +16 -51
  239. package/modules/hall-ui/public/roster.html +1 -1
  240. package/modules/hall-ui/public/sessions.html +6 -8
  241. package/modules/hall-ui/public/sessions.js +7 -7
  242. package/modules/hall-ui/public/settings.html +1 -1
  243. package/modules/hall-ui/public/shell-trail.js +1 -1
  244. package/modules/hall-ui/public/shell.js +17 -17
  245. package/modules/hall-ui/public/street-deck.css +2 -1
  246. package/modules/hall-ui/public/street-deck.js +10 -2
  247. package/modules/hall-ui/public/street-desk.js +16 -5
  248. package/modules/hall-ui/public/street.html +1 -1
  249. package/modules/hall-ui/public/studio-lib.js +4 -0
  250. package/modules/hall-ui/public/studio.css +2 -0
  251. package/modules/hall-ui/public/studio.html +1 -1
  252. package/modules/hall-ui/public/studio.js +27 -1
  253. package/modules/hall-ui/public/style.css +43 -26
  254. package/modules/hall-ui/public/task-detail.js +10 -7
  255. package/modules/hall-ui/public/task.css +2 -0
  256. package/modules/hall-ui/public/task.html +3 -1
  257. package/modules/hall-ui/public/task.js +23 -7
  258. package/modules/hall-ui/public/thinking.html +1 -1
  259. package/modules/hall-ui/public/tweak-editor.html +1 -1
  260. package/modules/hall-ui/public/vote-control.js +208 -0
  261. package/modules/hall-ui/public/watch.html +3 -5
  262. package/modules/hall-ui/public/watch.js +5 -4
  263. package/modules/hall-ui/public/welcome-boot.css +130 -0
  264. package/modules/hall-ui/public/welcome-boot.js +334 -0
  265. package/modules/hall-ui/public/welcome-day.webp +0 -0
  266. package/modules/hall-ui/public/welcome-night.webp +0 -0
  267. package/modules/hall-ui/public/work-summary.js +1 -1
  268. package/modules/hall-ui/public/work.css +1 -0
  269. package/modules/hall-ui/public/work.html +3 -1
  270. package/modules/hall-ui/public/work.js +2 -1
  271. package/modules/hall-ui/records/accomplishments.md +16 -0
  272. package/modules/hall-ui/records/hall-ask-card.md +33 -0
  273. package/modules/hall-ui/records/karma-vote-control.md +13 -0
  274. package/modules/hall-ui/records/oversight-family.md +1 -1
  275. package/modules/hall-ui/records/profile-connections.md +2 -0
  276. package/modules/hall-ui/records/profile-roles.md +1 -1
  277. package/modules/hall-ui/records/reading-rooms.md +1 -1
  278. package/modules/hall-ui/records/welcome-tower.md +50 -0
  279. package/modules/ideas/migrations/ideas_011_idea_votes.sql +31 -0
  280. package/modules/ideas/projection.js +1 -1
  281. package/modules/ideas/routes/blockers.js +3 -3
  282. package/modules/ideas/routes/inbox.js +29 -1
  283. package/modules/ideas/routes/ratify-goal.js +1 -1
  284. package/modules/ideas/routing.js +1 -1
  285. package/modules/ideas/templates.js +1 -1
  286. package/modules/ideas/trail-descent.js +1 -1
  287. package/modules/ideas/trail-size.js +1 -1
  288. package/modules/ideas/votes.js +93 -0
  289. package/modules/lifecycle/abandon-leftovers.js +1 -1
  290. package/modules/lifecycle/cascade.js +1 -1
  291. package/modules/lifecycle/conflict-resolve.js +13 -21
  292. package/modules/lifecycle/criterion-ref.js +1 -1
  293. package/modules/lifecycle/db-analytics.js +57 -4
  294. package/modules/lifecycle/db-deps-criteria.js +1 -1
  295. package/modules/lifecycle/db-ship.js +2 -2
  296. package/modules/lifecycle/db-tasks.js +2 -2
  297. package/modules/lifecycle/db-versions.js +1 -1
  298. package/modules/lifecycle/db.js +2 -0
  299. package/modules/lifecycle/dead-deps.js +3 -3
  300. package/modules/lifecycle/dependency-advisory.js +3 -3
  301. package/modules/lifecycle/goal-category.js +1 -1
  302. package/modules/lifecycle/goal-forest.js +1 -1
  303. package/modules/lifecycle/goal-task-relevance-advisory.js +1 -1
  304. package/modules/lifecycle/kickoff-checklist.js +1 -1
  305. package/modules/lifecycle/kickoff-seed.js +1 -1
  306. package/modules/lifecycle/lifecycle.js +2 -0
  307. package/modules/lifecycle/merge-reach.js +29 -15
  308. package/modules/lifecycle/missing-dep-classify.js +3 -3
  309. package/modules/lifecycle/module.json +2 -1
  310. package/modules/lifecycle/page-tweak-approve.js +85 -1
  311. package/modules/lifecycle/page-tweak-hold.js +1 -1
  312. package/modules/lifecycle/publish-reconciler.js +1 -2
  313. package/modules/lifecycle/rot.js +1 -1
  314. package/modules/lifecycle/routes/artist-gate.js +1 -1
  315. package/modules/lifecycle/routes/gate-approvals.js +22 -1
  316. package/modules/lifecycle/routes/goals.js +1 -1
  317. package/modules/lifecycle/routes/task-route-helpers.js +1 -1
  318. package/modules/lifecycle/routes/task-votes.js +54 -0
  319. package/modules/lifecycle/routes/task-write-routes.js +1 -1
  320. package/modules/lifecycle/routes/tasks.js +2 -2
  321. package/modules/lifecycle/routes/versions.js +2 -2
  322. package/modules/lifecycle/ship-card.js +4 -4
  323. package/modules/lifecycle/ship-preflight.js +1 -1
  324. package/modules/lifecycle/task-classifier.js +1 -1
  325. package/modules/lifecycle/task-status.js +1 -1
  326. package/modules/lifecycle/task-visual-db.js +1 -1
  327. package/modules/memory/learnings.js +1 -1
  328. package/modules/memory/pollers/search-index.js +2 -2
  329. package/modules/memory/routes/learnings.js +1 -1
  330. package/modules/memory/routes/memory.js +1 -1
  331. package/modules/memory/search.js +2 -2
  332. package/modules/npm-release/release.js +1 -1
  333. package/modules/onboarding/howto-moments.js +1 -1
  334. package/modules/onboarding/newcomer-restock.js +3 -3
  335. package/modules/onboarding/onboarding.js +1 -1
  336. package/modules/pixel-art/skills/otb-tile-generate/SKILL.md +1 -1
  337. package/modules/platform-identity/origin-containment.js +1 -1
  338. package/modules/platform-identity/publish-gate.js +1 -1
  339. package/modules/platform-identity/tests/platform-identity.mjs +1 -1
  340. package/modules/provisioning/capacity.js +1 -1
  341. package/modules/provisioning/core-upgrade.js +15 -9
  342. package/modules/provisioning/credential-preflight.js +3 -3
  343. package/modules/provisioning/disconnect.js +1 -1
  344. package/modules/provisioning/dns-resolves.js +1 -1
  345. package/modules/provisioning/module.json +1 -1
  346. package/modules/provisioning/onboard-plan.js +1 -1
  347. package/modules/provisioning/paid-shape-gate.js +2 -2
  348. package/modules/provisioning/planet-physics.js +11 -2
  349. package/modules/provisioning/pollers/liveness-sweep.js +1 -1
  350. package/modules/provisioning/pollers/runner-drift-notify.js +5 -5
  351. package/modules/provisioning/provisioning.js +2 -2
  352. package/modules/provisioning/render-lookup.js +1 -1
  353. package/modules/provisioning/render-standup.js +3 -3
  354. package/modules/provisioning/repo-private.js +1 -1
  355. package/modules/provisioning/routes/callback-page.js +1 -1
  356. package/modules/provisioning/routes/core-upgrade.js +23 -3
  357. package/modules/provisioning/routes/provisioning.js +2 -2
  358. package/modules/provisioning/routes/render-standup.js +1 -1
  359. package/modules/provisioning/routes/repo-private.js +1 -1
  360. package/modules/provisioning/soft-limits.js +1 -1
  361. package/modules/provisioning/starter-bundles.js +4 -2
  362. package/modules/provisioning/tests/provisioning.mjs +1 -1
  363. package/modules/public-landing/public/account.html +4 -6
  364. package/modules/public-landing/public/assets/cosmos.css +13 -6
  365. package/modules/public-landing/public/connections.html +4 -6
  366. package/modules/public-landing/public/contact.html +4 -6
  367. package/modules/public-landing/public/guild.html +4 -6
  368. package/modules/public-landing/public/index.html +11 -9
  369. package/modules/public-landing/public/invitations.html +4 -6
  370. package/modules/public-landing/public/privacy.html +4 -6
  371. package/modules/public-landing/public/projects.html +168 -46
  372. package/modules/public-landing/public/terms.html +4 -6
  373. package/modules/raise/content/copy.json +40 -0
  374. package/modules/raise/content/nda.html +39 -0
  375. package/modules/raise/content/settings.json +49 -0
  376. package/modules/raise/db.js +95 -0
  377. package/modules/raise/migrations/raise_001_tables.sql +71 -0
  378. package/modules/raise/module.json +28 -0
  379. package/modules/raise/page.js +194 -0
  380. package/modules/raise/public/edit.js +152 -0
  381. package/modules/raise/public/favicon.svg +1 -0
  382. package/modules/raise/public/logo-ink.svg +1 -0
  383. package/modules/raise/public/logo-night.svg +1 -0
  384. package/modules/raise/public/mode.js +8 -0
  385. package/modules/raise/public/raise.css +234 -0
  386. package/modules/raise/public/raise.js +91 -0
  387. package/modules/raise/raise.js +174 -0
  388. package/modules/raise/routes/raise.js +152 -0
  389. package/modules/raise/views/gate.html +39 -0
  390. package/modules/raise/views/nda.html +21 -0
  391. package/modules/raise/views/page.html +133 -0
  392. package/modules/raise/web.js +72 -0
  393. package/modules/render-deploy/deploys.js +1 -1
  394. package/modules/render-deploy/render.js +2 -2
  395. package/modules/security/secret-scrub.js +3 -3
  396. package/modules/security/security.js +1 -1
  397. package/modules/security/tests/artifact_scan.mjs +1 -1
  398. package/modules/security/tests/mirror.mjs +1 -1
  399. package/modules/security/tests/scan_store.mjs +1 -1
  400. package/modules/sessions/db.js +2 -2
  401. package/modules/sessions/pulse.js +2 -2
  402. package/modules/sessions/routes/sessions.js +1 -1
  403. package/modules/specialities/specialities.js +1 -1
  404. package/modules/status-ui/public/README.md +3 -4
  405. package/modules/status-ui/public/index.html +5 -31
  406. package/modules/status-ui/public/status.js +6 -174
  407. package/modules/status-ui/public/style.css +4 -133
  408. package/modules/ui-design/docs/design-contract.md +3 -3
  409. package/modules/ui-design/kit/README.md +1 -1
  410. package/modules/ui-design/kit/serve.js +13 -4
  411. package/modules/ui-design/scripts/design-sync.js +1 -1
  412. package/modules/ui-design/scripts/figma-design-sync.js +1 -1
  413. package/modules/ui-design/scripts/validate-design.js +1 -1
  414. package/package-lock.json +27 -11
  415. package/package.json +2 -3
  416. package/release-notes.json +178 -0
  417. package/scripts/bongos/CLAUDE.md +15 -0
  418. package/scripts/bongos/abandon.js +137 -0
  419. package/scripts/bongos/accessibility-replay.js +195 -0
  420. package/scripts/bongos/address-park-sweep.sh +91 -0
  421. package/scripts/bongos/adopt-detect.js +123 -0
  422. package/scripts/bongos/adopt-import.js +111 -0
  423. package/scripts/bongos/adopt-preflight.js +187 -0
  424. package/scripts/bongos/adr-namespace.js +273 -0
  425. package/scripts/bongos/agent-invoke.js +689 -0
  426. package/scripts/bongos/agents-sync.js +502 -0
  427. package/scripts/bongos/api-alias-caller-scan.js +256 -0
  428. package/scripts/bongos/api-artifacts.js +91 -0
  429. package/scripts/bongos/api.js +86 -0
  430. package/scripts/bongos/api.ps1 +26 -0
  431. package/scripts/bongos/architect-audit.js +294 -0
  432. package/scripts/bongos/artifact-audit.js +326 -0
  433. package/scripts/bongos/artifact-format.js +203 -0
  434. package/scripts/bongos/artifact-staleness.js +267 -0
  435. package/scripts/bongos/ask.js +231 -0
  436. package/scripts/bongos/audit-authorship.sh +329 -0
  437. package/scripts/bongos/audit-deps.js +189 -0
  438. package/scripts/bongos/audit-gate.js +121 -0
  439. package/scripts/bongos/audit-rank-roles.js +172 -0
  440. package/scripts/bongos/audit-replay.sh +205 -0
  441. package/scripts/bongos/autobongos-digest.js +123 -0
  442. package/scripts/bongos/autobongos-grade-cap.js +187 -0
  443. package/scripts/bongos/autobongos-loop.js +210 -0
  444. package/scripts/bongos/autobongos-run.js +1361 -0
  445. package/scripts/bongos/autobongos-service.cmd +50 -0
  446. package/scripts/bongos/autobongos-service.ps1 +270 -0
  447. package/scripts/bongos/autobongos-tweak-lane.js +262 -0
  448. package/scripts/bongos/autobongos-verify.js +618 -0
  449. package/scripts/bongos/autonomy-gate.js +135 -0
  450. package/scripts/bongos/autonomy-gauge-statusline.js +124 -0
  451. package/scripts/bongos/autonomy-gauge.js +84 -0
  452. package/scripts/bongos/backfill-cost.js +176 -0
  453. package/scripts/bongos/backfill-disciplines.js +144 -0
  454. package/scripts/bongos/backfill-session-earnings.js +123 -0
  455. package/scripts/bongos/backfill-session-types.js +87 -0
  456. package/scripts/bongos/backfill-sessions.js +411 -0
  457. package/scripts/bongos/backfill-subagent-rewards.js +485 -0
  458. package/scripts/bongos/backfill-task-rewards.js +413 -0
  459. package/scripts/bongos/backlog-review.js +399 -0
  460. package/scripts/bongos/backup-dropin-sweep.sh +95 -0
  461. package/scripts/bongos/backup.js +116 -0
  462. package/scripts/bongos/baseline-staleness.js +217 -0
  463. package/scripts/bongos/bfg-principal-token.js +65 -0
  464. package/scripts/bongos/bug-attachment-audit.js +149 -0
  465. package/scripts/bongos/bug-attachment-recover.js +198 -0
  466. package/scripts/bongos/bug-triage.js +292 -0
  467. package/scripts/bongos/build-bongos.js +94 -0
  468. package/scripts/bongos/bump-version.js +221 -0
  469. package/scripts/bongos/capture.js +481 -0
  470. package/scripts/bongos/category-advisory-guard.js +206 -0
  471. package/scripts/bongos/ci-grade.js +82 -0
  472. package/scripts/bongos/claim-recall.js +112 -0
  473. package/scripts/bongos/claim.js +789 -0
  474. package/scripts/bongos/classify-discipline.js +153 -0
  475. package/scripts/bongos/claude-materialize.js +1200 -0
  476. package/scripts/bongos/claude-md-template.js +142 -0
  477. package/scripts/bongos/cleanup-orphans.js +74 -0
  478. package/scripts/bongos/cli-lib.js +1226 -0
  479. package/scripts/bongos/client-baseurl-guard.js +116 -0
  480. package/scripts/bongos/codemod-rename-scripts-gds.js +381 -0
  481. package/scripts/bongos/codemod-rename-src-gds.js +145 -0
  482. package/scripts/bongos/conductor-dispatch.js +535 -0
  483. package/scripts/bongos/context-pack.js +326 -0
  484. package/scripts/bongos/control-manifest.js +199 -0
  485. package/scripts/bongos/copy-apply.js +758 -0
  486. package/scripts/bongos/copy-inventory.js +571 -0
  487. package/scripts/bongos/core-origin-follow.js +185 -0
  488. package/scripts/bongos/core-pin-sync.js +260 -0
  489. package/scripts/bongos/coreB-carve-proof.sh +725 -0
  490. package/scripts/bongos/cost-report.js +63 -0
  491. package/scripts/bongos/cost.js +47 -0
  492. package/scripts/bongos/credential-presence.js +296 -0
  493. package/scripts/bongos/cutover-codemod.js +240 -0
  494. package/scripts/bongos/db-backup-nightly.sh +232 -0
  495. package/scripts/bongos/db-backup-offsite.sh +267 -0
  496. package/scripts/bongos/demote.js +45 -0
  497. package/scripts/bongos/deploy-divergence.js +454 -0
  498. package/scripts/bongos/deploy-main-audit-gate.sh +97 -0
  499. package/scripts/bongos/design-sync.js +12 -0
  500. package/scripts/bongos/dev-box-guard.js +166 -0
  501. package/scripts/bongos/dev-lib.js +722 -0
  502. package/scripts/bongos/dev.js +645 -0
  503. package/scripts/bongos/device-flow-help.js +72 -0
  504. package/scripts/bongos/diagnose-achievements.js +118 -0
  505. package/scripts/bongos/diagram-facts.js +355 -0
  506. package/scripts/bongos/discord-channels.js +77 -0
  507. package/scripts/bongos/do-api.js +109 -0
  508. package/scripts/bongos/doc-cli-guard.js +274 -0
  509. package/scripts/bongos/doc-comment-coverage.js +139 -0
  510. package/scripts/bongos/doc-control-claims.js +170 -0
  511. package/scripts/bongos/docs-entropy.js +453 -0
  512. package/scripts/bongos/doctor.js +493 -0
  513. package/scripts/bongos/enroll-control-plane.js +101 -0
  514. package/scripts/bongos/exec-path-guard.js +564 -0
  515. package/scripts/bongos/feedback-send.js +249 -0
  516. package/scripts/bongos/fetch-art-key.js +106 -0
  517. package/scripts/bongos/fetch-sound-prefs.js +126 -0
  518. package/scripts/bongos/figma-design-sync.js +11 -0
  519. package/scripts/bongos/find-untested.js +371 -0
  520. package/scripts/bongos/fitness-checks-error-envelope.js +134 -0
  521. package/scripts/bongos/fitness-checks-identity.js +343 -0
  522. package/scripts/bongos/fitness-checks-packaging.js +132 -0
  523. package/scripts/bongos/fitness-checks-route-pins.js +76 -0
  524. package/scripts/bongos/fitness-checks-vocabulary.js +392 -0
  525. package/scripts/bongos/fitness-checks-write-validation.js +157 -0
  526. package/scripts/bongos/fitness-lib.js +127 -0
  527. package/scripts/bongos/fitness-migration-contraction.js +50 -0
  528. package/scripts/bongos/fitness-ratchets.js +594 -0
  529. package/scripts/bongos/fitness.js +1498 -0
  530. package/scripts/bongos/forwarder.js +80 -0
  531. package/scripts/bongos/gate-review.js +330 -0
  532. package/scripts/bongos/gating.js +348 -0
  533. package/scripts/{gds → bongos}/gds-db-backup.service +6 -6
  534. package/scripts/{gds → bongos}/gds-db-backup.timer +4 -4
  535. package/scripts/{gds → bongos}/gds-db-offsite.service +4 -4
  536. package/scripts/{gds → bongos}/gds-db-offsite.timer +4 -4
  537. package/scripts/bongos/gds-literal-scan.js +196 -0
  538. package/scripts/bongos/gen-api-client.js +576 -0
  539. package/scripts/bongos/gen-api-docs.js +1111 -0
  540. package/scripts/bongos/gen-atlas.js +366 -0
  541. package/scripts/bongos/gen-diagrams.js +608 -0
  542. package/scripts/bongos/gen-file-map.js +337 -0
  543. package/scripts/bongos/gen-freshness.js +32 -0
  544. package/scripts/bongos/gen-interaction-posture.js +122 -0
  545. package/scripts/bongos/gen-repo-map.js +540 -0
  546. package/scripts/bongos/gen-role-responsibilities.js +134 -0
  547. package/scripts/bongos/gen-session-index.js +243 -0
  548. package/scripts/bongos/gen-sounds.js +176 -0
  549. package/scripts/bongos/git-merge-regen.js +254 -0
  550. package/scripts/bongos/go-live.js +1071 -0
  551. package/scripts/bongos/goal-names.js +102 -0
  552. package/scripts/bongos/goal.js +272 -0
  553. package/scripts/bongos/government-walk.js +1477 -0
  554. package/scripts/bongos/grade-correlation-audit.js +310 -0
  555. package/scripts/bongos/grade-replay.js +237 -0
  556. package/scripts/bongos/grade-smoke.js +205 -0
  557. package/scripts/bongos/home-isolation-guard.js +126 -0
  558. package/scripts/bongos/hooks/pre-push.js +211 -0
  559. package/scripts/bongos/howto.js +145 -0
  560. package/scripts/bongos/http-api-client.js +81 -0
  561. package/scripts/bongos/identity-strip.js +75 -0
  562. package/scripts/bongos/init.js +1159 -0
  563. package/scripts/bongos/install-git-hooks.js +200 -0
  564. package/scripts/bongos/instance-apex.js +38 -0
  565. package/scripts/bongos/intent-retry.js +52 -0
  566. package/scripts/bongos/key-card.js +222 -0
  567. package/scripts/bongos/key-status.js +126 -0
  568. package/scripts/bongos/land-watch.js +201 -0
  569. package/scripts/bongos/leak-scan-allowlist.js +293 -0
  570. package/scripts/bongos/learning-capture.js +145 -0
  571. package/scripts/bongos/lib.sh +74 -0
  572. package/scripts/bongos/linkify-refs.js +655 -0
  573. package/scripts/bongos/lint-infra-exec.js +70 -0
  574. package/scripts/bongos/lint-migrations.js +102 -0
  575. package/scripts/bongos/lint-workflow-exec.js +63 -0
  576. package/scripts/bongos/local-preview-lib.js +128 -0
  577. package/scripts/bongos/local-preview.js +82 -0
  578. package/scripts/bongos/login.js +360 -0
  579. package/scripts/bongos/main-audit.js +625 -0
  580. package/scripts/bongos/me.js +97 -0
  581. package/scripts/bongos/memory-map.js +176 -0
  582. package/scripts/bongos/merge-lock.js +71 -0
  583. package/scripts/bongos/migration-namespace.js +313 -0
  584. package/scripts/bongos/mirror-lineage-check.js +343 -0
  585. package/scripts/bongos/mirror-redact.js +350 -0
  586. package/scripts/bongos/module-artifact.js +289 -0
  587. package/scripts/bongos/module-assess-docs.js +238 -0
  588. package/scripts/bongos/module-assess-installs.js +228 -0
  589. package/scripts/bongos/module-assess-score.js +111 -0
  590. package/scripts/bongos/module-assess-security.js +252 -0
  591. package/scripts/bongos/module-assess-tests.js +278 -0
  592. package/scripts/bongos/module-assess-version.js +92 -0
  593. package/scripts/bongos/module-error-report.js +148 -0
  594. package/scripts/{gds → bongos}/module-test-runner/README.md +3 -3
  595. package/scripts/{gds → bongos}/module-test-runner/module-tests.yml +2 -2
  596. package/scripts/bongos/module-test-runner.js +414 -0
  597. package/scripts/bongos/module.js +1376 -0
  598. package/scripts/bongos/move-escalation.js +141 -0
  599. package/scripts/{gds → bongos}/newcomer-floor.config.json +1 -1
  600. package/scripts/bongos/newcomer-floor.js +421 -0
  601. package/scripts/{gds → bongos}/newcomer-floor.templates.json +13 -13
  602. package/scripts/bongos/newcomer-floor.test.js +235 -0
  603. package/scripts/bongos/next-number.js +163 -0
  604. package/scripts/bongos/oauth-secret.js +202 -0
  605. package/scripts/bongos/onboard.js +267 -0
  606. package/scripts/bongos/onboarding-analyze.js +226 -0
  607. package/scripts/bongos/onboarding-config.js +179 -0
  608. package/scripts/bongos/onboarding-ship.js +92 -0
  609. package/scripts/bongos/pack-env-prefix.js +73 -0
  610. package/scripts/bongos/package-core.js +1200 -0
  611. package/scripts/bongos/page-inventory.js +348 -0
  612. package/scripts/bongos/page-reader.js +722 -0
  613. package/scripts/bongos/paste-token.js +212 -0
  614. package/scripts/bongos/plain-cards.js +351 -0
  615. package/scripts/bongos/portability-smoke-art.sh +85 -0
  616. package/scripts/bongos/portability-smoke-memory.sh +176 -0
  617. package/scripts/bongos/preflight.js +214 -0
  618. package/scripts/bongos/probe-cache.js +246 -0
  619. package/scripts/bongos/prove-strict-versioning.js +284 -0
  620. package/scripts/bongos/provision-auto-upgrade.js +162 -0
  621. package/scripts/bongos/provision-byo-host.js +68 -0
  622. package/scripts/bongos/provision-capacity.js +79 -0
  623. package/scripts/bongos/provision-caps.js +63 -0
  624. package/scripts/bongos/provision-config.js +233 -0
  625. package/scripts/bongos/provision-core-upgrade.js +1166 -0
  626. package/scripts/bongos/provision-disconnect.js +88 -0
  627. package/scripts/bongos/provision-github-setup.js +168 -0
  628. package/scripts/bongos/provision-net.js +357 -0
  629. package/scripts/bongos/provision-pin-key.js +176 -0
  630. package/scripts/bongos/provision-pin-replay.js +126 -0
  631. package/scripts/bongos/provision-process.js +170 -0
  632. package/scripts/bongos/provision-render.js +201 -0
  633. package/scripts/bongos/provision-repo-auth.js +164 -0
  634. package/scripts/bongos/provision-repo-private.js +98 -0
  635. package/scripts/bongos/provision-repo.js +1337 -0
  636. package/scripts/bongos/provision-teardown.js +106 -0
  637. package/scripts/bongos/provision-units.js +469 -0
  638. package/scripts/bongos/provision.js +1479 -0
  639. package/scripts/bongos/publish-credential-check.js +66 -0
  640. package/scripts/bongos/publish-integration-gate.js +142 -0
  641. package/scripts/bongos/publish-manifest.js +440 -0
  642. package/scripts/bongos/publish-watch.js +268 -0
  643. package/scripts/bongos/pulse.js +336 -0
  644. package/scripts/bongos/push-main.js +56 -0
  645. package/scripts/bongos/push-path-brief.js +100 -0
  646. package/scripts/bongos/read-session-export.js +359 -0
  647. package/scripts/bongos/reauth.js +155 -0
  648. package/scripts/bongos/recall.js +183 -0
  649. package/scripts/bongos/redteam-patrol.js +437 -0
  650. package/scripts/bongos/regen-instance-docs.js +47 -0
  651. package/scripts/bongos/release-core.js +80 -0
  652. package/scripts/bongos/release-notes.js +271 -0
  653. package/scripts/bongos/release.js +139 -0
  654. package/scripts/bongos/rename-goals.js +109 -0
  655. package/scripts/bongos/rename-history-check.js +369 -0
  656. package/scripts/bongos/rename-ledger-prose.js +482 -0
  657. package/scripts/bongos/render-api.js +197 -0
  658. package/scripts/bongos/render-check.js +206 -0
  659. package/scripts/bongos/render-ideas.js +226 -0
  660. package/scripts/bongos/render-payload.js +85 -0
  661. package/scripts/bongos/repo-metrics.js +363 -0
  662. package/scripts/bongos/review-sheet.js +108 -0
  663. package/scripts/bongos/role-pack-guard.js +142 -0
  664. package/scripts/bongos/route-shadow-guard.js +175 -0
  665. package/scripts/bongos/routine-schedule.js +283 -0
  666. package/scripts/bongos/run-routine.js +257 -0
  667. package/scripts/bongos/run-unit-tests.js +654 -0
  668. package/scripts/bongos/runner-drift.js +151 -0
  669. package/scripts/bongos/sandbox-stage.js +459 -0
  670. package/scripts/bongos/scope-map-guard.js +300 -0
  671. package/scripts/bongos/scope-roster-guard.js +118 -0
  672. package/scripts/bongos/seam-wiring-guard.js +275 -0
  673. package/scripts/bongos/search-ingest-db.js +288 -0
  674. package/scripts/bongos/search-ingest-md.js +269 -0
  675. package/scripts/bongos/seed-adopt-tasks.js +75 -0
  676. package/scripts/bongos/seed-api-contract-goal-tasks.js +141 -0
  677. package/scripts/bongos/seed-board-room-tasks.js +196 -0
  678. package/scripts/bongos/seed-bongos-app-tasks.js +294 -0
  679. package/scripts/bongos/seed-bongos-coreB-tranche1-tasks.js +81 -0
  680. package/scripts/bongos/seed-bongos-coreB-tranche2-tasks.js +100 -0
  681. package/scripts/bongos/seed-bongos-goal-hierarchy-tasks.js +307 -0
  682. package/scripts/bongos/seed-bongos-module-system-tasks.js +346 -0
  683. package/scripts/bongos/seed-bongos-tasks.js +214 -0
  684. package/scripts/bongos/seed-bongos-v1-idea-routing-tasks.js +152 -0
  685. package/scripts/bongos/seed-bongos-v1-seo-tasks.js +104 -0
  686. package/scripts/bongos/seed-bv1-community-tasks.js +131 -0
  687. package/scripts/bongos/seed-bv1-privacy-invites-tasks.js +133 -0
  688. package/scripts/bongos/seed-bv1-profile-page-tasks.js +161 -0
  689. package/scripts/bongos/seed-bv1-profiles-tasks.js +135 -0
  690. package/scripts/bongos/seed-bv1-r01-delta-tasks.js +154 -0
  691. package/scripts/bongos/seed-bv2-ideator-surface-tasks.js +390 -0
  692. package/scripts/bongos/seed-bv2-tweak-mode-tasks.js +277 -0
  693. package/scripts/bongos/seed-gds-v4-tasks.js +624 -0
  694. package/scripts/bongos/seed-governance-tasks.js +340 -0
  695. package/scripts/bongos/seed-medusa-tasks.js +440 -0
  696. package/scripts/bongos/seed-module-upstreaming.js +219 -0
  697. package/scripts/bongos/seed-productization-tasks.js +235 -0
  698. package/scripts/bongos/seed-project-admin-console-tasks.js +88 -0
  699. package/scripts/bongos/seed-provisioning-tasks.js +83 -0
  700. package/scripts/bongos/seed-staging.sh +117 -0
  701. package/scripts/bongos/seed-strict-versioning-tasks.js +275 -0
  702. package/scripts/bongos/seed-v2-world-tasks.js +283 -0
  703. package/scripts/bongos/seed-verify-criteria.js +124 -0
  704. package/scripts/bongos/sequence.js +597 -0
  705. package/scripts/bongos/session-cost.js +430 -0
  706. package/scripts/bongos/session-digest-build.js +293 -0
  707. package/scripts/bongos/session-digest.js +200 -0
  708. package/scripts/bongos/session-eval.js +631 -0
  709. package/scripts/bongos/session-transcript-build.js +155 -0
  710. package/scripts/bongos/session-transcript-upload.js +29 -0
  711. package/scripts/bongos/session.js +404 -0
  712. package/scripts/bongos/setup.js +646 -0
  713. package/scripts/bongos/ship-check.js +89 -0
  714. package/scripts/bongos/ship-deploy-target.js +393 -0
  715. package/scripts/bongos/ship-escalation.js +167 -0
  716. package/scripts/bongos/ship-finish.js +420 -0
  717. package/scripts/bongos/ship-flow.js +1217 -0
  718. package/scripts/bongos/ship-git.js +100 -0
  719. package/scripts/bongos/ship-grade-steps.js +547 -0
  720. package/scripts/bongos/ship-grade.js +426 -0
  721. package/scripts/bongos/ship-honesty.js +314 -0
  722. package/scripts/bongos/ship-io.js +139 -0
  723. package/scripts/bongos/ship-land.js +1130 -0
  724. package/scripts/bongos/ship-memory-sync.js +249 -0
  725. package/scripts/bongos/ship-merge-gate.js +225 -0
  726. package/scripts/bongos/ship-merge.js +466 -0
  727. package/scripts/bongos/ship-mode-ask.js +138 -0
  728. package/scripts/bongos/ship-mode-manual.js +54 -0
  729. package/scripts/bongos/ship-preflight-steps.js +399 -0
  730. package/scripts/bongos/ship-regen.js +292 -0
  731. package/scripts/bongos/ship-resume.js +201 -0
  732. package/scripts/bongos/ship-session-upload.js +313 -0
  733. package/scripts/bongos/ship-state.js +110 -0
  734. package/scripts/bongos/ship-surprise.js +84 -0
  735. package/scripts/bongos/ship-visual.js +75 -0
  736. package/scripts/bongos/ship.js +382 -0
  737. package/scripts/bongos/shipping-mode.js +71 -0
  738. package/scripts/bongos/skill-lint.js +250 -0
  739. package/scripts/bongos/skill-preflight.js +361 -0
  740. package/scripts/bongos/smoke-batch-claim.sh +238 -0
  741. package/scripts/bongos/smoke-batch-release.sh +316 -0
  742. package/scripts/bongos/smoke-claim-consistency.sh +222 -0
  743. package/scripts/bongos/smoke-dependencies.sh +143 -0
  744. package/scripts/bongos/smoke-gds.js +256 -0
  745. package/scripts/bongos/smoke-write.sh +275 -0
  746. package/scripts/bongos/source-text-test-scan.js +106 -0
  747. package/scripts/bongos/spark.js +294 -0
  748. package/scripts/bongos/stale-worktrees.js +212 -0
  749. package/scripts/bongos/start-goals.js +102 -0
  750. package/scripts/bongos/start.js +1090 -0
  751. package/scripts/bongos/status.js +545 -0
  752. package/scripts/bongos/strand-watch.js +315 -0
  753. package/scripts/bongos/stranded-rows.js +200 -0
  754. package/scripts/bongos/stray-unit-sweep.sh +71 -0
  755. package/scripts/bongos/surface.js +101 -0
  756. package/scripts/bongos/task.js +273 -0
  757. package/scripts/bongos/test-path-guard.js +99 -0
  758. package/scripts/bongos/triage.js +742 -0
  759. package/scripts/bongos/turn-end-sound.js +74 -0
  760. package/scripts/bongos/tweak-halt.js +70 -0
  761. package/scripts/bongos/tweak-renders.js +200 -0
  762. package/scripts/bongos/uat.js +120 -0
  763. package/scripts/bongos/ui-kit-transform.js +43 -0
  764. package/scripts/bongos/update-channel.js +512 -0
  765. package/scripts/bongos/update-sweep.js +829 -0
  766. package/scripts/bongos/upgrade-artist-gate.js +46 -0
  767. package/scripts/bongos/upgrade-commit-identity.js +32 -0
  768. package/scripts/bongos/upgrade-migrate.js +224 -0
  769. package/scripts/bongos/upgrade-operator.js +73 -0
  770. package/scripts/bongos/upgrade-outcome.js +174 -0
  771. package/scripts/bongos/upgrade.js +1499 -0
  772. package/scripts/bongos/validate-design.js +12 -0
  773. package/scripts/bongos/version-close.js +621 -0
  774. package/scripts/bongos/version-literal-guard.js +140 -0
  775. package/scripts/bongos/version-select.js +79 -0
  776. package/scripts/bongos/visual-review-nudge.js +39 -0
  777. package/scripts/bongos/wedge-remedy.js +174 -0
  778. package/scripts/bongos/worktree-claim-guard.js +130 -0
  779. package/scripts/bongos/worktree.js +449 -0
  780. package/scripts/discord/post.js +1 -1
  781. package/scripts/gds/README.md +9 -0
  782. package/scripts/gds/abandon.js +6 -136
  783. package/scripts/gds/accessibility-replay.js +5 -194
  784. package/scripts/gds/address-park-sweep.sh +7 -90
  785. package/scripts/gds/adopt-detect.js +5 -121
  786. package/scripts/gds/adopt-import.js +5 -109
  787. package/scripts/gds/adopt-preflight.js +5 -185
  788. package/scripts/gds/adr-namespace.js +5 -271
  789. package/scripts/gds/agent-invoke.js +5 -687
  790. package/scripts/gds/agents-sync.js +5 -500
  791. package/scripts/gds/api-alias-caller-scan.js +5 -255
  792. package/scripts/gds/api-artifacts.js +6 -0
  793. package/scripts/gds/api.js +6 -85
  794. package/scripts/gds/api.ps1 +8 -26
  795. package/scripts/gds/architect-audit.js +6 -293
  796. package/scripts/gds/artifact-audit.js +5 -324
  797. package/scripts/gds/artifact-format.js +6 -203
  798. package/scripts/gds/artifact-staleness.js +5 -265
  799. package/scripts/gds/ask.js +5 -229
  800. package/scripts/gds/audit-authorship.sh +7 -328
  801. package/scripts/gds/audit-deps.js +6 -188
  802. package/scripts/gds/audit-gate.js +5 -119
  803. package/scripts/gds/audit-rank-roles.js +6 -171
  804. package/scripts/gds/audit-replay.sh +7 -204
  805. package/scripts/gds/autobongos-digest.js +5 -121
  806. package/scripts/gds/autobongos-grade-cap.js +5 -186
  807. package/scripts/gds/autobongos-loop.js +5 -208
  808. package/scripts/gds/autobongos-run.js +5 -1359
  809. package/scripts/gds/autobongos-service.cmd +8 -49
  810. package/scripts/gds/autobongos-service.ps1 +8 -270
  811. package/scripts/gds/autobongos-tweak-lane.js +5 -261
  812. package/scripts/gds/autobongos-verify.js +5 -616
  813. package/scripts/gds/autonomy-gate.js +5 -133
  814. package/scripts/gds/autonomy-gauge-statusline.js +5 -122
  815. package/scripts/gds/autonomy-gauge.js +5 -82
  816. package/scripts/gds/backfill-cost.js +6 -175
  817. package/scripts/gds/backfill-disciplines.js +5 -142
  818. package/scripts/gds/backfill-session-earnings.js +5 -121
  819. package/scripts/gds/backfill-session-types.js +5 -85
  820. package/scripts/gds/backfill-sessions.js +5 -409
  821. package/scripts/gds/backfill-subagent-rewards.js +5 -483
  822. package/scripts/gds/backfill-task-rewards.js +5 -411
  823. package/scripts/gds/backlog-review.js +6 -398
  824. package/scripts/gds/backup-dropin-sweep.sh +7 -94
  825. package/scripts/gds/backup.js +6 -115
  826. package/scripts/gds/baseline-staleness.js +5 -215
  827. package/scripts/gds/bfg-principal-token.js +6 -64
  828. package/scripts/gds/bug-attachment-audit.js +5 -147
  829. package/scripts/gds/bug-attachment-recover.js +5 -196
  830. package/scripts/gds/bug-triage.js +6 -291
  831. package/scripts/gds/build-bongos.js +5 -92
  832. package/scripts/gds/bump-version.js +5 -219
  833. package/scripts/gds/capture.js +6 -480
  834. package/scripts/gds/category-advisory-guard.js +5 -205
  835. package/scripts/gds/ci-grade.js +6 -81
  836. package/scripts/gds/claim-recall.js +6 -111
  837. package/scripts/gds/claim.js +6 -788
  838. package/scripts/gds/classify-discipline.js +6 -152
  839. package/scripts/gds/claude-materialize.js +5 -1198
  840. package/scripts/gds/claude-md-template.js +5 -140
  841. package/scripts/gds/cleanup-orphans.js +6 -73
  842. package/scripts/gds/cli-lib.js +6 -1204
  843. package/scripts/gds/client-baseurl-guard.js +5 -114
  844. package/scripts/gds/codemod-rename-src-gds.js +6 -144
  845. package/scripts/gds/conductor-dispatch.js +6 -534
  846. package/scripts/gds/context-pack.js +6 -325
  847. package/scripts/gds/control-manifest.js +5 -197
  848. package/scripts/gds/copy-apply.js +5 -756
  849. package/scripts/gds/copy-inventory.js +5 -569
  850. package/scripts/gds/core-origin-follow.js +5 -184
  851. package/scripts/gds/core-pin-sync.js +5 -258
  852. package/scripts/gds/coreB-carve-proof.sh +7 -724
  853. package/scripts/gds/cost-report.js +6 -62
  854. package/scripts/gds/cost.js +6 -46
  855. package/scripts/gds/credential-presence.js +5 -294
  856. package/scripts/gds/cutover-codemod.js +5 -239
  857. package/scripts/gds/db-backup-nightly.sh +7 -231
  858. package/scripts/gds/db-backup-offsite.sh +7 -266
  859. package/scripts/gds/demote.js +6 -44
  860. package/scripts/gds/deploy-divergence.js +6 -445
  861. package/scripts/gds/deploy-main-audit-gate.sh +7 -96
  862. package/scripts/gds/design-sync.js +5 -10
  863. package/scripts/gds/dev-box-guard.js +5 -164
  864. package/scripts/gds/dev-lib.js +5 -721
  865. package/scripts/gds/dev.js +5 -643
  866. package/scripts/gds/device-flow-help.js +5 -70
  867. package/scripts/gds/diagnose-achievements.js +5 -116
  868. package/scripts/gds/diagram-facts.js +6 -355
  869. package/scripts/gds/discord-channels.js +5 -75
  870. package/scripts/gds/do-api.js +6 -109
  871. package/scripts/gds/doc-cli-guard.js +5 -266
  872. package/scripts/gds/doc-comment-coverage.js +5 -137
  873. package/scripts/gds/doc-control-claims.js +5 -166
  874. package/scripts/gds/docs-entropy.js +5 -443
  875. package/scripts/gds/doctor.js +6 -492
  876. package/scripts/gds/enroll-control-plane.js +5 -99
  877. package/scripts/gds/exec-path-guard.js +5 -562
  878. package/scripts/gds/feedback-send.js +5 -247
  879. package/scripts/gds/fetch-art-key.js +5 -104
  880. package/scripts/gds/fetch-sound-prefs.js +5 -124
  881. package/scripts/gds/figma-design-sync.js +5 -9
  882. package/scripts/gds/find-untested.js +5 -369
  883. package/scripts/gds/fitness-checks-error-envelope.js +5 -133
  884. package/scripts/gds/fitness-checks-identity.js +5 -342
  885. package/scripts/gds/fitness-checks-packaging.js +5 -131
  886. package/scripts/gds/fitness-checks-route-pins.js +5 -75
  887. package/scripts/gds/fitness-checks-vocabulary.js +5 -391
  888. package/scripts/gds/fitness-checks-write-validation.js +5 -156
  889. package/scripts/gds/fitness-lib.js +5 -126
  890. package/scripts/gds/fitness-migration-contraction.js +5 -49
  891. package/scripts/gds/fitness-ratchets.js +5 -563
  892. package/scripts/gds/fitness.js +5 -1493
  893. package/scripts/gds/gate-review.js +5 -328
  894. package/scripts/gds/gating.js +5 -346
  895. package/scripts/gds/gds-literal-scan.js +5 -194
  896. package/scripts/gds/gen-api-client.js +5 -555
  897. package/scripts/gds/gen-api-docs.js +5 -1100
  898. package/scripts/gds/gen-atlas.js +5 -364
  899. package/scripts/gds/gen-diagrams.js +6 -607
  900. package/scripts/gds/gen-file-map.js +5 -335
  901. package/scripts/gds/gen-freshness.js +5 -31
  902. package/scripts/gds/gen-interaction-posture.js +5 -120
  903. package/scripts/gds/gen-repo-map.js +5 -538
  904. package/scripts/gds/gen-role-responsibilities.js +5 -133
  905. package/scripts/gds/gen-session-index.js +5 -241
  906. package/scripts/gds/gen-sounds.js +5 -174
  907. package/scripts/gds/git-merge-regen.js +6 -291
  908. package/scripts/gds/go-live.js +5 -1069
  909. package/scripts/gds/goal-names.js +5 -100
  910. package/scripts/gds/goal.js +6 -271
  911. package/scripts/gds/government-walk.js +5 -1475
  912. package/scripts/gds/grade-correlation-audit.js +5 -308
  913. package/scripts/gds/grade-replay.js +5 -235
  914. package/scripts/gds/grade-smoke.js +6 -204
  915. package/scripts/gds/home-isolation-guard.js +5 -125
  916. package/scripts/gds/hooks/pre-push.js +5 -209
  917. package/scripts/gds/howto.js +5 -143
  918. package/scripts/gds/http-api-client.js +6 -81
  919. package/scripts/gds/identity-strip.js +5 -74
  920. package/scripts/gds/init.js +5 -1157
  921. package/scripts/gds/install-git-hooks.js +5 -198
  922. package/scripts/gds/instance-apex.js +5 -37
  923. package/scripts/gds/intent-retry.js +5 -51
  924. package/scripts/gds/key-card.js +6 -221
  925. package/scripts/gds/key-status.js +5 -124
  926. package/scripts/gds/land-watch.js +5 -199
  927. package/scripts/gds/leak-scan-allowlist.js +5 -291
  928. package/scripts/gds/learning-capture.js +6 -144
  929. package/scripts/gds/lib.sh +7 -73
  930. package/scripts/gds/linkify-refs.js +6 -654
  931. package/scripts/gds/lint-infra-exec.js +5 -68
  932. package/scripts/gds/lint-migrations.js +5 -100
  933. package/scripts/gds/lint-workflow-exec.js +5 -61
  934. package/scripts/gds/local-preview-lib.js +6 -128
  935. package/scripts/gds/local-preview.js +6 -81
  936. package/scripts/gds/login.js +5 -358
  937. package/scripts/gds/main-audit.js +5 -623
  938. package/scripts/gds/me.js +6 -96
  939. package/scripts/gds/memory-map.js +5 -174
  940. package/scripts/gds/merge-lock.js +6 -70
  941. package/scripts/gds/migration-namespace.js +5 -311
  942. package/scripts/gds/mirror-lineage-check.js +5 -341
  943. package/scripts/gds/mirror-redact.js +5 -348
  944. package/scripts/gds/module-artifact.js +6 -289
  945. package/scripts/gds/module-assess-docs.js +6 -237
  946. package/scripts/gds/module-assess-installs.js +6 -227
  947. package/scripts/gds/module-assess-score.js +6 -110
  948. package/scripts/gds/module-assess-security.js +6 -251
  949. package/scripts/gds/module-assess-tests.js +6 -277
  950. package/scripts/gds/module-assess-version.js +6 -91
  951. package/scripts/gds/module-error-report.js +5 -146
  952. package/scripts/gds/module-test-runner.js +6 -413
  953. package/scripts/gds/module.js +5 -1374
  954. package/scripts/gds/move-escalation.js +5 -140
  955. package/scripts/gds/newcomer-floor.js +6 -420
  956. package/scripts/gds/newcomer-floor.test.js +6 -234
  957. package/scripts/gds/next-number.js +6 -162
  958. package/scripts/gds/oauth-secret.js +5 -200
  959. package/scripts/gds/onboard.js +5 -265
  960. package/scripts/gds/onboarding-analyze.js +6 -225
  961. package/scripts/gds/onboarding-config.js +6 -179
  962. package/scripts/gds/onboarding-ship.js +6 -91
  963. package/scripts/gds/pack-env-prefix.js +5 -72
  964. package/scripts/gds/package-core.js +5 -1102
  965. package/scripts/gds/page-inventory.js +5 -346
  966. package/scripts/gds/page-reader.js +5 -720
  967. package/scripts/gds/paste-token.js +6 -211
  968. package/scripts/gds/plain-cards.js +5 -350
  969. package/scripts/gds/portability-smoke-art.sh +7 -84
  970. package/scripts/gds/portability-smoke-memory.sh +7 -175
  971. package/scripts/gds/preflight.js +5 -212
  972. package/scripts/gds/probe-cache.js +5 -244
  973. package/scripts/gds/prove-strict-versioning.js +6 -283
  974. package/scripts/gds/provision-auto-upgrade.js +5 -161
  975. package/scripts/gds/provision-byo-host.js +5 -67
  976. package/scripts/gds/provision-capacity.js +5 -78
  977. package/scripts/gds/provision-caps.js +5 -62
  978. package/scripts/gds/provision-config.js +5 -232
  979. package/scripts/gds/provision-core-upgrade.js +5 -1165
  980. package/scripts/gds/provision-disconnect.js +5 -87
  981. package/scripts/gds/provision-github-setup.js +5 -167
  982. package/scripts/gds/provision-net.js +5 -356
  983. package/scripts/gds/provision-pin-key.js +5 -175
  984. package/scripts/gds/provision-pin-replay.js +5 -125
  985. package/scripts/gds/provision-process.js +5 -169
  986. package/scripts/gds/provision-render.js +5 -200
  987. package/scripts/gds/provision-repo-auth.js +5 -163
  988. package/scripts/gds/provision-repo-private.js +5 -97
  989. package/scripts/gds/provision-repo.js +5 -1336
  990. package/scripts/gds/provision-teardown.js +5 -105
  991. package/scripts/gds/provision-units.js +5 -468
  992. package/scripts/gds/provision.js +5 -1477
  993. package/scripts/gds/publish-credential-check.js +6 -65
  994. package/scripts/gds/publish-integration-gate.js +5 -140
  995. package/scripts/gds/publish-manifest.js +5 -437
  996. package/scripts/gds/publish-watch.js +5 -266
  997. package/scripts/gds/pulse.js +6 -335
  998. package/scripts/gds/push-main.js +5 -54
  999. package/scripts/gds/push-path-brief.js +5 -98
  1000. package/scripts/gds/read-session-export.js +5 -357
  1001. package/scripts/gds/reauth.js +6 -154
  1002. package/scripts/gds/recall.js +6 -182
  1003. package/scripts/gds/redteam-patrol.js +5 -435
  1004. package/scripts/gds/regen-instance-docs.js +5 -45
  1005. package/scripts/gds/release-core.js +5 -78
  1006. package/scripts/gds/release-notes.js +5 -270
  1007. package/scripts/gds/release.js +6 -138
  1008. package/scripts/gds/rename-goals.js +5 -107
  1009. package/scripts/gds/rename-history-check.js +5 -367
  1010. package/scripts/gds/rename-ledger-prose.js +5 -480
  1011. package/scripts/gds/render-api.js +5 -196
  1012. package/scripts/gds/render-check.js +5 -204
  1013. package/scripts/gds/render-ideas.js +6 -225
  1014. package/scripts/gds/render-payload.js +5 -84
  1015. package/scripts/gds/repo-metrics.js +6 -362
  1016. package/scripts/gds/review-sheet.js +5 -106
  1017. package/scripts/gds/role-pack-guard.js +5 -141
  1018. package/scripts/gds/route-shadow-guard.js +5 -173
  1019. package/scripts/gds/routine-schedule.js +5 -281
  1020. package/scripts/gds/run-routine.js +5 -255
  1021. package/scripts/gds/run-unit-tests.js +6 -659
  1022. package/scripts/gds/runner-drift.js +5 -149
  1023. package/scripts/gds/sandbox-stage.js +6 -458
  1024. package/scripts/gds/scope-map-guard.js +5 -299
  1025. package/scripts/gds/scope-roster-guard.js +5 -117
  1026. package/scripts/gds/seam-wiring-guard.js +5 -274
  1027. package/scripts/gds/search-ingest-db.js +6 -287
  1028. package/scripts/gds/search-ingest-md.js +6 -268
  1029. package/scripts/gds/seed-adopt-tasks.js +6 -74
  1030. package/scripts/gds/seed-api-contract-goal-tasks.js +6 -140
  1031. package/scripts/gds/seed-board-room-tasks.js +6 -196
  1032. package/scripts/gds/seed-bongos-app-tasks.js +6 -293
  1033. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +6 -80
  1034. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +6 -99
  1035. package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +6 -306
  1036. package/scripts/gds/seed-bongos-module-system-tasks.js +6 -345
  1037. package/scripts/gds/seed-bongos-tasks.js +6 -213
  1038. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +6 -152
  1039. package/scripts/gds/seed-bongos-v1-seo-tasks.js +6 -104
  1040. package/scripts/gds/seed-bv1-community-tasks.js +6 -131
  1041. package/scripts/gds/seed-bv1-privacy-invites-tasks.js +6 -133
  1042. package/scripts/gds/seed-bv1-profile-page-tasks.js +6 -161
  1043. package/scripts/gds/seed-bv1-profiles-tasks.js +6 -135
  1044. package/scripts/gds/seed-bv1-r01-delta-tasks.js +6 -154
  1045. package/scripts/gds/seed-bv2-ideator-surface-tasks.js +6 -390
  1046. package/scripts/gds/seed-bv2-tweak-mode-tasks.js +6 -277
  1047. package/scripts/gds/seed-gds-v4-tasks.js +6 -623
  1048. package/scripts/gds/seed-governance-tasks.js +6 -339
  1049. package/scripts/gds/seed-medusa-tasks.js +6 -439
  1050. package/scripts/gds/seed-module-upstreaming.js +5 -217
  1051. package/scripts/gds/seed-productization-tasks.js +6 -234
  1052. package/scripts/gds/seed-project-admin-console-tasks.js +6 -88
  1053. package/scripts/gds/seed-provisioning-tasks.js +6 -82
  1054. package/scripts/gds/seed-staging.sh +7 -116
  1055. package/scripts/gds/seed-strict-versioning-tasks.js +6 -274
  1056. package/scripts/gds/seed-v2-world-tasks.js +6 -282
  1057. package/scripts/gds/seed-verify-criteria.js +6 -124
  1058. package/scripts/gds/sequence.js +6 -596
  1059. package/scripts/gds/session-cost.js +6 -429
  1060. package/scripts/gds/session-digest-build.js +6 -293
  1061. package/scripts/gds/session-digest.js +6 -199
  1062. package/scripts/gds/session-eval.js +6 -630
  1063. package/scripts/gds/session-transcript-build.js +6 -155
  1064. package/scripts/gds/session-transcript-upload.js +6 -29
  1065. package/scripts/gds/session.js +6 -403
  1066. package/scripts/gds/setup.js +6 -645
  1067. package/scripts/gds/ship-check.js +5 -85
  1068. package/scripts/gds/ship-deploy-target.js +5 -392
  1069. package/scripts/gds/ship-escalation.js +5 -166
  1070. package/scripts/gds/ship-finish.js +5 -419
  1071. package/scripts/gds/ship-flow.js +5 -1216
  1072. package/scripts/gds/ship-git.js +5 -99
  1073. package/scripts/gds/ship-grade-steps.js +5 -546
  1074. package/scripts/gds/ship-grade.js +5 -425
  1075. package/scripts/gds/ship-honesty.js +5 -312
  1076. package/scripts/gds/ship-io.js +5 -138
  1077. package/scripts/gds/ship-land.js +5 -1129
  1078. package/scripts/gds/ship-memory-sync.js +5 -248
  1079. package/scripts/gds/ship-merge-gate.js +5 -224
  1080. package/scripts/gds/ship-merge.js +5 -465
  1081. package/scripts/gds/ship-mode-ask.js +5 -137
  1082. package/scripts/gds/ship-mode-manual.js +5 -53
  1083. package/scripts/gds/ship-preflight-steps.js +5 -398
  1084. package/scripts/gds/ship-regen.js +5 -313
  1085. package/scripts/gds/ship-resume.js +5 -200
  1086. package/scripts/gds/ship-session-upload.js +5 -312
  1087. package/scripts/gds/ship-state.js +5 -109
  1088. package/scripts/gds/ship-surprise.js +5 -83
  1089. package/scripts/gds/ship-visual.js +5 -74
  1090. package/scripts/gds/ship.js +5 -380
  1091. package/scripts/gds/shipping-mode.js +5 -69
  1092. package/scripts/gds/skill-lint.js +5 -248
  1093. package/scripts/gds/skill-preflight.js +5 -359
  1094. package/scripts/gds/smoke-batch-claim.sh +7 -237
  1095. package/scripts/gds/smoke-batch-release.sh +7 -315
  1096. package/scripts/gds/smoke-claim-consistency.sh +7 -221
  1097. package/scripts/gds/smoke-dependencies.sh +7 -142
  1098. package/scripts/gds/smoke-gds.js +6 -255
  1099. package/scripts/gds/smoke-write.sh +7 -274
  1100. package/scripts/gds/source-text-test-scan.js +7 -0
  1101. package/scripts/gds/spark.js +6 -293
  1102. package/scripts/gds/stale-worktrees.js +5 -210
  1103. package/scripts/gds/start-goals.js +5 -101
  1104. package/scripts/gds/start.js +6 -1089
  1105. package/scripts/gds/status.js +6 -544
  1106. package/scripts/gds/strand-watch.js +5 -313
  1107. package/scripts/gds/stranded-rows.js +5 -198
  1108. package/scripts/gds/stray-unit-sweep.sh +7 -70
  1109. package/scripts/gds/surface.js +5 -100
  1110. package/scripts/gds/task.js +6 -272
  1111. package/scripts/gds/test-path-guard.js +5 -97
  1112. package/scripts/gds/triage.js +6 -741
  1113. package/scripts/gds/turn-end-sound.js +5 -72
  1114. package/scripts/gds/tweak-halt.js +5 -68
  1115. package/scripts/gds/tweak-renders.js +5 -198
  1116. package/scripts/gds/uat.js +6 -119
  1117. package/scripts/gds/ui-kit-transform.js +5 -41
  1118. package/scripts/gds/update-channel.js +5 -510
  1119. package/scripts/gds/update-sweep.js +5 -827
  1120. package/scripts/gds/upgrade-artist-gate.js +5 -45
  1121. package/scripts/gds/upgrade-commit-identity.js +5 -31
  1122. package/scripts/gds/upgrade-migrate.js +5 -223
  1123. package/scripts/gds/upgrade-operator.js +6 -73
  1124. package/scripts/gds/upgrade-outcome.js +5 -173
  1125. package/scripts/gds/upgrade.js +5 -1497
  1126. package/scripts/gds/validate-design.js +5 -10
  1127. package/scripts/gds/version-close.js +6 -620
  1128. package/scripts/gds/version-literal-guard.js +5 -138
  1129. package/scripts/gds/version-select.js +5 -77
  1130. package/scripts/gds/visual-review-nudge.js +5 -38
  1131. package/scripts/gds/wedge-remedy.js +5 -173
  1132. package/scripts/gds/worktree-claim-guard.js +5 -129
  1133. package/scripts/gds/worktree.js +6 -448
  1134. package/scripts/hall-preview/refresh-fixtures.js +1 -1
  1135. package/scripts/hall-preview/server.js +2 -2
  1136. package/scripts/migrate.sh +3 -3
  1137. package/scripts/public-mirror-export.js +3 -3
  1138. package/scripts/setup-builder.js +7 -7
  1139. package/src/bongos/api-errors.js +1 -0
  1140. package/src/bongos/api-prefix.js +1 -1
  1141. package/src/bongos/auth-github.js +19 -3
  1142. package/src/bongos/auth-idp.js +7 -0
  1143. package/src/bongos/claim-attribution.js +2 -2
  1144. package/src/bongos/core-moves.js +1 -1
  1145. package/src/bongos/core-update.js +3 -3
  1146. package/src/bongos/craft-mode.js +2 -2
  1147. package/src/bongos/db-kernel.js +15 -3
  1148. package/src/bongos/db.js +30 -4
  1149. package/src/bongos/github-repos.js +1 -1
  1150. package/src/bongos/llm-cache.js +1 -1
  1151. package/src/bongos/llm-pricing.js +1 -1
  1152. package/src/bongos/metrics.js +1 -1
  1153. package/src/bongos/middleware/rate-limit.js +2 -2
  1154. package/src/bongos/module-listing.js +93 -1
  1155. package/src/bongos/module-scope-map.js +90 -85
  1156. package/src/bongos/module-store.js +1 -1
  1157. package/src/bongos/module-submissions.js +1 -1
  1158. package/src/bongos/optimizer.js +1 -1
  1159. package/src/bongos/package-registry.js +1 -1
  1160. package/src/bongos/path-match.js +1 -1
  1161. package/src/bongos/permission-path-check.js +3 -3
  1162. package/src/bongos/platform-visibility-gate.js +3 -5
  1163. package/src/bongos/prelaunch-gate.js +7 -6
  1164. package/src/bongos/route-rank-check.js +2 -2
  1165. package/src/bongos/routes/auth.js +15 -2
  1166. package/src/bongos/routes/backup.js +1 -1
  1167. package/src/bongos/routes/builders.js +29 -1
  1168. package/src/bongos/routes/me.js +49 -18
  1169. package/src/bongos/routes/modules.js +29 -9
  1170. package/src/bongos/routes/public.js +3 -72
  1171. package/src/bongos/schema-lag.js +1 -1
  1172. package/src/bongos/sensitive-surfaces.js +1 -1
  1173. package/src/bongos/serve-internal.js +65 -16
  1174. package/src/bongos/software-update.js +2 -2
  1175. package/src/bongos/upgrade-hold.js +3 -3
  1176. package/src/hall-look.js +6 -5
  1177. package/src/module-api.js +3 -3
  1178. package/src/module-loader/catalog.js +1 -1
  1179. package/src/module-loader/error-tally.js +3 -3
  1180. package/src/module-loader/manifest-schema.js +3 -3
  1181. package/src/platform-server.js +10 -0
  1182. package/src/role-responsibilities.js +1 -1
  1183. package/src/stale-timer.js +2 -2
  1184. package/tests/accessibility_replay.mjs +1 -1
  1185. package/tests/activity_rollup_order_db.mjs +1 -1
  1186. package/tests/activity_snapshots_db.mjs +1 -1
  1187. package/tests/adopt_detect.mjs +1 -1
  1188. package/tests/adopt_import.mjs +1 -1
  1189. package/tests/adopt_preflight.mjs +1 -1
  1190. package/tests/adr_0089_scope.mjs +10 -7
  1191. package/tests/adr_0162_citation.mjs +1 -1
  1192. package/tests/adr_0162_gate_citation.mjs +1 -1
  1193. package/tests/agent_invoke.mjs +1 -1
  1194. package/tests/agent_invoke_live.mjs +3 -3
  1195. package/tests/agents_cron_trigger.mjs +2 -2
  1196. package/tests/agents_roster.mjs +1 -1
  1197. package/tests/agents_sync.mjs +4 -4
  1198. package/tests/allow_rule_guard.mjs +20 -20
  1199. package/tests/api_alias_caller_ratchet.mjs +9 -10
  1200. package/tests/api_alias_exceptions.mjs +7 -6
  1201. package/tests/api_artifacts.mjs +214 -0
  1202. package/tests/api_cli_flags.mjs +3 -3
  1203. package/tests/api_client.mjs +56 -54
  1204. package/tests/api_docs.mjs +30 -9
  1205. package/tests/api_error_envelope_buildcheck.mjs +1 -1
  1206. package/tests/api_msys_path_repair.mjs +2 -2
  1207. package/tests/architect.mjs +1 -1
  1208. package/tests/art_stage.mjs +2 -2
  1209. package/tests/artifact_audit.mjs +2 -2
  1210. package/tests/artifact_staleness.mjs +9 -9
  1211. package/tests/atlas.mjs +1 -1
  1212. package/tests/audit_deps.mjs +1 -1
  1213. package/tests/audit_gate.mjs +1 -1
  1214. package/tests/auth_flow_slice1.mjs +3 -3
  1215. package/tests/auth_inactive_builder.mjs +43 -5
  1216. package/tests/auth_session_expiry_db.mjs +16 -4
  1217. package/tests/auth_session_ttl.mjs +23 -0
  1218. package/tests/authorship_audit.mjs +2 -2
  1219. package/tests/autobongos_cadence.mjs +1 -1
  1220. package/tests/autobongos_fence.mjs +1 -1
  1221. package/tests/autobongos_grade_cap.mjs +2 -2
  1222. package/tests/autobongos_heartbeat_head.mjs +1 -1
  1223. package/tests/autobongos_host_access.mjs +3 -3
  1224. package/tests/autobongos_loop.mjs +17 -17
  1225. package/tests/autobongos_service_ps1.mjs +3 -3
  1226. package/tests/autobongos_tweak_lane.mjs +2 -2
  1227. package/tests/autobongos_verify.mjs +2 -2
  1228. package/tests/autonomous_fit_protected_paths.mjs +3 -3
  1229. package/tests/autonomy_config_idle.mjs +1 -1
  1230. package/tests/autonomy_digest.mjs +1 -1
  1231. package/tests/autonomy_gate.mjs +1 -1
  1232. package/tests/autonomy_gauge.mjs +2 -2
  1233. package/tests/autonomy_runner_identity.mjs +1 -1
  1234. package/tests/backfill_sessions.mjs +8 -8
  1235. package/tests/backfill_subagent_rewards.mjs +1 -1
  1236. package/tests/backfill_task_rewards.mjs +2 -2
  1237. package/tests/backlog_review.mjs +3 -3
  1238. package/tests/baseline_staleness.mjs +2 -2
  1239. package/tests/bfg.mjs +11 -5
  1240. package/tests/bfg_write.mjs +20 -11
  1241. package/tests/blockers_hall.mjs +17 -5
  1242. package/tests/blockers_page_ui.mjs +56 -12
  1243. package/tests/bongos_dispatch.mjs +5 -5
  1244. package/tests/bongos_login.mjs +2 -2
  1245. package/tests/bug_attachment_audit.mjs +1 -1
  1246. package/tests/bug_attachment_recover.mjs +2 -2
  1247. package/tests/bug_triage.mjs +3 -3
  1248. package/tests/build_info.mjs +1 -1
  1249. package/tests/builder_tester_tag.mjs +184 -0
  1250. package/tests/bump_version.mjs +3 -3
  1251. package/tests/canonical_profile_url.mjs +1 -1
  1252. package/tests/capture_error_format.mjs +1 -1
  1253. package/tests/capture_goal_routing.mjs +2 -2
  1254. package/tests/category_advisory_guard.mjs +3 -3
  1255. package/tests/claim_error_surface.mjs +2 -2
  1256. package/tests/claim_from_task_and_home.mjs +1 -1
  1257. package/tests/claim_gate_open_blocker.mjs +7 -4
  1258. package/tests/claim_gate_rebase.mjs +12 -8
  1259. package/tests/claim_recall.mjs +4 -4
  1260. package/tests/claim_resolve_worktree_lock.mjs +1 -1
  1261. package/tests/claude_materialize.mjs +58 -58
  1262. package/tests/clawback_confirmed_backlog.mjs +8 -5
  1263. package/tests/cli_allowlist_permissions.mjs +11 -11
  1264. package/tests/cli_dispatcher.mjs +2 -2
  1265. package/tests/cli_err_code.mjs +6 -6
  1266. package/tests/cli_exit_no_abort.mjs +7 -7
  1267. package/tests/cli_lib_formatters.mjs +2 -2
  1268. package/tests/cli_sessions.mjs +5 -5
  1269. package/tests/cli_surface.mjs +15 -15
  1270. package/tests/cli_token_reissue.mjs +2 -2
  1271. package/tests/client_baseurl_guard.mjs +1 -1
  1272. package/tests/client_bundle_route.mjs +35 -4
  1273. package/tests/cloud_bongos_pack.mjs +1 -1
  1274. package/tests/community_leaderboard_db.mjs +1 -1
  1275. package/tests/conductor.mjs +18 -18
  1276. package/tests/conflict_resolve.mjs +14 -16
  1277. package/tests/consumer_layout_boot.mjs +12 -12
  1278. package/tests/context_pack.mjs +6 -6
  1279. package/tests/control_manifest.mjs +4 -4
  1280. package/tests/copy_desk_page_reads.mjs +1 -1
  1281. package/tests/copy_desk_page_release.mjs +192 -0
  1282. package/tests/copy_inventory.mjs +2 -2
  1283. package/tests/core_auto_upgrade.mjs +1 -1
  1284. package/tests/core_move_notice.mjs +2 -2
  1285. package/tests/core_origin_follow.mjs +7 -7
  1286. package/tests/core_pin_sync.mjs +3 -3
  1287. package/tests/core_upgrade_door.mjs +2 -2
  1288. package/tests/core_upgrade_owner_door.mjs +34 -1
  1289. package/tests/core_upgrade_runner.mjs +19 -19
  1290. package/tests/credential_presence.mjs +2 -2
  1291. package/tests/credit_grant.mjs +3 -3
  1292. package/tests/credit_log_single_writer.mjs +5 -5
  1293. package/tests/criterion_ref_status.mjs +2 -2
  1294. package/tests/cross_discipline_priority_direction.mjs +3 -3
  1295. package/tests/cutover_codemod.mjs +2 -4
  1296. package/tests/db_backup_nightly.mjs +1 -1
  1297. package/tests/db_backup_offsite.mjs +1 -1
  1298. package/tests/db_ownership_handover.mjs +2 -2
  1299. package/tests/dead_deps.mjs +3 -3
  1300. package/tests/dependency_advisory.mjs +1 -1
  1301. package/tests/deploy_audit_gate.mjs +4 -4
  1302. package/tests/deploy_divergence_line.mjs +36 -16
  1303. package/tests/deploy_page_projects.mjs +35 -4
  1304. package/tests/dev_lib.mjs +2 -2
  1305. package/tests/dev_windows.mjs +2 -2
  1306. package/tests/diagram_facts_offset.mjs +1 -1
  1307. package/tests/diagram_repo_slug.mjs +1 -1
  1308. package/tests/diff_derived_signals.mjs +2 -2
  1309. package/tests/dns_preflight.mjs +2 -2
  1310. package/tests/do_api.mjs +3 -3
  1311. package/tests/doc_cli_guard.mjs +28 -28
  1312. package/tests/doc_comment_coverage.mjs +1 -1
  1313. package/tests/doc_control_claims.mjs +11 -11
  1314. package/tests/docs_entropy.mjs +2 -2
  1315. package/tests/docs_openapi_route.mjs +8 -6
  1316. package/tests/doctor_hooks.mjs +1 -1
  1317. package/tests/edit_hints.mjs +3 -2
  1318. package/tests/effective_visibility_predicate.mjs +3 -3
  1319. package/tests/env_knobs_neutral_prefix.mjs +13 -13
  1320. package/tests/exec_path_guard.mjs +4 -4
  1321. package/tests/executed_closure.mjs +18 -12
  1322. package/tests/file_map.mjs +1 -1
  1323. package/tests/find_untested.mjs +13 -13
  1324. package/tests/first_admin_bootstrap.mjs +1 -1
  1325. package/tests/fitness.mjs +16 -16
  1326. package/tests/fitness_gds_ratchet.mjs +2 -2
  1327. package/tests/fitness_installed_core.mjs +3 -3
  1328. package/tests/fitness_no_raw_nul.mjs +1 -1
  1329. package/tests/fitness_ratchets.mjs +3 -3
  1330. package/tests/fitness_scope_roster.mjs +2 -2
  1331. package/tests/fitness_two_root.mjs +8 -8
  1332. package/tests/fixtures/accessibility-replay.json +5 -5
  1333. package/tests/fixtures/grade-replay/recorded-panel-grades.json +1 -1
  1334. package/tests/fixtures/ideator-prefold/README.md +1 -1
  1335. package/tests/fixtures/page-ledger.mjs +22 -0
  1336. package/tests/fixtures/session-506-digest.json +5 -5
  1337. package/tests/gate_approvals.mjs +50 -0
  1338. package/tests/gate_review.mjs +8 -8
  1339. package/tests/gating_review_retired.mjs +2 -2
  1340. package/tests/gen_freshness.mjs +3 -3
  1341. package/tests/git_guard.mjs +3 -3
  1342. package/tests/git_merge_regen.mjs +41 -65
  1343. package/tests/github_one_trip.mjs +4 -4
  1344. package/tests/github_pick_up.mjs +2 -2
  1345. package/tests/github_push_merge_driver.mjs +1 -1
  1346. package/tests/go_live.mjs +3 -2
  1347. package/tests/goal_category.mjs +1 -1
  1348. package/tests/goal_cli.mjs +2 -2
  1349. package/tests/goal_create_spec_entry.mjs +1 -1
  1350. package/tests/goal_invite_consent.mjs +3 -1
  1351. package/tests/goal_move.mjs +1 -1
  1352. package/tests/goal_names.mjs +2 -2
  1353. package/tests/goal_working_area.mjs +1 -1
  1354. package/tests/government_agent_asks.mjs +7 -7
  1355. package/tests/government_board_room_copy.mjs +6 -1
  1356. package/tests/government_board_view.mjs +39 -0
  1357. package/tests/government_board_vote_ui.mjs +39 -1
  1358. package/tests/government_config.mjs +2 -2
  1359. package/tests/government_live_proof_shape.mjs +1 -1
  1360. package/tests/government_protected_surfaces.mjs +54 -53
  1361. package/tests/government_require_permission.mjs +9 -1
  1362. package/tests/government_vanilla_boot.mjs +1 -1
  1363. package/tests/government_vocabulary.mjs +2 -2
  1364. package/tests/government_walk.mjs +2 -2
  1365. package/tests/grade_body_limit.mjs +6 -4
  1366. package/tests/grade_correlation_audit.mjs +3 -3
  1367. package/tests/grade_diff_hash.mjs +1 -1
  1368. package/tests/grade_engine_replay.mjs +2 -2
  1369. package/tests/grade_server_authoritative.mjs +1 -1
  1370. package/tests/grade_unavailable_display.mjs +1 -1
  1371. package/tests/grader.mjs +8 -24
  1372. package/tests/grader_generated_provenance.mjs +14 -14
  1373. package/tests/grader_no_artifact.mjs +1 -1
  1374. package/tests/grader_prompt_fencing.mjs +1 -1
  1375. package/tests/grader_quality_window_overflow.mjs +1 -1
  1376. package/tests/grader_reader_lens.mjs +3 -3
  1377. package/tests/grader_regrade_delta.mjs +1 -1
  1378. package/tests/grader_unbacked_score.mjs +2 -2
  1379. package/tests/hall_acclaim_vote_control.mjs +113 -0
  1380. package/tests/hall_asset_cache.mjs +127 -0
  1381. package/tests/hall_audit.mjs +63 -0
  1382. package/tests/hall_board_world.mjs +20 -0
  1383. package/tests/hall_city_card_words.mjs +61 -0
  1384. package/tests/hall_client_request_shape.mjs +5 -1
  1385. package/tests/hall_home_ships_bounded.mjs +160 -0
  1386. package/tests/hall_landing_boot.mjs +15 -2
  1387. package/tests/hall_nav.mjs +33 -0
  1388. package/tests/hall_onboarding_bongos_setup.mjs +1 -1
  1389. package/tests/hall_oversight_world.mjs +44 -4
  1390. package/tests/hall_palette.mjs +12 -9
  1391. package/tests/hall_preview_security.mjs +1 -1
  1392. package/tests/hall_profile_world.mjs +17 -0
  1393. package/tests/hall_reading_world.mjs +16 -1
  1394. package/tests/hall_roster_world.mjs +2 -1
  1395. package/tests/hall_studio_world.mjs +4 -1
  1396. package/tests/hall_work_history_id.mjs +39 -0
  1397. package/tests/held_tweak_reporting.mjs +4 -4
  1398. package/tests/helpers.mjs +3 -3
  1399. package/tests/home_attention_cards.mjs +2 -0
  1400. package/tests/home_bounded_reads.mjs +1 -1
  1401. package/tests/home_isolation_guard.mjs +1 -1
  1402. package/tests/hook_core_resolve.mjs +7 -7
  1403. package/tests/hook_user_agents.mjs +1 -1
  1404. package/tests/hooks_drain.mjs +2 -2
  1405. package/tests/host_topology_skips.mjs +1 -1
  1406. package/tests/howto_guide.mjs +1 -1
  1407. package/tests/howto_moments.mjs +3 -3
  1408. package/tests/hub_account_page.mjs +1 -1
  1409. package/tests/idea_capture_grades.mjs +2 -2
  1410. package/tests/idea_develop_spark.mjs +1 -1
  1411. package/tests/idea_filed_via.mjs +2 -2
  1412. package/tests/idea_ideate_full.mjs +1 -1
  1413. package/tests/idea_spark_mark.mjs +1 -1
  1414. package/tests/idea_spark_queue.mjs +1 -1
  1415. package/tests/idea_triage.mjs +1 -1
  1416. package/tests/idea_triage_grade.mjs +3 -3
  1417. package/tests/idea_vote_permission.mjs +113 -0
  1418. package/tests/idea_votes_fold_db.mjs +123 -0
  1419. package/tests/infra_exec_paths.mjs +12 -12
  1420. package/tests/init.mjs +2 -2
  1421. package/tests/instance_db_migrated_on_code_move.mjs +5 -5
  1422. package/tests/instance_feedback.mjs +9 -9
  1423. package/tests/instance_mismatch_guard.mjs +2 -2
  1424. package/tests/integration_parked_ratchet.mjs +24 -2
  1425. package/tests/intent_retry.mjs +1 -1
  1426. package/tests/interaction_posture.mjs +3 -3
  1427. package/tests/invite_expiry_db.mjs +1 -1
  1428. package/tests/joinability_invite_only.mjs +1 -1
  1429. package/tests/karma_vote_lists.mjs +270 -0
  1430. package/tests/key-card.mjs +2 -2
  1431. package/tests/key-status.mjs +2 -2
  1432. package/tests/knip_ratchet_ambient.mjs +2 -2
  1433. package/tests/known_failing_ratchet.mjs +1 -1
  1434. package/tests/land_watch.mjs +2 -2
  1435. package/tests/landing_legal_pages.mjs +1 -1
  1436. package/tests/landing_page.mjs +2 -2
  1437. package/tests/leaderboard_roles.mjs +4 -1
  1438. package/tests/leak_scan_allowlist.mjs +8 -8
  1439. package/tests/leak_scan_fail_closed.mjs +1 -1
  1440. package/tests/lib_sh_resolution.mjs +9 -9
  1441. package/tests/lifecycle-card.mjs +7 -7
  1442. package/tests/linkify_check.mjs +2 -2
  1443. package/tests/linkify_refs.mjs +1 -1
  1444. package/tests/llm-cache-route.mjs +1 -1
  1445. package/tests/local_preview.mjs +2 -2
  1446. package/tests/main_audit.mjs +3 -3
  1447. package/tests/main_audit_attestation.mjs +1 -1
  1448. package/tests/main_audit_db_roster.mjs +2 -2
  1449. package/tests/main_worktree_busy_reason.mjs +3 -3
  1450. package/tests/markdown_line_endings.mjs +2 -2
  1451. package/tests/me_streak_leaderboard_queries.mjs +193 -0
  1452. package/tests/membership_kind_lockstep.mjs +1 -1
  1453. package/tests/memory_isolation.mjs +16 -8
  1454. package/tests/memory_map.mjs +2 -2
  1455. package/tests/memory_pull.mjs +33 -25
  1456. package/tests/merge_driver_register.mjs +3 -3
  1457. package/tests/migration_allocation.mjs +2 -2
  1458. package/tests/migration_namespace.mjs +1 -1
  1459. package/tests/migrations_forward_safe.mjs +1 -1
  1460. package/tests/mingle.mjs +1 -1
  1461. package/tests/mirror_lineage_fulltree.mjs +3 -3
  1462. package/tests/mirror_lineage_proof.mjs +2 -2
  1463. package/tests/mirror_redact.mjs +4 -4
  1464. package/tests/missing_dep_classify.mjs +3 -3
  1465. package/tests/module-scope-map.mjs +22 -22
  1466. package/tests/module_api_lazy.mjs +1 -1
  1467. package/tests/module_assess_docs.mjs +2 -2
  1468. package/tests/module_assess_installs.mjs +3 -3
  1469. package/tests/module_assess_price_parity.mjs +5 -5
  1470. package/tests/module_assess_score.mjs +5 -5
  1471. package/tests/module_assess_security.mjs +4 -4
  1472. package/tests/module_assess_tests.mjs +3 -3
  1473. package/tests/module_assessments_migration.mjs +1 -1
  1474. package/tests/module_catalog.mjs +2 -2
  1475. package/tests/module_cli.mjs +3 -3
  1476. package/tests/module_entitlements.mjs +1 -1
  1477. package/tests/module_error_counts.mjs +1 -1
  1478. package/tests/module_install.mjs +4 -4
  1479. package/tests/module_loader.mjs +3 -1
  1480. package/tests/module_owned_tests.mjs +1 -1
  1481. package/tests/module_release_channels.mjs +1 -1
  1482. package/tests/module_store_howto.mjs +3 -3
  1483. package/tests/module_store_listing.mjs +139 -2
  1484. package/tests/module_store_publish.mjs +4 -4
  1485. package/tests/module_store_publish_route.mjs +1 -1
  1486. package/tests/module_store_reassess.mjs +1 -1
  1487. package/tests/module_store_registry_migration.mjs +1 -1
  1488. package/tests/module_test_runner.mjs +3 -3
  1489. package/tests/module_update.mjs +4 -4
  1490. package/tests/module_upgrade_updates.mjs +1 -1
  1491. package/tests/move_escalation.mjs +2 -2
  1492. package/tests/nav_permission_atoms.mjs +3 -2
  1493. package/tests/needs_rebase.mjs +7 -3
  1494. package/tests/newcomer_floor.mjs +1 -1
  1495. package/tests/newcomer_generator.mjs +48 -0
  1496. package/tests/next_number.mjs +1 -1
  1497. package/tests/no_artifact_escalation.mjs +3 -3
  1498. package/tests/npm_release_where.mjs +1 -1
  1499. package/tests/oauth_secret.mjs +2 -2
  1500. package/tests/onboard.mjs +6 -6
  1501. package/tests/onboarding_gate.mjs +2 -2
  1502. package/tests/opt_in_skill_modules.mjs +3 -3
  1503. package/tests/own_scope_guard.mjs +1 -1
  1504. package/tests/own_session_revoke.mjs +4 -1
  1505. package/tests/package_core.mjs +10 -11
  1506. package/tests/page_inventory.mjs +5 -5
  1507. package/tests/page_reader.mjs +7 -7
  1508. package/tests/page_tweak_hold.mjs +6 -6
  1509. package/tests/parallel-load.mjs +1 -1
  1510. package/tests/paste_token_api_base.mjs +1 -1
  1511. package/tests/paste_token_session_store.mjs +2 -2
  1512. package/tests/pending_invite_purge_db.mjs +1 -1
  1513. package/tests/permission_path.mjs +1 -1
  1514. package/tests/pin_replay.mjs +1 -1
  1515. package/tests/pin_write_key.mjs +7 -7
  1516. package/tests/plain_cards.mjs +15 -15
  1517. package/tests/pr_assign.mjs +1 -1
  1518. package/tests/pre_push_hook.mjs +3 -3
  1519. package/tests/preflight_checks.mjs +2 -2
  1520. package/tests/prelaunch_gate.mjs +1 -1
  1521. package/tests/privacy_matrix.mjs +1 -1
  1522. package/tests/probe_cache.mjs +6 -6
  1523. package/tests/profile_connections_ui.mjs +4 -3
  1524. package/tests/profile_fields.mjs +11 -1
  1525. package/tests/profile_privacy_owner_view.mjs +1 -1
  1526. package/tests/profile_role_headline.mjs +10 -9
  1527. package/tests/project_admin_console_model.mjs +1 -1
  1528. package/tests/projects_hub.mjs +1 -1
  1529. package/tests/projects_hub_cloud_hop.mjs +1 -1
  1530. package/tests/promote_goal_id.mjs +6 -6
  1531. package/tests/promotion_sweep.mjs +1 -1
  1532. package/tests/provision.mjs +24 -24
  1533. package/tests/provision_account_identity.mjs +2 -2
  1534. package/tests/provision_byo_host.mjs +1 -1
  1535. package/tests/provision_caddy_wiring.mjs +2 -2
  1536. package/tests/provision_disconnect.mjs +2 -2
  1537. package/tests/provision_dns_first.mjs +1 -1
  1538. package/tests/provision_render.mjs +9 -9
  1539. package/tests/provision_repo_private.mjs +3 -3
  1540. package/tests/provision_resource_caps.mjs +5 -5
  1541. package/tests/provision_restart.mjs +3 -3
  1542. package/tests/provision_settings_apply.mjs +7 -7
  1543. package/tests/provision_teardown_address.mjs +2 -2
  1544. package/tests/provisioning_capacity.mjs +5 -5
  1545. package/tests/provisioning_credential_preflight.mjs +1 -1
  1546. package/tests/provisioning_disconnect.mjs +1 -1
  1547. package/tests/provisioning_error_note_scope.mjs +4 -4
  1548. package/tests/provisioning_paid_shape_gate.mjs +2 -2
  1549. package/tests/provisioning_planet_physics.mjs +16 -0
  1550. package/tests/provisioning_runner_drift_notice.mjs +2 -2
  1551. package/tests/provisioning_settings_env.mjs +1 -1
  1552. package/tests/pruned_lockfile_integrity.mjs +1 -1
  1553. package/tests/public_mirror_export.mjs +1 -1
  1554. package/tests/publish_integration_gate.mjs +2 -2
  1555. package/tests/publish_manifest.mjs +6 -6
  1556. package/tests/publish_watch.mjs +1 -1
  1557. package/tests/push_path_brief.mjs +2 -2
  1558. package/tests/raise.mjs +248 -0
  1559. package/tests/rank_roles_audit.mjs +1 -1
  1560. package/tests/rank_tier_single_source.mjs +2 -2
  1561. package/tests/rate_limit_public.mjs +1 -1
  1562. package/tests/read_default_meter.mjs +2 -2
  1563. package/tests/read_session_export.mjs +1 -1
  1564. package/tests/rebase_gate_set_aside.mjs +1 -1
  1565. package/tests/recall_cli.mjs +1 -1
  1566. package/tests/recall_corpus_health.mjs +3 -2
  1567. package/tests/recall_hints.mjs +1 -1
  1568. package/tests/recruiter_sliver_boundary.mjs +1 -1
  1569. package/tests/redteam_patrol.mjs +2 -2
  1570. package/tests/regrade_actual_minutes.mjs +2 -2
  1571. package/tests/regrade_eligibility.mjs +2 -2
  1572. package/tests/release_core.mjs +2 -2
  1573. package/tests/release_notes.mjs +4 -4
  1574. package/tests/rename_history_restraint.mjs +3 -3
  1575. package/tests/rename_ledger_prose.mjs +6 -6
  1576. package/tests/render_api.mjs +1 -1
  1577. package/tests/render_check.mjs +4 -4
  1578. package/tests/render_deploy.mjs +1 -1
  1579. package/tests/repo_info_binding.mjs +1 -1
  1580. package/tests/repo_map.mjs +5 -5
  1581. package/tests/reward_mode_cost_plus_only.mjs +7 -3
  1582. package/tests/reward_mode_surfacing.mjs +1 -1
  1583. package/tests/role_responsibilities.mjs +1 -1
  1584. package/tests/rot_inbox.mjs +10 -7
  1585. package/tests/route_permission_check.mjs +1 -1
  1586. package/tests/route_shadow_guard.mjs +1 -1
  1587. package/tests/route_validation.mjs +1 -1
  1588. package/tests/routine_capture_kind.mjs +6 -6
  1589. package/tests/routine_schedule.mjs +9 -9
  1590. package/tests/run_routine.mjs +5 -5
  1591. package/tests/run_routine_two_root.mjs +5 -5
  1592. package/tests/runner_drift.mjs +17 -17
  1593. package/tests/sandbox_stage.mjs +5 -5
  1594. package/tests/scope_map_guard.mjs +7 -7
  1595. package/tests/scouting_owner_access_and_reach.mjs +1 -1
  1596. package/tests/scripts_gds_forwarders.mjs +224 -0
  1597. package/tests/scrubber_corpus.mjs +2 -2
  1598. package/tests/seam_wiring_guard.mjs +1 -1
  1599. package/tests/search_ingest.mjs +2 -2
  1600. package/tests/search_ingest_db.mjs +1 -1
  1601. package/tests/search_ingest_nul.mjs +6 -6
  1602. package/tests/seed_verify_criteria.mjs +3 -3
  1603. package/tests/sequence.mjs +3 -3
  1604. package/tests/served_paths_shipped.mjs +3 -3
  1605. package/tests/session_506_regression.mjs +1 -1
  1606. package/tests/session_accessibility.mjs +1 -1
  1607. package/tests/session_caps.mjs +1 -1
  1608. package/tests/session_cost.mjs +1 -1
  1609. package/tests/session_digest.mjs +2 -2
  1610. package/tests/session_eval.mjs +6 -6
  1611. package/tests/session_index.mjs +1 -1
  1612. package/tests/session_records.mjs +4 -4
  1613. package/tests/session_rename_fallback.mjs +2 -2
  1614. package/tests/session_reward_on_land.mjs +7 -149
  1615. package/tests/session_reward_on_land_db.mjs +191 -0
  1616. package/tests/session_reward_reconcile.mjs +6 -88
  1617. package/tests/session_reward_reconcile_db.mjs +132 -0
  1618. package/tests/session_transcript.mjs +1 -1
  1619. package/tests/sessions_kit_pager.mjs +2 -1
  1620. package/tests/setup_device_flow_fallback.mjs +2 -2
  1621. package/tests/setup_smoke.mjs +12 -5
  1622. package/tests/setup_status_facts.mjs +54 -12
  1623. package/tests/ship_autolinkify.mjs +2 -2
  1624. package/tests/ship_automerge_injection.mjs +1 -1
  1625. package/tests/ship_base_flag.mjs +1 -1
  1626. package/tests/ship_broadcast_routing.mjs +1 -1
  1627. package/tests/ship_broadcast_server.mjs +2 -2
  1628. package/tests/ship_builder_model.mjs +1 -1
  1629. package/tests/ship_cannot_lie.mjs +9 -9
  1630. package/tests/ship_card.mjs +2 -2
  1631. package/tests/ship_ci_deploy.mjs +7 -7
  1632. package/tests/ship_error_shape.mjs +1 -1
  1633. package/tests/ship_land_ci_not_started.mjs +3 -3
  1634. package/tests/ship_land_conflict.mjs +3 -3
  1635. package/tests/ship_land_proof.mjs +3 -3
  1636. package/tests/ship_land_red_pr.mjs +5 -5
  1637. package/tests/ship_merge_gate.mjs +14 -14
  1638. package/tests/ship_mode.mjs +1 -1
  1639. package/tests/ship_mode_first_ship.mjs +4 -4
  1640. package/tests/ship_mode_hands_off.mjs +8 -8
  1641. package/tests/ship_post_land_verify.mjs +1 -1
  1642. package/tests/ship_preflight.mjs +19 -19
  1643. package/tests/ship_premerge.mjs +1 -1
  1644. package/tests/ship_publish_error.mjs +2 -2
  1645. package/tests/ship_push_diagnosis.mjs +1 -1
  1646. package/tests/ship_regen_copy_inventory.mjs +3 -3
  1647. package/tests/ship_resume.mjs +4 -4
  1648. package/tests/ship_smoke_gate.mjs +1 -1
  1649. package/tests/ship_upload_skip.mjs +1 -1
  1650. package/tests/ship_upstream_deletion.mjs +1 -1
  1651. package/tests/ship_vendored_instance.mjs +8 -8
  1652. package/tests/ship_visual_regrade.mjs +3 -3
  1653. package/tests/ship_zero_commit.mjs +1 -1
  1654. package/tests/skill_docs_unavailable_regrade.mjs +3 -3
  1655. package/tests/skill_friction_kind.mjs +1 -1
  1656. package/tests/skill_grade_recover.mjs +1 -1
  1657. package/tests/skill_grader_health.mjs +1 -1
  1658. package/tests/skill_lint.mjs +1 -1
  1659. package/tests/skill_menu_ruling.mjs +1 -1
  1660. package/tests/skill_preflight.mjs +7 -7
  1661. package/tests/skip_is_not_pass.mjs +22 -1
  1662. package/tests/smoke_dependencies_witness.mjs +2 -2
  1663. package/tests/smoke_preflight.mjs +1 -1
  1664. package/tests/smoke_target.mjs +2 -2
  1665. package/tests/smoke_write_contract.mjs +2 -2
  1666. package/tests/sound_player.mjs +8 -8
  1667. package/tests/source_text_test_ratchet.mjs +97 -0
  1668. package/tests/speciality_corpus_scope.mjs +1 -1
  1669. package/tests/speciality_session_skills.mjs +1 -1
  1670. package/tests/sso_checkin_legacy_field_gone.mjs +4 -2
  1671. package/tests/stale_timer.mjs +3 -3
  1672. package/tests/stale_worktrees.mjs +1 -1
  1673. package/tests/start_env_guard.mjs +1 -1
  1674. package/tests/start_goal_first.mjs +3 -3
  1675. package/tests/start_inbox_count.mjs +1 -1
  1676. package/tests/start_rebase_warning.mjs +1 -1
  1677. package/tests/status_default_version.mjs +3 -3
  1678. package/tests/status_mirror_sync.mjs +1 -1
  1679. package/tests/status_page_no_dead_uptime.mjs +80 -0
  1680. package/tests/stop_refcheck.mjs +1 -1
  1681. package/tests/strand_watch.mjs +1 -1
  1682. package/tests/stranded_rows.mjs +1 -1
  1683. package/tests/stuck_detector.mjs +14 -14
  1684. package/tests/sweep_app_account.mjs +3 -3
  1685. package/tests/task_cli.mjs +2 -2
  1686. package/tests/task_detail_ui.mjs +11 -1
  1687. package/tests/task_discipline_required.mjs +2 -2
  1688. package/tests/task_list_paging.mjs +1 -1
  1689. package/tests/task_visual_slots.mjs +2 -2
  1690. package/tests/terms_acceptance.mjs +1 -1
  1691. package/tests/terms_grandfather_db.mjs +1 -1
  1692. package/tests/test_path_guard.mjs +1 -1
  1693. package/tests/triage_development.mjs +1 -1
  1694. package/tests/tweak_batch_apply.mjs +2 -2
  1695. package/tests/tweak_land_heal.mjs +3 -3
  1696. package/tests/tweak_unattended.mjs +3 -3
  1697. package/tests/ui_design_skills.mjs +2 -2
  1698. package/tests/unit_report_status.mjs +2 -2
  1699. package/tests/unit_runner_serial.mjs +2 -2
  1700. package/tests/unit_runner_teardown_abort.mjs +1 -1
  1701. package/tests/update_channel.mjs +2 -2
  1702. package/tests/update_channel_db.mjs +4 -4
  1703. package/tests/update_subscription_engine.mjs +26 -26
  1704. package/tests/update_sweep_home.mjs +14 -14
  1705. package/tests/upgrade.mjs +11 -11
  1706. package/tests/upgrade_artist_gate.mjs +4 -4
  1707. package/tests/upgrade_commit_identity.mjs +2 -2
  1708. package/tests/upgrade_migrate.mjs +7 -7
  1709. package/tests/upgrade_operator.mjs +2 -2
  1710. package/tests/upgrade_outcome.mjs +2 -2
  1711. package/tests/upgrade_persist_pin.mjs +5 -5
  1712. package/tests/upkeep_home.mjs +1 -1
  1713. package/tests/version_close.mjs +2 -2
  1714. package/tests/version_close_cli.mjs +2 -2
  1715. package/tests/version_close_route.mjs +1 -1
  1716. package/tests/version_literals.mjs +23 -23
  1717. package/tests/visual_review.mjs +5 -5
  1718. package/tests/wedge_remedy.mjs +5 -5
  1719. package/tests/welcome_boot.mjs +116 -0
  1720. package/tests/welcome_boot_browser.mjs +271 -0
  1721. package/tests/wizard_born_first_board.mjs +3 -3
  1722. package/tests/wizard_demo.mjs +1 -1
  1723. package/tests/wizard_one_page.mjs +4 -3
  1724. package/tests/wizard_physics.mjs +3 -1
  1725. package/tests/wizard_physics_more.mjs +42 -3
  1726. package/tests/work_title_wrap.mjs +1 -1
  1727. package/tests/workflow_exec_paths.mjs +6 -6
  1728. package/tests/worktree_claim_guard.mjs +1 -1
  1729. package/tests/worktree_helper.mjs +2 -2
  1730. package/tests/write_validation_gaps.mjs +3 -3
  1731. package/scripts/gds/api.sh +0 -6
  1732. package/scripts/gds/audit-exports.js +0 -128
  1733. package/scripts/gds/resolve-skill-model.js +0 -57
  1734. package/scripts/gds/security-baseline-check.sh +0 -180
  1735. package/scripts/gds/spike-task-map.js +0 -899
  1736. package/scripts/status-probe.mjs +0 -213
  1737. package/src/bongos/uptime-poller.js +0 -93
  1738. package/tests/government_fold_bench.mjs +0 -50
  1739. package/tests/spike_task_map.mjs +0 -422
  1740. package/tests/status-probe.mjs +0 -89
  1741. /package/{scripts/gds → modules/raise}/CLAUDE.md +0 -0
  1742. /package/scripts/{gds → bongos}/cloudbongos-token-isolation.conf +0 -0
  1743. /package/scripts/{gds → bongos}/discipline-modes.json +0 -0
  1744. /package/scripts/{gds → bongos}/retired-core-skills.json +0 -0
@@ -0,0 +1,1200 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // claude-materialize.js — materialize the .claude/ methodology surface into an instance
4
+ // (ADR 0108 §3, configurable-root W3 / task 1883).
5
+ //
6
+ // WHY. Claude Code discovers .claude/settings.json + hooks/ + skills/ from the PROJECT ROOT, never
7
+ // from a dependency. Once the Cloud Bongos core installs as a pinned npm package (ADR 0108), the
8
+ // ~35 skills sit in node_modules/@bongos/core/.claude/skills/ where Claude Code will not look —
9
+ // so `bongos init`/`upgrade` must COPY .claude/ into the instance repo. And a copied skill can't run
10
+ // `node scripts/bongos/<x>.js`: scripts/ lives in the package, not at the instance root. So every
11
+ // invocation is rewritten to the `bongos` bin, which resolves the heavy CLI inside the package —
12
+ // a dedicated verb where one exists (`bongos ship`), else the generic `bongos exec scripts/bongos/<x>.js`.
13
+ //
14
+ // BOUNDARY (publish-manifest). skills/ ships IN the core package (isPublishable) → materialized by
15
+ // copy+transform. hooks/ + settings.json are TOPOLOGY (PROTECTED_TOPOLOGY_EXCLUDE) → NOT in the
16
+ // package; this module copies+transforms them when they ARE present at the core root (today's single
17
+ // checkout, and the core repo itself), and no-ops with a note when they aren't (an installed package).
18
+ // Hooks self-resolve their core require()s at RUNTIME via the copied _core-resolve.js sibling
19
+ // (task 2139, the former W3 follow-up), so no require-path rewriting happens here. The topology
20
+ // STARTER for a package-only install is now HALF built: settings.json is written from
21
+ // renderStarterSettings() below — permissions only, no hooks — because an instance that received
22
+ // the skills but no permissions met the classifier on every blessed command (task 1003962). A hooks
23
+ // starter remains a follow-up (task 1883), and is a different question: hooks ARE gate machinery,
24
+ // where a list of allowed command names is not.
25
+ //
26
+ // SELF-COPY GUARD. When the instance dir IS the core root (running init inside the core checkout /
27
+ // OTB today), there is nothing to materialize — a self-copy would be a no-op at best and corrupting
28
+ // at worst. This module detects that and skips, so it is byte-identical for the live instance.
29
+
30
+ const fs = require('node:fs');
31
+ const path = require('node:path');
32
+ const { spawnSync } = require('node:child_process');
33
+ const crypto = require('node:crypto');
34
+ const { VERBS } = require('../../bin/bongos.js'); // side-effect-free require (guarded main)
35
+ const ic = require('../../src/instance-config'); // neutral configDir/envPrefix fallbacks (never a founder literal)
36
+ const { isCorePackageName, CORE_PACKAGE_NAMES } = require('../../src/module-loader/catalog'); // one definition of "this checkout IS the core"
37
+ const { renderInstanceClaudeMd, refreshStarterCliLines } = require('./claude-md-template'); // task 2104 — the starter CLAUDE.md
38
+
39
+ // script basename (e.g. "ship.js") → dedicated bongos verb, for verbs that map to a bare script with
40
+ // NO prefixArgs. Verbs whose script is driven by prefixArgs (box → api.js) are EXCLUDED so a generic
41
+ // `node scripts/bongos/dev.js …` never mis-maps to `bongos serve`; those fall to `bongos exec`. `exec`
42
+ // itself has no script and is skipped.
43
+ function scriptToVerb(verbs = VERBS) {
44
+ const m = {};
45
+ for (const [verb, def] of Object.entries(verbs)) {
46
+ if (!def || def.prefixArgs || !def.script) continue;
47
+ if (!(def.script in m)) m[def.script] = verb;
48
+ }
49
+ return m;
50
+ }
51
+
52
+ // Match `node [<quote>][$CLAUDE_PROJECT_DIR/|./]scripts/bongos/<name>.js[<quote>]` — the invocation form
53
+ // skills + settings.json hooks use. The optional $CLAUDE_PROJECT_DIR/ or ./ prefix and surrounding
54
+ // quote are consumed so the whole thing collapses to the bongos form. `.claude/hooks/<x>.js` refs are
55
+ // deliberately NOT matched (this targets scripts/bongos/) — those stay instance-local after materialize.
56
+ // The launcher is bare `node`, OR the hook resolver `sh "$CLAUDE_PROJECT_DIR/.claude/hooks/run-node.sh"`
57
+ // that every settings.json hook command goes through since task 1003548 (it finds node when the hook
58
+ // shell's PATH lacks it). Both collapse to the same bongos form; a resolver call whose target is a
59
+ // .claude/hooks/*.js stays untouched exactly like the bare-node form did.
60
+ const LAUNCHER = String.raw`(?:node|sh\s+"?(?:\$CLAUDE_PROJECT_DIR\/|\.\/)?\.claude\/hooks\/run-node\.sh"?)`;
61
+ const GDS_INVOCATION_RE = new RegExp(LAUNCHER + String.raw`\s+"?(?:\$CLAUDE_PROJECT_DIR\/|\.\/)?scripts\/(?:gds|bongos)\/([a-zA-Z0-9_-]+)\.js"?`, 'g');
62
+ // A non-gds core script under scripts/ (rare in skills, but keep the transform total).
63
+ const OTHER_SCRIPT_RE = new RegExp(LAUNCHER + String.raw`\s+"?(?:\$CLAUDE_PROJECT_DIR\/|\.\/)?scripts\/((?!(?:gds|bongos)\/)[a-zA-Z0-9_./-]+\.js)"?`, 'g');
64
+
65
+ // How a project runs the CLI (task 1004621). The `bongos` bin ships inside the @bongos/core
66
+ // dependency (node_modules/.bin/bongos), which is NOT on PATH, so a bare `bongos ship` written
67
+ // into a project's skills failed with `command not found` on every session's first call and the
68
+ // assistant had to recover by retrying through npx. `npx` finds the project's own bin right after
69
+ // `npm install`, with no setup, on every OS and shell — so that is the spelling a project reads.
70
+ const PROJECT_CLI = 'npx bongos';
71
+
72
+ // A hand-written bare `bongos <verb>` in skill prose (e.g. "`bongos paste-token <token>`"), so it
73
+ // takes the npx spelling too. Case-sensitive on purpose ("Bongos status" is a product noun), only a
74
+ // KNOWN verb, and never when already prefixed by `npx ` or glued to a path/name (`@bongos/core`,
75
+ // `bongos-feedback`, `bongos: command not found` all stay). The `npx ` lookbehind is what keeps a
76
+ // second run from writing `npx npx bongos`.
77
+ function bareVerbRe(verbs) {
78
+ const names = Object.keys(verbs || {}).filter((v) => /^[a-z][a-z-]*$/.test(v));
79
+ if (!names.length) return null;
80
+ names.sort((a, b) => b.length - a.length); // `paste-token` before a shorter prefix of it
81
+ return new RegExp(String.raw`(?<![\w@/.\-])(?<!npx )bongos (${names.join('|')})(?![\w-])`, 'g');
82
+ }
83
+
84
+ // Pure: rewrite core-script invocations in a skill/settings command string to the project's CLI
85
+ // spelling (`npx bongos <verb>`, else `npx bongos exec scripts/bongos/<x>.js`), and give any bare
86
+ // `bongos <verb>` the same npx prefix. Idempotent: its own output contains neither a
87
+ // `node scripts/…` invocation nor an un-prefixed `bongos <verb>`, so a second run changes nothing.
88
+ function bongosify(text, verbs = VERBS) {
89
+ const map = scriptToVerb(verbs);
90
+ const bare = bareVerbRe(verbs);
91
+ let out = String(text == null ? '' : text);
92
+ if (bare) out = out.replace(bare, (_whole, verb) => `${PROJECT_CLI} ${verb}`);
93
+ return out
94
+ .replace(GDS_INVOCATION_RE, (_whole, script) => {
95
+ const verb = map[`${script}.js`];
96
+ return verb ? `${PROJECT_CLI} ${verb}` : `${PROJECT_CLI} exec scripts/bongos/${script}.js`;
97
+ })
98
+ .replace(OTHER_SCRIPT_RE, (_whole, rel) => `${PROJECT_CLI} exec scripts/${rel}`);
99
+ }
100
+
101
+ // ---- instance rebrand (task 2103) -----------------------------------------
102
+ // The scaffolded .claude/ used to carry the SOURCE instance's identity verbatim:
103
+ // hooks hardcoded the founder origin (e.g. a `https://example.com` fallback)
104
+ // and config dir (`~/.config/otb`), so a fresh clone's hooks phoned home to the
105
+ // WRONG instance — the 2026-07-08 demo-session failure. materialize now rewrites
106
+ // those founder literals to the TARGET instance's own values, derived from the two
107
+ // branding objects, so no source host survives. Focused + FULL-HOST (a subdomain
108
+ // like demo.cloudbongos.com is preserved), fail-open (a missing field drops that
109
+ // one rule), a no-op when source == target, and it touches ONLY the copied output
110
+ // (never the running source hooks). It does NOT rewrite hooks' internal
111
+ // require('scripts/bongos/…') paths — those self-resolve at runtime via the copied
112
+ // _core-resolve.js sibling (task 2139); this rule lands the origin/config-dir neutralization.
113
+
114
+ function reEsc(s) { return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }
115
+ function hostOf(origin) { try { return new URL(String(origin)).host || null; } catch { return null; } }
116
+
117
+ // Effective config dir / env prefix for a branding — the SAME neutral fallbacks
118
+ // instance-config uses, so nothing here is ever a founder literal (R76-safe).
119
+ function effConfigDir(b) { return (b && b.configDir) || ic.FALLBACK_DIR; }
120
+ function effEnvPrefix(b) { return (b && b.envPrefix) || ic.FALLBACK_ENV_PREFIX; }
121
+ // The brand token outbound User-Agents are built from, mirroring src/branding.js
122
+ // userAgent(): repo name, else env prefix, lowercased. Kept in sync by the
123
+ // tests/claude_materialize.mjs UA-rule case + tests/hook_user_agents.mjs.
124
+ function effUaBase(b) {
125
+ const base = (b && b.repo && b.repo.name) || (b && b.envPrefix) || '';
126
+ return String(base).toLowerCase();
127
+ }
128
+
129
+ // Ordered source→target rebrand rules from two branding objects. PURE + exported.
130
+ function buildRebrandRules(from = {}, to = {}) {
131
+ const rules = [];
132
+ const add = (a, b) => { if (a && b && a !== b) rules.push({ pattern: new RegExp(reEsc(a), 'g'), replace: b }); };
133
+ // Every configured origin HOST (public/builders/status/oauth) → the target's SAME-key
134
+ // host, or its publicOrigin host when that key is unset (so a source subdomain like
135
+ // builders.<founder> maps to the target's canonical origin, not builders.<target>).
136
+ // Full-host keeps real target subdomains; a bare founder host anywhere is caught too.
137
+ // Dedup by source host (first mapping wins) so one founder host can't spawn conflicting rules.
138
+ const fromD = from.domains || {}, toD = to.domains || {};
139
+ const toPublicHost = hostOf(toD.publicOrigin);
140
+ const hostMap = new Map();
141
+ for (const key of Object.keys(fromD)) {
142
+ const fh = hostOf(fromD[key]);
143
+ if (!fh || hostMap.has(fh)) continue;
144
+ const th = hostOf(toD[key]) || toPublicHost;
145
+ if (th) hostMap.set(fh, th);
146
+ }
147
+ for (const [fh, th] of hostMap) add(fh, th);
148
+ // Config dir in the shapes hooks reference it (~/.config/<dir>, /etc/<dir>, the [<dir>] log tag).
149
+ const fc = effConfigDir(from), tc = effConfigDir(to);
150
+ add(`.config/${fc}`, `.config/${tc}`);
151
+ add(`/etc/${fc}`, `/etc/${tc}`);
152
+ add(`[${fc}]`, `[${tc}]`);
153
+ // The instance env-var prefix (e.g. OTB_ → BONGOS_), bounded by its underscore.
154
+ add(`${effEnvPrefix(from)}_`, `${effEnvPrefix(to)}_`);
155
+ // task 1002672: the bare User-Agent brand token (e.g. `example-gds-cli/1.0`
156
+ // in a hook's outbound fetch). It carries no TLD, so none of the HOST rules above
157
+ // ever matched it and a founder-branded UA leaked into every materialized
158
+ // instance verbatim. Bounded by the `-gds` suffix (the userAgent() convention)
159
+ // so a bare founder word in prose is NOT rewritten — only the UA token shape.
160
+ // Both bases must resolve: an empty side would degenerate into a bare `-gds`
161
+ // rule that rewrites every occurrence of the suffix itself.
162
+ const fromUa = effUaBase(from), toUa = effUaBase(to);
163
+ if (fromUa && toUa) add(`${fromUa}-gds`, `${toUa}-gds`);
164
+ // Longest literal first so a full host is replaced before any bare token inside it.
165
+ rules.sort((x, y) => y.pattern.source.length - x.pattern.source.length);
166
+ return rules;
167
+ }
168
+
169
+ function rebrandText(text, rules) {
170
+ if (typeof text !== 'string' || !text || !rules || !rules.length) return text;
171
+ let out = text;
172
+ for (const r of rules) out = out.replace(r.pattern, r.replace);
173
+ return out;
174
+ }
175
+
176
+ function readJsonSafe(p) { try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch { return null; } }
177
+
178
+ // Every module that declares `contributes.skills`, with whether the TARGET instance
179
+ // enables it: the target's config/modules.json wins, else the module's own `default`.
180
+ // The one place that rule lives — disabledModuleSkills and moduleSkillSources both
181
+ // read it. PURE-ish (reads the fs) + exported.
182
+ function moduleSkillRoster({ coreRoot, instanceDir }) {
183
+ const roster = [];
184
+ const modulesDir = path.join(coreRoot, 'modules');
185
+ if (!fs.existsSync(modulesDir)) return roster;
186
+ const targetCfg = readJsonSafe(path.join(instanceDir, 'config', 'modules.json')) || {};
187
+ const enabledMap = (targetCfg.modules && typeof targetCfg.modules === 'object') ? targetCfg.modules : {};
188
+ for (const dir of fs.readdirSync(modulesDir)) {
189
+ const mj = readJsonSafe(path.join(modulesDir, dir, 'module.json'));
190
+ const skills = mj && mj.contributes && mj.contributes.skills;
191
+ if (!Array.isArray(skills)) continue;
192
+ const key = mj.key || dir;
193
+ const explicit = enabledMap[key];
194
+ const enabled = explicit === undefined ? mj.default === true : explicit === true;
195
+ roster.push({ key, dir: path.join(modulesDir, dir), enabled, skills });
196
+ }
197
+ return roster;
198
+ }
199
+
200
+ // Skills owned by a module that is DISABLED in the TARGET instance (task 2103b).
201
+ // A skill owned by NO module is core and is never skipped.
202
+ function disabledModuleSkills(opts) {
203
+ const skip = new Set();
204
+ for (const m of moduleSkillRoster(opts)) if (!m.enabled) for (const s of m.skills) skip.add(s);
205
+ return skip;
206
+ }
207
+
208
+ // A declared skill name is a path segment the materialiser WRITES under
209
+ // .claude/skills/, so it is allowlisted before it ever reaches path.join: lowercase
210
+ // slug only, no dots, no separators. A manifest carrying "../x" names nothing.
211
+ const SKILL_NAME_RE = /^[a-z0-9][a-z0-9-]{0,63}$/;
212
+
213
+ // The vendoring gate a THIRD-PARTY skill must pass at copy time, not only in CI
214
+ // (ADR 0198 §1–3): a PROVENANCE.md sidecar whose frontmatter names a licence on the
215
+ // allowlist and a scan verdict that may land. The module's own skills/policy.json
216
+ // (the ui-design shape) is the source of both lists when present; these defaults
217
+ // are the same five licences and two verdicts otherwise. A gate that cannot read
218
+ // the sidecar refuses — an unvetted copy never lands because a file was missing.
219
+ const VENDOR_DEFAULT_POLICY = Object.freeze({
220
+ licenceAllowlist: ['Apache-2.0', 'MIT', 'BSD-2-Clause', 'BSD-3-Clause', 'CC-BY-4.0'],
221
+ verdictsThatMayLand: ['clean', 'caution'],
222
+ });
223
+
224
+ function sidecarFrontmatter(file) {
225
+ let text;
226
+ try { text = fs.readFileSync(file, 'utf8').replace(/\r\n/g, '\n'); } catch { return null; }
227
+ const m = text.match(/^---\n([\s\S]*?)\n---\n/);
228
+ if (!m) return null;
229
+ const out = {};
230
+ for (const line of m[1].split('\n')) {
231
+ const kv = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/);
232
+ if (kv) out[kv[1]] = kv[2].replace(/^["']|["']$/g, '').trim();
233
+ }
234
+ return out;
235
+ }
236
+
237
+ // → { ok: true } or { ok: false, reason } for one vendored skill dir. Exported for the test.
238
+ function vendoredSkillGate(dir, policy = VENDOR_DEFAULT_POLICY) {
239
+ const fm = sidecarFrontmatter(path.join(dir, 'PROVENANCE.md'));
240
+ if (!fm) return { ok: false, reason: 'no PROVENANCE.md sidecar (or no frontmatter)' };
241
+ const licences = Array.isArray(policy.licenceAllowlist) ? policy.licenceAllowlist : VENDOR_DEFAULT_POLICY.licenceAllowlist;
242
+ const verdicts = Array.isArray(policy.verdictsThatMayLand) ? policy.verdictsThatMayLand : VENDOR_DEFAULT_POLICY.verdictsThatMayLand;
243
+ if (!licences.includes(fm.licence)) return { ok: false, reason: `licence "${fm.licence || ''}" is not on the allowlist` };
244
+ if (!verdicts.includes(fm.scanVerdict)) return { ok: false, reason: `scan verdict "${fm.scanVerdict || ''}" may not land` };
245
+ return { ok: true };
246
+ }
247
+
248
+ // Skills a module ships from its OWN tree instead of .claude/skills/ (task 1003321,
249
+ // ADR 0198): modules/<key>/skills/<name>/ for a skill the module authors, or
250
+ // modules/<key>/skills/vendor/<name>/ for a third-party skill carried with its
251
+ // PROVENANCE.md sidecar (the `vendor/` segment is the one fitness-ratchets exempts
252
+ // from the first-party line budgets). Only a name the module DECLARES in
253
+ // contributes.skills resolves — the manifest stays the single declaration — a name
254
+ // that fails SKILL_NAME_RE is refused before any path is built, a dir with no
255
+ // SKILL.md is not a skill, and a vendored dir must pass vendoredSkillGate. Refusals
256
+ // come back in `refused[]` so the caller can log them. Accepts a precomputed
257
+ // `roster` so materializeClaude walks modules/ once. PURE-ish (reads the fs) + exported.
258
+ function moduleSkillSources(opts) {
259
+ const out = [];
260
+ const refused = [];
261
+ const roster = (opts && opts.roster) || moduleSkillRoster(opts);
262
+ for (const m of roster) {
263
+ const policy = readJsonSafe(path.join(m.dir, 'skills', 'policy.json')) || VENDOR_DEFAULT_POLICY;
264
+ for (const name of m.skills) {
265
+ if (typeof name !== 'string' || !SKILL_NAME_RE.test(name)) { refused.push({ name: String(name), module: m.key, reason: 'name is not a lowercase slug' }); continue; }
266
+ const own = path.join(m.dir, 'skills', name);
267
+ const vendored = path.join(m.dir, 'skills', 'vendor', name);
268
+ const src = [own, vendored].find((p) => fs.existsSync(path.join(p, 'SKILL.md')));
269
+ if (!src) continue;
270
+ if (src === vendored) {
271
+ const gate = vendoredSkillGate(src, policy);
272
+ if (!gate.ok) { refused.push({ name, module: m.key, reason: gate.reason }); continue; }
273
+ }
274
+ out.push({ name, module: m.key, dir: src, enabled: m.enabled, vendored: src === vendored });
275
+ }
276
+ }
277
+ out.refused = refused;
278
+ return out;
279
+ }
280
+
281
+ // ---- retired core skills: the tombstone list (task 1004482) -----------------
282
+ // A skill the core USED to ship from its own .claude/skills/ and no longer does (the dev-box
283
+ // verbs, the old /dev /ideate /paint role playbooks, the pixel-art skills that moved into a
284
+ // default-off module). Every instance materialized before task 1004482 received them as core
285
+ // skills, and the provenance manifest then recorded only module-declared names — so step 1c
286
+ // could never prove it had put them there and they stayed in .claude/skills/ for the harness to
287
+ // load and the hall's Commands page to list, forever.
288
+ //
289
+ // From task 1004482 on the manifest records EVERY skill a materialize lands, so a skill the core
290
+ // drops later is withdrawn by step 1c's ordinary rule. This list closes the historical gap only,
291
+ // and is therefore a closed set: it should not need a new entry.
292
+ //
293
+ // "Never touch a skill the instance authored" is held by a fingerprint, not by the name: each
294
+ // entry lists sha256 digests (first 16 hex) of every description the core ever shipped under that
295
+ // name, as written and as bongosify() rewrote it. A dir whose SKILL.md description matches none of
296
+ // them is not ours and is left in place with a note — an owner who wrote their own /dev keeps it.
297
+ const RETIRED_CORE_SKILLS_FILE = path.join(__dirname, 'retired-core-skills.json');
298
+
299
+ // The `description:` value of a SKILL.md's frontmatter, whitespace-collapsed — a plain scalar,
300
+ // a quoted one, or a block scalar (`>` / `|`) with its indented continuation lines. null when
301
+ // the file has no frontmatter or no description. PURE + exported.
302
+ function skillDescription(text) {
303
+ const m = String(text == null ? '' : text).replace(/\r\n/g, '\n').match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
304
+ if (!m) return null;
305
+ const lines = m[1].split('\n');
306
+ const i = lines.findIndex((l) => /^description:/.test(l));
307
+ if (i < 0) return null;
308
+ const parts = [lines[i].replace(/^description:\s*/, '')];
309
+ if (/^[>|][+-]?$/.test(parts[0])) parts[0] = '';
310
+ for (let j = i + 1; j < lines.length && /^\s+\S/.test(lines[j]); j += 1) parts.push(lines[j]);
311
+ const value = parts.join(' ').replace(/\s+/g, ' ').trim().replace(/^(["'])([\s\S]*)\1$/, '$2').trim();
312
+ return value || null;
313
+ }
314
+
315
+ function descriptionDigest(desc) {
316
+ return crypto.createHash('sha256').update(String(desc)).digest('hex').slice(0, 16);
317
+ }
318
+
319
+ // Does this instance skill dir carry a description the core shipped under `name`? Reads the
320
+ // tombstone's digests; an unreadable SKILL.md or a missing description answers "no" (keep it).
321
+ function isRetiredCoreCopy(dir, digests) {
322
+ if (!Array.isArray(digests) || !digests.length) return false;
323
+ let text;
324
+ try { text = fs.readFileSync(path.join(dir, 'SKILL.md'), 'utf8'); } catch { return false; }
325
+ const desc = skillDescription(text);
326
+ return desc != null && digests.includes(descriptionDigest(desc));
327
+ }
328
+
329
+ function readRetiredCoreSkills(file = RETIRED_CORE_SKILLS_FILE) {
330
+ const j = readJsonSafe(file);
331
+ return j && j.skills && typeof j.skills === 'object' ? j.skills : {};
332
+ }
333
+
334
+ // ---- I/O: copy a tree, transforming text files through bongosify ----------
335
+
336
+ const TEXT_EXT = new Set(['.md', '.txt', '.sh']); // command-bearing text we rewrite (skills are SKILL.md)
337
+
338
+ // Every file under `dir`, as paths relative to it. Used to name a withdrawn skill dir's
339
+ // files before it is removed — a deletion git reports one file at a time, never the dir.
340
+ function listFilesRecursive(dir, base = '') {
341
+ const out = [];
342
+ let entries;
343
+ try { entries = fs.readdirSync(path.join(dir, base), { withFileTypes: true }); } catch { return out; }
344
+ for (const e of entries) {
345
+ const rel = path.join(base, e.name);
346
+ if (e.isDirectory()) out.push(...listFilesRecursive(dir, rel));
347
+ else out.push(rel);
348
+ }
349
+ return out;
350
+ }
351
+
352
+ // `overwrite` defaults true (greenfield init / upgrade — byte-identical to before).
353
+ // `overwrite: false` is the `bongos init --adopt` layering path (ADR 0121): a file
354
+ // that already exists at the destination is NEVER clobbered — it is skipped and
355
+ // recorded in the returned `skipped[]` so the caller can report it.
356
+ // `transform` (text→text) is applied to any file whose extension is in `textExt`
357
+ // (default: bongosify over .md/.txt/.sh — the historical skills behavior). `skip(rel)`
358
+ // excludes a whole subtree BEFORE it is walked (task 2103b — drop a disabled module's
359
+ // skill dir); excluded top-level entries are returned in `excluded[]`.
360
+ function copyTreeTransformed(srcDir, destDir, { dryRun, onFile, overwrite = true, transform = bongosify, textExt = TEXT_EXT, skip } = {}) {
361
+ let files = 0;
362
+ const skipped = [];
363
+ const excluded = [];
364
+ const walk = (rel) => {
365
+ if (skip && skip(rel)) { excluded.push(rel); return; }
366
+ const absSrc = path.join(srcDir, rel);
367
+ const st = fs.statSync(absSrc);
368
+ if (st.isDirectory()) {
369
+ for (const name of fs.readdirSync(absSrc)) walk(path.join(rel, name));
370
+ return;
371
+ }
372
+ const absDest = path.join(destDir, rel);
373
+ if (!overwrite && fs.existsSync(absDest)) { // adopt: leave-and-report, never clobber
374
+ skipped.push(rel);
375
+ if (onFile) onFile(rel, { skipped: true });
376
+ return;
377
+ }
378
+ files += 1;
379
+ if (dryRun) { if (onFile) onFile(rel); return; }
380
+ fs.mkdirSync(path.dirname(absDest), { recursive: true });
381
+ if (textExt.has(path.extname(rel))) {
382
+ fs.writeFileSync(absDest, transform(fs.readFileSync(absSrc, 'utf8')));
383
+ } else {
384
+ fs.copyFileSync(absSrc, absDest); // binary / other — verbatim
385
+ }
386
+ if (onFile) onFile(rel);
387
+ };
388
+ if (!fs.existsSync(srcDir)) return { files: 0, skipped, excluded, present: false };
389
+ for (const name of fs.readdirSync(srcDir)) walk(name);
390
+ return { files, skipped, excluded, present: true };
391
+ }
392
+
393
+ // Transform settings.json: parse, rewrite every hook command through bongosify, re-serialize. Keeps
394
+ // .claude/hooks/*.js commands (instance-local) untouched and rewrites the scripts/bongos/*.js ones.
395
+ // The blessed commands an instance builder runs to do the methodology, one rule
396
+ // each (task 1003962). This MIRRORS the core repo's own `.claude/settings.json`
397
+ // allow-list (ADR 0104 / task 1051), translated from `node scripts/bongos/<x>.js`
398
+ // into the verb form a materialized instance actually invokes — bongosify()
399
+ // rewrites every skill to `bongos <verb>`, so a path-shaped rule would match
400
+ // nothing there.
401
+ //
402
+ // THE GAP THIS CLOSES. `.claude/settings.json` is excluded from the published
403
+ // package on purpose (PROTECTED_TOPOLOGY_EXCLUDE, beside infra/ and .github/):
404
+ // the core's own copy is deploy and gate machinery that means nothing on an
405
+ // instance. But the skills ship, so an instance received the methodology and
406
+ // none of the permissions that let it run — every instance builder met the
407
+ // auto-mode classifier on the normal workflow, which is how a live builder came
408
+ // to be stuck mid-re-auth with no way forward.
409
+ //
410
+ // WHY THIS IS NOT AN AUTHORITY GRANT (ADR 0016). An allow-rule stops the local
411
+ // agent REFUSING to run a command; it changes nothing about what the server
412
+ // permits. Rank is read fresh from the database on every request by
413
+ // `requireRank`, so a builder who edits this file grants themselves exactly
414
+ // nothing. That is the distinction that makes shipping a list of command names
415
+ // safe where shipping hooks — actual local gate machinery — is not.
416
+ //
417
+ // DELIBERATELY ABSENT: `bongos exec`. It runs any script inside the core by
418
+ // path and is the agent's escape hatch, so allow-listing it would be a blanket
419
+ // grant wearing a narrow rule's clothes. The one script the core's own list
420
+ // blesses (`api.js`) is named in full instead.
421
+ //
422
+ // EVERY RULE IS THE `npx bongos` SPELLING (task 1004621): a project has no bare
423
+ // `bongos` on PATH, so its skills, its CLAUDE.md and Settings → CLI access
424
+ // (task 1004575) all say `npx bongos …`, and a bare-`bongos` rule would allow a
425
+ // command nothing runs. An instance that took the older bare starter gains the
426
+ // npx twin of each bare rule it still holds on its next upgrade
427
+ // (topUpNpxAllowTwins below).
428
+ const STARTER_COMMANDS = [
429
+ 'npx bongos claim:*',
430
+ 'npx bongos ship:*',
431
+ 'npx bongos release:*',
432
+ 'npx bongos reauth:*',
433
+ 'npx bongos paste-token:*',
434
+ 'npx bongos exec scripts/bongos/api.js:*',
435
+ // The read-only subset (task 1003992, ADR 0304). `git branch` and `git fetch`
436
+ // are exact forms on purpose: a flag turns either into a write or an exec. No
437
+ // `git diff|log|show` rule, also on purpose: the harness already runs their
438
+ // read-only forms unprompted, and a prefix rule would switch off its flag check
439
+ // (`--output=<file>` writes anywhere, `diff --no-index` reads any file).
440
+ // tests/cli_allowlist_permissions.mjs pins this list to the core's, rule for rule.
441
+ 'npx bongos start:*',
442
+ 'npx bongos status:*',
443
+ // Exact form, no `:*`: reading the ship mode is how the agent knows whether to ship on its own
444
+ // (task 1004631, ADR 0369). `ship-mode auto|manual` WRITES it, and stays a prompt.
445
+ 'npx bongos ship-mode',
446
+ 'npx bongos recall:*',
447
+ 'npx bongos exec scripts/bongos/me.js:*',
448
+ 'npx bongos doctor:*',
449
+ 'npx bongos exec scripts/bongos/preflight.js:*',
450
+ 'npx bongos exec scripts/bongos/skill-preflight.js:*',
451
+ 'npx bongos exec scripts/bongos/ship-check.js:*',
452
+ 'npx bongos exec scripts/bongos/fitness.js:*',
453
+ 'npx bongos exec scripts/bongos/strand-watch.js:*',
454
+ 'npx bongos exec scripts/bongos/stale-worktrees.js:*',
455
+ 'npx bongos exec scripts/bongos/read-session-export.js:*',
456
+ 'git status:*',
457
+ 'git branch --list',
458
+ 'git branch --show-current',
459
+ 'git branch -a',
460
+ 'git branch -vv',
461
+ 'git fetch',
462
+ 'git fetch origin',
463
+ 'git fetch origin main',
464
+ 'gh pr view:*',
465
+ 'gh pr checks:*',
466
+ 'gh pr list:*',
467
+ 'gh run view:*',
468
+ 'gh run list:*',
469
+ ];
470
+ // One rule per command PER SHELL TOOL (task 1004014): the shell tool is `PowerShell` on a Windows
471
+ // laptop, and a `Bash(...)` rule says nothing about its commands. The tools are the ones the guards
472
+ // see (`.claude/hooks/shell-tools.js`) — held equal by tests/cli_allowlist_permissions.mjs, not a require.
473
+ const STARTER_SHELL_TOOLS = ['Bash', 'PowerShell'];
474
+ const STARTER_ALLOW = STARTER_SHELL_TOOLS.flatMap((tool) => STARTER_COMMANDS.map((command) => `${tool}(${command})`));
475
+
476
+ // The deny half (task 1003966): what the local agent may not READ. Keys are the
477
+ // same exposure on every instance, so those rules ship verbatim.
478
+ const STARTER_DENY_SECRETS = [
479
+ 'Read(.env)', 'Read(**/.env)', 'Read(.env.local)', 'Read(**/.env.local)',
480
+ 'Read(.env.*.local)', 'Read(**/.env.*.local)',
481
+ 'Read(**/*.pem)', 'Read(**/id_rsa*)', 'Read(**/id_ed25519*)',
482
+ ];
483
+ const SESSION_STORE_DENY = `Read(~/.config/${ic.FALLBACK_DIR}/instances/**)`;
484
+
485
+ // A checkout's settings.json takes the identity rebrand like every copied file, and the store's
486
+ // dir is one of the core's `.config/<dir>` literals it rewrites. The store does not move with the
487
+ // brand (task 1003741), so its rule is put back where the CLI reads it (task 1004155).
488
+ function rebrandSettings(text, rebrand) {
489
+ const moved = rebrand(SESSION_STORE_DENY);
490
+ return rebrand(text).split(JSON.stringify(moved)).join(JSON.stringify(SESSION_STORE_DENY));
491
+ }
492
+
493
+ // Credential files are derived from where the CLI actually reads them, not rebranded from the
494
+ // core's literals: the rebrand would also move the host-keyed store, which sits at a fixed anchor
495
+ // whatever the brand (cli-lib sessionStoreDir, task 1003741).
496
+ //
497
+ // credentialDeny is the half that may be added to a settings.json the instance already owns.
498
+ // Every rule here stops the agent READING A SECRET, and nothing an instance legitimately does
499
+ // requires reading its own key or session token from inside an agent session — which is what
500
+ // makes appending one provably safe (ADR 0326: a deny rule is monotonic in the safe direction).
501
+ function credentialDeny(branding = {}) {
502
+ const dirs = [...new Set([effConfigDir(branding), ...ic.LEGACY_DIRS])];
503
+ const credentialFiles = ['env', ...ic.SESSION_FILENAMES];
504
+ return [
505
+ ...STARTER_DENY_SECRETS,
506
+ ...dirs.flatMap((dir) => credentialFiles.map((file) => `Read(~/.config/${dir}/${file})`)),
507
+ SESSION_STORE_DENY,
508
+ ];
509
+ }
510
+
511
+ // starterDeny — what a FRESH instance gets: the credential half plus the shelf rules, which are
512
+ // the only layer an instance has against the repo-global stash stack since the git-guard hook is
513
+ // topology and does not ship.
514
+ //
515
+ // The shelf rules are starter-only, and deliberately NOT in the top-up (task 1004158, amending
516
+ // ADR 0326, which named this exclusion as the remedy if the rule ever bit). They guard a WORKFLOW
517
+ // rather than a secret, so the monotonicity argument that licenses the top-up does not reach them:
518
+ // with no provenance by design, and deny beating allow in Claude Code's permission order, an
519
+ // instance whose builders used the shelf as a set-aside could not re-enable it from its own
520
+ // settings.json afterwards. A fresh instance is different in kind — there the rule is a visible
521
+ // default present from the first commit, editable before any workflow has grown around it.
522
+ function starterDeny(branding = {}) {
523
+ return [
524
+ ...credentialDeny(branding),
525
+ ...STARTER_SHELL_TOOLS.map((tool) => `${tool}(git stash:*)`),
526
+ ];
527
+ }
528
+
529
+ // topUpStarterDeny — the deny rules an instance's OWN settings.json is missing, added to it
530
+ // (task 1004156). The starter is only ever written when the file is ABSENT, so every instance
531
+ // that took the allow-only starter from task 1003962 keeps it forever and its local agent can
532
+ // still read .env files, keys and session tokens. ADDING is the whole safety argument: a deny
533
+ // rule can only ever narrow what the agent may do, so appending one cannot widen this instance's
534
+ // permissions — which is why the owner's call (task 1004156) was "add them, and say which".
535
+ // "Never clobber" is unchanged in the sense that matters: nothing the instance wrote is removed
536
+ // or rewritten. Returns { text, added, reason }; `text` is null when nothing should be written.
537
+ // `reason` is the STRUCTURED signal that the file could not be CHECKED — null means "healthy",
538
+ // so callers branch on its presence rather than on the wording of a message. An unparseable or
539
+ // unexpectedly-shaped file is LEFT ALONE and reported, the posture task 1004023 took for a
540
+ // settings.json that will not parse: a half-understood rewrite of a permissions file is worse
541
+ // than the gap it closes. Note the write re-emits the whole document at 2-space JSON, so an
542
+ // instance indented some other way sees a whole-file diff — the RULES are still append-only,
543
+ // which is what the safety argument rests on, and the run output says so.
544
+ function topUpStarterDeny(existingText, wanted) {
545
+ const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
546
+ const cannotCheck = (reason) => ({ text: null, added: [], reason });
547
+ let doc;
548
+ try { doc = JSON.parse(existingText); } catch (err) { return cannotCheck(`not valid JSON (${err.message})`); }
549
+ if (!isObject(doc)) return cannotCheck('its top level is not a JSON object');
550
+ const perms = doc.permissions === undefined ? {} : doc.permissions;
551
+ if (!isObject(perms)) return cannotCheck('its "permissions" is not an object');
552
+ const deny = perms.deny === undefined ? [] : perms.deny;
553
+ if (!Array.isArray(deny)) return cannotCheck('its "permissions.deny" is not an array');
554
+ const have = new Set(deny);
555
+ const added = wanted.filter((rule) => !have.has(rule));
556
+ if (!added.length) return { text: null, added: [], reason: null }; // healthy: every rule already there
557
+ const next = { ...doc, permissions: { ...perms, deny: [...deny, ...added] } };
558
+ return { text: `${JSON.stringify(next, null, 2)}\n`, added, reason: null };
559
+ }
560
+
561
+ // topUpNpxAllowTwins — the `npx bongos` twin of every bare-`bongos` allow rule an instance's OWN
562
+ // settings.json holds (task 1004621). The skills an upgrade lands now say `npx bongos ship`, and a
563
+ // `Bash(bongos ship:*)` rule does not match that, so without the twin the upgrade would trade a
564
+ // `command not found` for a permission prompt on every blessed command. This is NOT the shell-rule
565
+ // top-up task 1004158 ruled out: nothing new is offered. Each twin is a rule the owner already
566
+ // holds, respelled for the one launcher that reaches the same project-local bin — a rule they
567
+ // removed gets no twin, and nothing they wrote is removed or rewritten. Same { text, added, reason }
568
+ // contract as topUpStarterDeny; an unreadable shape is left alone and reported.
569
+ const BARE_BONGOS_RULE_RE = /^(\w+)\(bongos (.+)\)$/;
570
+ function topUpNpxAllowTwins(existingText) {
571
+ const isObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
572
+ const cannotCheck = (reason) => ({ text: null, added: [], reason });
573
+ let doc;
574
+ try { doc = JSON.parse(existingText); } catch (err) { return cannotCheck(`not valid JSON (${err.message})`); }
575
+ if (!isObject(doc)) return cannotCheck('its top level is not a JSON object');
576
+ const perms = doc.permissions === undefined ? {} : doc.permissions;
577
+ if (!isObject(perms)) return cannotCheck('its "permissions" is not an object');
578
+ const allow = perms.allow === undefined ? [] : perms.allow;
579
+ if (!Array.isArray(allow)) return cannotCheck('its "permissions.allow" is not an array');
580
+ const have = new Set(allow);
581
+ const added = [];
582
+ for (const rule of allow) {
583
+ const m = typeof rule === 'string' && rule.match(BARE_BONGOS_RULE_RE);
584
+ const twin = m && `${m[1]}(${PROJECT_CLI} ${m[2]})`;
585
+ if (twin && !have.has(twin)) { have.add(twin); added.push(twin); }
586
+ }
587
+ if (!added.length) return { text: null, added: [], reason: null };
588
+ const next = { ...doc, permissions: { ...perms, allow: [...allow, ...added] } };
589
+ return { text: `${JSON.stringify(next, null, 2)}\n`, added, reason: null };
590
+ }
591
+
592
+ // The starter an instance gets when the core root carries no settings.json — a
593
+ // package-only install. Permissions ONLY: no hooks (they are topology), no env.
594
+ function renderStarterSettings(branding = {}) {
595
+ return `${JSON.stringify({
596
+ _doc: 'Starter written by scripts/bongos/claude-materialize.js (tasks 1003962, 1003966). Permissions only — the blessed Bongos commands, mirroring the core repo\'s own allow-list (ADR 0104), and the deny rules that keep the local agent from reading keys and session tokens. An allow-rule lets the local agent RUN a command; it grants no authority, which the server decides per request from your live rank (ADR 0016). Yours to edit: a later materialize never removes or rewrites a rule you wrote. It will ADD a CREDENTIAL deny rule this starter has gained since (task 1004156) and name it in the run output — additive only, so it can never widen what the local agent may do. Only that half is topped up: the shell rules below guard a workflow rather than a secret, so once this file exists they are yours alone and an upgrade will neither add nor remove one (task 1004158).',
597
+ permissions: { allow: STARTER_ALLOW, deny: starterDeny(branding) },
598
+ }, null, 2)}\n`;
599
+ }
600
+
601
+ // readSettingsTransform — the transform, as a result rather than a string:
602
+ // { text, parsed, reason }. transformSettings below is the string face of it,
603
+ // kept because that is what the tests and the historical callers use.
604
+ //
605
+ // WHY A PARSE FAILURE IS COPIED THROUGH UNTOUCHED (task 1004023). The old
606
+ // fallback was `bongosify(raw)` — a best-effort regex rewrite over the whole
607
+ // file. The script-invocation regex ends in an optional quote so it can swallow the
608
+ // closing quote of a QUOTED PATH inside a command; run over raw JSON text it
609
+ // swallows the JSON string's own closing quote instead:
610
+ //
611
+ // bongosify('{"command": "node scripts/bongos/strand-watch.js", }')
612
+ // -> {"command": "bongos exec scripts/bongos/strand-watch.js, }
613
+ //
614
+ // So a file that was one trailing comma from valid was written to the instance
615
+ // MORE broken than it arrived, with its strings running into each other. A
616
+ // rewrite of text we could not parse is not worth a worse file: the raw bytes
617
+ // are copied through unchanged and the caller is handed a reason to report. The
618
+ // operator fixes one comma instead of unpicking mangled strings.
619
+ //
620
+ // The parse failure is NOT made fatal: the core's own settings.json is valid
621
+ // JSON (pinned by a test), so reaching this means the operator has edited
622
+ // theirs, and refusing the whole materialize over one file would be a worse
623
+ // trade than copying it and saying so.
624
+ function readSettingsTransform(srcPath) {
625
+ const raw = fs.readFileSync(srcPath, 'utf8');
626
+ let json;
627
+ try {
628
+ json = JSON.parse(raw);
629
+ } catch (err) {
630
+ return { text: raw, parsed: false, reason: (err && err.message) || 'not valid JSON' };
631
+ }
632
+ const hooks = json && json.hooks;
633
+ if (hooks && typeof hooks === 'object') {
634
+ for (const event of Object.values(hooks)) {
635
+ for (const matcher of Array.isArray(event) ? event : []) {
636
+ for (const h of (matcher && Array.isArray(matcher.hooks)) ? matcher.hooks : []) {
637
+ if (typeof h.command === 'string') h.command = bongosify(h.command);
638
+ }
639
+ }
640
+ }
641
+ }
642
+ // Permission rules name the SAME commands the hooks and skills do, so they take the same
643
+ // rewrite — a rule left as `node scripts/bongos/ship.js` matches nothing once the instance's
644
+ // skills run `bongos ship` (task 1004012). `allow` gets the one spelling the skills use; a
645
+ // restrictive list gets BOTH ways an instance can reach the script, or it guards only one.
646
+ const perms = json && json.permissions;
647
+ if (perms && typeof perms === 'object') {
648
+ for (const [key, rules] of Object.entries(perms)) {
649
+ if (!Array.isArray(rules)) continue;
650
+ // an empty verb table makes bongosify emit the `bongos exec scripts/bongos/<x>.js` spelling
651
+ const spellings =(r) => (key === 'allow' ? [bongosify(r)] : [bongosify(r), bongosify(r, {})]);
652
+ perms[key] = [...new Set(rules.flatMap((r) => (typeof r === 'string' ? spellings(r) : [r])))];
653
+ }
654
+ }
655
+ return { text: JSON.stringify(json, null, 2) + '\n', parsed: true, reason: null };
656
+ }
657
+
658
+ // transformSettings — the string face of readSettingsTransform. A caller that
659
+ // only wants the bytes keeps working; one that needs to know the file could not
660
+ // be parsed calls readSettingsTransform and reads `parsed`.
661
+ function transformSettings(srcPath) {
662
+ return readSettingsTransform(srcPath).text;
663
+ }
664
+
665
+ // Materialize the .claude/ surface from `coreRoot` into `instanceDir`. Returns a summary.
666
+ // `overwrite` defaults true (greenfield init / upgrade — unchanged). `overwrite: false`
667
+ // is the `bongos init --adopt` layering path (ADR 0121): every pre-existing .claude/
668
+ // file is LEFT untouched and recorded in `summary.skippedFiles` (never clobbered). The ONE
669
+ // exception is settings.json in a package-only install, which GAINS any starter deny rule it is
670
+ // missing and reports them in `summary.settingsDenyAdded` (task 1004156) — additive only, so
671
+ // nothing the instance wrote is removed or rewritten.
672
+ const HOOK_TEXT_EXT = new Set(['.js', '.mjs', '.cjs', '.json', '.sh', '.md', '.txt']); // hooks are .js — rebrand them too
673
+
674
+ function materializeClaude({ coreRoot, instanceDir, dryRun = false, overwrite = true, log = () => {} }) {
675
+ const summary = { skipped: false, skills: 0, moduleSkills: 0, settings: false, settingsUnparsed: false, settingsDenyAdded: [], settingsDenyUncheckable: null, hooks: 0, scheduledTasks: 0, skippedFiles: [], excludedSkills: [], withdrawnSkills: [], rebrandRules: 0, claudeMd: false, writtenPaths: [], notes: [] };
676
+ // Every instance-relative path this run WROTE or REMOVED (task 1003957). `bongos upgrade`
677
+ // hands these to persistPin as artifactPaths, exactly as task 1003926 already does for
678
+ // regenerateApiArtifacts' output: committing only the pin left the materialized files dirty,
679
+ // so the NEXT sweep's clean-tree guard called them "a human's work" and skipped the instance
680
+ // FOREVER — an enrolled co-tenant upgraded exactly once (proven on `charter` 2026-09-16).
681
+ //
682
+ // Recording what we wrote is a STRONGER provenance than a static file list: every path here
683
+ // is one this very run produced. It cannot carry an owner's edit either, and not for the
684
+ // "generated end to end" reason API_ARTIFACT_FILES gives — for a sharper one. Under
685
+ // `overwrite` the copy ALREADY replaced whatever the file held before reaching this line, so
686
+ // the only choice left is commit that overwrite or strand the instance; leaving it dirty
687
+ // protects nothing and stops every future update. Under `overwrite: false` (the `init
688
+ // --adopt` path) nothing is clobbered — copyTreeTransformed reports those as `skipped` and
689
+ // addWritten ignores them — so an adopting instance records nothing here and commits nothing.
690
+ const rel = (p) => String(p).split(path.sep).join('/');
691
+ const addWritten = (p) => { summary.writtenPaths.push(rel(p)); };
692
+ // A copyTreeTransformed onFile that records real writes under `base` and ignores the
693
+ // leave-and-report entries adopt mode emits.
694
+ const recordUnder = (base) => (r, info) => { if (!info || !info.skipped) addWritten(path.join(base, r)); };
695
+ if (path.resolve(instanceDir) === path.resolve(coreRoot)) {
696
+ summary.skipped = true;
697
+ summary.notes.push('instance dir is the core root — nothing to materialize (byte-identical no-op).');
698
+ log(' • .claude/ materialize: instance dir == core root — skipped (nothing to copy).');
699
+ return summary;
700
+ }
701
+ const srcClaude = path.join(coreRoot, '.claude');
702
+ const destClaude = path.join(instanceDir, '.claude');
703
+ const left = (n) => (overwrite || n === 0 ? '' : ` (${n} left untouched)`);
704
+
705
+ // Rebrand: rewrite the SOURCE instance's identity (origin host, config dir, env
706
+ // prefix) to the TARGET's, so a copied hook never phones home to the founder's
707
+ // instance (task 2103a). Derived from both config/branding.json files; empty — and
708
+ // thus a no-op — when they match or either is unreadable.
709
+ const fromBranding = readJsonSafe(path.join(coreRoot, 'config', 'branding.json')) || {};
710
+ const toBranding = readJsonSafe(path.join(instanceDir, 'config', 'branding.json')) || {};
711
+ const rebrandRules = buildRebrandRules(fromBranding, toBranding);
712
+ const rebrand = (t) => rebrandText(t, rebrandRules);
713
+ summary.rebrandRules = rebrandRules.length;
714
+ if (rebrandRules.length) log(` • rebranding ${rebrandRules.length} founder literal(s) in the copied .claude/ → this instance's identity.`);
715
+
716
+ // Drop skills owned by a module this instance hasn't enabled (task 2103b). One
717
+ // walk of modules/ serves both this skip and step 1b's module-owned sources.
718
+ const roster = moduleSkillRoster({ coreRoot, instanceDir });
719
+ const skipSkills = new Set();
720
+ for (const m of roster) if (!m.enabled) for (const s of m.skills) skipSkills.add(s);
721
+ // A core checkout that materialised module skills into its own .claude/skills/ (task 1003330)
722
+ // carries them as untracked copies plus two dotfiles; step 1 must not ship those as core
723
+ // skills — step 1b lands them from the module, transformed, like everywhere else.
724
+ const materialisedInCore = readModuleSkillsManifest(path.join(coreRoot, '.claude', 'skills')).skills;
725
+ // The INSTANCE's own provenance record — what a PREVIOUS materialize landed here.
726
+ // Distinct from materialisedInCore above (that one is the core checkout's). Step 1c
727
+ // withdraws from this set and nothing else.
728
+ const landedPreviously = readInstanceSkillsManifest(path.join(destClaude, 'skills')).skills;
729
+ const skillSkip = (rel) => { const top = String(rel).split(/[\\/]/)[0]; return skipSkills.has(top) || top === MODULE_SKILLS_MANIFEST || top === INSTANCE_SKILLS_MANIFEST || top === '.gitignore' || Object.prototype.hasOwnProperty.call(materialisedInCore, top); };
730
+
731
+ // 1. skills — ship in the core package; copy, rewrite invocations→bongos, rebrand
732
+ // identity, and exclude any skill owned by a disabled module.
733
+ const skillsSrc = path.join(srcClaude, 'skills');
734
+ const skillsRes = copyTreeTransformed(skillsSrc, path.join(destClaude, 'skills'), {
735
+ dryRun, overwrite, transform: (t) => rebrand(bongosify(t)), skip: skillSkip,
736
+ onFile: recordUnder('.claude/skills'),
737
+ });
738
+ summary.skills = skillsRes.files;
739
+ summary.excludedSkills = skillsRes.excluded || [];
740
+ for (const rel of skillsRes.skipped || []) summary.skippedFiles.push(`skills/${rel}`);
741
+ if (!skillsRes.present) summary.notes.push('.claude/skills not found at the core root — none materialized.');
742
+ if (summary.excludedSkills.length) log(` • excluded ${summary.excludedSkills.length} skill(s) owned by disabled module(s): ${summary.excludedSkills.join(', ')}`);
743
+ log(` ${dryRun ? '[dry-run] would materialize' : '✓ materialized'} ${skillsRes.files} skill file(s) → .claude/skills/ (invocations→bongos, identity rebranded)${left((skillsRes.skipped || []).length)}`);
744
+
745
+ // 1b. module-owned skills — shipped from modules/<key>/skills/ (own) or
746
+ // modules/<key>/skills/vendor/ (third-party + PROVENANCE.md) and landed in the
747
+ // SAME .claude/skills/<name>/ the builder's harness reads (task 1003321, ADR
748
+ // 0198). Same transforms as step 1; a disabled module's are excluded by the same
749
+ // rule; a name the core's own .claude/skills/ already carries keeps the core copy;
750
+ // a name that is not a slug, or a vendored dir that fails the sidecar gate, is
751
+ // REFUSED here at copy time — the CI test is the second line, not the only one.
752
+ const sources = moduleSkillSources({ roster });
753
+ for (const r of sources.refused) {
754
+ summary.notes.push(`module skill "${r.name}" (${r.module}) refused: ${r.reason}.`);
755
+ log(` ✗ refused module skill "${r.name}" (${r.module}): ${r.reason}`);
756
+ }
757
+ for (const s of sources) {
758
+ if (!s.enabled) { if (!summary.excludedSkills.includes(s.name)) summary.excludedSkills.push(s.name); continue; }
759
+ if (fs.existsSync(path.join(skillsSrc, s.name)) && !Object.prototype.hasOwnProperty.call(materialisedInCore, s.name)) {
760
+ summary.notes.push(`module skill "${s.name}" (${s.module}) also exists under the core's .claude/skills/ — the core copy was materialized, the module copy ignored.`);
761
+ continue;
762
+ }
763
+ const r = copyTreeTransformed(s.dir, path.join(destClaude, 'skills', s.name), { dryRun, overwrite, transform: (t) => rebrand(bongosify(t)), onFile: recordUnder(`.claude/skills/${s.name}`) });
764
+ summary.moduleSkills += r.files;
765
+ for (const rel of r.skipped || []) summary.skippedFiles.push(`skills/${s.name}/${rel}`);
766
+ }
767
+ if (summary.moduleSkills) log(` ${dryRun ? '[dry-run] would materialize' : '✓ materialized'} ${summary.moduleSkills} module-owned skill file(s) → .claude/skills/ (from modules/<key>/skills/)`);
768
+
769
+ // 1c. WITHDRAW a skill a previous materialize landed here that this run no longer
770
+ // lands — the module was switched off (or stopped declaring the name) on an
771
+ // instance that ALREADY has the files. Step 1's skillSkip and step 1b's
772
+ // `enabled` check both only decline to COPY, which is the whole bug: disabling
773
+ // a module was honoured on a fresh instance and silently ignored on
774
+ // `bongos upgrade`, leaving stale dirs in .claude/skills/ for the harness to
775
+ // keep loading (task 1003632, found by the on/off proof of task 1003331).
776
+ // materializeModuleSkillsIntoCore has done this for the core checkout since
777
+ // task 1003330; this is the same mechanism for the instance side.
778
+ //
779
+ // PROVENANCE-GATED, and that gate is the safety property: only a name the
780
+ // manifest says a previous run LANDED is eligible. A skill the instance's owner
781
+ // wrote by hand was never in the manifest, so it can never be deleted here even
782
+ // if a module happens to declare the same name. With no manifest at all — an
783
+ // instance last materialized before this shipped — nothing is withdrawn and a
784
+ // note says so: that first run writes the provenance, and every run after it
785
+ // honours a disable. Refusing to guess is the point; deleting a builder's skill
786
+ // because we cannot prove we put it there is the one outcome worth avoiding.
787
+ const skillsDest = path.join(destClaude, 'skills');
788
+ const landedNow = {};
789
+ for (const src of sources) {
790
+ if (!src.enabled) continue;
791
+ // A dry run copied nothing, so it records what WOULD land; a real run confirms
792
+ // the dir is actually there before claiming provenance over it.
793
+ if (!dryRun && !fs.existsSync(path.join(skillsDest, src.name))) continue;
794
+ landedNow[src.name] = { module: src.module, source: path.relative(coreRoot, src.dir).split(path.sep).join('/'), vendored: src.vendored };
795
+ }
796
+ // A core-SHIPPED skill whose name a module also declares is landed by step 1, not
797
+ // step 1b — but it is withdrawable by the same disabled-module rule, so it needs
798
+ // provenance too.
799
+ for (const mod of roster) {
800
+ if (!mod.enabled) continue;
801
+ for (const name of mod.skills) {
802
+ if (landedNow[name] || !fs.existsSync(path.join(skillsSrc, name))) continue;
803
+ landedNow[name] = { module: mod.key, source: `.claude/skills/${name}`, coreShipped: true };
804
+ }
805
+ }
806
+ // A name the CORE ships now is the core's, whatever an older manifest said — a core
807
+ // skill can take over a name a module once owned, and step 1 copies it in on this very
808
+ // run. Without this guard 1c deleted it again immediately (task 1003818, a regression
809
+ // in 1003632's own first cut). materializeModuleSkillsIntoCore states the same rule for
810
+ // the checkout side via its `tracked(name)` check; this is the instance-side twin.
811
+ //
812
+ // The `!skipSkills.has(name)` half is load-bearing, not belt-and-braces: when a DISABLED
813
+ // module declares a core-shipped name, step 1 SKIPS the copy (that is the task 2103b
814
+ // exclusion), so the instance's dir really is stale and must still be withdrawn. Keeping
815
+ // it on the strength of "the core ships this name" would resurrect exactly the bug 1c
816
+ // exists to fix. Deliberately asked of the CORE source tree rather than the roster, so a
817
+ // name no enabled module declares any more is still recognised as legitimately sourced.
818
+ const coreShipsNow = (name) => fs.existsSync(path.join(skillsSrc, name)) && !skipSkills.has(name);
819
+ // Every CORE skill step 1 landed is recorded too (task 1004482), so a skill the core stops
820
+ // shipping in a later release is withdrawn by the rule below instead of lingering forever.
821
+ // When the core's .claude/skills/ could not be read at all, nothing was landed from it and
822
+ // nothing may be withdrawn on that account: the previous core entries are carried forward.
823
+ const coreTreeRead = skillsRes.present;
824
+ if (coreTreeRead) {
825
+ for (const name of fs.readdirSync(skillsSrc)) {
826
+ if (landedNow[name] || !SKILL_NAME_RE.test(name) || skillSkip(name)) continue;
827
+ if (!fs.statSync(path.join(skillsSrc, name)).isDirectory()) continue;
828
+ if (!dryRun && !fs.existsSync(path.join(skillsDest, name))) continue;
829
+ landedNow[name] = { source: `.claude/skills/${name}`, coreShipped: true };
830
+ }
831
+ } else {
832
+ for (const [name, rec] of Object.entries(landedPreviously)) if (rec && rec.coreShipped && !rec.module && !landedNow[name]) landedNow[name] = rec;
833
+ }
834
+ const withdrawable = Object.keys(landedPreviously).filter((n) => SKILL_NAME_RE.test(n) && !landedNow[n] && !coreShipsNow(n));
835
+ // The historical half (task 1004482): a skill the core retired BEFORE the manifest recorded
836
+ // core skills is withdrawn when its dir still carries a description the core shipped under
837
+ // that name. Anything else under a retired name is the instance's own and stays.
838
+ const retired = readRetiredCoreSkills();
839
+ const keptAsOwn = [];
840
+ for (const [name, entry] of Object.entries(retired)) {
841
+ if (!SKILL_NAME_RE.test(name) || landedNow[name] || coreShipsNow(name) || withdrawable.includes(name)) continue;
842
+ const dir = path.join(skillsDest, name);
843
+ if (!fs.existsSync(dir)) continue;
844
+ if (isRetiredCoreCopy(dir, entry && entry.descriptionDigests)) withdrawable.push(name);
845
+ else keptAsOwn.push(name);
846
+ }
847
+ if (keptAsOwn.length) summary.notes.push(`${keptAsOwn.length} skill dir(s) share a name the core once shipped but are not the core's copy (their description is not one it shipped), so they were left in place as the instance's own: ${keptAsOwn.sort().join(', ')}.`);
848
+ if (!overwrite) {
849
+ // adopt mode never clobbers what the owner already has; withdrawing is a clobber.
850
+ if (withdrawable.length) summary.notes.push(`${withdrawable.length} skill(s) the core no longer lands here were left in place (adopt mode does not withdraw): ${withdrawable.sort().join(', ')}.`);
851
+ } else {
852
+ for (const name of withdrawable.sort()) {
853
+ const dir = path.join(skillsDest, name);
854
+ if (!fs.existsSync(dir)) continue;
855
+ // A DELETION is a dirty path too, and `git status` names the individual files rather
856
+ // than the directory — so enumerate before removing, or the withdrawal is exactly the
857
+ // kind of leftover that wedges the next sweep (task 1003957).
858
+ for (const f of listFilesRecursive(dir)) addWritten(path.join('.claude/skills', name, f));
859
+ if (!dryRun) fs.rmSync(dir, { recursive: true, force: true });
860
+ summary.withdrawnSkills.push(name);
861
+ }
862
+ if (summary.withdrawnSkills.length) log(` ${dryRun ? '[dry-run] would withdraw' : '✓ withdrew'} ${summary.withdrawnSkills.length} stale skill dir(s) the core no longer ships here (retired, or its module is off): ${summary.withdrawnSkills.join(', ')}`);
863
+ }
864
+ if (!Object.keys(landedPreviously).length && summary.excludedSkills.length) {
865
+ summary.notes.push('no .instance-skills.json provenance in .claude/skills/ yet, so nothing was withdrawn — this run records it; a later run can withdraw the skills of a module that has since been disabled.');
866
+ }
867
+ // Record what landed, so the NEXT run can withdraw what this one placed.
868
+ //
869
+ // REPORTED on a dry run, written only on a real one — the same split the starter CLAUDE.md
870
+ // below already uses. writtenPaths is a "what this run rewrites" list, and a dry run's job is
871
+ // to preview exactly that: upgrade.js asks for one to decide which dirty paths its clean-tree
872
+ // pre-flight may ignore (task 1004122), so a generated file missing from the preview is a file
873
+ // the pre-flight halts on and the real run then rewrites anyway.
874
+ if (overwrite) {
875
+ const names = Object.keys(landedNow).sort();
876
+ const manifest = { _doc: 'GENERATED by scripts/bongos/claude-materialize.js (tasks 1003632, 1004482): every skill a materialize landed in this instance, core and module alike. It is the provenance record that lets a later run WITHDRAW a skill the core stopped shipping or whose module has since been disabled — a name absent from here is never deleted on that account, so a hand-written skill is safe. Commit it; do not hand-edit.', skills: Object.fromEntries(names.map((n) => [n, landedNow[n]])) };
877
+ if (!dryRun) {
878
+ fs.mkdirSync(skillsDest, { recursive: true });
879
+ fs.writeFileSync(path.join(skillsDest, INSTANCE_SKILLS_MANIFEST), JSON.stringify(manifest, null, 2) + '\n');
880
+ }
881
+ addWritten(path.join('.claude/skills', INSTANCE_SKILLS_MANIFEST));
882
+ }
883
+
884
+ // 2. settings.json — topology; present in the checkout/core repo, absent in a package-only install.
885
+ const settingsSrc = path.join(srcClaude, 'settings.json');
886
+ if (fs.existsSync(settingsSrc)) {
887
+ const settingsDest = path.join(destClaude, 'settings.json');
888
+ if (!overwrite && fs.existsSync(settingsDest)) { // adopt: never clobber an owner's settings.json
889
+ summary.skippedFiles.push('settings.json');
890
+ log(' • .claude/settings.json already present — left untouched (adopt merges nothing here yet).');
891
+ } else {
892
+ // task 1004023: an unparseable settings.json is copied through BYTE FOR
893
+ // BYTE — no bongosify, no rebrand. Both are regex passes written for the
894
+ // strings inside a parsed file, and over raw JSON text they damage it.
895
+ // The instance gets what the core had, plus a note naming the parse error.
896
+ const settingsOut = readSettingsTransform(settingsSrc);
897
+ if (!dryRun) {
898
+ fs.mkdirSync(destClaude, { recursive: true });
899
+ fs.writeFileSync(settingsDest, settingsOut.parsed ? rebrandSettings(settingsOut.text, rebrand) : settingsOut.text);
900
+ }
901
+ addWritten('.claude/settings.json');
902
+ summary.settings = true;
903
+ if (!settingsOut.parsed) {
904
+ summary.settingsUnparsed = true;
905
+ summary.notes.push(`.claude/settings.json is not valid JSON (${settingsOut.reason}) — copied through UNCHANGED: no hook-command or permission-rule rewrite to bongos, and no identity rebrand. Fix the JSON at the core root and materialize again, or edit the instance copy by hand.`);
906
+ }
907
+ log(` ${dryRun ? '[dry-run] would write' : '✓ wrote'} .claude/settings.json ${settingsOut.parsed ? '(hook commands + permission rules→bongos, identity rebranded)' : '(UNCHANGED — not valid JSON, nothing rewritten)'}`);
908
+ }
909
+ } else {
910
+ // Package-only install: the core root carries no settings.json to copy, so
911
+ // write the STARTER instead of leaving the instance with no permissions at
912
+ // all (task 1003962 — the note that used to sit here said "provide it from a
913
+ // starter" and nothing ever did). Written only when ABSENT, the same rule
914
+ // the starter CLAUDE.md below follows: an instance that has grown its own
915
+ // permissions owns them, and a later materialize must never clobber them.
916
+ const settingsDest = path.join(destClaude, 'settings.json');
917
+ if (fs.existsSync(settingsDest)) {
918
+ // The instance owns this file — but a deny rule the starter has gained since is ADDED to
919
+ // it rather than withheld forever (task 1004156). Nothing of theirs is removed or changed.
920
+ // Only the CREDENTIAL half is offered: the starter's shelf rules guard a workflow, not a
921
+ // secret, and are starter-only (task 1004158).
922
+ // The read is guarded: existsSync passing does not mean readable (a directory at that path,
923
+ // a locked or root-owned file), and this runs AFTER the pin moved and the migrations ran, so
924
+ // a throw here would leave a half-applied upgrade. It fails soft, like its sibling above.
925
+ // The npx twins of the owner's own bare-`bongos` allow rules ride the same single read and
926
+ // write (task 1004621): applied first, so the deny top-up below works on — and writes — the
927
+ // text that already carries them. An unparseable file trips both the same way and is
928
+ // reported once, by the deny half.
929
+ let topUp;
930
+ let twins = { text: null, added: [], reason: null };
931
+ try {
932
+ const raw = fs.readFileSync(settingsDest, 'utf8');
933
+ twins = topUpNpxAllowTwins(raw);
934
+ topUp = topUpStarterDeny(twins.text || raw, credentialDeny(toBranding));
935
+ } catch (err) { topUp = { text: null, added: [], reason: `it could not be read (${err.code || err.message})` }; }
936
+ if (twins.added.length) {
937
+ summary.settingsAllowTwinsAdded = twins.added;
938
+ summary.notes.push(`.claude/settings.json kept every rule it already had and GAINED the \`npx bongos\` twin of ${twins.added.length} bare-\`bongos\` allow rule(s) it held — the skills now say \`npx bongos …\`, which a bare rule does not match: ${twins.added.join(', ')}`);
939
+ log(` ${dryRun ? '[dry-run] would add' : '✓ added'} the npx twin of ${twins.added.length} bare-bongos allow rule(s) to .claude/settings.json (skills now run \`npx bongos …\`; every rule you wrote is kept): ${twins.added.join(', ')}`);
940
+ if (!topUp.text && !topUp.reason) {
941
+ if (!dryRun) fs.writeFileSync(settingsDest, twins.text);
942
+ if (!dryRun) addWritten('.claude/settings.json'); // real run only — the same reasoning as the deny write below
943
+ }
944
+ }
945
+ if (topUp.text) {
946
+ if (!dryRun) fs.writeFileSync(settingsDest, topUp.text);
947
+ // Reported as written only on the REAL run, deliberately. writtenPaths doubles as the set
948
+ // the upgrade pre-flight IGNORES when it checks for a dirty tree (task 1004122), and that
949
+ // waiver is justified by "materialize overwrites these unconditionally, so whatever they
950
+ // hold now is discarded either way" — which is precisely NOT true of a top-up, the one
951
+ // path here that preserves existing content. Leaving it out of the dry-run preview keeps
952
+ // an owner's uncommitted edit to settings.json halting the bump, as it always did; putting
953
+ // it in the real run's summary still hands it to persistPin, so the pin commit carries the
954
+ // added rules and the next upgrade does not read them as a human's stray work.
955
+ if (!dryRun) addWritten('.claude/settings.json');
956
+ summary.settingsDenyAdded = topUp.added;
957
+ summary.notes.push(`.claude/settings.json kept every rule it already had and GAINED ${topUp.added.length} missing deny rule(s) — an instance that took the starter before task 1003966 carried none of them, so its local agent could still read keys and session tokens: ${topUp.added.join(', ')}`);
958
+ log(` ${dryRun ? '[dry-run] would add' : '✓ added'} ${topUp.added.length} missing deny rule(s) to .claude/settings.json — every rule you wrote is kept, the file is re-indented to 2 spaces: ${topUp.added.join(', ')}`);
959
+ } else if (topUp.reason) {
960
+ // The security gap PERSISTS here, so it does not get the same quiet bullet as the
961
+ // all-clear. upgrade.js never iterates summary.notes, so this log line is the only
962
+ // channel that reaches the operator's terminal.
963
+ summary.skippedFiles.push('settings.json');
964
+ summary.settingsDenyUncheckable = topUp.reason;
965
+ summary.notes.push(`.claude/settings.json could not be checked for missing deny rules — ${topUp.reason}. It was left exactly as it is, so if it predates task 1003966 its local agent can still read keys and session tokens; compare its permissions.deny against the starter by hand, or fix the file and upgrade again.`);
966
+ log(` ! .claude/settings.json could NOT be checked for missing deny rules — ${topUp.reason}. Left untouched; its deny half may still be missing.`);
967
+ } else if (!twins.added.length) {
968
+ summary.skippedFiles.push('settings.json');
969
+ log(' • .claude/settings.json already present — left untouched (the instance owns it; it already carries every credential deny rule. The starter\'s shelf rules are not offered here — they guard a workflow, not a secret, and are starter-only: task 1004158).');
970
+ }
971
+ } else {
972
+ if (!dryRun) {
973
+ fs.mkdirSync(destClaude, { recursive: true });
974
+ fs.writeFileSync(settingsDest, renderStarterSettings(toBranding));
975
+ }
976
+ addWritten('.claude/settings.json');
977
+ summary.settings = true;
978
+ summary.notes.push(`.claude/settings.json written from the starter — ${STARTER_COMMANDS.length} blessed command(s) for each of ${STARTER_SHELL_TOOLS.join(' + ')}, permissions only.`);
979
+ log(` ${dryRun ? '[dry-run] would write' : '✓ wrote'} .claude/settings.json (starter: ${STARTER_COMMANDS.length} blessed commands × ${STARTER_SHELL_TOOLS.length} shell tools, no hooks)`);
980
+ }
981
+ }
982
+
983
+ // 3. hooks — topology; copied WITH an identity rebrand (their .js internals carried
984
+ // the founder origin/config-dir). Their core require()s self-resolve at runtime via
985
+ // the copied _core-resolve.js sibling (task 2139) — no path rewriting needed here.
986
+ const hooksRes = copyTreeTransformed(path.join(srcClaude, 'hooks'), path.join(destClaude, 'hooks'), {
987
+ dryRun, overwrite, transform: rebrand, textExt: HOOK_TEXT_EXT, onFile: recordUnder('.claude/hooks'),
988
+ });
989
+ summary.hooks = hooksRes.files;
990
+ for (const rel of hooksRes.skipped || []) summary.skippedFiles.push(`hooks/${rel}`);
991
+ if (!hooksRes.present) {
992
+ summary.notes.push('.claude/hooks not present at the core root (topology, excluded from the package) — provide them from a starter.');
993
+ } else {
994
+ log(` ${dryRun ? '[dry-run] would materialize' : '✓ materialized'} ${hooksRes.files} hook file(s) → .claude/hooks/ (founder identity rebranded)${left((hooksRes.skipped || []).length)}`);
995
+ summary.notes.push('hooks: founder origin/config-dir rebranded to this instance; their internal `require(scripts/bongos/…)` paths self-resolve inside the package at runtime via the copied _core-resolve.js sibling (task 2139).');
996
+ }
997
+
998
+ // 3b. scheduled-tasks — the cron routines (System 4 dispatcher, ADR 0078; task 2138). TOPOLOGY
999
+ // like hooks (NOT in the package — PROTECTED_TOPOLOGY_EXCLUDE), so materialized by copy when
1000
+ // present at the core root and a no-op-with-note in a package-only install. Bodies (.md) are
1001
+ // bongosified so a judgment routine's `node scripts/bongos/x.js` model-instructions become
1002
+ // `bongos exec …`; the deterministic routines' `.claude/scheduled-tasks/<x>.js` step commands
1003
+ // are NOT matched by bongosify and stay as-is. Companion .js are rebranded but keep their
1004
+ // paths: they resolve core require()s at runtime via the copied _core-resolve.js sibling
1005
+ // (task 2139), and run-routine.js finds the routines under resolveInstanceRoot() post-split.
1006
+ const routinesRes = copyTreeTransformed(path.join(srcClaude, 'scheduled-tasks'), path.join(destClaude, 'scheduled-tasks'), {
1007
+ dryRun, overwrite, transform: (t) => rebrand(bongosify(t)), textExt: HOOK_TEXT_EXT, onFile: recordUnder('.claude/scheduled-tasks'),
1008
+ });
1009
+ summary.scheduledTasks = routinesRes.files;
1010
+ for (const rel of routinesRes.skipped || []) summary.skippedFiles.push(`scheduled-tasks/${rel}`);
1011
+ if (!routinesRes.present) {
1012
+ summary.notes.push('.claude/scheduled-tasks not present at the core root (topology, excluded from the package) — provide them from a starter.');
1013
+ } else {
1014
+ log(` ${dryRun ? '[dry-run] would materialize' : '✓ materialized'} ${routinesRes.files} scheduled-task file(s) → .claude/scheduled-tasks/ (bodies→bongos, founder identity rebranded)${left((routinesRes.skipped || []).length)}`);
1015
+ summary.notes.push('scheduled-tasks: cron routines materialized; run-routine.js resolves them under resolveInstanceRoot() and their companion .js resolve core via the copied _core-resolve.js sibling (task 2138).');
1016
+ }
1017
+
1018
+ // 4. CLAUDE.md — the project-root framing an agent reads every session (task 2104).
1019
+ // Written from the neutral starter template, brand-substituted from THIS instance's
1020
+ // branding. Written only when ABSENT — never clobber a CLAUDE.md the instance has
1021
+ // grown (safe for init, adopt, and upgrade alike; the self-copy guard above already
1022
+ // keeps this from ever touching the core/OTB checkout's own CLAUDE.md).
1023
+ // One narrow exception (task 1004621): the starter's OWN sentences that told the assistant to
1024
+ // type a bare `bongos …` — not on PATH in a project — are swapped for their `npx bongos …` form
1025
+ // where they still read exactly as the starter wrote them (refreshStarterCliLines). Not in
1026
+ // adopt mode, which never touches what the owner already had.
1027
+ const claudeMdPath = path.join(instanceDir, 'CLAUDE.md');
1028
+ if (fs.existsSync(claudeMdPath)) {
1029
+ let refreshed = { changed: 0 };
1030
+ if (overwrite) {
1031
+ try { refreshed = refreshStarterCliLines(fs.readFileSync(claudeMdPath, 'utf8')); } catch { /* unreadable: leave it, as before */ }
1032
+ }
1033
+ if (refreshed.changed) {
1034
+ if (!dryRun) fs.writeFileSync(claudeMdPath, refreshed.text);
1035
+ // Real run only, like the settings top-up: it preserves content, so the upgrade pre-flight's
1036
+ // "materialize overwrites this anyway" waiver must not cover an owner's uncommitted edit.
1037
+ if (!dryRun) addWritten('CLAUDE.md');
1038
+ summary.claudeMdCliLines = refreshed.changed;
1039
+ summary.notes.push(`CLAUDE.md kept as the instance's own, except ${refreshed.changed} unedited starter sentence(s) now say \`npx bongos …\` — the CLI is not on PATH in a project, so a bare \`bongos\` failed with command not found.`);
1040
+ log(` ${dryRun ? '[dry-run] would update' : '✓ updated'} ${refreshed.changed} unedited starter sentence(s) in CLAUDE.md to \`npx bongos …\` (everything else untouched)`);
1041
+ } else {
1042
+ summary.notes.push('CLAUDE.md already present — left untouched (the instance owns it).');
1043
+ }
1044
+ } else {
1045
+ if (!dryRun) {
1046
+ fs.mkdirSync(instanceDir, { recursive: true });
1047
+ fs.writeFileSync(claudeMdPath, renderInstanceClaudeMd(toBranding));
1048
+ }
1049
+ addWritten('CLAUDE.md');
1050
+ summary.claudeMd = true;
1051
+ log(` ${dryRun ? '[dry-run] would write' : '✓ wrote'} CLAUDE.md (starter, brand-substituted for this instance)`);
1052
+ }
1053
+ return summary;
1054
+ }
1055
+
1056
+ // materializeWillRewrite — the instance-relative paths a materialize WOULD rewrite here, changing
1057
+ // nothing. `bongos upgrade` asks before it starts, to decide which dirty paths its clean-tree
1058
+ // pre-flight may waive.
1059
+ //
1060
+ // THE WEDGE THIS EXISTS FOR (task 1004122). The upgrade's materialize step rewrites `.claude/`
1061
+ // from the new core on EVERY bump, so after an upgrade that did not commit it — one from before
1062
+ // task 1003957, or any run without --commit-pin — the instance carries ~40 modified
1063
+ // `.claude/skills/*` files that nobody edited. upgrade.js's clean-tree pre-flight then read them
1064
+ // as a human's uncommitted work and refused, so the instance took exactly one upgrade and stuck:
1065
+ // `test4` (instance 11) failed its Deploy-page upgrade this way, and provision-core-upgrade.js
1066
+ // passes --commit-pin but NOT --force, so the button stayed dead until someone committed by hand.
1067
+ //
1068
+ // Asking materializeClaude what it WOULD write is a real provenance answer, not a path
1069
+ // allow-list: the set is derived from the core actually installed here, and every path in it
1070
+ // is one the materialize step overwrites unconditionally a few seconds later. Whatever those files hold right
1071
+ // now is discarded either way, so refusing on them protects nothing and stops every future
1072
+ // update. A path materialize would NOT touch — an owner's own skill, a dirty migration, a
1073
+ // half-finished edit — is absent from the set and still halts the bump, which is the whole
1074
+ // safety property. Under --commit-pin the same paths come back from that step as persistPin's
1075
+ // artifactPaths and are committed, so the tree ends clean and the next upgrade needs none of this.
1076
+ //
1077
+ // Probed against the core on disk NOW, not the target: the target is not installed yet, and the
1078
+ // two ship the same `.claude/` surface. Fail-soft — a materialize that throws (no core
1079
+ // installed, an unreadable tree) returns nothing and the pre-flight is as strict as it ever was.
1080
+ function materializeWillRewrite({ instanceDir, coreRoot, materialize = materializeClaude }, err = console.error) {
1081
+ try {
1082
+ const root = coreRoot || path.join(instanceDir, 'node_modules', CORE_PACKAGE_NAMES[0]);
1083
+ const sum = materialize({ coreRoot: root, instanceDir, dryRun: true, log: () => {} });
1084
+ return (sum && Array.isArray(sum.writtenPaths)) ? sum.writtenPaths : [];
1085
+ } catch (e) {
1086
+ err(` ! could not preview the .claude/ materialization (${e && e.message ? e.message : e}) — pre-flight will treat every dirty path as a human's work.`);
1087
+ return [];
1088
+ }
1089
+ }
1090
+
1091
+ // ---- the dev checkout: module-owned skills materialised INTO the core (task 1003330, ADR 0224) ----
1092
+ // materializeClaude's self-copy guard is right for init/upgrade (instance == core is a no-op),
1093
+ // but Claude Code discovers only .claude/skills/ at the project root, so a builder working IN
1094
+ // the core checkout never sees modules/<key>/skills/. This lands every ENABLED module's skills
1095
+ // there as UNTRACKED, self-ignored dirs: verbatim copies (no bongosify — the checkout runs
1096
+ // `node scripts/bongos/…`), a generated .claude/skills/.module-skills.json manifest naming what
1097
+ // was materialised and from where, and a generated .claude/skills/.gitignore covering the
1098
+ // manifest, itself and every materialised dir, so `git status` shows nothing new and nothing
1099
+ // can be committed by accident. The same vendoredSkillGate + SKILL_NAME_RE apply; a name the
1100
+ // core's own tracked .claude/skills/ carries is left to the core. Idempotent: every run first
1101
+ // removes what the last manifest named (so a skill a module stopped declaring does not
1102
+ // linger), then lands the current set; `clean` stops after the removal.
1103
+ // Is `root` the core CHECKOUT — a workbench a builder edits — rather than the core
1104
+ // package installed under a scaffolded instance's node_modules? Only a checkout's own
1105
+ // .claude/skills/ is the directory Claude Code reads for that project, so only there
1106
+ // does materialising the module-owned skills put them in front of anyone; an instance
1107
+ // already received them at ITS root from `bongos init`, and a second copy under
1108
+ // node_modules/@bongos/core would be invisible (task 1003486). Fail-soft by
1109
+ // construction: an unreadable package.json answers "not the core checkout", which is
1110
+ // the conservative no-op rather than a copy into a tree we could not identify.
1111
+ function isCoreCheckoutRoot(root) {
1112
+ try {
1113
+ const abs = path.resolve(root);
1114
+ if (abs.split(/[\\/]+/).includes('node_modules')) return false;
1115
+ return isCorePackageName(JSON.parse(fs.readFileSync(path.join(abs, 'package.json'), 'utf8')).name);
1116
+ } catch (_) {
1117
+ return false;
1118
+ }
1119
+ }
1120
+
1121
+ const MODULE_SKILLS_MANIFEST = '.module-skills.json';
1122
+ // The INSTANCE-side provenance record, deliberately a DIFFERENT filename from the
1123
+ // core's (task 1003632). They are different artifacts: MODULE_SKILLS_MANIFEST lists
1124
+ // the untracked copies materializeModuleSkillsIntoCore made inside a core CHECKOUT,
1125
+ // and is asserted never to travel to an instance; this one lists what materializeClaude
1126
+ // landed INTO an instance, and is what step 1c withdraws against. Sharing one name made
1127
+ // the instance's own record look like a core dotfile that had leaked across the boundary.
1128
+ const INSTANCE_SKILLS_MANIFEST = '.instance-skills.json';
1129
+ function readSkillsManifest(skillsDir, file) {
1130
+ const m = readJsonSafe(path.join(skillsDir, file));
1131
+ return m && m.skills && typeof m.skills === 'object' ? m : { skills: {} };
1132
+ }
1133
+ function readModuleSkillsManifest(skillsDir) {
1134
+ return readSkillsManifest(skillsDir, MODULE_SKILLS_MANIFEST);
1135
+ }
1136
+ function readInstanceSkillsManifest(skillsDir) {
1137
+ return readSkillsManifest(skillsDir, INSTANCE_SKILLS_MANIFEST);
1138
+ }
1139
+ function materializeModuleSkillsIntoCore({ coreRoot, dryRun = false, clean = false, log = () => {} }) {
1140
+ const skillsDir = path.join(coreRoot, '.claude', 'skills');
1141
+ const summary = { materialized: [], removed: [], refused: [], excluded: [], keptCore: [], files: 0, notes: [] };
1142
+ const previous = readModuleSkillsManifest(skillsDir);
1143
+ // A dir git tracks is the core's, whatever an older manifest said (a core skill can take
1144
+ // over a name a module once owned); it is never removed or overwritten here.
1145
+ const tracked = (name) => { try { return spawnSync('git', ['-C', coreRoot, 'ls-files', '--error-unmatch', '--', `.claude/skills/${name}`], { encoding: 'utf8' }).status === 0; } catch { return false; } };
1146
+ for (const name of Object.keys(previous.skills)) {
1147
+ const dir = path.join(skillsDir, name);
1148
+ if (!SKILL_NAME_RE.test(name) || !fs.existsSync(dir)) continue;
1149
+ if (tracked(name)) { summary.keptCore.push(name); summary.notes.push(`"${name}" is tracked by git now — the last manifest's copy was not removed; the core's dir is kept.`); continue; }
1150
+ if (!dryRun) fs.rmSync(dir, { recursive: true, force: true });
1151
+ summary.removed.push(name);
1152
+ }
1153
+ if (clean) {
1154
+ for (const f of [MODULE_SKILLS_MANIFEST, '.gitignore']) { const p = path.join(skillsDir, f); if (fs.existsSync(p) && !dryRun) fs.rmSync(p); }
1155
+ log(` ${dryRun ? '[dry-run] would remove' : '✓ removed'} ${summary.removed.length} materialised module skill dir(s), the manifest and .claude/skills/.gitignore`);
1156
+ return summary;
1157
+ }
1158
+ const roster = moduleSkillRoster({ coreRoot, instanceDir: coreRoot });
1159
+ const sources = moduleSkillSources({ roster });
1160
+ for (const r of sources.refused) { summary.refused.push(`${r.name} (${r.module}): ${r.reason}`); log(` ✗ refused module skill "${r.name}" (${r.module}): ${r.reason}`); }
1161
+ const manifest = { _doc: 'GENERATED by `node scripts/bongos/claude-materialize.js --module-skills-only` (task 1003330, ADR 0224): the module-owned skills materialised into this core checkout as UNTRACKED copies so Claude Code sees them here. Every dir named below is ignored by the sibling .gitignore and removed by --clean; edit the module\'s skills/<name>/ source, never these copies, and re-run to refresh.', skills: {} };
1162
+ for (const s of sources) {
1163
+ if (!s.enabled) { summary.excluded.push(s.name); continue; }
1164
+ const dest = path.join(skillsDir, s.name);
1165
+ if (fs.existsSync(dest) && (!Object.prototype.hasOwnProperty.call(previous.skills, s.name) || tracked(s.name))) {
1166
+ summary.keptCore.push(s.name);
1167
+ summary.notes.push(`"${s.name}" (${s.module}) already exists under .claude/skills/ and is not a materialised copy — the core's own dir is kept.`);
1168
+ continue;
1169
+ }
1170
+ const r = copyTreeTransformed(s.dir, dest, { dryRun, overwrite: true, transform: (t) => t });
1171
+ summary.files += r.files;
1172
+ summary.materialized.push(s.name);
1173
+ manifest.skills[s.name] = { module: s.module, source: path.relative(coreRoot, s.dir).split(path.sep).join('/'), vendored: s.vendored, files: r.files };
1174
+ }
1175
+ const names = Object.keys(manifest.skills).sort();
1176
+ manifest.skills = Object.fromEntries(names.map((n) => [n, manifest.skills[n]]));
1177
+ const ignore = ['# GENERATED by scripts/bongos/claude-materialize.js --module-skills-only (task 1003330): the module-owned skills', '# materialised into this checkout are untracked copies; this file and the manifest ignore themselves. Never commit these.', '/.gitignore', `/${MODULE_SKILLS_MANIFEST}`, ...names.map((n) => `/${n}/`)].join('\n') + '\n';
1178
+ if (!dryRun) {
1179
+ fs.mkdirSync(skillsDir, { recursive: true });
1180
+ fs.writeFileSync(path.join(skillsDir, MODULE_SKILLS_MANIFEST), JSON.stringify(manifest, null, 2) + '\n');
1181
+ fs.writeFileSync(path.join(skillsDir, '.gitignore'), ignore);
1182
+ }
1183
+ log(` ${dryRun ? '[dry-run] would materialize' : '✓ materialized'} ${summary.materialized.length} module-owned skill(s) (${summary.files} file(s)) → .claude/skills/ as untracked copies: ${names.join(', ') || 'none'}`);
1184
+ return summary;
1185
+ }
1186
+
1187
+ // The CLI entry is the dev-checkout path only; init/upgrade call materializeClaude directly.
1188
+ if (require.main === module) {
1189
+ const argv = process.argv.slice(2);
1190
+ if (!argv.includes('--module-skills-only') || argv.includes('--help')) {
1191
+ process.stderr.write('usage: node scripts/bongos/claude-materialize.js --module-skills-only [--dry-run] [--clean]\n Lands every enabled module\'s skills (modules/<key>/skills/<name>/) into THIS checkout\'s .claude/skills/ as untracked,\n self-ignored copies so Claude Code sees them here (task 1003330). --clean removes them. The library behind bongos init / upgrade otherwise.\n');
1192
+ process.exit(argv.includes('--help') ? 0 : 2);
1193
+ }
1194
+ const s = materializeModuleSkillsIntoCore({ coreRoot: path.resolve(__dirname, '..', '..'), dryRun: argv.includes('--dry-run'), clean: argv.includes('--clean'), log: (l) => process.stdout.write(l + '\n') });
1195
+ for (const n of s.notes) process.stdout.write(` • ${n}\n`);
1196
+ process.stdout.write(`module skills → .claude/skills/: ${s.materialized.length} materialised (${s.files} file(s)), ${s.removed.length} refreshed or removed, ${s.excluded.length} excluded (module off), ${s.keptCore.length} kept as the core's own, ${s.refused.length} refused\n`);
1197
+ process.exit(s.refused.length ? 1 : 0);
1198
+ }
1199
+
1200
+ module.exports = { skillDescription, descriptionDigest, isRetiredCoreCopy, readRetiredCoreSkills, RETIRED_CORE_SKILLS_FILE, scriptToVerb, bongosify, PROJECT_CLI, topUpNpxAllowTwins, transformSettings, readSettingsTransform, renderStarterSettings, STARTER_ALLOW, copyTreeTransformed, materializeClaude, materializeWillRewrite, materializeModuleSkillsIntoCore, isCoreCheckoutRoot, readModuleSkillsManifest, MODULE_SKILLS_MANIFEST, readInstanceSkillsManifest, INSTANCE_SKILLS_MANIFEST, GDS_INVOCATION_RE, buildRebrandRules, rebrandText, disabledModuleSkills, moduleSkillRoster, moduleSkillSources, vendoredSkillGate, SKILL_NAME_RE, VENDOR_DEFAULT_POLICY };