@bongos/core 1.24.41 → 1.24.43

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 +117 -92
  2. package/docs/copy-inventory.md +98 -137
  3. package/docs/copy-registry.json +244 -644
  4. package/docs/module-api-changelog.md +4 -0
  5. package/docs/onboarding/primer.md +1 -1
  6. package/docs/page-inventory.json +3 -3
  7. package/docs/page-readings.json +494 -535
  8. package/modules/hall-ui/public/ai-studio.html +4 -4
  9. package/modules/hall-ui/public/atlas.html +4 -4
  10. package/modules/hall-ui/public/blockers.html +4 -4
  11. package/modules/hall-ui/public/board-room.html +4 -4
  12. package/modules/hall-ui/public/builders.js +35 -763
  13. package/modules/hall-ui/public/city.html +4 -4
  14. package/modules/hall-ui/public/collab.html +4 -4
  15. package/modules/hall-ui/public/commands.html +4 -4
  16. package/modules/hall-ui/public/copy-desk.html +4 -4
  17. package/modules/hall-ui/public/craft-mode.js +1 -1
  18. package/modules/hall-ui/public/deploy.html +4 -4
  19. package/modules/hall-ui/public/dom-utils.js +2 -1
  20. package/modules/hall-ui/public/goal-map.html +4 -4
  21. package/modules/hall-ui/public/goals.html +4 -4
  22. package/modules/hall-ui/public/government.html +4 -4
  23. package/modules/hall-ui/public/hall-render.js +25 -771
  24. package/modules/hall-ui/public/hall-widgets.js +14 -123
  25. package/modules/hall-ui/public/idea.html +4 -4
  26. package/modules/hall-ui/public/ideas.html +4 -4
  27. package/modules/hall-ui/public/index.html +8 -22
  28. package/modules/hall-ui/public/index.states.json +0 -33
  29. package/modules/hall-ui/public/market-watch-item.html +4 -4
  30. package/modules/hall-ui/public/market-watch-rules.html +4 -4
  31. package/modules/hall-ui/public/market-watch.html +4 -4
  32. package/modules/hall-ui/public/modules.html +4 -4
  33. package/modules/hall-ui/public/money.html +4 -4
  34. package/modules/hall-ui/public/my-agents.html +4 -4
  35. package/modules/hall-ui/public/palette.js +7 -6
  36. package/modules/hall-ui/public/primer.html +4 -4
  37. package/modules/hall-ui/public/profile-own.js +639 -0
  38. package/modules/hall-ui/public/profile.css +2 -1
  39. package/modules/hall-ui/public/profile.html +48 -5
  40. package/modules/hall-ui/public/profile.js +27 -2
  41. package/modules/hall-ui/public/profile.states.json +18 -0
  42. package/modules/hall-ui/public/project-settings.html +4 -4
  43. package/modules/hall-ui/public/roadmap.html +4 -4
  44. package/modules/hall-ui/public/roster.html +4 -4
  45. package/modules/hall-ui/public/settings.html +4 -4
  46. package/modules/hall-ui/public/setup-gate.js +156 -0
  47. package/modules/hall-ui/public/shell-trail.js +2 -1
  48. package/modules/hall-ui/public/shell.js +44 -26
  49. package/modules/hall-ui/public/street.html +4 -4
  50. package/modules/hall-ui/public/studio.html +4 -4
  51. package/modules/hall-ui/public/style.css +85 -117
  52. package/modules/hall-ui/public/task.html +4 -4
  53. package/modules/hall-ui/public/thinking.html +4 -4
  54. package/modules/hall-ui/public/tweak-editor.html +4 -4
  55. package/modules/hall-ui/public/watch.html +4 -4
  56. package/modules/hall-ui/public/work.html +4 -4
  57. package/modules/hall-ui/records/setup-gate.md +43 -0
  58. package/modules/lifecycle/routes/tasks.js +2 -2
  59. package/modules/onboarding/onboarding-state.js +41 -20
  60. package/package-lock.json +2 -2
  61. package/package.json +1 -1
  62. package/release-notes.json +12 -0
  63. package/src/bongos/routes/me.js +2 -2
  64. package/src/module-api.js +1 -1
  65. package/tests/curve_controls_delegation.mjs +9 -8
  66. package/tests/curve_kind_overlay.mjs +5 -5
  67. package/tests/hall_acclaim_vote_control.mjs +5 -3
  68. package/tests/hall_audit.mjs +10 -6
  69. package/tests/hall_board_world.mjs +41 -27
  70. package/tests/hall_builders_page_pass.mjs +14 -5
  71. package/tests/hall_home_ships_bounded.mjs +10 -21
  72. package/tests/hall_kit_charts.mjs +3 -2
  73. package/tests/hall_landing_boot.mjs +2 -3
  74. package/tests/hall_loading.mjs +2 -1
  75. package/tests/hall_nav.mjs +36 -37
  76. package/tests/hall_numbers_page.mjs +100 -0
  77. package/tests/hall_onboarding_bongos_setup.mjs +14 -14
  78. package/tests/hall_palette.mjs +19 -24
  79. package/tests/hall_profile_world.mjs +7 -2
  80. package/tests/hall_reading_room.mjs +3 -2
  81. package/tests/helpers.mjs +8 -2
  82. package/tests/leaderboard_roles.mjs +1 -1
  83. package/tests/module_contributions.mjs +10 -6
  84. package/tests/nav_permission_atoms.mjs +4 -2
  85. package/tests/onboarding_state.mjs +33 -0
  86. package/tests/page_tweak_artist.mjs +2 -1
  87. package/tests/rank_tier_single_source.mjs +3 -0
  88. package/tests/setup_flow.mjs +242 -0
  89. package/tests/task_visuals.mjs +3 -1
  90. package/tests/welcome_boot.mjs +3 -2
