@bongos/core 1.19.803 โ†’ 1.19.805

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 (235) hide show
  1. package/.bongos-core.json +261 -236
  2. package/.claude/skills/ask-for-help/SKILL.md +6 -6
  3. package/.claude/skills/backlog-review/SKILL.md +1 -1
  4. package/.claude/skills/blocker-review/SKILL.md +7 -7
  5. package/.claude/skills/blocker-solve/SKILL.md +5 -5
  6. package/.claude/skills/bug-triage/SKILL.md +7 -7
  7. package/.claude/skills/builder-claim/SKILL.md +3 -3
  8. package/.claude/skills/builder-cost/SKILL.md +2 -2
  9. package/.claude/skills/builder-end/SKILL.md +2 -2
  10. package/.claude/skills/builder-exit/SKILL.md +7 -7
  11. package/.claude/skills/builder-key/SKILL.md +2 -2
  12. package/.claude/skills/builder-reauth/SKILL.md +2 -2
  13. package/.claude/skills/builder-redteam/SKILL.md +7 -7
  14. package/.claude/skills/builder-release/SKILL.md +2 -2
  15. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  16. package/.claude/skills/builder-setup/SKILL.md +3 -3
  17. package/.claude/skills/builder-ship/SKILL.md +1 -1
  18. package/.claude/skills/builder-stage/SKILL.md +1 -1
  19. package/.claude/skills/builder-start/SKILL.md +1 -1
  20. package/.claude/skills/fix-task/SKILL.md +4 -4
  21. package/.claude/skills/goal-create/SKILL.md +18 -18
  22. package/.claude/skills/goal-review/SKILL.md +7 -7
  23. package/.claude/skills/grade-audit/SKILL.md +5 -5
  24. package/.claude/skills/grade-recover/SKILL.md +4 -4
  25. package/.claude/skills/grader-health/SKILL.md +6 -6
  26. package/.claude/skills/idea-triage/SKILL.md +14 -14
  27. package/.claude/skills/merge-mode/SKILL.md +3 -3
  28. package/.claude/skills/planning-session/SKILL.md +20 -20
  29. package/.claude/skills/priority-session/SKILL.md +10 -10
  30. package/.claude/skills/recall/SKILL.md +1 -1
  31. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  32. package/.claude/skills/status/SKILL.md +2 -2
  33. package/.claude/skills/strand-fix/SKILL.md +2 -2
  34. package/clients/bongos-client/README.md +1 -1
  35. package/clients/bongos-client/bongos-client.global.js +2 -0
  36. package/clients/bongos-client/index.cjs +2 -0
  37. package/clients/bongos-client/index.d.ts +2 -0
  38. package/clients/bongos-client/index.mjs +2 -0
  39. package/docs/api/openapi.json +45 -11
  40. package/docs/api-reference.md +11 -10
  41. package/docs/module-api-changelog.md +4 -0
  42. package/modules/builder-settings/profile-nudge-prefs.js +1 -1
  43. package/modules/builder-settings/render-prefs.js +1 -1
  44. package/modules/dev-box/app/README.md +1 -1
  45. package/modules/dev-box/app/src/gds-client.js +11 -9
  46. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  47. package/modules/dev-box/app/test/unit.mjs +13 -13
  48. package/modules/dev-box/box-access.js +3 -3
  49. package/modules/dev-box/box-onboard.js +7 -7
  50. package/modules/discord/bug-attachments.js +1 -1
  51. package/modules/economy/cost-classify.js +6 -6
  52. package/modules/grading/grader-rubric.json +1 -1
  53. package/modules/grading/grader-score.js +1 -1
  54. package/modules/hall-ui/module.json +1 -1
  55. package/modules/hall-ui/public/drachmae.js +3 -3
  56. package/modules/hall-ui/public/idea.js +1 -1
  57. package/modules/hall-ui/public/md-reader.js +1 -1
  58. package/modules/hall-ui/public/people.html +5 -1
  59. package/modules/hall-ui/public/people.js +44 -5
  60. package/modules/hall-ui/public/primer.js +4 -4
  61. package/modules/hall-ui/public/roster.js +1 -1
  62. package/modules/hall-ui/public/shell.js +1 -1
  63. package/modules/hall-ui/public/task.js +1 -1
  64. package/modules/ideas/inbox.js +2 -2
  65. package/modules/lifecycle/db-analytics.js +1 -1
  66. package/modules/lifecycle/done-when.js +4 -4
  67. package/modules/lifecycle/version-close.js +1 -1
  68. package/modules/memory/learnings.js +2 -2
  69. package/modules/memory/memory.js +1 -1
  70. package/modules/onboarding/onboarding.js +1 -1
  71. package/modules/platform-identity/routes/my-projects.js +1 -1
  72. package/modules/platform-identity/routes/sso.js +2 -2
  73. package/modules/public-landing/public/index.html +2 -2
  74. package/modules/public-landing/public/projects-floor.states.json +1 -1
  75. package/modules/public-landing/public/projects.html +1 -1
  76. package/modules/public-landing/public/projects.states.json +1 -1
  77. package/modules/sessions/db.js +120 -0
  78. package/modules/sessions/module.json +2 -2
  79. package/modules/sessions/pollers/session-upload-health.js +111 -0
  80. package/modules/sessions/pulse.js +2 -2
  81. package/modules/sessions/routes/sessions.js +46 -0
  82. package/modules/sessions/upload-health.js +197 -0
  83. package/modules/status-ui/module.json +1 -1
  84. package/modules/status-ui/public/explore.js +1 -1
  85. package/package-lock.json +2 -2
  86. package/package.json +1 -1
  87. package/scripts/gds/agent-invoke.js +3 -3
  88. package/scripts/gds/api.js +4 -4
  89. package/scripts/gds/api.sh +1 -1
  90. package/scripts/gds/architect-audit.js +1 -1
  91. package/scripts/gds/artifact-audit.js +2 -2
  92. package/scripts/gds/audit-ships.js +2 -2
  93. package/scripts/gds/backfill-cost.js +1 -1
  94. package/scripts/gds/backfill-sessions.js +1 -1
  95. package/scripts/gds/backfill-subagent-rewards.js +1 -1
  96. package/scripts/gds/backfill-task-rewards.js +2 -2
  97. package/scripts/gds/box-auth-check.js +1 -1
  98. package/scripts/gds/box-sync.js +3 -3
  99. package/scripts/gds/box.js +10 -10
  100. package/scripts/gds/build-cli-package.js +3 -3
  101. package/scripts/gds/capture.js +2 -2
  102. package/scripts/gds/ci-grade.js +1 -1
  103. package/scripts/gds/claim-recall.js +2 -2
  104. package/scripts/gds/cli-lib.js +3 -3
  105. package/scripts/gds/context-pack.js +1 -1
  106. package/scripts/gds/copy-apply.js +2 -2
  107. package/scripts/gds/dev-lib.js +2 -2
  108. package/scripts/gds/fetch-art-key.js +2 -2
  109. package/scripts/gds/fetch-sound-prefs.js +3 -3
  110. package/scripts/gds/grade-smoke.js +1 -1
  111. package/scripts/gds/hooks/pre-push.js +1 -1
  112. package/scripts/gds/init.js +9 -9
  113. package/scripts/gds/key-card.js +1 -1
  114. package/scripts/gds/learning-capture.js +2 -2
  115. package/scripts/gds/linkify-refs.js +2 -2
  116. package/scripts/gds/local-preview-lib.js +1 -1
  117. package/scripts/gds/login.js +11 -10
  118. package/scripts/gds/main-audit.js +1 -1
  119. package/scripts/gds/newcomer-floor.config.json +1 -1
  120. package/scripts/gds/newcomer-floor.js +2 -2
  121. package/scripts/gds/newcomer-floor.templates.json +2 -2
  122. package/scripts/gds/onboarding-ship.js +1 -1
  123. package/scripts/gds/paste-token.js +3 -3
  124. package/scripts/gds/portability-smoke-memory.sh +5 -5
  125. package/scripts/gds/prove-strict-versioning.js +2 -2
  126. package/scripts/gds/provision-net.js +2 -2
  127. package/scripts/gds/provision-units.js +3 -3
  128. package/scripts/gds/pulse.js +2 -2
  129. package/scripts/gds/push-path-brief.js +2 -2
  130. package/scripts/gds/reauth.js +1 -1
  131. package/scripts/gds/recall.js +1 -1
  132. package/scripts/gds/redteam-patrol.js +3 -3
  133. package/scripts/gds/render-ideas.js +5 -5
  134. package/scripts/gds/repo-metrics.js +1 -1
  135. package/scripts/gds/sandbox-stage.js +3 -3
  136. package/scripts/gds/seed-adopt-tasks.js +3 -3
  137. package/scripts/gds/seed-board-room-tasks.js +1 -1
  138. package/scripts/gds/seed-bongos-app-tasks.js +2 -2
  139. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
  140. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
  141. package/scripts/gds/seed-bongos-tasks.js +5 -5
  142. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
  143. package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
  144. package/scripts/gds/seed-bv1-community-tasks.js +1 -1
  145. package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
  146. package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
  147. package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
  148. package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
  149. package/scripts/gds/seed-gds-v4-tasks.js +3 -3
  150. package/scripts/gds/seed-medusa-tasks.js +1 -1
  151. package/scripts/gds/seed-productization-tasks.js +1 -1
  152. package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
  153. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  154. package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
  155. package/scripts/gds/seed-v2-world-tasks.js +2 -2
  156. package/scripts/gds/seed-verify-criteria.js +1 -1
  157. package/scripts/gds/session-digest.js +1 -1
  158. package/scripts/gds/session.js +2 -2
  159. package/scripts/gds/setup.js +7 -7
  160. package/scripts/gds/ship-flow.js +3 -3
  161. package/scripts/gds/ship-grade-steps.js +3 -3
  162. package/scripts/gds/ship-memory-sync.js +1 -1
  163. package/scripts/gds/ship-session-upload.js +3 -3
  164. package/scripts/gds/smoke-batch-claim.sh +10 -10
  165. package/scripts/gds/smoke-batch-release.sh +14 -14
  166. package/scripts/gds/smoke-claim-consistency.sh +19 -19
  167. package/scripts/gds/smoke-dependencies.sh +9 -9
  168. package/scripts/gds/smoke-write.sh +11 -11
  169. package/scripts/gds/start.js +1 -1
  170. package/scripts/gds/status.js +2 -2
  171. package/scripts/gds/strand-watch.js +1 -1
  172. package/scripts/gds/triage.js +4 -4
  173. package/scripts/gds/version-close.js +2 -2
  174. package/scripts/hall-preview/README.md +1 -1
  175. package/scripts/hall-preview/server.js +1 -1
  176. package/src/bongos/auth-admission.js +3 -3
  177. package/src/bongos/auth-idp.js +2 -2
  178. package/src/bongos/auth.js +3 -3
  179. package/src/bongos/db.js +2 -2
  180. package/src/bongos/llm-cache.js +2 -2
  181. package/src/bongos/metrics.js +1 -1
  182. package/src/bongos/middleware/audit.js +3 -3
  183. package/src/bongos/middleware/rate-limit.js +1 -1
  184. package/src/bongos/platform-visibility-gate.js +2 -2
  185. package/src/bongos/routes/_helpers.js +1 -1
  186. package/src/bongos/routes/audit-log.js +1 -1
  187. package/src/bongos/routes/auth.js +5 -5
  188. package/src/bongos/routes/backup.js +1 -1
  189. package/src/bongos/routes/builders.js +1 -1
  190. package/src/bongos/routes/instance.js +1 -1
  191. package/src/bongos/routes/live.js +1 -1
  192. package/src/bongos/routes/me.js +2 -2
  193. package/src/bongos/routes/modules.js +2 -2
  194. package/src/bongos/routes/public.js +1 -1
  195. package/src/bongos/routes/security.js +4 -4
  196. package/src/bongos/routes.js +1 -1
  197. package/src/bongos/serve-internal.js +6 -6
  198. package/src/branding.js +1 -1
  199. package/src/module-api.js +1 -1
  200. package/src/module-seams.js +2 -2
  201. package/src/platform-server.js +2 -2
  202. package/tests/api_alias_exceptions.mjs +67 -0
  203. package/tests/application_echo.mjs +12 -12
  204. package/tests/artifact_audit.mjs +1 -1
  205. package/tests/auth_page_gate.mjs +4 -4
  206. package/tests/auth_web_recovery.mjs +11 -11
  207. package/tests/bongos_login.mjs +7 -4
  208. package/tests/box_env.mjs +6 -6
  209. package/tests/bug_attachments.mjs +1 -1
  210. package/tests/cli_sessions.mjs +1 -1
  211. package/tests/dev_lib.mjs +1 -1
  212. package/tests/discord_bugs.mjs +2 -2
  213. package/tests/discord_inbound.mjs +2 -2
  214. package/tests/explore_visible_states.mjs +1 -1
  215. package/tests/government_page_gates.mjs +1 -1
  216. package/tests/hall_reference_world.mjs +1 -1
  217. package/tests/idea_ideate_full.mjs +1 -1
  218. package/tests/idp_federation.mjs +2 -2
  219. package/tests/llm-cache.mjs +1 -1
  220. package/tests/manage_manifest_shared_read.mjs +3 -3
  221. package/tests/people_directory_clip.mjs +219 -0
  222. package/tests/planning_session_skill.mjs +1 -1
  223. package/tests/platform_visibility_gate.mjs +15 -15
  224. package/tests/profile_route.mjs +37 -26
  225. package/tests/projects_hub.mjs +2 -2
  226. package/tests/provision.mjs +2 -2
  227. package/tests/provision_settings_apply.mjs +4 -4
  228. package/tests/sandbox_stage.mjs +8 -8
  229. package/tests/scouting_owner_access_and_reach.mjs +3 -3
  230. package/tests/session_upload_health.mjs +329 -0
  231. package/tests/setup_device_flow_fallback.mjs +1 -1
  232. package/tests/skill_ask_for_help.mjs +3 -3
  233. package/tests/skill_grade_audit.mjs +2 -2
  234. package/tests/skill_grader_health.mjs +3 -3
  235. package/tests/smoke_write_contract.mjs +1 -1
