@bongos/core 1.17.0 → 1.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.bongos-core.json +154 -83
  2. package/CLAUDE.md +11 -238
  3. package/bin/bongos.js +1 -0
  4. package/clients/bongos-client/README.md +4 -4
  5. package/clients/bongos-client/bongos-client.global.js +14 -1
  6. package/clients/bongos-client/index.cjs +14 -1
  7. package/clients/bongos-client/index.d.ts +19 -2
  8. package/clients/bongos-client/index.mjs +11 -1
  9. package/clients/bongos-client/package.json +1 -1
  10. package/docs/adr/0133-github-app-manifest-onboarding-signin.md +2 -0
  11. package/docs/adr/0134-private-first-npm-distribution.md +20 -6
  12. package/docs/adr/0135-module-upstream-submission-interim-queue.md +34 -0
  13. package/docs/adr/README.md +5 -4
  14. package/docs/api/openapi.json +315 -6
  15. package/docs/api-reference.md +10 -5
  16. package/docs/architecture.md +1 -1
  17. package/docs/file-map.md +2 -2
  18. package/docs/modules-contract.md +2 -0
  19. package/docs/recipes/instance-deploy.md +4 -4
  20. package/docs/recipes/instance-first-run.md +51 -0
  21. package/docs/recipes/packaging-the-core.md +5 -5
  22. package/docs/recipes/private-npm-distribution.md +22 -12
  23. package/docs/recipes/self-host.md +1 -1
  24. package/docs/recipes/upgrading-the-core.md +8 -8
  25. package/migrations/core_191_module_submissions.sql +45 -0
  26. package/modules/autonomy/CLAUDE.md +11 -45
  27. package/modules/builder-settings/CLAUDE.md +11 -54
  28. package/modules/dev-box/CLAUDE.md +11 -34
  29. package/modules/discord/CLAUDE.md +11 -46
  30. package/modules/economy/CLAUDE.md +11 -44
  31. package/modules/grading/CLAUDE.md +11 -38
  32. package/modules/hall-ui/CLAUDE.md +11 -57
  33. package/modules/hall-ui/public/goals-page.js +227 -22
  34. package/modules/hall-ui/public/goals.html +16 -0
  35. package/modules/hall-ui/public/new-project-wizard.js +5 -4
  36. package/modules/ideas/CLAUDE.md +11 -33
  37. package/modules/lifecycle/CLAUDE.md +11 -59
  38. package/modules/lifecycle/routes/goals.js +80 -0
  39. package/modules/memory/CLAUDE.md +11 -36
  40. package/modules/onboarding/CLAUDE.md +11 -51
  41. package/modules/security/CLAUDE.md +11 -40
  42. package/modules/sessions/CLAUDE.md +11 -35
  43. package/modules/status-ui/CLAUDE.md +11 -43
  44. package/package-lock.json +2 -2
  45. package/package.json +1 -1
  46. package/public-landing/create.html +58 -12
  47. package/public-landing/index.html +40 -21
  48. package/scripts/gds/CLAUDE.md +11 -140
  49. package/scripts/gds/claude-materialize.js +151 -18
  50. package/scripts/gds/claude-md-template.js +84 -0
  51. package/scripts/gds/cli-lib.js +112 -2
  52. package/scripts/gds/gen-api-client.js +10 -10
  53. package/scripts/gds/init.js +53 -13
  54. package/scripts/gds/migration-namespace.js +1 -1
  55. package/scripts/gds/module.js +118 -4
  56. package/scripts/gds/npmrc.js +93 -0
  57. package/scripts/gds/onboard.js +13 -24
  58. package/scripts/gds/package-core.js +56 -14
  59. package/scripts/gds/provision.js +102 -17
  60. package/scripts/gds/seed-adopt-tasks.js +1 -1
  61. package/scripts/gds/status.js +6 -1
  62. package/scripts/gds/task.js +166 -0
  63. package/scripts/gds/upgrade.js +58 -18
  64. package/src/bongos/CLAUDE.md +11 -60
  65. package/src/bongos/auth.js +11 -0
  66. package/src/bongos/module-submissions.js +56 -0
  67. package/src/bongos/route-rank-check.js +6 -0
  68. package/src/bongos/routes/CLAUDE.md +11 -39
  69. package/src/bongos/routes/auth.js +6 -1
  70. package/src/bongos/routes/modules.js +123 -21
  71. package/src/instance-config.js +1 -1
  72. package/src/module-api.js +13 -1
  73. package/tests/claude_materialize.mjs +105 -0
  74. package/tests/device_flow_start.mjs +73 -0
  75. package/tests/first_run_engine_check.mjs +79 -0
  76. package/tests/goal_membership_requests.mjs +33 -3
  77. package/tests/hook_user_agents.mjs +62 -0
  78. package/tests/init.mjs +59 -6
  79. package/tests/instance_mismatch_guard.mjs +101 -0
  80. package/tests/module_cli.mjs +130 -2
  81. package/tests/module_submissions.mjs +135 -0
  82. package/tests/npmrc.mjs +105 -0
  83. package/tests/onboard.mjs +49 -0
  84. package/tests/package_core.mjs +68 -22
  85. package/tests/platform_boot.mjs +5 -2
  86. package/tests/provision.mjs +107 -8
  87. package/tests/provisioning_github_app_routes.mjs +29 -2
  88. package/tests/served_paths_shipped.mjs +2 -2
  89. package/tests/task_cli.mjs +99 -0
  90. package/tests/upgrade.mjs +89 -25
@@ -62,10 +62,24 @@ body{
62
62
  text-transform:lowercase;color:var(--ink);text-decoration:none;
63
63
  }
64
64
  .top .mark span{color:var(--accent);}
65
+ .top-right{display:flex;align-items:center;gap:clamp(10px,2vw,18px);}
66
+ /* exit the wizard — Esc, or this button (task 2098). Nothing is created until the
67
+ final step, so leaving simply drops the in-progress project. */
68
+ .exit-wizard{
69
+ display:inline-flex;align-items:center;gap:7px;cursor:pointer;
70
+ background:transparent;border:1px solid rgba(42,31,23,0.16);border-radius:999px;
71
+ padding:7px 14px;font-family:var(--font-body);font-weight:600;font-size:13px;color:var(--ink-soft);
72
+ transition:background .14s ease,border-color .14s ease,color .14s ease;
73
+ }
74
+ .exit-wizard:hover{background:rgba(42,31,23,0.05);color:var(--ink);border-color:rgba(42,31,23,0.28);}
75
+ .exit-wizard kbd{font-family:var(--font-mono);font-size:10px;line-height:1;background:rgba(42,31,23,0.08);border-radius:4px;padding:2px 5px;color:var(--ink-faint);}
65
76
  .who{display:flex;align-items:center;gap:10px;font-size:14px;font-weight:600;color:var(--ink-soft);min-height:34px;}