@@ -1356,6 +1356,88 @@ html[data-fullscreen="on"][data-fullscreen-plain="on"] .app-content { padding-to
1356
1356
  "ask me again" box. Each door carries its scene from the approved prototype,
1357
1357
  which is night-dark in either theme because every scene is a night one. */
1358
1358
  html.craft-picker-open { overflow: hidden; }
1359
+ /* The setup flow (setup-gate.js, task 1005076): the one screen a new builder sees until set up. */
1360
+ html.setup-gate-open { overflow: hidden; }
1361
+ .setup-gate {
1362
+ position: fixed;
1363
+ inset: 0;
1364
+ z-index: calc(var(--z-modal) + 1);
1365
+ display: flex;
1366
+ justify-content: center;
1367
+ align-items: flex-start;
1368
+ padding: max(24px, 6vh) 16px 24px;
1369
+ overflow-y: auto;
1370
+ background: var(--bg);
1371
+ }
1372
+ .setup-gate__panel {
1373
+ width: min(640px, 100%);
1374
+ box-sizing: border-box;
1375
+ padding: 36px 40px 28px;
1376
+ border-radius: 22px;
1377
+ background: var(--bg-card);
1378
+ color: var(--ink);
1379
+ }
1380
+ .setup-gate__count { margin: 0; font-size: 13px; color: var(--ink-faint); }
1381
+ .setup-gate__title { margin: 6px 0 8px; font-family: var(--font-display); font-size: clamp(26px, 4vw, 34px); font-weight: 300; letter-spacing: -0.02em; line-height: 1.2; }
1382
+ .setup-gate__lede { margin: 0 0 24px; font-size: 16px; line-height: 1.5; color: var(--ink-soft); }
1383
+ .setup-gate__steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
1384
+ .setup-gate__step { display: flex; gap: 14px; padding: 12px 0; border-top: 1px solid var(--rule-soft); }
1385
+ .setup-gate__step:first-child { border-top: 0; }
1386
+ .setup-gate__mark {
1387
+ flex: none;
1388
+ display: inline-flex;
1389
+ align-items: center;
1390
+ justify-content: center;
1391
+ width: 28px;
1392
+ height: 28px;
1393
+ border-radius: var(--radius-pill);
1394
+ border: 1px solid var(--rule);
1395
+ font-size: 13px;
1396
+ color: var(--ink-soft);
1397
+ }
1398
+ .setup-gate__mark svg { width: 16px; height: 16px; }
1399
+ .setup-gate__step.is-done .setup-gate__mark { border-color: transparent; background: var(--ok-weak); color: var(--ok); }
1400
+ .setup-gate__step.is-current .setup-gate__mark { border-color: var(--accent); color: var(--ink); }
1401
+ .setup-gate__body { min-width: 0; flex: 1; }
1402
+ .setup-gate__label { margin: 4px 0 0; font-size: 16px; font-weight: 500; }
1403
+ .setup-gate__step.is-done .setup-gate__label { color: var(--ink-soft); font-weight: 400; }
1404
+ .setup-gate__hint { margin: 6px 0 0; font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
1405
+ .setup-gate__how { margin: 10px 0 0; padding-left: 20px; font-size: 15px; line-height: 1.6; }
1406
+ /* The clone block is several commands, one per line: `pre` keeps the breaks on screen and in
1407
+ copy-on-click (it copies innerText). Both axes named: the one-axis-strip rule. */
1408
+ .setup-gate__code {
1409
+ display: block;
1410
+ margin: 12px 0 0;
1411
+ padding: 10px 14px;
1412
+ border-radius: var(--radius-sm);
1413
+ background: var(--glass);
1414
+ font-family: var(--font-mono);
1415
+ font-size: 13px;
1416
+ white-space: pre;
1417
+ overflow-x: auto;
1418
+ overflow-y: hidden;
1419
+ }
1420
+ .setup-gate code { font-family: var(--font-mono); font-size: 14px; padding: 1px 6px; border-radius: 6px; background: var(--glass); }
1421
+ .setup-gate__crafts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
1422
+ .setup-gate__craft,
1423
+ .setup-gate__save {
1424
+ min-height: 36px;
1425
+ padding: 0 16px;
1426
+ border-radius: var(--radius-pill);
1427
+ border: 1px solid var(--rule);
1428
+ background: none;
1429
+ color: var(--ink);
1430
+ font: inherit;
1431
+ font-size: 14px;
1432
+ cursor: pointer;
1433
+ }
1434
+ .setup-gate__craft[aria-pressed="true"] { border-color: var(--accent); background: var(--accent-tint); }
1435
+ .setup-gate__save { margin-top: 12px; background: var(--accent); border-color: var(--accent); color: var(--accent-on); }
1436
+ .setup-gate__save:disabled { opacity: .5; cursor: default; }
1437
+ .setup-gate__err { margin: 8px 0 0; font-size: 14px; color: var(--danger); }
1438
+ .setup-gate__foot { margin: 24px 0 0; font-size: 14px; }
1439
+ .setup-gate__foot a { color: var(--ink-soft); }
1440
+ @media (max-width: 640px) { .setup-gate__panel { padding: 28px 20px 20px; border-radius: 18px; } }
1359
1441
  .craft-picker {
1360
1442
  position: fixed;
1361
1443
  inset: 0;
@@ -2116,8 +2198,7 @@ html.pb-editing main { padding-bottom: 180px; }
2116
2198
  text-align: center;
2117
2199
  }
2118
2200
 
2119
- .pill-link,
2120
- #welcome-reopen a {
2201
+ .pill-link {
2121
2202
  display: inline-flex;
2122
2203
  align-items: center;
2123
2204
  min-height: 28px;
@@ -2129,7 +2210,6 @@ html.pb-editing main { padding-bottom: 180px; }
2129
2210
  border-radius: var(--radius-pill);
2130
2211
  padding: 0 12px;
2131
2212
  }
2132
- #welcome-reopen { margin: 0; }
2133
2213
  .pill-link:hover { color: var(--ink); text-decoration: none; border-color: var(--ink-faint); }
2134
2214
 
2135
2215
  /* ---------- stat tiles (Home) ----------
@@ -3166,119 +3246,8 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
3166
3246
 
3167
3247
  .curve__kinds { display: flex; flex-direction: column; gap: 6px; margin-top: 16px; }
3168
3248
 
3169
- /* ---------- onboarding checklist ---------- */
3170
-
3171
- .onboarding-list {
3172
- list-style: none;
3173
- margin: 0;
3174
- padding: 0;
3175
- display: flex;
3176
- flex-direction: column;
3177
- }
3178
- .onboarding-item {
3179
- display: grid;
3180
- grid-template-columns: 26px minmax(0, 1fr) auto;
3181
- gap: 4px 12px;
3182
- align-items: start;
3183
- padding: 12px 4px;
3184
- border-bottom: 1px solid var(--rule-soft);
3185
- }
3186
- .onboarding-item:last-child { border-bottom: none; }
3187
- .onboarding-item--placeholder { color: var(--ink-faint); }
3188
- .onboarding-item__mark {
3189
- width: 22px; height: 22px;
3190
- border-radius: 50%;
3191
- border: 1.5px solid var(--border-strong);
3192
- display: flex;
3193
- align-items: center;
3194
- justify-content: center;
3195
- font-size: 12px;
3196
- color: var(--ink-faint);
3197
- background: var(--surface);
3198
- }
3199
- .onboarding-item--cleared .onboarding-item__mark {
3200
- background: var(--ok);
3201
- border-color: var(--ok);
3202
- color: #fff;
3203
- }
3204
- .onboarding-item--current .onboarding-item__mark { border-color: var(--accent); color: var(--accent-text); }
3205
- .onboarding-item--current { background: var(--accent-weak); border-radius: var(--radius-sm); padding-left: 10px; padding-right: 10px; border-bottom-color: transparent; }
3206
- .onboarding-item--locked { opacity: 0.6; }
3207
- .onboarding-item__body { min-width: 0; }
3208
- .onboarding-item__label { font-weight: 600; font-size: 13.5px; }
3209
- .onboarding-item--cleared .onboarding-item__label { color: var(--ink-soft); font-weight: 500; }
3210
- .onboarding-item__hint { font-size: 12.5px; color: var(--ink-soft); margin-top: 1px; }
3211
- .onboarding-item__detail { font-size: 12.5px; color: var(--ink-soft); margin-top: 6px; }
3212
- .onboarding-item__detail code { background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
3213
- .onboarding-item__action { align-self: center; }
3214
- .onboarding-item__disc-pick { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
3215
- .onboarding-item__disc {
3216
- border: 1px solid var(--border-strong);
3217
- background: var(--surface);
3218
- color: var(--ink-soft);
3219
- border-radius: 999px;
3220
- font-size: 12.5px;
3221
- font-weight: 500;
3222
- padding: 4px 12px;
3223
- cursor: pointer;
3224
- }
3225
- .onboarding-item__disc:hover { background: var(--surface-2); }
3226
- .onboarding-item__disc--on {
3227
- background: var(--accent-weak);
3228
- color: var(--accent-text);
3229
- border-color: color-mix(in srgb, var(--accent) 40%, transparent);
3230
- }
3231
- .onboarding-item__discord { font-weight: 600; }
3232
-
3233
- @media (max-width: 560px) {
3234
- .onboarding-item { grid-template-columns: 26px minmax(0, 1fr); }
3235
- .onboarding-item__action { grid-column: 2; justify-self: start; }
3236
- }
3237
-
3238
- /* ---------- welcome panel + setup selector ---------- */
3239
-
3240
- .scroll--welcome {
3241
- position: relative;
3242
- border-left: 3px solid var(--accent);
3243
- }
3244
- .scroll--welcome--minimized .welcome { display: none; }
3245
- .welcome__minimize {
3246
- position: absolute;
3247
- top: 12px; right: 12px;
3248
- width: 26px; height: 26px;
3249
- border: 1px solid var(--border);
3250
- border-radius: var(--radius-sm);
3251
- background: var(--surface);
3252
- color: var(--ink-soft);
3253
- font-size: 14px;
3254
- line-height: 1;
3255
- cursor: pointer;
3256
- }
3257
- .welcome__minimize:hover { background: var(--surface-2); }
3258
- .welcome__lede { font-size: 13.5px; color: var(--ink-soft); max-width: 70ch; }
3259
- .welcome__unlocks { margin: 8px 0; padding-left: 18px; font-size: 13px; color: var(--ink-soft); }
3260
- .welcome__cmd, .welcome__paste {
3261
- font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
3262
- font-size: 12.5px;
3263
- background: var(--surface-2);
3264
- border: 1px solid var(--border);
3265
- border-radius: var(--radius-sm);
3266
- padding: 8px 12px;
3267
- overflow-x: auto;
3268
- }
3269
- /* The get-the-code block is several commands, one per line. Without `pre` the
3270
- line breaks collapse on screen AND in copy-on-click (it copies innerText),
3271
- so a builder pasted every command onto one line. Both axes named: see the
3272
- one-axis-strip rule in this module's CLAUDE.md. */
3273
- .setup__getcode .welcome__paste {
3274
- display: block;
3275
- white-space: pre;
3276
- overflow-y: hidden;
3277
- }
3249
+ /* ---------- setup selector (the tab strip; .setup__tab is the kit's tab idiom) ---------- */
3278
3250
 
3279
- .setup { margin-top: 12px; }
3280
- .setup__intro { font-size: 13px; color: var(--ink-soft); }
3281
- .setup__toggle { display: flex; border: 0; border-bottom: 1px solid var(--rule); margin: 8px 0 12px; flex-wrap: wrap; }
3282
3251
  /* An open tab is the live thing in the strip, so it is what the accent lights:
3283
3252
  a 2px underline sitting on the strip’s own hairline. */
3284
3253
  .setup__tab {
@@ -3366,8 +3335,7 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
3366
3335
  html[data-door="out"] .app-sidebar,
3367
3336
  html[data-door="out"] .app-scrim,
3368
3337
  html[data-door="out"] .app-topbar,
3369
- html[data-door="out"] .app-foot,
3370
- html[data-door="out"] #welcome-reopen { display: none; }
3338
+ html[data-door="out"] .app-foot { display: none; }
3371
3339
  html[data-door="out"] .app-body { margin-left: 0; }
3372
3340
  /* body in the selector outranks Home's own body[data-page="home"] .page-head--hall. */
3373
3341
  html[data-door="out"] body .page-head {
@@ -56,10 +56,10 @@
56
56
 
57
57
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
58
58
  time so the chrome exists before the deferred page scripts execute. -->
59
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
60
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
61
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
62
- <script src="/builders/shell.js?v=2026-11-05-oversight"></script>
59
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
60
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
61
+ <script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
62
+ <script src="/builders/shell.js?v=2026-11-05-numbers"></script>
63
63
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
64
64
  <script src="/builders/palette.js" defer></script>
65
65
  <!-- task-detail.js still owns the #/idea/N and #/blocker/N deep-link overlay
@@ -138,10 +138,10 @@
138
138
  </div>
139
139
  </div>
140
140
 
141
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
142
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
143
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
144
- <script src="/builders/shell.js?v=2026-11-05-oversight"></script>
141
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
142
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
143
+ <script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
144
+ <script src="/builders/shell.js?v=2026-11-05-numbers"></script>
145
145
  <script src="/builders/palette.js" defer></script>
146
146
 
147
147
  <script src="/builders/idea-objects.js?v=2026-09-27-split"></script>
@@ -142,10 +142,10 @@
142
142
 
143
143
  <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
144
144
 
145
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
146
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
147
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
148
- <script src="/builders/shell.js?v=2026-11-05-oversight"></script>
145
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
146
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
147
+ <script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
148
+ <script src="/builders/shell.js?v=2026-11-05-numbers"></script>
149
149
  <script src="/builders/palette.js" defer></script>
150
150
  <script src="/builders/brand-holes.js?v=2026-09-29-aqfix"></script>
151
151
  <script src="/builders/tweak-editor-lib.js?v=2026-09-29-tw27"></script>
@@ -268,10 +268,10 @@
268
268
 
269
269
  <!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
270
270
  chrome exists before the page script runs. -->
271
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
272
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
273
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
274
- <script src="/builders/shell.js?v=2026-11-05-oversight"></script>
271
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
272
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
273
+ <script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
274
+ <script src="/builders/shell.js?v=2026-11-05-numbers"></script>
275
275
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
276
276
  <script src="/builders/palette.js" defer></script>
277
277
  <!-- shared component kit (window.OTBKit) — tabs, ledger, pager (task 2166). -->
@@ -171,10 +171,10 @@
171
171
 
172
172
  <!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
173
173
  time so the chrome exists before the deferred page scripts execute. -->
174
- <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
175
- <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
176
- <script src="/builders/craft-mode.js?v=2026-11-05-oversight"></script>
177
- <script src="/builders/shell.js?v=2026-11-05-oversight"></script>
174
+ <script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
175
+ <script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
176
+ <script src="/builders/craft-mode.js?v=2026-11-05-numbers"></script>
177
+ <script src="/builders/shell.js?v=2026-11-05-numbers"></script>
178
178
  <!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
179
179
  <script src="/builders/palette.js" defer></script>
180
180
  <!-- task 1004727: the ONE karma vote control every task/idea list renders -->
@@ -0,0 +1,43 @@
1
+ # The setup flow — one screen a new builder finishes once, and no setup banner on Home (task 1005076)
2
+
3
+ The owner, 2026-11-05: Home's Welcome banner (the clone / `npx bongos setup` / download Claude steps) and the
4
+ Getting started checklist below it stayed until a builder had shipped THREE tasks, so builders who were fully
5
+ set up kept seeing a setup banner across the top of the hall. The decision: a new builder is held on a setup
6
+ flow when they get in and goes through each step; once set up they are in for good, with no banner and no
7
+ reminders.
8
+
9
+ **What people see.** While `/me`'s `onboarding.setup.complete` is false, every hall page shows only
10
+ `setup-gate.js`'s screen: "N of 4 done", the four steps in order, the current one open with what to do, a Sign
11
+ out link. Each step ticks itself; the screen re-reads `/me` every 8 seconds and reloads into the hall the moment
12
+ setup is complete.
13
+
14
+ 1. **Sign in** — always done by the time the screen can draw.
15
+ 2. **Get the project and Claude on your machine, and link it** — a CLI session exists (`npx bongos setup`).
16
+ 3. **Choose your role** — chosen on the screen itself, saved through `PATCH /me/disciplines`.
17
+ 4. **Run /builder-start in Claude** — the `first_start` stage, which `GET /tasks/claimable` now marks only for
18
+ a CLI session (the hall's own pages read that feed from the browser and used to tick it for everyone).
19
+
20
+ **Who is never held.** Anyone graduated, anyone who has claimed a task, and any rank above xenos — every existing
21
+ builder goes straight in. An older server that sends no `setup` holds nobody. The rule is
22
+ `modules/onboarding/onboarding-state.js` `setupForApi`; the hall never re-derives it.
23
+
24
+ **How it is wired.** `shell.js` `holdForSetup` loads `setup-gate.js` on demand (`loadHallScript`, the
25
+ core-move-notice way), so a set-up builder never downloads it, and while it holds, neither the daily welcome
26
+ (`welcome-boot.js`) nor the craft picker is asked. Both `applyAccess` callers pass `setup` (`shell.js`'s own
27
+ `/me` probe and Home's `hall-render.js`). Its styles are `.setup-gate*` in `style.css`, on the hall tokens in
28
+ both modes; the overlay sits one above `--z-modal`.
29
+
30
+ **Removed.** The `welcome-scroll` and `onboarding-scroll` Home widgets, the "Show the setup guide again" link,
31
+ and everything that drew them: `renderWelcomeCore` / `renderOnboarding` and their helpers in `hall-render.js`;
32
+ `renderWelcome`, `reopenWelcomeFromNav`, `pickDiscipline`, the instance-repo loader and the checklist's /me poll
33
+ in `builders.js`; the `.welcome*` / `.onboarding-item*` styles. The clone block (this project's own repository
34
+ from `GET /instance`, never a hardcoded one) now lives on the setup screen's machine step, with Node and
35
+ `npm install` named before `npx bongos setup`, as the welcome panel had them. The role step says "role", the
36
+ word ADR 0174 fixed for that axis, through `OTB.roleAxisLabel` / `OTB.roleLabel`.
37
+
38
+ **Loaded once.** `applyAccess` can run several times before the script lands; `holdForSetup` asks for it once
39
+ (`setupGateLoading`), or two screens would stack.
40
+
41
+ **Tests.** `tests/setup_flow.mjs` (the claimable guard run for a CLI and a web session, the screen drawn and
42
+ driven, the shell loading it with nothing over it, Home with no banner), `tests/onboarding_state.mjs` (the
43
+ rule), `tests/welcome_boot.mjs` (the shell's ask order). Each was mutation-checked against its half of the change.
@@ -237,8 +237,8 @@ module.exports = function buildTasksRouter() {
237
237
  // and forget — the response should never wait on or fail because of the
238
238
  // onboarding write. safeMarkStage swallows errors and handles the
239
239
  // graduation broadcast. Through the `onboarding` kernel port (BV1.R81 / ADR
240
- // 0093 §1); ?. degrades to a no-op when the module is off.
241
- seams.resolveOptional('onboarding')?.safeMarkStage(pool, req.builder.id, 'first_start', req.builder);
240
+ // 0093 §1); ?. degrades to a no-op when the module is off. CLI only (task 1005076: the hall reads this feed too).
241
+ if (req.gdsSession && req.gdsSession.source === 'cli') seams.resolveOptional('onboarding')?.safeMarkStage(pool, req.builder.id, 'first_start', req.builder);
242
242
  // `claimable_total` keeps the limit honest: the length of the sliced array, never a
243
243
  // second count query (ADR 0197).
244
244
  res.json({ claimable, claimable_total: feed.length, active_claims: active });
@@ -79,23 +79,6 @@ const STAGES = [
79
79
  const GRADUATED = 'graduated';
80
80
  const ALL_STAGES = [...STAGES, GRADUATED];
81
81
 
82
- // The pre-auth, INFORMATIONAL step that sits AHEAD of auth_complete (task 470).
83
- // The state machine's first ENGINE stage is auth_complete, but the genuine
84
- // first action a newcomer takes is "obtain the repo" — clone it locally. That
85
- // step is manual/external
86
- // (there is no server event for it) and intentionally NOT a member of STAGES, so
87
- // it never gates graduation, never advances current_stage, and never appears in
88
- // shapeForApi's tracked checklist. It exists purely so the system's own model of
89
- // "the path into the city" begins where the path really begins. The hall renders
90
- // it as a static lead-in line on the displayed checklist; the auth_complete hint
91
- // above also surfaces the same clone instruction.
92
- const PRE_AUTH_STEP = {
93
- id: 'obtain_repo',
94
- label: 'Obtain the repo',
95
- hint: 'Clone the project to thy machine and run npm install in it. The build commands live inside the repo, so this comes first.',
96
- informational: true,
97
- };
98
-
99
82
  // How many shipped tasks the terminal 'ship_three' stage requires. Kept in
100
83
  // lockstep with db.THETES_GRADUATION_THRESHOLD (#692 / ADR 0034) so the
101
84
  // checklist's graduation coincides with the xenos→thetes promotion. Used only
@@ -124,7 +107,7 @@ const STAGE_LABELS = {
124
107
  // machine you'll build from — the /builder-* commands live INSIDE the repo, so
125
108
  // nothing (not even sign-in via the CLI) can happen before it exists. The
126
109
  // onboarding model never named that step, so the hint now points at it ahead of
127
- // the sign-in itself. See PRE_AUTH_STEP below for the standalone representation.
110
+ // the sign-in itself. The setup flow's cli_setup step (task 1005076) carries it too.
128
111
  const STAGE_HINTS = {
129
112
  auth_complete: 'First obtain the repo — clone it — then sign in with npx bongos setup in that folder.',
130
113
  pick_disciplines: 'Pick the work that calls thee — engineer, artist, ideator, or any mix.',
@@ -189,6 +172,42 @@ const DISPLAY_HINTS = {
189
172
  ship_three: 'Carry three tasks through with /builder-ship — the third makes thee a Thetes.',
190
173
  };
191
174
 
175
+ // ---- the setup flow (task 1005076) -------------------------------------------
176
+ //
177
+ // What a newcomer must finish before the hall opens to them (owner, 2026-11-05):
178
+ // the hall holds them on one setup screen until every step below is cleared, and
179
+ // after that they are in for good — no banner, no reminders. Each step ticks
180
+ // itself from a signal the server already records:
181
+ //
182
+ // signed_in — they are reading /me, so always cleared.
183
+ // cli_setup — a source='cli' session exists (ran `npx bongos setup`).
184
+ // pick_disciplines — the engine stage choosing a role marks (PATCH /me/disciplines).
185
+ // first_start — the engine stage, which GET /tasks/claimable marks only for a
186
+ // CLI session: proof /builder-start ran from Claude.
187
+ //
188
+ // Setup is also complete for anyone already past it: graduated, claimed a task
189
+ // (first_claim cleared), or holding any rank above xenos. Existing builders go
190
+ // straight in and are never held.
191
+ const SETUP_STEPS = [
192
+ { id: 'signed_in', label: 'Sign in', hint: 'Done — you are signed in.' },
193
+ { id: 'cli_setup', label: 'Get the project and Claude on your machine, and link it', hint: 'Three things on your own computer. This ticks itself once your machine is linked.' },
194
+ { id: 'pick_disciplines', label: 'Choose your role', hint: 'Pick the work you want to do — engineer, artist, ideator, or any mix.' },
195
+ { id: 'first_start', label: 'Run /builder-start in Claude', hint: 'Open the project in Claude and type /builder-start. This ticks itself the first time it runs, which proves everything works.' },
196
+ ];
197
+
198
+ function setupForApi(state, { cliAuthed = false, rank = null } = {}) {
199
+ const completed = new Set((state && state.completed_stages) || []);
200
+ const current = (state && state.current_stage) || STAGES[0];
201
+ const cleared = (stage) => current === GRADUATED || completed.has(stage)
202
+ || (STAGES.indexOf(current) > STAGES.indexOf(stage) && STAGES.indexOf(stage) >= 0);
203
+ const steps = SETUP_STEPS.map((s) => ({
204
+ ...s,
205
+ cleared: s.id === 'signed_in' ? true : s.id === 'cli_setup' ? !!cliAuthed : cleared(s.id),
206
+ }));
207
+ const pastIt = current === GRADUATED || cleared('first_claim') || (!!rank && rank !== 'xenos');
208
+ return { complete: pastIt || steps.every((s) => s.cleared), steps };
209
+ }
210
+
192
211
  // Pick the first uncompleted stage from STAGES (canonical order), or
193
212
  // GRADUATED if all six are done. Mirrors the migration 045 backfill CASE so
194
213
  // app-layer behaviour matches DB-layer reconstruction.
@@ -441,7 +460,9 @@ function stageDetail(stageId, shipCount) {
441
460
  // 'join_discord' step (the OAuth flow sets the link).
442
461
  // opts.cliAuthed — whether the builder has ever authenticated the GDS CLI
443
462
  // (db.hasCliSession). Clears the 'cli_setup' step.
444
- function shapeForApi(state, { shipCount = null, discordLinked = false, cliAuthed = false } = {}) {
463
+ // opts.rank — the builder's rank; any rank above xenos counts as set up
464
+ // (the `setup` block, task 1005076).
465
+ function shapeForApi(state, { shipCount = null, discordLinked = false, cliAuthed = false, rank = null } = {}) {
445
466
  const completed = new Set((state && state.completed_stages) || []);
446
467
  const currentReal = (state && state.current_stage) || STAGES[0];
447
468
  const graduated = currentReal === GRADUATED;
@@ -487,6 +508,7 @@ function shapeForApi(state, { shipCount = null, discordLinked = false, cliAuthed
487
508
  progress: { cleared: clearedCount, total: DISPLAY_STEPS.length },
488
509
  stages: display,
489
510
  graduated,
511
+ setup: setupForApi(state, { cliAuthed, rank }),
490
512
  };
491
513
  }
492
514
 
@@ -494,7 +516,6 @@ module.exports = {
494
516
  STAGES,
495
517
  GRADUATED,
496
518
  ALL_STAGES,
497
- PRE_AUTH_STEP,
498
519
  STAGE_HINTS,
499
520
  DISPLAY_LABELS,
500
521
  isKnownStage,
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.41",
3
+ "version": "1.24.43",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.24.41",
9
+ "version": "1.24.43",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.24.41",
3
+ "version": "1.24.43",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -11209,5 +11209,17 @@
11209
11209
  "id": "1005049",
11210
11210
  "text": "Watch is now the one oversight page. Sessions and Autobongos moved off the sidebar and became two tabs on Watch, next to People, Operations and Security. Old links to /sessions and /gate open the right tab. Who can see and pre"
11211
11211
  }
11212
+ ],
11213
+ "1.24.42": [
11214
+ {
11215
+ "id": "1005076",
11216
+ "text": "New builders now get one clear setup screen they finish once, and everyone already set up no longer sees a setup banner across the top of Home."
11217
+ }
11218
+ ],
11219
+ "1.24.43": [
11220
+ {
11221
+ "id": "1005050",
11222
+ "text": "Your numbers are on one page now: your Profile. The separate Accomplishments page is gone from the sidebar. The parts only you should see — your rank and how to reach the next one, how your work was reviewed, your karma histor"
11223
+ }
11212
11224
  ]
11213
11225
  }
@@ -535,7 +535,7 @@ module.exports = function buildMeRouter() {
535
535
  // returns a stage-1 "nothing cleared" view so the client renders the
536
536
  // checklist either way. Through the `onboarding` port (BV1.R81); null when
537
537
  // the module is off.
538
- onboarding: onboarding ? onboarding.shapeForApi(onboardingRow, { shipCount, discordLinked: !!discordLink, cliAuthed: !!cliAuthed }) : null,
538
+ onboarding: onboarding ? onboarding.shapeForApi(onboardingRow, { shipCount, discordLinked: !!discordLink, cliAuthed: !!cliAuthed, rank: req.builder.rank }) : null,
539
539
  // F7 (ADR 0033): Discord link state for the hall's Connect/Unlink UI.
540
540
  // `configured` tells the client whether the server even has Discord OAuth
541
541
  // creds — when false the hall renders nothing (the start route 503s).
@@ -714,7 +714,7 @@ module.exports = function buildMeRouter() {
714
714
  discordIsLinked(req.builder.id),
715
715
  db.hasCliSession(req.builder.id),
716
716
  ]);
717
- const onboarding = onboardingPort ? onboardingPort.shapeForApi(state, { shipCount, discordLinked: !!discordLink, cliAuthed: !!cliAuthed }) : null;
717
+ const onboarding = onboardingPort ? onboardingPort.shapeForApi(state, { shipCount, discordLinked: !!discordLink, cliAuthed: !!cliAuthed, rank: req.builder.rank }) : null;
718
718
  res.json({ builder, onboarding });
719
719
  } catch (err) {
720
720
  if (err.code === 'invalid_discipline' || err.code === 'invalid_main_discipline') {
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.24.41'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.24.43'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -23,18 +23,19 @@ import { fileURLToPath } from 'node:url';
23
23
 
24
24
  const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
25
25
  const PUB = path.join(ROOT, 'modules/hall-ui/public');
26
- const widgetsSrc = fs.readFileSync(path.join(PUB, 'hall-widgets.js'), 'utf8');
27
- const buildersSrc = fs.readFileSync(path.join(PUB, 'builders.js'), 'utf8');
26
+ // task 1005050: the Progress section moved with Accomplishments to the Profile
27
+ // page's "Just you" screen — its markup is profile.html's, its wiring profile-own.js's.
28
+ const pageSrc = fs.readFileSync(path.join(PUB, 'profile.html'), 'utf8');
29
+ const buildersSrc = fs.readFileSync(path.join(PUB, 'profile-own.js'), 'utf8');
28
30
 
29
31
  const SECTION_ID = 'analytics-scroll';
30
32
 
31
33
  // The Progress widget's markup: the concatenated string literals of its w() call.
32
34
  function progressMarkup() {
33
- const start = widgetsSrc.indexOf(`w('${SECTION_ID}'`);
34
- assert.ok(start >= 0, `hall-widgets.js no longer registers '${SECTION_ID}'`);
35
- const end = widgetsSrc.indexOf("{ view: 'standing'", start);
36
- const call = widgetsSrc.slice(start, end);
37
- return [...call.matchAll(/'((?:[^'\\]|\\.)*)'/g)].map((m) => m[1]).slice(2).join('');
35
+ const start = pageSrc.indexOf(`id="${SECTION_ID}"`);
36
+ assert.ok(start >= 0, `profile.html no longer carries '${SECTION_ID}'`);
37
+ const open = pageSrc.lastIndexOf('<section', start);
38
+ return pageSrc.slice(open, pageSrc.indexOf('</section>', start) + '</section>'.length);
38
39
  }
39
40
 
40
41
  // True if the element with id=`outer` encloses the element with id=`inner`.
@@ -57,7 +58,7 @@ function encloses(html, outer, inner) {
57
58
  // The selector each curve-control listener is attached to in builders.js.
58
59
  function delegationTarget(marker) {
59
60
  const at = buildersSrc.indexOf(marker);
60
- assert.ok(at >= 0, `builders.js no longer handles ${marker}`);
61
+ assert.ok(at >= 0, `profile-own.js no longer handles ${marker}`);
61
62
  const before = buildersSrc.slice(0, at);
62
63
  const all = [...before.matchAll(/\$\('#([\w-]+)'\)\?\.addEventListener\('(click|change)'/g)];
63
64
  assert.ok(all.length, `no delegated listener found before ${marker}`);
@@ -254,7 +254,7 @@ test('cost is WITHHELD under a kind filter, not faked', () => {
254
254
  });
255
255
 
256
256
  test('the client hides the cost chart and stat rather than printing $0.00', () => {
257
- const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/hall-render.js'), 'utf8');
257
+ const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/profile-own.js'), 'utf8');
258
258
  assert.match(render, /costUnavailable = Array\.isArray\(data\.unavailable\) && data\.unavailable\.includes\('cost_trend'\)/);
259
259
  assert.match(render, /costUnavailable\s*\?\s*statCard\('Cost \/ work', '—'/,
260
260
  'a withheld cost must render as —, never as a price');
@@ -264,7 +264,7 @@ test('the controls are written BEFORE every early return', () => {
264
264
  // A kind with nothing shipped in the window takes the totalShipped === 0
265
265
  // branch, which blanks the body. If the filter were drawn after that, the
266
266
  // reader would be stranded at "no data" with no control to undo it.
267
- const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/hall-render.js'), 'utf8');
267
+ const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/profile-own.js'), 'utf8');
268
268
  const fn = render.slice(render.indexOf('function renderCurveBody()'));
269
269
  const controls = fn.indexOf('kindFilterHtml()');
270
270
  const firstReturn = fn.indexOf('if (!data) {');
@@ -275,8 +275,8 @@ test('the controls are written BEFORE every early return', () => {
275
275
  });
276
276
 
277
277
  test('the scope toggle is no longer rank-gated', () => {
278
- const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/hall-render.js'), 'utf8');
279
- const builders = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/builders.js'), 'utf8');
278
+ const render = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/profile-own.js'), 'utf8');
279
+ const builders = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/profile-own.js'), 'utf8');
280
280
  assert.ok(!/analyticsState\.isArchon\s*&&/.test(render),
281
281
  'the scope toggle is still gated on rank');
282
282
  // The field is REMOVED, not merely unread — a write-only state flag is how a
@@ -288,7 +288,7 @@ test('the scope toggle is no longer rank-gated', () => {
288
288
  });
289
289
 
290
290
  test('a kind change re-fetches BOTH series, and the newest answer wins', () => {
291
- const builders = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/builders.js'), 'utf8');
291
+ const builders = fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/profile-own.js'), 'utf8');
292
292
  const fn = builders.slice(builders.indexOf('async function reloadCurveForKind'));
293
293
  const body = fn.slice(0, fn.indexOf('\n }') + 4);
294
294
  assert.match(body, /analytics\/builder\/\$\{id\}\?days=90\$\{q\}/);