@@ -32,13 +32,14 @@ const { branding } = require('../../src/branding');
32
32
  // --- pure helpers (unit-tested) ---------------------------------------------
33
33
 
34
34
  // Normalize whatever the user pastes into an origin: add https:// if no scheme,
35
- // drop trailing slashes, and tolerate a pasted /api/gds suffix.
35
+ // drop trailing slashes, and tolerate a pasted API base โ€” the canonical
36
+ // /api/bongos or the permanent /api/gds alias, with or without the /v1 segment.
36
37
  function normalizeInstanceBase(raw) {
37
38
  let s = String(raw || '').trim();
38
39
  if (!s) throw new Error('missing instance URL');
39
40
  if (!/^https?:\/\//i.test(s)) s = `https://${s}`;
40
41
  s = s.replace(/\/+$/, '');
41
- s = s.replace(/\/api\/gds\/?$/i, '');
42
+ s = s.replace(/\/api\/(?:bongos|gds)(?:\/v1)?\/?$/i, '');
42
43
  return s;
43
44
  }
44
45
 
@@ -95,7 +96,7 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
95
96
  // The instance's OWN admission gate runs at poll (direct) or exchange (federated),
96
97
  // so the stranger path is identical for both.
97
98
  async function runDeviceFlow(base, { log, idp = null }) {
98
- const startUrl = idp ? `${idp.origin}/api/gds/sso/device/start` : `${base}/api/gds/auth/device/start`;
99
+ const startUrl = idp ? `${idp.origin}/api/bongos/sso/device/start` : `${base}/api/bongos/auth/device/start`;
99
100
  const start = await fetchJson(startUrl, {
100
101
  method: 'POST',
101
102
  // Federated: the hub resolves + binds the client from the USER-TYPED origin
@@ -136,7 +137,7 @@ async function runDeviceFlow(base, { log, idp = null }) {
136
137
  openBrowser(verification_uri);
137
138
  log(' Waiting for you to approve in the browserโ€ฆ');
138
139
 
139
- const pollUrl = idp ? `${idp.origin}/api/gds/sso/device/poll` : `${base}/api/gds/auth/device/poll`;
140
+ const pollUrl = idp ? `${idp.origin}/api/bongos/sso/device/poll` : `${base}/api/bongos/auth/device/poll`;
140
141
  const deadline = Date.now() + expires * 1000;
141
142
  while (Date.now() < deadline) {
142
143
  await sleep(interval * 1000);
@@ -150,7 +151,7 @@ async function runDeviceFlow(base, { log, idp = null }) {
150
151
  if (st === 'ok') {
151
152
  if (!idp) return { state: 'ok', token: poll.data.token, builder: poll.data.builder };
152
153
  // Federated: exchange the hub assertion at the instance for a real session.
153
- const ex = await fetchJson(`${base}/api/gds/auth/device/exchange`, {
154
+ const ex = await fetchJson(`${base}/api/bongos/auth/device/exchange`, {
154
155
  method: 'POST',
155
156
  body: JSON.stringify({ assertion: poll.data.assertion }),
156
157
  });
@@ -200,9 +201,9 @@ async function main() {
200
201
  // 1. Manifest โ€” brand + admission posture, and a check that this really is a
201
202
  // Cloud Bongos instance before we start a device flow.
202
203
  log(`โ–ธ Connecting to ${base}โ€ฆ`);
203
- const man = await fetchJson(`${base}/api/gds/instance`);
204
+ const man = await fetchJson(`${base}/api/bongos/instance`);
204
205
  if (!man.ok || !man.data || man.data.schema !== 'instance-manifest/v1') {
205
- console.error(`โœ– ${base} does not look like a Cloud Bongos instance (no /api/gds/instance manifest).`);
206
+ console.error(`โœ– ${base} does not look like a Cloud Bongos instance (no /api/bongos/instance manifest).`);
206
207
  process.exit(1);
207
208
  }
208
209
  const instanceName = man.data.name || base;
@@ -230,7 +231,7 @@ async function main() {
230
231
  let stored = null;
231
232
  try { stored = await loadStoredSession(base); } catch (_) { stored = null; }
232
233
  if (stored && stored.token) {
233
- const me = await fetchJson(`${base}/api/gds/me`, { headers: { Authorization: `Bearer ${stored.token}` } });
234
+ const me = await fetchJson(`${base}/api/bongos/me`, { headers: { Authorization: `Bearer ${stored.token}` } });
234
235
  if (me.ok && me.data && me.data.builder) {
235
236
  await saveSession({ ...stored, builder: me.data.builder, api_base: base,
236
237
  instance: { name: instanceName, origin: base } });
@@ -265,7 +266,7 @@ async function main() {
265
266
  console.error('โœ– need your GitHub username to request access.');
266
267
  process.exit(2);
267
268
  }
268
- const reqRes = await fetchJson(`${base}/api/gds/access-requests`, {
269
+ const reqRes = await fetchJson(`${base}/api/bongos/access-requests`, {
269
270
  method: 'POST',
270
271
  body: JSON.stringify({ github_login: ghLogin, note: 'via bongos login' }),
271
272
  });
@@ -287,7 +288,7 @@ async function main() {
287
288
  const admitDeadline = Date.now() + 30 * 60 * 1000; // 30 min
288
289
  for (;;) {
289
290
  await sleep(5000);
290
- const s = await fetchJson(`${base}/api/gds/access-requests/status?github_login=${encodeURIComponent(ghLogin)}`);
291
+ const s = await fetchJson(`${base}/api/bongos/access-requests/status?github_login=${encodeURIComponent(ghLogin)}`);
291
292
  const decision = pollDecision(s.data);
292
293
  if (decision === 'admitted') {
293
294
  log('\n โœ“ Approved! Finishing sign-in โ€” approve once more in your browser.');
@@ -282,7 +282,7 @@ async function fetchRankMap({ useDb = false } = {}) {
282
282
  // Caveat: a zero-activity builder may be absent โ†’ resolves as UNRESOLVED
283
283
  // ('review' finding), never as falsely-trusted.
284
284
  try {
285
- const res = await fetch(`${API_BASE}/api/gds/public/leaderboard`);
285
+ const res = await fetch(`${API_BASE}/api/bongos/public/leaderboard`);
286
286
  if (res.ok) {
287
287
  const data = await res.json();
288
288
  return rowsToMap(data?.leaderboard || []);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "_doc": "Supply knob for the deterministic newcomer-task floor replenisher (scripts/gds/newcomer-floor.js) and the on-claim restock (src/bongos/newcomer-restock.js). As of task 1488 each discipline holds a LIST of chore templates, and each chore keeps its OWN standing pool to its OWN `floor` (declared per-template in newcomer-floor.templates.json). The `floor` in this disciplines map is now the DEFAULT applied to any template that omits its own โ€” i.e. a fallback, not the primary knob. The pool is measured in READY copies of each template (source_ref tmpl:<discipline>:<template_id>:<seq>); when a chore's ready copies drop below its floor, fresh identical copies are stamped โ€” deterministic, no AI subagent, no 401. The CHORE definitions (and their per-template floors) live in templates.json (edit there to add/change a chore or tune its pool depth).",
3
- "_review_gate": "`auto_promote` is the review toggle for the CLI seeder. true -> stamped copies land at status='ready' (claimable immediately). Safe here because output is deterministic and the templates are pre-approved (set true 2026-06-16, owner decision). false -> copies land at status='backlog' (NOT Xenos-claimable) for an Archon to promote via POST /api/gds/tasks/:id/promote. (The on-claim restock always stamps 'ready' โ€” it tops a just-claimed chore's pool back up so the shelf is never empty.)",
3
+ "_review_gate": "`auto_promote` is the review toggle for the CLI seeder. true -> stamped copies land at status='ready' (claimable immediately). Safe here because output is deterministic and the templates are pre-approved (set true 2026-06-16, owner decision). false -> copies land at status='backlog' (NOT Xenos-claimable) for an Archon to promote via POST /api/bongos/tasks/:id/promote. (The on-claim restock always stamps 'ready' โ€” it tops a just-claimed chore's pool back up so the shelf is never empty.)",
4
4
  "_floor_note": "Per-template `floor` lives in newcomer-floor.templates.json (next to each chore's credits_reward + est_minutes). The disciplines map below is only the per-discipline DEFAULT used when a template omits its own floor. credits_reward is never read from here.",
5
5
  "templates_path": "newcomer-floor.templates.json",
6
6
  "auto_promote": true,
@@ -37,7 +37,7 @@
37
37
  // deterministic and the templates are pre-approved.
38
38
  // false -> copies land status='backlog' for an Archon to promote.
39
39
  //
40
- // AUTH: POST /api/gds/tasks is archon-gated (creating work is scope-shaping โ€”
40
+ // AUTH: POST /api/bongos/tasks is archon-gated (creating work is scope-shaping โ€”
41
41
  // ADR 0016). Run under an Archon session (on the droplet, the operator's).
42
42
  //
43
43
  // Usage:
@@ -393,7 +393,7 @@ function report(summary, FLAGS, { checkOnly }) {
393
393
  }
394
394
  if (!summary.autoPromote && !FLAGS.dryRun && summary.stamped.some((g) => g.task_id)) {
395
395
  console.log('\nNext: a Metic+ builder promotes the new backlog copies to ready:');
396
- console.log(' node scripts/gds/api.js POST /api/gds/tasks/<id>/promote (or the builders\' hall)');
396
+ console.log(' node scripts/gds/api.js POST /api/bongos/tasks/<id>/promote (or the builders\' hall)');
397
397
  }
398
398
  }
399
399
 
@@ -70,13 +70,13 @@
70
70
  "est_minutes": 45,
71
71
  "credits_reward": 12,
72
72
  "title": "Idea-seed pass: file 5-8 fresh in-world ideas (names, lore, or builder-UX) into the idea inbox",
73
- "description": "## What you'll do\n\nThe seed of almost everything built here is the **idea_inbox** โ€” a queue anyone can drop ideas into, which trusted builders later triage into real tasks. Your first ship as an ideator is simple and concrete: **add a small batch of fresh ideas to that inbox.** You write no code, touch no game, change no system โ€” you think, write a few short well-shaped ideas, and file them with one command each.\n\nIt is identical for every newcomer and **always valuable**: the inbox is never \"done\" โ€” every triage pass consumes ideas (promote/discard/merge), so it is permanently hungry for fresh input, and a growing world always wants more names, more lore, more texture. Your batch is brand-new content, so it can never duplicate \"the work\" โ€” the supply IS the work.\n\n## Pick ONE branch\n\n- **Branch A โ€” PRODUCT flavour (default).** Ideas that grow the world players see: **names + one line of lore** for a character, structure, landmark, district, ship, or festival; or a world-background snippet (a custom, a superstition, a line a named NPC says). Tone: mythic, mysterious, a \"discovered secret\"; Mediterranean ancient-Greek coast (just south of Athens); NOT modern, NOT tongue-in-cheek-modern. Ground it in CLAUDE.md ยง3/ยง6/ยง7.\n- **Branch B โ€” INTERNAL / builder-UX.** Small user-experience improvement ideas for the GDS / builders' hall (the surfaces builders use, not the game): a clearer label, a confusing onboarding message, a quality-of-life tweak to a status page or a slash-command's output. See `docs/TRACKS.md` for product vs internal.\n\n## How to find your way in\n\n1. (Branch A) Read CLAUDE.md ยง3/ยง6/ยง7 for tone. (Branch B) Skim `docs/TRACKS.md` and click around your instance's /builders hall for the rough edge you'll write up.\n2. See what's already filed so you don't repeat it: `node scripts/gds/api.js GET /api/gds/inbox`.\n3. File each idea with `node scripts/gds/capture.js \"<title>\" --body-file <path>` (filing an idea is the open-to-all path โ€” a Xenos/Thetes session is allowed to do it; you just can't triage them). Put one line of detail + a `track: product` or `track: internal` line in each body file.",
73
+ "description": "## What you'll do\n\nThe seed of almost everything built here is the **idea_inbox** โ€” a queue anyone can drop ideas into, which trusted builders later triage into real tasks. Your first ship as an ideator is simple and concrete: **add a small batch of fresh ideas to that inbox.** You write no code, touch no game, change no system โ€” you think, write a few short well-shaped ideas, and file them with one command each.\n\nIt is identical for every newcomer and **always valuable**: the inbox is never \"done\" โ€” every triage pass consumes ideas (promote/discard/merge), so it is permanently hungry for fresh input, and a growing world always wants more names, more lore, more texture. Your batch is brand-new content, so it can never duplicate \"the work\" โ€” the supply IS the work.\n\n## Pick ONE branch\n\n- **Branch A โ€” PRODUCT flavour (default).** Ideas that grow the world players see: **names + one line of lore** for a character, structure, landmark, district, ship, or festival; or a world-background snippet (a custom, a superstition, a line a named NPC says). Tone: mythic, mysterious, a \"discovered secret\"; Mediterranean ancient-Greek coast (just south of Athens); NOT modern, NOT tongue-in-cheek-modern. Ground it in CLAUDE.md ยง3/ยง6/ยง7.\n- **Branch B โ€” INTERNAL / builder-UX.** Small user-experience improvement ideas for the GDS / builders' hall (the surfaces builders use, not the game): a clearer label, a confusing onboarding message, a quality-of-life tweak to a status page or a slash-command's output. See `docs/TRACKS.md` for product vs internal.\n\n## How to find your way in\n\n1. (Branch A) Read CLAUDE.md ยง3/ยง6/ยง7 for tone. (Branch B) Skim `docs/TRACKS.md` and click around your instance's /builders hall for the rough edge you'll write up.\n2. See what's already filed so you don't repeat it: `node scripts/gds/api.js GET /api/bongos/inbox`.\n3. File each idea with `node scripts/gds/capture.js \"<title>\" --body-file <path>` (filing an idea is the open-to-all path โ€” a Xenos/Thetes session is allowed to do it; you just can't triage them). Put one line of detail + a `track: product` or `track: internal` line in each body file.",
74
74
  "done_when": [
75
75
  "You filed 5โ€“8 fresh ideas into the idea_inbox via `node scripts/gds/capture.js` (each prints a `Captured idea #N` confirmation), all in ONE branch (A product, or B internal/UX).",
76
76
  "Each idea has a clear title and a body with at least one sentence of detail โ€” for Branch A, one line of in-world lore (who/what it is); for Branch B, what the rough edge is and what 'better' looks like.",
77
77
  "Branch A ideas are in the world's voice and consistent with CLAUDE.md ยง3/ยง6/ยง7 (ancient-Greek coast, Example, mythic 'discovered secret' tone โ€” not modern/anachronistic).",
78
78
  "Each idea body declares its track on a `track: product` or `track: internal` line so triage can route it.",
79
- "Before filing you ran `GET /api/gds/inbox` and confirmed your ideas are not near-duplicates of open ones.",
79
+ "Before filing you ran `GET /api/bongos/inbox` and confirmed your ideas are not near-duplicates of open ones.",
80
80
  "You touched only the idea_inbox via capture.js โ€” no code, no migrations, no infra, no permission/pipeline files; nothing committed to the repo."
81
81
  ],
82
82
  "touches": [],
@@ -11,7 +11,7 @@
11
11
  // realized as a privacy-preserving two-step: this script gzips completed
12
12
  // transcripts into a local spool, and onboarding-analyze.js then ships only
13
13
  // the *distilled friction signal* (not the raw transcript) to the shared GDS
14
- // via POST /api/gds/inbox. The raw transcript never leaves the machine โ€” a
14
+ // via POST /api/bongos/inbox. The raw transcript never leaves the machine โ€” a
15
15
  // deliberate privacy choice given transcripts can contain anything the builder
16
16
  // typed. A dedicated upload endpoint would need a new route + storage table
17
17
  // (migration), both outside this task's touches[].
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // scripts/gds/paste-token.js โ€” V3.R91 / #401.
3
3
  //
4
- // Accept a CLI bearer minted by the builders' hall (POST /api/gds/auth/cli-token/issue)
4
+ // Accept a CLI bearer minted by the builders' hall (POST /api/bongos/auth/cli-token/issue)
5
5
  // and write it into ~/.config/otb/bongos-session.json. Preserves any existing
6
6
  // fields (notably gemini_api_key registered via /builder-setup) so a token
7
7
  // paste never silently un-registers a builder's Gemini key.
@@ -14,7 +14,7 @@
14
14
  // builder can copy + paste a single line.
15
15
  //
16
16
  // Safety contract:
17
- // 1. The token is verified against /api/gds/me BEFORE the session file is
17
+ // 1. The token is verified against /api/bongos/me BEFORE the session file is
18
18
  // touched. A bad paste exits non-zero with a clear message and leaves
19
19
  // the existing session intact.
20
20
  // 2. The file is written with mode 0600, same as setup.js.
@@ -70,7 +70,7 @@ async function main() {
70
70
  // paste was meant to REPLACE, not destroy.
71
71
  let me;
72
72
  try {
73
- const res = await fetch(`${API_BASE}/api/gds/me`, {
73
+ const res = await fetch(`${API_BASE}/api/bongos/me`, {
74
74
  headers: { Authorization: `Bearer ${token}` },
75
75
  });
76
76
  if (res.status === 401) {
@@ -109,11 +109,11 @@ if [ -z "$REMOTE" ]; then bad "could not resolve origin remote for fresh-clone t
109
109
  fi
110
110
 
111
111
  # --- 3. unauthenticated memory read is rejected (guard) ----------------------
112
- code=$(curl -sS -o /dev/null -w '%{http_code}' "$BASE/api/gds/memory/files" || echo 000)
112
+ code=$(curl -sS -o /dev/null -w '%{http_code}' "$BASE/api/bongos/memory/files" || echo 000)
113
113
  [ "$code" = "401" ] && ok "unauth GET /memory/files โ†’ 401" || bad "unauth GET /memory/files โ†’ $code (expected 401)"
114
114
 
115
115
  # --- 4. authenticated builder can pull their server-canonical memory ---------
116
- FILES_JSON=$(curl -sS -H "Authorization: Bearer $TOKEN" "$BASE/api/gds/memory/files" || echo '{}')
116
+ FILES_JSON=$(curl -sS -H "Authorization: Bearer $TOKEN" "$BASE/api/bongos/memory/files" || echo '{}')
117
117
  COUNT=$(echo "$FILES_JSON" | python3 -c "import json,sys;print(json.load(sys.stdin).get('count',-1))" 2>/dev/null || echo -1)
118
118
  if [ "$COUNT" -ge 1 ] 2>/dev/null; then
119
119
  ok "authenticated pull lists $COUNT server-canonical memory file(s)"
@@ -125,7 +125,7 @@ fi
125
125
  # Take the first listed file, fetch it, recompute sha256, compare to server's.
126
126
  FIRST_PATH=$(echo "$FILES_JSON" | python3 -c "import json,sys;f=json.load(sys.stdin).get('files',[]);print(f[0]['path'] if f else '')" 2>/dev/null || echo "")
127
127
  if [ -n "$FIRST_PATH" ]; then
128
- VERDICT=$(curl -sS -H "Authorization: Bearer $TOKEN" --get "$BASE/api/gds/memory/file" --data-urlencode "path=$FIRST_PATH" \
128
+ VERDICT=$(curl -sS -H "Authorization: Bearer $TOKEN" --get "$BASE/api/bongos/memory/file" --data-urlencode "path=$FIRST_PATH" \
129
129
  | python3 -c "
130
130
  import json,sys,hashlib
131
131
  d=json.load(sys.stdin)
@@ -158,9 +158,9 @@ if [ "${GDS_SMOKE_ALLOW_WRITE:-0}" = "1" ] && [ "$TOKEN_SRC" = "env" ]; then
158
158
  PUSH_BODY=$(python3 -c "import json,sys;print(json.dumps({'files':[{'path':'$SPATH','content':sys.argv[1]}]}))" "$STAMP")
159
159
  PUSH_CODE=$(curl -sS -o /dev/null -w '%{http_code}' -X POST \
160
160
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
161
- "$BASE/api/gds/memory/sync" -d "$PUSH_BODY" || echo 000)
161
+ "$BASE/api/bongos/memory/sync" -d "$PUSH_BODY" || echo 000)
162
162
  if [ "$PUSH_CODE" = "200" ]; then
163
- RT=$(curl -sS -H "Authorization: Bearer $TOKEN" --get "$BASE/api/gds/memory/file" --data-urlencode "path=$SPATH" \
163
+ RT=$(curl -sS -H "Authorization: Bearer $TOKEN" --get "$BASE/api/bongos/memory/file" --data-urlencode "path=$SPATH" \
164
164
  | python3 -c "import json,sys;d=json.load(sys.stdin);print('OK' if d.get('content')==sys.argv[1] else 'MISMATCH')" "$STAMP" 2>/dev/null || echo ERR)
165
165
  [ "$RT" = "OK" ] && ok "pushโ†’pull sync round-trip (content persisted + retrieved intact)" \
166
166
  || bad "pushโ†’pull round-trip content mismatch ($RT)"
@@ -71,14 +71,14 @@ function errorCode(body) {
71
71
 
72
72
  /** GET a Bongos API path, returning the parsed body. Throws on a non-2xx. */
73
73
  async function get(path) {
74
- const r = await apiCall('GET', `/api/gds${path}`);
74
+ const r = await apiCall('GET', `/api/bongos${path}`);
75
75
  if (!r.ok) throw new Error(`GET ${path} โ†’ ${r.status}`);
76
76
  return r.data;
77
77
  }
78
78
 
79
79
  /** POST a probe. Returns the status WITHOUT throwing โ€” the status IS the proof. */
80
80
  async function probePost(path, body) {
81
- const r = await apiCall('POST', `/api/gds${path}`, body || {});
81
+ const r = await apiCall('POST', `/api/bongos${path}`, body || {});
82
82
  return { status: r.status, body: r.data, why: errorCode(r.data) };
83
83
  }
84
84
 
@@ -55,7 +55,7 @@ function shouldFederate(inst, deps) {
55
55
  // device sign-in (and a wrong origin would be a takeover vector). client_id is the
56
56
  // (unique, DNS-safe) slug, so a re-provision rotates the SAME row's secret via
57
57
  // registerClient's ON CONFLICT rather than orphaning a client. redirect_uri lists both
58
- // callback prefixes the core may emit (/api/gds is what auth.js builds today) so the
58
+ // callback prefixes the core may emit (/api/bongos is what auth.js builds today) so the
59
59
  // hub's exact-match allow-list accepts the browser leg. --apply gates the real hub
60
60
  // write; dry-run returns a placeholder block (so webEnvBody can still be composed) + logs.
61
61
  async function federateInstance(inst, deps) {
@@ -246,7 +246,7 @@ function healthzCmd(inst) {
246
246
 
247
247
  // The instance manifest, read over loopback โ€” the identity companion to healthzCmd (task 1003740).
248
248
  function identityCmd(inst) {
249
- return `curl -sS --max-time 5 http://127.0.0.1:${inst.port}/api/gds/instance`;
249
+ return `curl -sS --max-time 5 http://127.0.0.1:${inst.port}/api/bongos/instance`;
250
250
  }
251
251
 
252
252
  // Does a freshly provisioned instance report ITSELF, or the platform it is hosted on?
@@ -153,7 +153,7 @@ WantedBy=timers.target
153
153
  //
154
154
  // The pin outlived it, and src/branding.js's ENV_OVERRIDES cover domains, auth.idp and landing โ€”
155
155
  // never `identity.productName`. So every hosted instance kept serving the NEUTRAL pack's name:
156
- // GET /api/gds/instance on hermeslines-marketing, mercury and demo all answered "Cloud Bongos"
156
+ // GET /api/bongos/instance on hermeslines-marketing, mercury and demo all answered "Cloud Bongos"
157
157
  // while each instance's own pack on disk said otherwise, and `bongos login <instance>` greeted a
158
158
  // newcomer with the platform's name at the moment they were deciding whether to trust it.
159
159
  //
@@ -310,10 +310,10 @@ function settingsEnvVarsFor(inst) {
310
310
  }
311
311
 
312
312
  // The instance's own public manifest โ€” the settings read-back ADR 0190 names
313
- // (GET /api/gds/instance โ†’ brand.project). Sibling of provision-net's healthzCmd:
313
+ // (GET /api/bongos/instance โ†’ brand.project). Sibling of provision-net's healthzCmd:
314
314
  // same loopback + timeout, a different question ("did you READ it?").
315
315
  function instanceManifestCmd(inst) {
316
- return `curl -sS --max-time 5 http://127.0.0.1:${inst.port}/api/gds/instance`;
316
+ return `curl -sS --max-time 5 http://127.0.0.1:${inst.port}/api/bongos/instance`;
317
317
  }
318
318
 
319
319
  // Did the restarted instance CONSUME the pushed settings? Compares each key of
@@ -15,7 +15,7 @@
15
15
  //
16
16
  // -------------------------------------------------------------------------
17
17
  // Pulse-mode follow-up note (unchanged from original):
18
- // POST /api/gds/pulse is NOT yet wired (route lives in src/bongos/routes.js,
18
+ // POST /api/bongos/pulse is NOT yet wired (route lives in src/bongos/routes.js,
19
19
  // which is OUT of THAT task's touches[]). Once a follow-up task adds
20
20
  // the route, the pulse path starts working with no changes. Until then,
21
21
  // running it will print a 404 from the server โ€” that is expected.
@@ -314,7 +314,7 @@ async function releaseStale({ timer, dryRun }) {
314
314
  const r = await api.request('POST', '/pulse', { body: { claim_id: claimId } });
315
315
  if (!r.ok) {
316
316
  // Fire-and-forget: log the diagnostic but do not fail.
317
- // Until the /api/gds/pulse route is mounted, this routinely returns 404.
317
+ // Until the /api/bongos/pulse route is mounted, this routinely returns 404.
318
318
  console.error(`pulse non-ok (status ${r.status}):`, r.data);
319
319
  process.exit(0);
320
320
  }
@@ -18,7 +18,7 @@
18
18
  // strand-watch.js. On the server-publish path (pushVia() 'server' โ€” no authenticated
19
19
  // gh, i.e. a dev box or any credential-less checkout) it prints ONE line stating the
20
20
  // credential model and where the truth about published work lives
21
- // (GET /api/gds/tasks/:id/publish-status). On a laptop that pushes locally
21
+ // (GET /api/bongos/tasks/:id/publish-status). On a laptop that pushes locally
22
22
  // (pushVia() 'local') it prints NOTHING โ€” a line that fires on every healthy laptop
23
23
  // becomes wallpaper and the real one gets scrolled past (the strand-watch lesson).
24
24
  //
@@ -40,7 +40,7 @@ const BRIEF = 'This machine holds NO GitHub push credential โ€” BY DESIGN (ADR 0
40
40
  + 'git push / ls-remote / fetch against origin fail with auth errors here, and that is not a fault to fix. '
41
41
  + 'Landing is server-mediated โ€” /builder-ship uploads a git bundle and the SERVER pushes, opens the PR, and lands it. '
42
42
  + 'NEVER ask the owner for a PAT or credential; that request is always wrong on this machine. '
43
- + 'To see whether work reached GitHub, use GET /api/gds/tasks/:id/publish-status โ€” never raw git probes.';
43
+ + 'To see whether work reached GitHub, use GET /api/bongos/tasks/:id/publish-status โ€” never raw git probes.';
44
44
 
45
45
  // briefLine(via) โ€” the unit-testable core: the SessionStart line for this publish
46
46
  // path, or null. Null IS the silence (the laptop case, and the undetermined case โ€”
@@ -11,7 +11,7 @@
11
11
  // getting back in โ€” the slow Device Flow, terminal codes, Gemini-key prompts โ€” is
12
12
  // not something to keep. This script is the fix:
13
13
  //
14
- // 1. Detect โ€” is the current session still valid? (GET /api/gds/me)
14
+ // 1. Detect โ€” is the current session still valid? (GET /api/bongos/me)
15
15
  // valid โ†’ print who you are + exit 0. Nothing to do.
16
16
  // invalid โ†’ exit 10 ("re-auth needed") after opening the browser.
17
17
  // 2. Guide โ€” open the builder's Settings page in the default browser (where
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // scripts/gds/recall.js โ€” one-call project-knowledge search (task 955, V4.R17 /
3
- // ADR 0060). Wraps POST /api/gds/search: lexical (FTS + pg_trgm) fused with RRF,
3
+ // ADR 0060). Wraps POST /api/bongos/search: lexical (FTS + pg_trgm) fused with RRF,
4
4
  // rank/owner-scoped server-side (a sub-Metic caller never sees protected docs;
5
5
  // you only ever see your own private chunks). Authenticated โ€” reads the builder
6
6
  // session like every other /builder-* CLI.
@@ -28,7 +28,7 @@
28
28
  //
29
29
  // Filing: DRY-RUN by default (prints what it would file). --file POSTs one
30
30
  // report PER CLASS (max severity within the class, details in repro_steps_md)
31
- // to /api/gds/security/reports. --canary proves the end-to-end pipe: plants a
31
+ // to /api/bongos/security/reports. --canary proves the end-to-end pipe: plants a
32
32
  // constructed token, asserts the scanner catches it, files a low "[canary]"
33
33
  // report, and dispute-closes it so the queue stays clean.
34
34
  //
@@ -317,14 +317,14 @@ function filingBlocker() {
317
317
 
318
318
  async function fileReport(report) {
319
319
  const { apiCall } = require('./cli-lib.js');
320
- const r = await apiCall('POST', '/api/gds/security/reports', report);
320
+ const r = await apiCall('POST', '/api/bongos/security/reports', report);
321
321
  const row = (r.data && r.data.report) || {};
322
322
  return row.id || null;
323
323
  }
324
324
 
325
325
  async function disputeReport(id, note) {
326
326
  const { apiCall } = require('./cli-lib.js');
327
- return apiCall('POST', `/api/gds/security/reports/${id}/dispute`, { note });
327
+ return apiCall('POST', `/api/bongos/security/reports/${id}/dispute`, { note });
328
328
  }
329
329
 
330
330
  // ---------- canary ----------
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  // Renders generative-ideas.md from the GDS idea_inbox table.
3
3
  //
4
- // Reads via GET /api/gds/inbox (authenticated). Writes a generated markdown
4
+ // Reads via GET /api/bongos/inbox (authenticated). Writes a generated markdown
5
5
  // view to the repo's top-level generative-ideas.md. The file is overwritten
6
6
  // on every run โ€” manual edits will not survive. Capture via /builder-capture
7
7
  // or `node scripts/gds/capture.js`; triage via /builder-triage or the API.
8
8
  //
9
- // Note (2026-05-10): the current GET /api/gds/inbox endpoint returns open
9
+ // Note (2026-05-10): the current GET /api/bongos/inbox endpoint returns open
10
10
  // ideas only (see src/bongos/inbox.js listOpenIdeas). The "Recently Promoted",
11
11
  // "Recently Discarded", and "Merged" sections will be empty until the API
12
12
  // is extended to expose those statuses. The script is forward-compatible:
@@ -33,7 +33,7 @@ const HEADER = `<!-- GENERATED FILE โ€” Edit via /builder-capture or /builder-tr
33
33
  >
34
34
  > **Capture an idea:** \`node scripts/gds/capture.js "short title"\` (or the \`/builder-capture\` slash command).
35
35
  >
36
- > **Triage open ideas:** \`/idea-triage\` (or \`PATCH /api/gds/inbox/<id>\` with \`{ status: 'promoted' | 'discarded' | 'merged', promoted_to_task_id: N }\`).
36
+ > **Triage open ideas:** \`/idea-triage\` (or \`PATCH /api/bongos/inbox/<id>\` with \`{ status: 'promoted' | 'discarded' | 'merged', promoted_to_task_id: N }\`).
37
37
  `;
38
38
 
39
39
  function fmtTimestamp(iso) {
@@ -102,13 +102,13 @@ function renderSection(heading, ideas, emptyMsg) {
102
102
  }
103
103
 
104
104
  async function fetchAllIdeas() {
105
- // GET /api/gds/inbox currently returns open ideas only. We request the max
105
+ // GET /api/bongos/inbox currently returns open ideas only. We request the max
106
106
  // limit so this works as the inbox grows. When the API is extended to
107
107
  // return other statuses, this script will pick them up automatically.
108
108
  const api = await cliClient();
109
109
  const { ok, status, data } = await api.inbox.getInbox({ query: { limit: 500 } });
110
110
  if (!ok) {
111
- throw new Error(`GET /api/gds/inbox failed: HTTP ${status} ${JSON.stringify(data)}`);
111
+ throw new Error(`GET /api/bongos/inbox failed: HTTP ${status} ${JSON.stringify(data)}`);
112
112
  }
113
113
  return data.ideas || [];
114
114
  }
@@ -5,7 +5,7 @@
5
5
  // "You can't manage what you don't measure." This dependency-free CLI shells
6
6
  // out to git / wc / knip and emits a JSON snapshot of repo health, then upserts
7
7
  // it into repo_health_snapshots (idempotent on calendar date โ€” rerun same day
8
- // = upsert, not a new row). The latest row feeds /api/gds/public/repo-health,
8
+ // = upsert, not a new row). The latest row feeds /api/bongos/public/repo-health,
9
9
  // which renders a trend tile on status.example.com.
10
10
  //
11
11
  // What the snapshot contains:
@@ -219,11 +219,11 @@ function restartPreview(deps = {}) {
219
219
  // task 1002607: the discriminator probe URL โ€” same origin as the health URL, at
220
220
  // the API healthz path only the FULL server mounts. Pure + exported for tests.
221
221
  function apiHealthzProbeUrl(healthUrl) {
222
- try { return new URL('/api/gds/healthz', healthUrl).toString(); } catch { return null; }
222
+ try { return new URL('/api/bongos/healthz', healthUrl).toString(); } catch { return null; }
223
223
  }
224
224
 
225
225
  // task 1002607: is the thing answering the health URL actually the MAIN server?
226
- // The game-only preview entry (ADR 0052) mounts no /api/gds, so a 200 from the
226
+ // The game-only preview entry (ADR 0052) mounts no /api/bongos, so a 200 from the
227
227
  // API healthz proves the answerer is the full server โ€” whose default bind is the
228
228
  // SAME 127.0.0.1:3000 the box health check probes โ€” not the preview. A probe
229
229
  // error/404 means "not the main server", which is the expected preview answer.
@@ -254,7 +254,7 @@ async function waitHealthy(deps = {}) {
254
254
  if (await answeredByMainServer(healthUrl, fetchImpl)) {
255
255
  return {
256
256
  ok: false,
257
- reason: `${healthUrl} is answered by the MAIN server (/api/gds/healthz responded 200), not the game preview โ€” the preview did not start (its port is taken by the full server)`,
257
+ reason: `${healthUrl} is answered by the MAIN server (/api/bongos/healthz responded 200), not the game preview โ€” the preview did not start (its port is taken by the full server)`,
258
258
  };
259
259
  }
260
260
  return { ok: true };
@@ -38,7 +38,7 @@ const TASKS = [
38
38
  const idByRef = {};
39
39
  // Phase 1: create tasks (idempotent on source_ref) + link the criterion.
40
40
  for (const t of TASKS) {
41
- const create = await apiCall('POST', '/api/gds/tasks', {
41
+ const create = await apiCall('POST', '/api/bongos/tasks', {
42
42
  version_id: 'BONGOS-V1',
43
43
  goal_id: GOAL_ID,
44
44
  title: t.title,
@@ -54,7 +54,7 @@ const TASKS = [
54
54
  const id = task && task.id;
55
55
  if (!id) { console.log(` ${t.ref}: CREATE FAILED โ€” ${create.status} ${JSON.stringify(create.data).slice(0, 160)}`); continue; }
56
56
  idByRef[t.ref] = id;
57
- const link = await apiCall('POST', `/api/gds/tasks/${id}/criteria`, { criterion_ids: t.crit });
57
+ const link = await apiCall('POST', `/api/bongos/tasks/${id}/criteria`, { criterion_ids: t.crit });
58
58
  console.log(` ${t.ref} -> task ${id} (${t.kind}, P${t.priority}, goal ${task.goal_id}) ยท criterion ${link.status === 200 ? 'ok' : (JSON.stringify(link.data).slice(0, 120))}`);
59
59
  }
60
60
  // Phase 2: dependency edges (idempotent on (task_id, depends_on_task_id)).
@@ -65,7 +65,7 @@ const TASKS = [
65
65
  const localDepIds = t.deps.map((d) => idByRef[d]).filter(Boolean);
66
66
  const allDeps = [...localDepIds, ...t.extDeps];
67
67
  for (const depId of allDeps) {
68
- const r = await apiCall('POST', `/api/gds/tasks/${id}/dependencies`, { depends_on_task_id: depId });
68
+ const r = await apiCall('POST', `/api/bongos/tasks/${id}/dependencies`, { depends_on_task_id: depId });
69
69
  console.log(` ${t.ref}(${id}) -> ${depId} ${r.status === 200 || r.status === 201 ? 'ok' : (JSON.stringify(r.data).slice(0, 120))}`);
70
70
  }
71
71
  }
@@ -15,7 +15,7 @@ const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json'
15
15
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
16
16
  async function api(method, path, body, _tries = 0) {
17
17
  await sleep(500); // base throttle to stay under the per-IP rate limit
18
- const res = await fetch(`${BASE}/api/gds${path}`, {
18
+ const res = await fetch(`${BASE}/api/bongos${path}`, {
19
19
  method, headers: H, body: body ? JSON.stringify(body) : undefined,
20
20
  });
21
21
  const text = await res.text();
@@ -6,8 +6,8 @@
6
6
  // Design home: the "Bongos App โ€” V1" plan artifact (favicon ๐Ÿฅ).
7
7
  //
8
8
  // Shape mirrors seed-bongos-tasks.js exactly:
9
- // - POST /api/gds/tasks { version_id:'BONGOS-V1', criterion_ids:['C1'], ... }
10
- // - POST /api/gds/tasks/:id/dependencies { depends_on_task_ids:[...] }
9
+ // - POST /api/bongos/tasks { version_id:'BONGOS-V1', criterion_ids:['C1'], ... }
10
+ // - POST /api/bongos/tasks/:id/dependencies { depends_on_task_ids:[...] }
11
11
  // - idempotent on source_ref (skips already-created); deps idempotent server-side.
12
12
  // Run migration 120_bongos_v1_planning_seed.sql FIRST so the version + C1..C4 exist.
13
13
  // After this runs, promote the zero-dependency tasks (R01/R02/R03) to 'ready'
@@ -53,12 +53,12 @@ async function post(path, body) {
53
53
  criterion_ids: ['C7'],
54
54
  source: 'planning', source_ref: `BONGOS-V1-coreB-${t.ref}`,
55
55
  };
56
- let { status, json } = await post('/api/gds/tasks', body);
56
+ let { status, json } = await post('/api/bongos/tasks', body);
57
57
  let id = json.id || (json.task && json.task.id);
58
58
  if (!id && t.kind === 'verify') {
59
59
  // memory: kind=verify has 500'd before (idea #357). Fall back, keep going.
60
60
  console.log(` ${t.ref}: kind=verify failed (${json.error || status}); retrying as kind=feature`);
61
- ({ status, json } = await post('/api/gds/tasks', { ...body, kind: 'feature' }));
61
+ ({ status, json } = await post('/api/bongos/tasks', { ...body, kind: 'feature' }));
62
62
  id = json.id || (json.task && json.task.id);
63
63
  }
64
64
  if (!id) { console.log(` ${t.ref}: CREATE FAILED โ€” ${status} ${JSON.stringify(json).slice(0, 160)}`); continue; }
@@ -73,7 +73,7 @@ async function post(path, body) {
73
73
  for (const dep of t.deps) {
74
74
  const depId = idByRef[dep];
75
75
  if (!depId) { console.log(` ${t.ref}: dep ${dep} not created โ€” skip`); continue; }
76
- const { status, json } = await post(`/api/gds/tasks/${id}/dependencies`, { depends_on_task_id: depId });
76
+ const { status, json } = await post(`/api/bongos/tasks/${id}/dependencies`, { depends_on_task_id: depId });
77
77
  console.log(` ${t.ref}(${id}) depends on ${dep}(${depId}) -> ${status === 200 || status === 201 ? 'ok' : (json.error || status)}`);
78
78
  }
79
79
  }
@@ -69,19 +69,19 @@ async function post(path, body) {
69
69
  criterion_ids: ['C7'],
70
70
  source: 'planning', source_ref: `BONGOS-V1-coreB-${t.ref}`,
71
71
  };
72
- let { status, json } = await post('/api/gds/tasks', body);
72
+ let { status, json } = await post('/api/bongos/tasks', body);
73
73
  let id = json.id || (json.task && json.task.id);
74
74
  if (!id && t.kind === 'verify') {
75
75
  // memory: kind=verify has 500'd before (idea #357). Fall back, keep going.
76
76
  console.log(` ${t.ref}: kind=verify failed (${json.error || status}); retrying as kind=feature`);
77
- ({ status, json } = await post('/api/gds/tasks', { ...body, kind: 'feature' }));
77
+ ({ status, json } = await post('/api/bongos/tasks', { ...body, kind: 'feature' }));
78
78
  id = json.id || (json.task && json.task.id);
79
79
  }
80
80
  if (!id) { console.log(` ${t.ref}: CREATE FAILED โ€” ${status} ${JSON.stringify(json).slice(0, 160)}`); continue; }
81
81
  idByRef[t.ref] = id;
82
82
  // Link C7 explicitly (criterion_ids at create is not honored on this build;
83
83
  // the /criteria endpoint is idempotent โ€” re-adding an existing link is a no-op).
84
- const link = await post(`/api/gds/tasks/${id}/criteria`, { criterion_ids: ['C7'] });
84
+ const link = await post(`/api/bongos/tasks/${id}/criteria`, { criterion_ids: ['C7'] });
85
85
  console.log(` ${t.ref} -> task ${id} (${t.kind}, P${t.priority}) ยท C7 link ${link.status === 200 ? 'ok' : (link.json.error || link.status)}`);
86
86
  }
87
87
  // Phase 2: wire dependencies (idempotent on (task_id, depends_on_task_id)).
@@ -92,7 +92,7 @@ async function post(path, body) {
92
92
  for (const dep of t.deps) {
93
93
  const depId = idByRef[dep];
94
94
  if (!depId) { console.log(` ${t.ref}: dep ${dep} not created โ€” skip`); continue; }
95
- const { status, json } = await post(`/api/gds/tasks/${id}/dependencies`, { depends_on_task_id: depId });
95
+ const { status, json } = await post(`/api/bongos/tasks/${id}/dependencies`, { depends_on_task_id: depId });
96
96
  console.log(` ${t.ref}(${id}) depends on ${dep}(${depId}) -> ${status === 200 || status === 201 ? 'ok' : (json.error || status)}`);
97
97
  }
98
98
  }
@@ -5,8 +5,8 @@
5
5
  // instance 1). Design doc: artifact 02bcca71 (the bongos toolkit).
6
6
  //
7
7
  // Shape mirrors seed-medusa-tasks.js exactly:
8
- // - POST /api/gds/tasks { version_id:'GDS-V4', criterion_ids:['C8'], ... }
9
- // - POST /api/gds/tasks/:id/dependencies { depends_on_task_ids:[...] }
8
+ // - POST /api/bongos/tasks { version_id:'GDS-V4', criterion_ids:['C8'], ... }
9
+ // - POST /api/bongos/tasks/:id/dependencies { depends_on_task_ids:[...] }
10
10
  // - idempotent on source_ref (skips already-created); deps idempotent server-side.
11
11
  //
12
12
  // Display R## numbers are assigned dynamically from the current max V4.R## in
@@ -81,12 +81,12 @@ A \`curl -fsSL https://get.bongos.dev | sh\` bootstrap (detects OS/arch, downloa
81
81
  },
82
82
  {
83
83
  key: 'P4A',
84
- title: 'Instance manifest endpoint โ€” GET /api/gds/instance (brand + modules + repo)',
84
+ title: 'Instance manifest endpoint โ€” GET /api/bongos/instance (brand + modules + repo)',
85
85
  description: `Part of Cloud Bongos / C8. Cross-ref: R53 (branding-contract layer), R54 (feature-module selection). This is the read-API over those two configs โ€” the conda "environment.yml" a CLI fetches to configure itself.
86
86
 
87
87
  A small public, read-only endpoint returning the instance descriptor assembled from the R53 branding contract + the R54 module flags: product/instance name + brand (identity, copy, theme โ€” NO secrets), enabled feature-modules, the GitHub repo binding, the rank ladder, supported auth methods (device-flow / app-pair), admission policy (invite-only vs open), and whether a managed dev-box backend is available. So \`bongos login <url>\` brands itself, knows the repo for \`--local\`, and hides verbs an instance doesn't run (e.g. no \`box\` if dev-box is off). Today GET /healthz returns only { ok, auth_configured } โ€” this is a genuine gap.
88
88
 
89
- **Done when:** GET /api/gds/instance returns a documented manifest assembled from the branding contract + module flags, contains no secrets/topology, is fetchable pre-auth (CORS read), and the CLI can brand + feature-gate itself from it. Depends on R53/R54 so the brand + module sources exist.`,
89
+ **Done when:** GET /api/bongos/instance returns a documented manifest assembled from the branding contract + module flags, contains no secrets/topology, is fetchable pre-auth (CORS read), and the CLI can brand + feature-gate itself from it. Depends on R53/R54 so the brand + module sources exist.`,
90
90
  kind: 'feature', discipline: 'engineer', priority: 3,
91
91
  est_minutes: 240, manual_degree: 2, credits_reward: 50,
92
92
  touches: ['src/bongos/routes/', 'src/bongos/'], criteria: ['C8'], deps: ['R53', 'R54'],
@@ -96,7 +96,7 @@ A small public, read-only endpoint returning the instance descriptor assembled f
96
96
  title: 'bongos login <instance> (instance-agnostic) + stranger access-request flow; folds in init/upgrade',
97
97
  description: `Part of Cloud Bongos / C8. Cross-ref: P1, P4A (manifest), R64 (\`medusa/bongos upgrade\`), R65 (\`init\`), ADR 0050/0057/0059 (admission).
98
98
 
99
- \`bongos login <instance-url>\` fetches the P4A manifest, runs the GitHub device-flow (browser-click, no token paste โ€” the UI-first rule), stores a per-instance scoped session, and brands the CLI for that instance. For someone NOT yet admitted, it files the public POST /api/gds/access-requests (their GitHub username) and polls โ€” telling them "an Archon will approve you with a ๐Ÿ‘ in Discord" โ€” until admission flips, then completes sign-in. No GitHub collaborator invite is involved. Default admission is invite-only. Also folds the already-planned \`bongos init\` (scaffold a brand-new instance, R65) and \`bongos upgrade\` (R64) in as subcommands of the same CLI.
99
+ \`bongos login <instance-url>\` fetches the P4A manifest, runs the GitHub device-flow (browser-click, no token paste โ€” the UI-first rule), stores a per-instance scoped session, and brands the CLI for that instance. For someone NOT yet admitted, it files the public POST /api/bongos/access-requests (their GitHub username) and polls โ€” telling them "an Archon will approve you with a ๐Ÿ‘ in Discord" โ€” until admission flips, then completes sign-in. No GitHub collaborator invite is involved. Default admission is invite-only. Also folds the already-planned \`bongos init\` (scaffold a brand-new instance, R65) and \`bongos upgrade\` (R64) in as subcommands of the same CLI.
100
100
 
101
101
  **Done when:** \`bongos login <any-instance-url>\` works end-to-end including the not-yet-admitted path (files the request, polls, completes once approved); the CLI is instance-agnostic (no hard-coded example); \`init\`/\`upgrade\` are reachable subcommands.`,
102
102
  kind: 'feature', discipline: 'engineer', priority: 3,
@@ -28,7 +28,7 @@ const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json'
28
28
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
29
29
  async function api(method, path, body, _tries = 0) {
30
30
  await sleep(400); // base throttle to stay under the per-IP rate limit
31
- const res = await fetch(`${BASE}/api/gds${path}`, {
31
+ const res = await fetch(`${BASE}/api/bongos${path}`, {
32
32
  method, headers: H, body: body ? JSON.stringify(body) : undefined,
33
33
  });
34
34
  const text = await res.text();
@@ -16,7 +16,7 @@ const H = { Authorization: `Bearer ${TOKEN}`, 'Content-Type': 'application/json'
16
16
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
17
17
  async function api(method, path, body, _tries = 0) {
18
18
  await sleep(400); // base throttle to stay under the per-IP rate limit
19
- const res = await fetch(`${BASE}/api/gds${path}`, {
19
+ const res = await fetch(`${BASE}/api/bongos${path}`, {
20
20
  method, headers: H, body: body ? JSON.stringify(body) : undefined,
21
21
  });
22
22
  const text = await res.text();