66
77
  .who img{width:30px;height:30px;border-radius:50%;border:2px solid #fff;box-shadow:0 2px 8px rgba(42,31,23,0.12);}
67
78
  .who a{color:var(--accent-deep);text-decoration:none;font-weight:700;}
68
79
  .who a:hover{text-decoration:underline;}
80
+ /* switch to a different GitHub account from inside the wizard (task 2098) */
81
+ .who .switch-acct{font-size:12px;font-weight:600;color:var(--ink-faint);padding-left:10px;margin-left:2px;border-left:1px solid rgba(42,31,23,0.16);}
82
+ .who .switch-acct:hover{color:var(--accent-deep);}
69
83
 
70
84
  /* ── layout ── */
71
85
  .wrap{
@@ -304,7 +318,10 @@ input[type=text].bad{border-color:var(--err);}
304
318
 
305
319
  <header class="top">
306
320
  <a class="mark" href="/"><span data-brand-product>cloud bongos</span></a>
307
- <div class="who" id="who" aria-live="polite"></div>
321
+ <div class="top-right">
322
+ <button type="button" class="exit-wizard" id="exitWizard" title="Leave the wizard — nothing is created">Exit <kbd>esc</kbd></button>
323
+ <div class="who" id="who" aria-live="polite"></div>
324
+ </div>
308
325
  </header>
309
326
 
310
327
  <div class="wrap">
@@ -445,7 +462,8 @@ input[type=text].bad{border-color:var(--err);}
445
462
  var API = '/api/bongos';
446
463
  var b = (typeof window !== 'undefined' && window.__BRANDING__) || {};
447
464
  var productName = (b.identity && b.identity.productName) || 'Cloud Bongos';
448
- var buildersOrigin = (b.domains && b.domains.buildersOrigin) || 'https://builders.cloudbongos.com';
465
+ // (task 2094: the wizard no longer links into cloud bongos's own builders hall,
466
+ // so the buildersOrigin it used to render is gone.)
449
467
  document.querySelectorAll('[data-brand-product]').forEach(function (n) { n.textContent = productName.toLowerCase(); });
450
468
  document.querySelectorAll('[data-brand-product-inline]').forEach(function (n) { n.textContent = productName; });
451
469
 
@@ -697,24 +715,24 @@ input[type=text].bad{border-color:var(--err);}
697
715
  var oa = state.domain ? oauthAppValues(state.domain) : null;
698
716
  $('doneLede').innerHTML = 'Provisioning is requested for <strong>' + esc(state.name || state.slug) + '</strong>' +
699
717
  (adopt ? ' — adopting your existing repo' : '') +
700
- '. The platform stands up the server, database, and address on its own; you’ll find its live status under <a href="' + esc(buildersOrigin) + '" style="color:var(--accent-deep);font-weight:700;">Instances in your hall</a>.';
718
+ '. The platform stands up the server, database, and address on its own — you can watch its live status right here.';
701
719
 
702
720
  var steps = [];
703
721
  var repoLabel = state.owner && state.repo ? '<strong>' + esc(state.owner + '/' + state.repo) + '</strong>' : 'your new repository';
704
722
  steps.push(adopt
705
- ? '<li><b>Layer onto your existing repo</b><p>In your repo run <code style="font-family:var(--font-mono)">bongos init --adopt</code>. It shows a conflict pre-flight and writes <em>nothing</em> until you accept — your files and history stay yours, and your existing backlog is imported. Commit and push.</p></li>'
706
- : '<li><b>Create the empty GitHub repo</b><p>On github.com: New repository → ' + repoLabel + ' → leave it completely empty.</p></li>');
723
+ ? '<li data-onboard-step="github-repo"><b>Layer onto your existing repo</b><p>In your repo run <code style="font-family:var(--font-mono)">bongos init --adopt</code>. It shows a conflict pre-flight and writes <em>nothing</em> until you accept — your files and history stay yours, and your existing backlog is imported. Commit and push.</p></li>'
724
+ : '<li data-onboard-step="github-repo"><b>Create the empty GitHub repo</b><p>On github.com: New repository → ' + repoLabel + ' → leave it completely empty.</p></li>');
707
725
  if (!state.domain) {
708
726
  steps.push('<li><b>Add a domain you own</b><p>Sign-in on your new instance needs a real domain. When you have one, come back here or ask your hall — the address gets wired in minutes.</p></li>');
709
727
  }
710
728
  if (oa) {
711
- steps.push('<li><b>Create the GitHub OAuth app</b><p>GitHub → <em>your account’s</em> Settings → Developer settings → OAuth Apps → New OAuth App. (Developer settings live under your account, not the repo.)</p>' +
729
+ steps.push('<li data-onboard-step="oauth-app"><b>Create the GitHub OAuth app</b><p>GitHub → <em>your account’s</em> Settings → Developer settings → OAuth Apps → New OAuth App. (Developer settings live under your account, not the repo.)</p>' +
712
730
  '<div class="kv"><span class="kk">Homepage URL</span><code>' + esc(oa.homepageUrl) + '</code>' + copyBtn(oa.homepageUrl) + '</div>' +
713
731
  '<div class="kv"><span class="kk">Callback URL</span><code>' + esc(oa.callbackUrl) + '</code>' + copyBtn(oa.callbackUrl) + '</div></li>');
714
732
  var cmd = 'bongos oauth-secret place ' + state.slug + ' --client-id <id> --client-secret <secret> --apply';
715
733
  steps.push('<li><b>Place the secret — verified</b><p>Never hand-edit the env file. On the control plane run the placement command; it checks the value is real and confirms sign-in works.</p>' +
716
734
  '<div class="kv"><code>' + esc(cmd) + '</code>' + copyBtn(cmd) + '</div></li>');
717
- steps.push('<li><b>First sign-in</b><p>Open <code style="font-family:var(--font-mono)">' + esc(oa.homepageUrl) + '</code> and sign in with GitHub once. That seats you as the owner — the founding Archon.</p></li>');
735
+ steps.push('<li data-onboard-step="first-sign-in"><b>First sign-in</b><p>Open <code style="font-family:var(--font-mono)">' + esc(oa.homepageUrl) + '</code> and sign in with GitHub once. That seats you as the owner — the founding Archon.</p></li>');
718
736
  steps.push('<li><b>Verify</b><p><code style="font-family:var(--font-mono)">' + esc(oa.homepageUrl) + '/healthz</code> should report <code style="font-family:var(--font-mono)">auth_configured: true</code>. Then the hall is yours.</p></li>');
719
737
  }
720
738
  $('humanSteps').innerHTML = steps.join('');
@@ -760,7 +778,7 @@ input[type=text].bad{border-color:var(--err);}
760
778
  } else if (s === 'error') {
761
779
  el.innerHTML = progressMarkup(1, 1,
762
780
  'The standup hit a snag' + (inst.error_note ? ': ' + esc(inst.error_note) : '') +
763
- '. The platform keeps retrying; details live under <a href="' + esc(buildersOrigin) + '">Instances in your hall</a>.', 'isErr');
781
+ '. The platform keeps retrying — this page updates as it recovers.', 'isErr');
764
782
  } else if (s === 'tearing_down' || s === 'torn_down') {
765
783
  el.innerHTML = progressMarkup(-1, 0, 'This instance was torn down. You can start another project below.', 'isErr');
766
784
  return true;
@@ -781,7 +799,7 @@ input[type=text].bad{border-color:var(--err);}
781
799
  fetch(API + '/provisioning/instances/' + encodeURIComponent(id), { credentials: 'same-origin' })
782
800
  .then(function (res) {
783
801
  if (res.status === 401) { throw new Error('gone:Your session expired — <a href="' + API + '/auth/web/start?return=/create">sign in again</a> to keep watching.'); }
784
- if (res.status === 404) { throw new Error('gone:Can’t see this instance any more — check <a href="' + esc(buildersOrigin) + '">Instances in your hall</a>.'); }
802
+ if (res.status === 404) { throw new Error('gone:Can’t see this instance any more — it may have been torn down.'); }
785
803
  if (!res.ok) throw new Error('soft');
786
804
  return res.json();
787
805
  })
@@ -821,15 +839,43 @@ input[type=text].bad{border-color:var(--err);}
821
839
  }
822
840
  wireAgain();
823
841
 
824
- /* ── boot: who am I? ── */
842
+ /* ── exit the wizard (task 2098) ── Esc, or the header button. Nothing is
843
+ provisioned until the final Create step, and the named orb is client-only
844
+ on the gate, so leaving simply means the project is not created. The form
845
+ draft persists in sessionStorage, so an accidental exit loses no typing. */
846
+ function exitWizard() { window.location.assign('/gate/'); }
847
+ $('exitWizard').addEventListener('click', exitWizard);
848
+ document.addEventListener('keydown', function (e) {
849
+ if (e.key === 'Escape') { e.preventDefault(); exitWizard(); }
850
+ });
851
+
852
+ /* ── switch GitHub account from inside the wizard (task 2098) ── you are not
853
+ locked to the account you entered with: sign out of the Cloud Bongos session,
854
+ then restart GitHub sign-in so the wizard reloads under whichever account you
855
+ pick. (To land on a *different* GitHub account, switch accounts on GitHub's
856
+ side; this un-locks our session so the next sign-in is honored.) */
857
+ function switchAccount(e) {
858
+ if (e) e.preventDefault();
859
+ var back = API + '/auth/web/start?return=/create';
860
+ fetch(API + '/auth/logout', { method: 'POST', credentials: 'same-origin' })
861
+ .then(function () { window.location.assign(back); })
862
+ .catch(function () { window.location.assign(back); });
863
+ }
864
+
865
+ /* ── boot: who am I? ── (task 2094: the wizard shows the signed-in identity
866
+ ONLY — never a link into cloud bongos's own builders hall. A project
867
+ creator enters a hall from their own project's landing, not from here.
868
+ task 2098: + a "switch account" action so you're not locked in.) ── */
825
869
  function renderWho() {
826
870
  var w = $('who');
827
871
  if (me) {
828
872
  w.innerHTML = (me.avatar_url ? '<img src="' + esc(me.avatar_url) + '" alt="">' : '') +
829
873
  '<span>' + esc(me.github_login || 'signed in') + '</span>' +
830
- '<a href="' + esc(buildersOrigin) + '">your hall →</a>';
874
+ '<a href="#" class="switch-acct" id="switchAcct">switch account</a>';
875
+ var sw = $('switchAcct');
876
+ if (sw) sw.addEventListener('click', switchAccount);
831
877
  } else {
832
- w.innerHTML = '<a href="' + esc(buildersOrigin) + '">the hall →</a>';
878
+ w.innerHTML = '';
833
879
  }
834
880
  }
835
881
 
@@ -50,12 +50,15 @@ body{
50
50
  /* a soft white glow behind the mascot so a white- or transparent-bg PNG blends */
51
51
  .hero-mascot{
52
52
  position:relative;width:min(540px,86vw);margin-bottom:6px;
53
+ /* cap by height on short viewports so the hall CTA + sign-in hint always clear
54
+ the fixed footer (task 2094); on tall desktops the width cap wins, unchanged */
55
+ max-height:50vh;display:flex;justify-content:center;
53
56
  }
54
57
  .hero-mascot::before{
55
58
  content:"";position:absolute;inset:-6% -10%;z-index:-1;border-radius:50%;
56
59
  background:radial-gradient(ellipse at center, rgba(255,255,255,0.95) 0%, rgba(255,255,255,0.7) 45%, rgba(255,255,255,0) 72%);
57
60
  }
58
- .hero-mascot img{display:block;width:100%;height:auto;}
61
+ .hero-mascot img{display:block;width:100%;height:auto;max-height:50vh;object-fit:contain;}
59
62
  /* fallback shown if buddha.png is not present yet */
60
63
  .mascot-fallback{
61
64
  width:min(540px,86vw);aspect-ratio:1.6/1;border-radius:28px;
@@ -95,6 +98,9 @@ body{
95
98
  font-size:14px;font-weight:600;color:var(--ink-soft);min-height:30px;
96
99
  }
97
100
  .who img{width:28px;height:28px;border-radius:50%;border:2px solid #fff;box-shadow:0 2px 8px rgba(42,31,23,0.14);}
101
+ .who a{color:var(--accent-deep);text-decoration:none;font-weight:700;}
102
+ .who a:hover{text-decoration:underline;}
103
+ .who .who-act{padding-left:10px;margin-left:2px;border-left:1px solid rgba(42,31,23,0.18);}
98
104
  .foot{
99
105
  position:fixed;bottom:18px;left:0;right:0;z-index:1;text-align:center;
100
106
  color:var(--ink-soft);font-size:13px;opacity:0.8;
@@ -114,10 +120,9 @@ body{
114
120
  <div class="wordmark" data-brand-product>cloud bongos</div>
115
121
  <p class="tagline" data-brand-tagline>Building software is laying down a beat.</p>
116
122
  <div class="cta-row">
117
- <a class="btn resting" id="createBtn" href="/api/bongos/auth/web/start?return=/create">Create a project</a>
118
- <a class="btn ghost" data-link-hall href="https://builders.cloudbongos.com">Enter the Hall →</a>
123
+ <a class="btn" id="hallBtn" data-link-hall href="https://builders.cloudbongos.com">Enter the Hall →</a>
119
124
  </div>
120
- <p class="signin-hint" id="signinHint" aria-live="polite"><a href="/api/bongos/auth/web/start?return=/create">Sign in with GitHub</a> to create a project — one click, and it's yours.</p>
125
+ <p class="signin-hint" id="signinHint" aria-live="polite"></p>
121
126
  </main>
122
127
  <div class="who" id="who" aria-live="polite"></div>
123
128
 
@@ -138,30 +143,44 @@ body{
138
143
  if (dom.buildersOrigin) document.querySelectorAll('[data-link-hall]').forEach(function(n){ n.setAttribute('href', dom.buildersOrigin); });
139
144
  }
140
145
 
141
- /* Platform sign-in state (goal 35, task 2084). Signed out: the create door
142
- rests grayed and clicking it starts GitHub sign-in, returning straight into
143
- /create. Signed in: it wakes to the full accent door to /create, and the
144
- builder chip appears top-right. The session cookie is apex-scoped, so
145
- sign-in here carries into the hall too. Degrades to the signed-out visual
146
- when the API is unreachable (static preview / standalone viewing). */
146
+ /* Membership-aware hall access (goal 35, task 2094). This is a PROJECT's own
147
+ landing page. Signed in as an admitted builder here → "Enter the Hall".
148
+ Otherwise → "Request access" (this project's own hall shows the request-
149
+ access card), with a quiet "already a builder? sign in" for returning
150
+ builders. Sign-in is itself gated to approved builders (auth.js), so a
151
+ newcomer who tries it is routed to request access anyway. The identity +
152
+ action live top-right. Degrades to the request-access visual when the API
153
+ is unreachable (static preview / standalone viewing). */
154
+ var hallHref = (b && b.domains && b.domains.buildersOrigin) || 'https://builders.cloudbongos.com';
155
+ var signInHref = '/api/bongos/auth/web/start?return=' + encodeURIComponent('/');
147
156
  function esc(s) {
148
157
  return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
149
158
  return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
150
159
  });
151
160
  }
161
+ var hallBtn = document.getElementById('hallBtn');
162
+ var signinHint = document.getElementById('signinHint');
163
+ var who = document.getElementById('who');
164
+
165
+ function showSignedOut() {
166
+ if (hallBtn) { hallBtn.textContent = 'Request access'; hallBtn.setAttribute('href', hallHref); }
167
+ if (signinHint) signinHint.innerHTML = 'Already a builder here? <a href="' + signInHref + '">Sign in with GitHub</a>.';
168
+ if (who) who.innerHTML = '<a href="' + signInHref + '">Sign in with GitHub</a>';
169
+ }
170
+ function showMember(me) {
171
+ if (hallBtn) { hallBtn.textContent = 'Enter the Hall →'; hallBtn.setAttribute('href', hallHref); }
172
+ if (signinHint) signinHint.textContent = '';
173
+ if (who) who.innerHTML =
174
+ (me.avatar_url ? '<img src="' + esc(me.avatar_url) + '" alt="">' : '') +
175
+ '<span>' + esc(me.github_login || 'signed in') + '</span>' +
176
+ '<a class="who-act" href="' + hallHref + '">Enter hall →</a>';
177
+ }
178
+
179
+ showSignedOut(); // default until /me resolves (and the no-JS request-access intent)
152
180
  fetch('/api/bongos/me', { credentials: 'same-origin' })
153
181
  .then(function (res) { if (!res.ok) throw new Error(String(res.status)); return res.json(); })
154
- .then(function (data) {
155
- var me = data.builder || data.me || data;
156
- var btn = document.getElementById('createBtn');
157
- btn.classList.remove('resting');
158
- btn.setAttribute('href', '/create');
159
- document.getElementById('signinHint').textContent = '';
160
- document.getElementById('who').innerHTML =
161
- (me.avatar_url ? '<img src="' + esc(me.avatar_url) + '" alt="">' : '') +
162
- '<span>' + esc(me.github_login || 'signed in') + '</span>';
163
- })
164
- .catch(function () { /* signed out or unreachable: keep the resting door + hint */ });
182
+ .then(function (data) { showMember(data.builder || data.me || data); })
183
+ .catch(function () { /* signed out / not a member / unreachable: request-access visual stands */ });
165
184
  })();
166
185
  </script>
167
186
  </body>
@@ -1,144 +1,15 @@
1
- # scripts/gds/ — builder CLI (agent notes)
1
+ # @bongos/core — installed platform dependency (not your project's CLAUDE.md)
2
2
 
3
- > Nested CLAUDE.md — loads on demand when you work here. Root [CLAUDE.md](../../CLAUDE.md) is the index. See [ADR 0061](../../docs/adr/<redacted>.md) for why these exist.
3
+ This file is a placeholder shipped inside the **@bongos/core** package. The core's own
4
+ internal agent notes are intentionally omitted from the published artifact so they cannot
5
+ load into your instance's context.
4
6
 
5
- **Purpose.** Cross-platform Node CLI behind the `/builder-*` slash commands (`.claude/skills/builder-*`). Every script talks to `/api/gds/*` on `example.com` (override `GDS_API_BASE` for local dev). `node` is the one guaranteed runtime — no bash/python/jq in the JS path ([#686](https://example.com/builders#/task/686)), so the skills shell out to `node scripts/gds/*.js`. Session token lives in the instance config dir — `~/.config/<configDir>/gds-session.json`, resolved via `src/instance-config.js` (R61/[#1200](https://example.com/builders#/task/1200)); OTB pins `configDir=otb` so it stays `~/.config/otb`, with read-fallback to the legacy dir + `pms-session.json`. Env vars resolve `<envPrefix>_<SUFFIX>` (OTB → `OTB_`) then legacy `OTB_`/`GDS_`/`PMS_`.
7
+ **It does not govern this repository.** Your own root `CLAUDE.md`, your `.claude/`
8
+ directory, and the live Bongos database are the source of truth for how work happens here
9
+ and who may do what.
6
10
 
7
- **Shared kit.** `cli-lib.js` — `apiCall(method, path, body)` (adds auth header, resolves token+base), `requireSession`, `arg`/`hasFlag` (argv parsing), `readSessionToken`, plus terminal format helpers + onboarding/cost nudges. `api.js` — generic `node api.js METHOD /path [--body | --body-file -]` caller; status→STDERR, JSON→STDOUT.
11
+ You are seeing this only because an agent opened a file under `node_modules/@bongos/core/`.
12
+ Nothing in here needs to be read to use the platform — run `bongos help` for commands.
8
13
 
9
- **Entry points (→ slash command).**
10
- - `start.js` → `/builder-start` — list claimable tasks (parallel-safe vs active claims); `--fit`, `--discipline`, `--version`, `--track`, `--json`.
11
- - `claim.js` → `/builder-claim N` — atomically claim a task; prints claim id + touches[] + relevant learnings/context-pack.
12
- - `ship.js` → `/builder-ship` — **the big one (~151KB)**; 3-step lifecycle completed→confirmed (credits, smoke)→shipped (merge+deploy). Flags: `--no-merge`, `--skip-grade`, `--regrade`, `--force`, `--allow-empty`. The empty-diff/phantom-ship guard runs **regardless of `--skip-grade`** (task 1365 closed the task-1363 hole where `--skip-grade` bypassed it and a never-committed deliverable confirmed + reconciler-shipped with no artifact on main); a no-artifact/DB-only ship now needs explicit `--allow-empty`, which is still **refused if the working tree is dirty/untracked** (that means you forgot to commit).
13
- - `release.js` → `/builder-release N` — cancel a claim (no credits); task returns to `ready`.
14
- - `capture.js` → idea_inbox — file an idea (`--kind`, `--body-file`, `--version`); `recall.js` → `/recall` — lexical (FTS+trigram/RRF) rank-scoped knowledge search; `learning-capture.js` — durable short-form learning into the DB.
15
- - `gen-diagrams.js` — regenerate the 5 onboarding `.mmd`/`.svg`/`.png` + `assertions.json` from live facts; `gen-repo-map.js` — regenerate the code symbol skeleton (`docs/repo-map.md` + the generated factual block in each nested CLAUDE.md; ADR 0063); `gen-session-index.js` — regenerate the session-log index (`docs/session-log-index.md` + the bounded CLAUDE.md §13 snippet) from `docs/session-logs/*.md` (ADR 0062 §8, task 1226); `gen-file-map.js` — regenerate the `.claude/skills/` + `.claude/scheduled-tasks/` sections of `docs/file-map.md` from disk, notes sourced from `docs/file-map.notes.json` (ADR 0066, task 1276; `--check` fails on drift or an undescribed skill/routine); `fitness.js` — architecture fitness gate (core↔host boundary, CLAUDE.md budget, nested-doc presence, rank-guard, generated-artifact freshness; ADR 0062 §9, enforced via `tests/fitness.mjs`); `architect-audit.js` — MAS Phase 5 bounded first-principles `--scope` audit → `docs/audits/`; `linkify-refs.js` — rewrite bare `#NNN` refs into hall links so GitHub doesn't mis-autolink.
16
- - `box.js` — operator/control-plane dev-box lifecycle (`provision`/`park`/`wake`/`deprovision`/`sweep-*`/`status`); rank-gated against live DB rank. **Runs on the control plane, never inside a box.**
17
- - `provision.js` — the **instance-provisioning** control-plane runner (ADR 0111 §2/§3, [#1944](https://example.com/builders#/task/1944)); a sibling of `box.js`. Sole holder of the DO/Cloudflare tokens; drains `provisioning_intents` (the web tier only enqueues) and composes the [`cloudbongos-standup`](../../docs/recipes/cloudbongos-standup.md) runbook — server (co-tenant port OR dedicated droplet) → `createdb` + GDS-only migrate → per-instance `/etc/<slug>/web.env` → systemd unit → per-instance Caddy snippet + reload → `/healthz` — **idempotent, dry-run-default** (nothing mutates without `--apply`), drift-reconciling. Driven by `infra/provision-intent-runner.timer`. Commands: `run-intents`/`provision <slug>`/`teardown <slug>`/`reconcile`/`status`/`dns-check <domain>` (the task-[#1980](https://example.com/builders#/task/1980) DNS token-scope PREFLIGHT — read-only, verifies the CF token reaches the domain's zone before the address step; provisioning also fail-fasts on it up front). Reuses `do-api.js` + `modules/provisioning/provisioning.js`. **Runs on the control plane, never inside the web tier.** The runner is `User=lars` (non-root), so the privileged steps (write `/etc`, `systemctl`, `createdb`/`migrate`) escalate via `sudo` (temp-file + `sudo install`, `sudo systemctl`, `sudo -u postgres`) **only under `PROVISION_SUDO=1`** — the runner unit sets it ([ADR 0128](../../docs/adr/<redacted>.md)); default OFF keeps CLI/test runs bare. The unit must NOT set `NoNewPrivileges=true` (it blocks `sudo`). With `PROVISION_REMOTE_HOST` set it also runs the box-mutating steps on a remote co-hosting box over `ssh` (control plane orchestrates co-tenants that live elsewhere → zero cloud tokens on that box), while the Cloudflare DNS hook stays local via `controlExec` ([ADR 0130](../../docs/adr/<redacted>.md), task 2065); default OFF = all-local, unchanged. The `cohost-*` control-plane runner units + the SSH DB tunnel that read the co-hosting box's queues over `127.0.0.1:5433` to activate this end-to-end are [ADR 0132](../../docs/adr/<redacted>.md) / task 2071.
18
- - `oauth-secret.js` — **verified, shell-independent OAuth-secret placement** for a provisioned instance (ADR 0111, [#1979](https://example.com/builders#/task/1979)); the onboarding step every form (skill/CLI/hall) drives. `place <slug> --client-id --client-secret [--apply]`: VALIDATES the creds (length/charset — catches the silent 26-char truncation `authConfigured()` misses, since it only checks presence), rewrites `/etc/<slug>/web.env` via Node (never a fragile `read -s`/`sed -i`), restarts the unit, then PROBES `/healthz` for `auth_configured:true`. Dry-run-default; control-plane only.
19
- - `do-api.js` · `cf-tunnel.js` · `http-api-client.js` — the **shared control-plane network clients** (DigitalOcean v2 · Cloudflare named-tunnel · their JSON-HTTP skeleton). Operator-CLI-only (never the web tier), injectable-transport + **dry-run-by-default**. Moved here from `modules/dev-box/` in BV1 task [#1943](https://example.com/builders#/task/1943) ([ADR 0111](../../docs/adr/<redacted>.md) §2) so both `box.js` AND the instance-provisioning runner `provision.js` (task #1944) reuse the DO client without a module→module import. (The Cloudflare **DNS-record** hook stays at `infra/box-dns-cloudflare.sh`, invoked by path via `BOX_DNS_HOOK`.)
20
- - `seed-v3-tasks.js` / `seed-gds-v4-tasks.js` — idempotent planning-session task seeders (skip on existing `source_ref`); `newcomer-floor.*` — deterministic copy-stamp replenisher for newcomer chores (`.js` + `.config.json` + `.templates.json` + `.test.js`).
21
-
22
- **Gotchas / invariants.**
23
- - `ship.js` is huge — search by phase keyword, don't read end-to-end. Every change here still needs a claimed GDS task (no admin loophole).
24
- - Cross-platform = no bash-isms in the `.js` path; keep `process.execPath`/`os.homedir()` patterns.
25
- - Never hand-edit generated `.mmd`/`assertions.json` — run `gen-diagrams.js`. Never hand-edit `linkify-refs.js`'s output by adding bare `#NNN`.
26
- - **The guardrails are two-root aware ([ADR 0108](../../docs/adr/<redacted>.md) §Consequences #4).** `fitness.js`, `gen-repo-map.js`, `gen-file-map.js` resolve `resolveCoreRoot()` (core code + the src/bongos·scripts/gds nested docs) vs `resolveInstanceRoot()` (the root CLAUDE.md, `.claude/`, instance modules + migrations); modules are scanned across both. Today both roots are the one checkout (byte-identical); post-split each inspects the right tree. **Do not reintroduce a hardcoded `path.resolve(__dirname,'..','..')`** in these files — it re-fuses the boundary and would point into `node_modules` post-split. `tests/fitness_two_root.mjs` diverges the roots to prove it.
27
- - **Migration filenames are namespaced by source ([ADR 0108](../../docs/adr/<redacted>.md) §5, `migration-namespace.js`).** A NEW core migration is `migrations/core_NNN_slug.sql`; a NEW module migration is `modules/<key>/migrations/<key>_NNN_slug.sql`; instance seeds stay bare `migrations/instance/NNN_slug.sql`. This is what lets the core repo and the instance repo version independently without their migrations colliding on the stem-keyed `schema_migrations`. Existing bare files are grandfathered (never rename one — it re-runs on prod). `fitness.js` Check 11b + `tests/migration_namespace.mjs` enforce it; `claim.js`/`next-number.js` suggest the namespaced form. `migrate.sh` merges three roots (core-package / instance / module) resolved via `resolveCoreRoot()`/`resolveInstanceRoot()`.
28
- - Many other files here are not slash-command entry points: smoke tests (`smoke-*.sh`/`smoke-gds.js`), audits (`audit-*`, `main-audit.js`, `gate-review.js`), session tooling (`session*.js`, `pulse.js`), and systemd units (`gds-db-*.{service,timer}`).
29
-
30
- <!-- BEGIN GENERATED REPO-MAP (scripts/gds/gen-repo-map.js — do not hand-edit) -->
31
- **Symbol skeleton (generated from the code — do not hand-edit; refresh: `node scripts/gds/gen-repo-map.js`).** Exported signatures, most-referenced first. The interpretive notes above are hand-written; this factual list is regenerated on deploy so it can't drift ([ADR 0063](../../docs/adr/<redacted>.md)).
32
-
33
- - `adopt-detect.js` — `detectStack({ dir, fs = nodeFs, path = nodePath } = {})`, `formatStackSummary(s)`, `detectPackageManager(exists, hasPkg)`
34
- - `adopt-import.js` — `DEFAULT_MAX`, `parseBacklogFile(text)`, `resolveBacklogTasks({ dir, repo = {}, githubToken, backlogFile, fetchImpl, fs = nodeFs, path = nodePath, max =…)`, `BACKLOG_FILENAMES`, `fetchGitHubIssues({ owner, repo, token, fetchImpl = globalThis.fetch, max = DEFAULT_MAX, onWarn = ()`, `findBacklogFile(dir, fs = nodeFs, path = nodePath)`, `parseGitHubIssues(issues)`
35
- - `adopt-preflight.js` — `SEV`, `formatPreflight(report)`, `INCOMING_PATHS`, `preflightAdopt({ dir, stack = {}, fs = nodeFs, path = nodePath } = {})`, `checkCiCollisions(workflows = [])`, `checkFitnessBoundary({ topLevelDirs = [], hasSrcBongos = false } = {})`, `checkMigrationNamespace(basenames = [])`, `checkProtectedPaths(incoming = INCOMING_PATHS)`, `CORE_EXPECTED_CHECKS`
36
- - `architect-audit.js` — `slug(scope)`, `buildPrompt({ scope, fileList, fileBlocks, version })`, `PROMPT_HEADER`, `pickValidKind(kind)`, `validateSeedIdeas(raw)`
37
- - `art-stage.js` — `waitHealthy(healthUrl, deps = {})`, `affectedTiles(explicit, deps = {})`, `copyAtlasToServed(deps = {})`, `rebuildAtlas(deps = {})` _(+1 more)_
38
- - `audit-deps.js` — `classify(tTouches, oTouches)`, `OPEN`, `findMissingDeps(tasks, { open = OPEN, isBlocker = isUnshippedBlocker } = {})`, `HOTSPOTS`, `isUnshippedBlocker(s)`
39
- - `audit-exports.js` — `TARGETS`, `buildCorpus()`, `classifyExports(targetAbsPath, exportNames, corpus)` _(+1 more)_
40
- - `audit-ships.js` — `findCommitForTask(taskId)`, `gitDiffStatsForCommit(sha)`, `filesTouchedByCommit(sha)`, `downstreamImpact(sha, files)`, `fetchShipped(days)`, `fetchFullTask(id)`, `fetchLearning(taskId)`
41
- - `autonomy-gate.js` — `decide({ enabled, routine = '', claimableCount = 0, openIdeasCount = 0, mtdSpendUsd = 0, ceiling …)`, `precheck(routine, deps = {})`, `isEnabled(env = process.env)`, `gatherSignals(routine, deps = {})`, `AUTONOMY_FLAG`, `DEFAULT_CEILING_USD`, `ceilingUsd(env = process.env)`, `autofixAllowed({ enabled = false, graderBypassOn = true, isProtected = true, confidence = 'low', fileCoun…)`
42
- - `backfill-cost.js` — `findLedger(argPath)`, `parseLedger(filePath)`, `postCost(row, sourceRef)`
43
- - `backfill-sessions.js` — `entryText(entry)`, `extractTaskIds(entries)`, `inScope(dirName)`, `PROJECT_TOKENS`, `TASK_MARKERS`
44
- - `backfill-task-rewards.js` — `BACKFILL_REASON`, `backfillKey(taskId)`, `computeTaskReward(taskId, rawCredits, kind)`, `netForBuilder(wouldBeTotal, costPlusAlreadyPaid)`, `planForBuilder(builderId, taskRewards, costPlusAlreadyPaid, alreadyBackfilled = new Set()`, `TOKEN_REWARD_REASON`
45
- - `backup.js` — `fmtBytes(n)`, `fetchStatus()`, `printStatus(data)`, `trigger()`
46
- - `box-auth-check.js` — `onBox()`, `decideBoxAuth({ onBox, hasToken, isBoxScoped, meStatus })`, `printReauth({ boxScoped })`, `printSetup()`
47
- - `box-connect-lib.js` — `RANK_ORDER`, `WORKSPACE`, `binPresent(bin, versionArgs = ['--version'])`, `buildKnownHostsUpsert(existing, hostname, hostKeysRaw)`, `buildRemoteShellCommand({ firstRun = false, workdir = WORKSPACE } = {})`, `buildSshAliasBlock({ hostname, identityFile })`, `CLAUDE_VSCODE_EXTENSION`, `fetchRank()`, `isFirstLogin(hostname)`, `parseEnsure(data)` _(+8 more)_
48
- - `box.js` — `deprovisionOne(pool, boxes, doApi, box, { actor, login, sleepFn } = {})`, `cmdProvision(pool, boxes, boxOnboard, ref, { apply })`, `markErrorUnlessDestroyed(pool, boxes, builderId, errNote)`, `runDnsHook(hostname, ip, hook = CONFIG.dnsHook)`, `deleteWithRetry(fn, { tries = 3, sleepMs = 2000, sleepFn } = {})`, `runDnsHookBlackhole(hostname, hook = CONFIG.dnsHook)`, `cmdReconcileDrift(pool, boxes, { apply })`
49
- - `build-bongos.js` — `VERSION`, `TARGETS`
50
- - `capture.js` — `resolveDefaultVersion()`
51
- - `cf-tunnel.js` — `class CfTunnelApi`, `terminalHostname(login, zone)`, `CfApiError`, `previewHostname(login, zone)`, `CF_API_BASE`, `CACHE_BYPASS_RULE_DESC`, `tunnelName(login)`, `CACHE_BYPASS_EXPRESSION`, `CFARGO_SUFFIX`, `GAME_SERVICE` _(+1 more)_
52
- - `ci-grade.js` — `git(args)`
53
- - `claim-recall.js` — `printClaimRecall(task, { excludeKeys = [] } = {})`, `RECALL_LIMIT`, `claimRecallQuery(task)`, `formatRecallSources(results, { limit = RECALL_LIMIT, excludeKeys = [], currentTaskId = null } = {})`, `rowKeys(row)`
54
- - `claim.js` — `printRelevantLearnings(task)`, `printDisciplineMode(task)`, `captureHeadSha()`, `warnIfToolingStale()`, `printClaimCard(task, widgetsEnabled = true)`
55
- - `classify-discipline.js` — `pad(s, n)`, `emoji(d)`
56
- - `claude-materialize.js` — `bongosify(text, verbs = VERBS)`, `materializeClaude({ coreRoot, instanceDir, dryRun = false, overwrite = true, log = ()`, `copyTreeTransformed(srcDir, destDir, { dryRun, onFile, overwrite = true } = {})`, `GDS_INVOCATION_RE`, `scriptToVerb(verbs = VERBS)`, `transformSettings(srcPath)`
57
- - `cli-lib.js` — `cliClient(opts = {})`, `arg(name, args = process.argv.slice(2)`, `requireSession()`, `API_BASE`, `hasFlag(name, args = process.argv.slice(2)`, `SESSION_PATH`, `apiCall(method, urlPath, body = null, opts = {})`, `loadSession()`, `fmtUsd(n)`, `fmtMinutes(m)` _(+13 more)_
58
- - `code.js` — `repoRoot()`, `runCode(args, { inherit = true } = {})`, `runLocal({ log })`
59
- - `codemod-rename-src-gds.js` — `segReplace(s)`, `isSrcTopLevel(rel)`, `gitMv()`, `isBinary(buf)`
60
- - `conductor-dispatch.js` — `autoDispatch(deps = {})`, `bestMatchingClaim(claims, changedFiles)`, `pickSpecialists(changedFiles)`, `selectAutonomousDispatch(gate, claimable)`
61
- - `context-pack.js` — `contextPack({ activeClaims = [], currentTaskId = null } = {})`, `formatContextPack(pack)`, `buildContextPack({)`, `formatContextPackCompact(pack)`, `apiContract()`, `formatClaims(claims)`, `formatOs(os)`, `normalizeClaims(activeClaims, currentTaskId)`, `osFacts({ platform, runWhich })`, `resolveWorktreeRoot({ runGit, cwd })`
62
- - `design-sync.js` — `arg(flag, args)`, `collectFiles(dir, root)`
63
- - `diagnose-achievements.js` — `backfill()`
64
- - `diagram-facts.js` — `repoSlug(repo)`, `gatherFacts({ repo })`, `defaultRank(migs)`, `readMigrations(repo)`, `CONCEPTUAL_TASK_IDS`, `conceptualFacts({ repo, migs })`, `DEV_BOX_TASK_IDS`, `liveVersions()`, `rankEnum(migs)`, `readGdsSource(repo)` _(+5 more)_
65
- - `do-api.js` — `class DoApi`, `DoApiError`, `DO_API_BASE`
66
- - `docs-entropy.js` — `parseFile(absPath)`, `collectMarkdownFiles()`, `scanStaleLinks(relFiles)`, `scanDuplicateProse(relFiles)`, `toSlug(heading)`
67
- - `doctor.js` — `section(title)`, `gitOut(cmd, opts = {})`, `checkSession()`, `checkToolchain()`, `checkGitPlumbing()`, `checkRepoState()`, `checkEnvironment()`, `checkDeployTooling()`
68
- - `feedback-latest.js` — `parseArgs(argv)`
69
- - `fetch-sound-prefs.js` — `writeAtomic(targetPath, contents)`
70
- - `figma-design-sync.js` — `arg(flag, args)`, `collectFiles(dir, root)`
71
- - `fitness.js` — `KERNEL_FILES`, `discoveredModuleKeys(modulesDir)`, `scanScopeMapSource(src)`, `checkCoreHostBoundary()`, `checkScopeMapImportsProtected()`, `moduleImportViolation(fromAbsFile, spec)`, `moduleNamespace(key)`, `moduleOwnerOf(absFile)`, `checkClaudeMdBudget(opts = {})`, `checkCoreCarriesNoModuleCode()` _(+20 more)_
72
- - `gate-review.js` — `classifyChanges({ files, blobAt, diffBytes = 0 } = {})`, `matchesHardFloor(f)`, `HARD_FLOOR_GLOBS`, `isCanonicalPath(p)`, `resolveAction({ verdict, trusted, ownerApproved })`, `certifyAllowlistNarrowing(base, head)`, `certifyRunUnitTestsNarrowing(base, head)`
73
- - `gating.js` — `repoSlug()`, `getProtection(repo)`, `toPutBody(p)`, `putProtection(repo, putBody)`, `deleteProtection(repo)`, `workflowState(repo, wf)`, `setWorkflow(repo, wf, enable)`, `readSnapshot()`, `writeSnapshot(obj)`, `summarize(putBody)` _(+3 more)_
74
- - `gen-api-client.js` — `build()`, `buildModel(spec)`, `camel(s)`, `groupByTag(ops)`, `renderClientJs(spec, ops)`, `renderTypes(spec, ops)`, `pascal(s)`
75
- - `gen-api-docs.js` — `build()`, `pathParams(route)`, `resolveScalar(expr, constants = {})`, `captureBalanced(str, from)`, `splitTopLevel(inner)`, `extractModel()`, `extractResponse(lines, i)`, `pascalCase(s)`, `requestSchemaFor(r)`, `resolveArray(expr, constants = {})` _(+18 more)_
76
- - `gen-atlas.js` — `buildContextView()`, `buildModuleView()`
77
- - `gen-diagrams.js` — `brand()`, `cap(s)`, `lifecycleMmd(f)`, `rankLadderMmd(f)`, `versioningMmd(f)`, `drachmaeKarmaMmd(f)`, `architectureMmd(f)`, `rebuildAssertions(prev, f)`
78
- - `gen-file-map.js` — `end(id)`, `buildModel()`, `begin(id)`, `SECTIONS`, `renderSection(model)`, `computeWrites()`, `injectSection(existing, model)`, `buildSection(section, notes)`
79
- - `gen-repo-map.js` — `BEGIN`, `END`, `buildModel()`, `NESTED_DIRS`, `injectBlock(existing, block)`, `renderNestedBlock(model, dir)`, `renderRepoMap(model)`
80
- - `gen-session-index.js` — `BEGIN`, `END`, `computeWrites()`, `collectEntries(dir = LOGS_DIR)`, `injectSnippet(existing, snippet)`, `renderIndex(entries)`, `SESSION_FILE_RE`, `cleanTitle(rawHeading)`, `parseEntry(filename, content)`, `renderSnippet(entries, count = SNIPPET_COUNT)` _(+1 more)_
81
- - `git-merge-regen.js` — `REGENERABLE`, `regenerateResolved(relpath, { base = '', ours = '', theirs = '' } = {})`, `resolveInWorktree(relpath)`, `hasMarkers(s)`, `threeWayMerge(base, ours, theirs)`, `MARKER_RE`
82
- - `grade-smoke.js` — `summarize(result, label)`
83
- - `http-api-client.js` — `class JsonHttpApi`, `makeApiError(name, code)`
84
- - `init.js` — `CORE_PKG`, `slugify(s, fallback = 'goal')`, `interview({ adopt = false } = {})`, `HOSTING_SHAPES`, `KNOWN_MODULES`, `coreVersionSafe()`, `coreDepRange()`, `provisioningRequest(spec)`, `seedViaApi(spec, { dryRun, log = console.log, api = apiCall } = {})`, `writeConfigs(spec, { dir, force, dryRun, coreDep, log = console.log })` _(+15 more)_
85
- - `install-git-hooks.js` — `activate()`, `registerMergeDriver(root)`, `MERGE_DRIVER_NAME`, `configuredHooksDir()`
86
- - `key-card.js` — `wrap(text, width)`, `esc(s)`, `safeBrand()`, `emitKeyCard(model, { log = console.log, widgetsEnabled = true } = {})`, `buildKeyCardModel(input = {})`, `renderKeyCardHtml(model)`, `renderMonospaceKeyCard(model)`
87
- - `key-status.js` — `KEYS`, `KEY_LIKE_RE`, `refuseIfKeyPasted(argv)`
88
- - `land-watch.js` — `watch({ nowMs = Date.now()`, `PENDING_DIR`, `readBreadcrumbs()`, `classifyLand(task, ageMs, { staleMs = DEFAULT_STALE_MS } = {})`, `DEFAULT_STALE_MS`, `writeBreadcrumb(taskId, data = {})`, `buildShippedEnvelope(crumb, task)`, `removeBreadcrumb(fileOrId)`
89
- - `learning-capture.js` — `csv(v)`, `readStdin()`, `autoDetectFiles()`
90
- - `linkify-refs.js` — `RESOLVER_BASE`, `linkifyText(text, ids, stats)`, `discoverDocs()`, `classifyKind(left, carried, prevKind)`, `linkifySegment(segment, ids, leftContext, stats)`, `RESOLVER_BASE_BLOCKER`, `RESOLVER_BASE_IDEA`, `upgradeLineCodeSpans(line, ids, stats)`, `normalizeIdSets(ids)`, `unlinkEntitySegment(segment, leftContext, stats)`
91
- - `local-preview-lib.js` — `start(deps = {})`, `REPO_ROOT`, `stop(deps = {})`, `restart(deps = {})`, `health(deps = {})`, `healthUrl(deps = {})`, `HOST`, `onBox(deps = {})`, `BOX_ENV_PATH`, `localUrl(deps = {})` _(+11 more)_
92
- - `local-preview.js` — `pollHealthy(ms = 20_000)`, `warnIfOnBox()`
93
- - `login.js` — `runDeviceFlow(base, { log })`, `normalizeInstanceBase(raw)`, `pollDecision(body)`
94
- - `main-audit.js` — `analyzeCommits(commits, rankByIdentity, { strict = false } = {})`, `parseCommits(range)`, `resolveRank(c, rankByIdentity)`
95
- - `memory-map.js` — `entries(text)`, `estTokens(bytes)`, `measure(text)`, `applyCompaction(mapPath, expectedText, newText, deps = {})`, `keepAlways(meta)`, `metaOf(file, memoryDir, deps = {})`, `parseLines(text)`, `planCompaction(text, opts = {})`, `WARN_BYTES`, `isRule(type)` _(+4 more)_
96
- - `merge-lock.js` — `mainWorktreeRoot()`
97
- - `migration-namespace.js` — `CORE_NS`, `INSTANCE_NS`, `filenameViolation(source, basename, { moduleKey } = {})`, `migrationNumberOf(basename)`, `stemCollisions(files)`, `nextInNamespace(basenames)`, `parseMigrationName(basename)`, `LEGACY_BARE_CORE_MAX`, `LEGACY_BARE_MODULES`, `sqlNamespace(moduleKey)` _(+2 more)_
98
- - `mirror-lineage-check.js` — `MIGRATION_BASENAME_RE`, `migrationNumbersFromPaths(paths)`, `parseEnumChecks(sql)`, `proveLineage({ publishableFiles, privateMigrationNumbers, ctx })`, `buildRedactionContext()`, `enumDrift(files)`, `numberingDivergence(privateSet, mirrorSet)`, `runSimulation()`
99
- - `mirror-redact.js` — `findLeaks(text, sensitiveLiterals)`, `buildRedactionRules(branding = {}, extra = {})`, `collectSensitiveLiterals(branding = {}, extra = {})`, `findSecretLeak(text, extraSecrets = [])`, `REDACTED_IP`, `escapeRegExp(s)`, `redactText(text, rules)`, `NEUTRAL_TOKEN`, `deriveInstanceLiterals(branding = {}, extra = {})`, `firstPublicIP(text)` _(+7 more)_
100
- - `module.js` — `coreVersion()`, `MODULES_DIR`, `camel(key)`, `printHelp(out = console.log)`, `cmdUpgrade(_args, { log = console.log, errlog = console.error, gather = gatherUpgrade } = {})`, `evaluateUpgrade({ rows = [], errors = [], core } = {})`, `gatherUpgrade({ modulesDir = MODULES_DIR, core = coreVersion()`, `buildManifest(key, { core = coreVersion()`, `checkModulePublishability(key, { modulesDir = MODULES_DIR } = {})`, `claudeMdTemplate(key, manifest)` _(+8 more)_
101
- - `newcomer-floor.js` — `VALID_DISCIPLINES`, `computeTemplateDeficits(supply, templatesByDisc, floorDefaults, { only = null } = {})`, `templateFloor(template, discipline, floorDefaults)`, `buildProposalFromTemplate(template, seq, { discipline } = {})`, `HARD_MAX_MINUTES`, `parseSeq(ref, discipline, templateId)`, `SOURCE_TAG`, `loadTemplates(templatesPath)`, `nextSeq(existingRefs, discipline, templateId)`, `parseRef(ref)` _(+3 more)_
102
- - `newcomer-floor.test.js` — `test(name, fn)`, `deficitFor(rows, templateId)`
103
- - `next-number.js` — `padMig(n)`, `nextFree(numberSet, start = 1)`, `padAdr(n)`, `nextNumbers({ runGit = defaultRunGit, readDir = defaultReadDir } = {})`, `computeNextNumbers({ committedPaths = [], localPaths = [], startAdr = 1, startMigration = 1 } = {})`, `gitTreePaths(ref, dirs, runGit)`, `parseNumbers(basenames, re)`
104
- - `oauth-secret.js` — `webEnvPath(slug, { etcBase = ETC_BASE } = {})`, `provisionedEnvPrefix()`, `validateClientId(id)`, `validateClientSecret(secret)`, `CLIENT_ID_MIN_LEN`, `parseHealthzAuth(stdout)`, `SECRET_MIN_LEN`, `fillOAuthEnv(body, { prefix, clientId, clientSecret })`, `portFromEnv(body)`
105
- - `onboard.js` — `oauthAppInstructions(domain)`, `buildInitSpec(a = {})`, `healthzUrl(domain)`, `onboardPlan(mode = 'greenfield')`
106
- - `onboarding-analyze.js` — `acquireLock()`, `releaseLock()`, `analyzeOne(name, entry)`
107
- - `onboarding-config.js` — `encodeProjectPath(absPath)`, `ensureDir(dir)`, `SPOOL_DIR`, `windowDays()`, `CONFIG_DIR`, `CONSENT_PATH`, `listTranscripts(dir)`, `readConsent()`, `MANIFEST_PATH`, `needsSpool(manifest, file)` _(+7 more)_
108
- - `package-core.js` — `coreVersion()`, `octal(n, width)`, `TAR_ROOT`, `normalizeMode(mode)`, `ARTIFACT_NAME`, `MANIFEST_SCHEMA`, `processCoreFile({ pathRel, raw, rules, sensitiveLiterals, envSecrets })`, `sha256hex(buf)`, `buildPackageJson({ version, sourceDeps, sourceOverrides })`, `ustarHeader({ name, prefix = '', mode, size, typeflag })` _(+14 more)_
109
- - `provision.js` — `CONFIG`, `standaloneRoot(inst, { base = CONFIG.standaloneBase } = {})`, `MAX_INTENT_ATTEMPTS`, `checkDnsTokenScope(domain, { token = <redacted>, zoneOverride = process.env.CLOUDFLARE_…)`, `webEnvPath(inst, { etcBase = CONFIG.etcBase } = {})`, `cmdRunIntents(deps)`, `cmdStatus(deps)`, `coreVersionSafe()`, `dnsUpsertEnv(inst, { publicIp, zone, proxied = false } = {})`, `provisionInstance(inst, deps)` _(+26 more)_
110
- - `publish-manifest.js` — `isPublishable(relPath)`, `normalize(p)`, `matchesDeny(relPath)`, `PUBLISH_ALLOWLIST`, `PUBLISH_DENYLIST`, `PROTECTED_TOPOLOGY_EXCLUDE`, `INSTANCE_EXCLUDE`, `matchesAllow(relPath)`, `CONTENT_EXCLUDE`, `SENSITIVE_DOC_EXCLUDE` _(+1 more)_
111
- - `pulse.js` — `loadDeps()`, `parseThresholdHours(args)`, `postDiscordPing(text)`, `releaseStale({ thresholdHours, dryRun })`
112
- - `push-main.js` — `pushMain(extra = [])`
113
- - `read-session-export.js` — `render(data, opts)`, `reduce(records)`, `loadExport(zipPath)`, `openZip(filePath)`, `readEntry(fd, entry)`
114
- - `reauth.js` — `openInBrowser(url)`, `printGuidance({ opened })`
115
- - `recall.js` — `parseArgs(argv)`, `truncate(s, n)`
116
- - `render-ideas.js` — `fmtTimestamp(iso)`, `daysAgo(iso)`, `renderIdea(idea)`, `renderSection(heading, ideas, emptyMsg)`, `fetchAllIdeas()`, `partition(ideas)`, `render(ideas)`
117
- - `repo-metrics.js` — `gatherFileSizes()`, `summarizeSizes(sizes)`, `scanDeadCode()`, `scanBranchHygiene()`, `countConfirmedUnshipped(pool)`, `upsertSnapshot(pool, snap)`
118
- - `run-routine.js` — `VALID_MODES`, `parseRoutineFrontmatter(skillMd)`, `VALID_SINKS`, `tokenize(cmd)`
119
- - `run-unit-tests.js` — `discoverModuleTests({ modulesDir = MODULES_DIR, isEnabled = isModuleEnabled } = {})`
120
- - `sandbox-stage.js` — `stage({ taskId } = {}, deps = {})`, `BOX_ENV_PATH`, `BOX_SERVED_ROOT`, `resolvePreviewContext(deps = {})`, `computeTreeStamp(deps = {})`, `PREVIEWABLE_PATHSPECS`, `markerPath(deps = {})`, `previewUrl(deps = {})`, `runShipGate({ taskId, files, skipStage, tty, approved }, deps = {})`, `verifyServedFresh(deps = {})` _(+11 more)_
121
- - `search-ingest-db.js` — `buildRows({ sourceRef, title, body, minRank = 'xenos', ownerBuilderId = null, scrub = false })`, `requirePool()`, `SOURCES`, `recentCommitRows(limit = 80)`
122
- - `search-ingest-md.js` — `SENSITIVE_DOC_GLOBS`, `requirePool()`, `collectMarkdown(dir, root, out = [])`, `minRankForDoc(rel)`, `chunkFile(abs)`, `ingestFile(client, rows, sourceRef)`
123
- - `<redacted>.js` — `post(path, body)`
124
- - `<redacted>.js` — `post(path, body)`
125
- - `seed-module-upstreaming.js` — `findOrCreateGoal()`
126
- - `seed-provisioning-tasks.js` — `post(path, body)`
127
- - `seed-v2-world-tasks.js` — `withRetry(fn)`
128
- - `session-cost.js` — `addTiers(acc, t)`, `emptyTiers()`, `newestTranscriptFor(cwd)`, `priceTranscript(transcriptPath)`, `roundTiers(t)`, `listJsonlRecursive(dir)`, `looksLikeGraderTranscript(file)`, `priceSubagents(sessionDir)`, `addComponents(acc, components)`
129
- - `session-digest.js` — `parseHookInput(stdinRaw, opts = {})`
130
- - `session-eval.js` — `computeOverhead(detail)`, `evaluateSession(record)`, `detectFootguns(detail, overhead = {}, opts = {})`, `FINDING_TEMPLATES`, `findingsByBuilder(evaluated)`, `verdictFor(overheadRatio)`, `classifyTurn(turn, opts = {})`, `interpretCorpusSearch(count, opts = {})`, `summarizeSystemicFindings(evaluated, opts = {})`
131
- - `session.js` — `readArgv(argv)`, `builderLocalHour(timezone)`, `isOvernightHour(hour)`, `recentShipsAllOvernightSafe(me)`, `suggestDefaults(me)`, `ask(rl, q, fallback)`, `interactive(defaults)`, `callOptimizer({ timeBudgetMin, mode, parallel })`, `fitsMode(task, mode)`, `disjointTouches(a, b)` _(+5 more)_
132
- - `setup.js` — `dryRunStep(msg)`, `promptGeminiKey()`, `readLocalAnthropicAccount()`, `promptAnthropicLink()`, `promptDisciplines()`, `promptOnboardingConsent()`
133
- - `shell.js` — `repoRoot()`, `runLocal({ remoteCmd, log })`
134
- - `ship.js` — `buildSessionDigest(entries, opts = {})`, `computeChangedFiles(baseline)`, `sanitizeGitHubRefs(text)`, `computeGraderBaseline(claim)`, `recordUploadSkip(taskId, { code, reason }, opts = {})`, `runSubagentGrader({ task, valueSummary, baseline, changedFiles: precomputedChanged })`, `buildMergeArgv(branch, valueSummary)`, `gradeAndRecord({ taskId, task, summary, baseline, committedFiles })`, `snippetOf(text, extraSecrets, max = 160)`, `buildGradePayload(gradeResult, committedFiles = null)` _(+9 more)_
135
- - `smoke-gds.js` — `isLocalTarget(hostname)`, `probeListener(host, port, timeoutMs = 1500)`
136
- - `start.js` — `progressBar(percent, width = 10)`, `formatVersionsRow(progress)`, `formatCostRow(cost)`, `formatRecentRow({ recentShipped, inboxCount, blockerCount })`, `statusParts({ progress, recentShipped, inboxCount, blockerCount })`, `quietStatusLine(header)`, `estimateShort(t)`, `clip(s, n)`, `cell(s)`, `disciplineLabel(t)` _(+10 more)_
137
- - `status.js` — `parseArgs(argv)`, `renderStatusWidget(data, criterion)`, `renderStatusMarkdown(data, criterion)`
138
- - `triage.js` — `formatDevelopment(block)`, `loadDevelopment(path)`, `parseDevelopment(text)`, `resolveDevelopmentPath(argv = process.argv, env = process.env)`
139
- - `upgrade.js` — `parseArgs(argv)`, `CORE_PKG`, `ARTIFACT`, `npmInstall(instanceDir, run = spawnSync)`, `readInstalledCoreVersion(instanceDir, fsImpl = fs)`, `regenerateApiArtifacts({ instanceDir, coreRoot }, run = spawnSync, fsImpl = fs)`, `vendorTarball({ instanceDir, fromTgz, targetVersion }, fsImpl = fs)`, `versionFromTgzPath(p)`, `gitTreeClean(instanceDir, run = spawnSync)`, `pollHealth(healthUrl, deps = {})` _(+8 more)_
140
- - `validate-design.js` — `readJson(filePath, label)`, `deepMerge(base, override)`, `isUri(s)`, `dirExists(p)`, `fileExists(p)`, `listDirs(p)`
141
- - `version-close.js` — `parseArgs(argv)`, `buildCommitMessage({ versionId, nextVersionId, shippedCount, carryCount })`, `buildManualSql({ versionId, versionName, nextVersionId, nextScopeDocPath, carryOverTasks, nextVersionExis…)`, `buildNextVersionStub({ nextVersionId, prevVersionId, carryOverTasks })`, `buildShippedArchive({ versionId, versionName, scopeDocPath, shippedTasks, originalScopeBody, shippedAt })`, `deriveNextScopePath(currentPath, nextVersionId)`, `deriveNextVersionId(currentId)`, `deriveShippedPath(currentPath, versionId)`
142
- <!-- END GENERATED REPO-MAP -->
143
-
144
- **See also.** `.claude/skills/builder-*` skill docs · [ADR 0061](../../docs/adr/<redacted>.md) · [docs/recipes/ops-gotchas.md](../../docs/recipes/ops-gotchas.md) · [src/bongos/](../../src/bongos/) (the server side these call).
14
+ _To work ON the platform core itself, use the standalone @bongos/core source repository,
15
+ not this vendored copy._