@bongos/core 1.23.22 → 1.24.2

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 (435) hide show
  1. package/.bongos-core.json +933 -413
  2. package/.claude/skills/blocker-review/SKILL.md +9 -1
  3. package/.claude/skills/blocker-solve/SKILL.md +1 -1
  4. package/.claude/skills/builder-claim/SKILL.md +1 -1
  5. package/.claude/skills/builder-reauth/SKILL.md +1 -1
  6. package/.claude/skills/builder-redteam/SKILL.md +1 -1
  7. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  8. package/.claude/skills/builder-setup/SKILL.md +1 -1
  9. package/.claude/skills/builder-ship/SKILL.md +1 -1
  10. package/.claude/skills/collab-review/SKILL.md +5 -2
  11. package/.claude/skills/design/SKILL.md +1 -1
  12. package/.claude/skills/goal-create/SKILL.md +2 -2
  13. package/.claude/skills/grade-recover/SKILL.md +1 -1
  14. package/.claude/skills/merge-mode/SKILL.md +1 -1
  15. package/.claude/skills/owner-review/SKILL.md +1 -1
  16. package/.claude/skills/planning-session/SKILL.md +11 -11
  17. package/.claude/skills/read-session-export/SKILL.md +1 -1
  18. package/.claude/skills/recall/SKILL.md +1 -1
  19. package/.claude/skills/scan-before-install/SKILL.md +1 -1
  20. package/.claude/skills/session-handoff/SKILL.md +1 -1
  21. package/.claude/skills/strand-fix/SKILL.md +13 -0
  22. package/.claude/skills/worktree-clean/SKILL.md +1 -1
  23. package/AGENTS.md +15 -0
  24. package/GEMINI.md +5 -0
  25. package/clients/bongos-client/README.md +1 -1
  26. package/clients/bongos-client/bongos-client.global.js +96 -0
  27. package/clients/bongos-client/index.cjs +96 -0
  28. package/clients/bongos-client/index.d.ts +155 -4
  29. package/clients/bongos-client/index.mjs +96 -0
  30. package/docs/adr/0054-session-token-reward-cost-plus.md +3 -1
  31. package/docs/adr/0055-server-mediated-branch-publish.md +1 -1
  32. package/docs/adr/0385-money-lives-with-a-processor-credits-stay-a-project-meter.md +12 -1
  33. package/docs/adr/0393-a-platform-account-is-a-person-and-github-is-one-way-in.md +37 -0
  34. package/docs/adr/0394-market-watch-searches-through-the-messages-api-on-the-projects-key-and-runs-from-its-own-poller.md +102 -0
  35. package/docs/adr/0395-a-task-says-what-it-needs-and-lists-show-only-what-you-can-do.md +36 -0
  36. package/docs/adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md +41 -0
  37. package/docs/adr/README.md +6 -2
  38. package/docs/api/openapi.json +8651 -5833
  39. package/docs/api-reference.md +66 -10
  40. package/docs/architecture.md +37 -1
  41. package/docs/canonical-permissions.md +1 -1
  42. package/docs/copy-inventory.md +427 -339
  43. package/docs/copy-registry.json +1376 -500
  44. package/docs/file-map.md +1 -0
  45. package/docs/module-api-changelog.md +7 -0
  46. package/docs/onboarding/diagrams/03-drachmae-karma.mmd +3 -3
  47. package/docs/onboarding/diagrams/README.md +1 -1
  48. package/docs/onboarding/drachmae-and-karma.md +15 -15
  49. package/docs/onboarding/primer.md +2 -2
  50. package/docs/page-inventory.json +57 -7
  51. package/docs/page-readings.json +1210 -1027
  52. package/docs/recipes/google-sign-in.md +60 -0
  53. package/docs/recipes/ops-gotchas.md +1 -1
  54. package/migrations/core_282_builders_lower_login_idx.sql +33 -0
  55. package/migrations/core_283_claimable_ignores_page_markers.sql +53 -0
  56. package/migrations/core_283_payout_approvals.sql +183 -0
  57. package/migrations/core_284_payout_gates.sql +179 -0
  58. package/migrations/core_285_task_needs.sql +74 -0
  59. package/modules/ai-studio/billing.js +67 -0
  60. package/modules/ai-studio/context.js +29 -0
  61. package/modules/ai-studio/db.js +172 -0
  62. package/modules/ai-studio/gemini.js +75 -0
  63. package/modules/ai-studio/generate.js +119 -0
  64. package/modules/ai-studio/keys.js +73 -0
  65. package/modules/ai-studio/migrations/ai_studio_001_keys.sql +22 -0
  66. package/modules/ai-studio/migrations/ai_studio_002_ledger.sql +48 -0
  67. package/modules/ai-studio/migrations/ai_studio_003_requests.sql +55 -0
  68. package/modules/ai-studio/openrouter.js +90 -0
  69. package/modules/ai-studio/payments.js +105 -0
  70. package/modules/ai-studio/pricing.js +92 -0
  71. package/modules/ai-studio/routes/ai-studio.js +235 -5
  72. package/modules/ai-studio/studio.js +121 -0
  73. package/modules/autonomy/fence.js +64 -1
  74. package/modules/builder-settings/builder-needs.js +27 -1
  75. package/modules/copy-desk/routes/copy-desk.js +5 -0
  76. package/modules/economy/achievements.js +22 -10
  77. package/modules/economy/cost-classify.js +9 -0
  78. package/modules/economy/cost-write-guard.js +52 -0
  79. package/modules/economy/cost.js +2 -1
  80. package/modules/economy/credits.js +18 -15
  81. package/modules/economy/goal-reward.js +161 -0
  82. package/modules/economy/reward.js +4 -0
  83. package/modules/economy/routes/cost.js +33 -7
  84. package/modules/government/access-routes.js +70 -0
  85. package/modules/government/access.js +88 -0
  86. package/modules/government/asks.js +5 -2
  87. package/modules/government/catalog.js +6 -0
  88. package/modules/government/db.js +72 -0
  89. package/modules/government/docket.js +48 -2
  90. package/modules/government/migrations/government_035_payout_approve.sql +29 -0
  91. package/modules/government/migrations/government_036_access_holders.sql +33 -0
  92. package/modules/government/pollers/board-expiry.js +108 -20
  93. package/modules/government/protected-surfaces.json +1 -0
  94. package/modules/government/routes/government.js +31 -0
  95. package/modules/government/routing.js +49 -7
  96. package/modules/government/waiting.js +78 -0
  97. package/modules/hall-ui/public/ai-studio-lib.js +268 -0
  98. package/modules/hall-ui/public/ai-studio.css +193 -0
  99. package/modules/hall-ui/public/ai-studio.html +98 -0
  100. package/modules/hall-ui/public/ai-studio.js +556 -0
  101. package/modules/hall-ui/public/ai-studio.states.json +94 -0
  102. package/modules/hall-ui/public/blockers-by-person.js +158 -0
  103. package/modules/hall-ui/public/blockers-lib.js +15 -1
  104. package/modules/hall-ui/public/blockers.html +8 -0
  105. package/modules/hall-ui/public/blockers.js +1 -1
  106. package/modules/hall-ui/public/claim-action.js +3 -0
  107. package/modules/hall-ui/public/collab.html +12 -0
  108. package/modules/hall-ui/public/craft-mode.js +4 -1
  109. package/modules/hall-ui/public/criterion-uat-ui.js +4 -1
  110. package/modules/hall-ui/public/drachmae.html +1 -1
  111. package/modules/hall-ui/public/genesis/r5-life-1-primordial-sea.jpg +0 -0
  112. package/modules/hall-ui/public/genesis/r5-life-2-first-cells-cut.webp +0 -0
  113. package/modules/hall-ui/public/genesis/r5-life-2-first-cells.jpg +0 -0
  114. package/modules/hall-ui/public/genesis/r5-life-3-genome-cut.webp +0 -0
  115. package/modules/hall-ui/public/genesis/r5-life-3-genome.jpg +0 -0
  116. package/modules/hall-ui/public/genesis/r5-life-4-membrane-cut.webp +0 -0
  117. package/modules/hall-ui/public/genesis/r5-life-4-membrane.jpg +0 -0
  118. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system-cut.webp +0 -0
  119. package/modules/hall-ui/public/genesis/r5-life-5-nervous-system.jpg +0 -0
  120. package/modules/hall-ui/public/goal-inbox.js +1 -1
  121. package/modules/hall-ui/public/goals-render.js +4 -0
  122. package/modules/hall-ui/public/goals.html +8 -0
  123. package/modules/hall-ui/public/gov-living.js +6 -2
  124. package/modules/hall-ui/public/government-access.js +108 -0
  125. package/modules/hall-ui/public/government.html +21 -0
  126. package/modules/hall-ui/public/hall-ask.css +5 -0
  127. package/modules/hall-ui/public/hall-ask.js +39 -3
  128. package/modules/hall-ui/public/notes-panel.css +20 -0
  129. package/modules/hall-ui/public/notes-panel.js +146 -0
  130. package/modules/hall-ui/public/project-settings.html +1 -1
  131. package/modules/hall-ui/public/project-settings.js +7 -5
  132. package/modules/hall-ui/public/settings-ai-keys.js +124 -0
  133. package/modules/hall-ui/public/settings.html +15 -0
  134. package/modules/hall-ui/public/street-deck.js +12 -3
  135. package/modules/hall-ui/public/studio.css +90 -8
  136. package/modules/hall-ui/public/studio.html +39 -10
  137. package/modules/hall-ui/public/studio.js +148 -18
  138. package/modules/hall-ui/public/task.html +2 -0
  139. package/modules/hall-ui/public/task.js +4 -0
  140. package/modules/hall-ui/public/tweak-editor.js +12 -3
  141. package/modules/hall-ui/public/welcome-boot.css +42 -6
  142. package/modules/hall-ui/public/welcome-boot.js +20 -6
  143. package/modules/hall-ui/public/work.js +20 -0
  144. package/modules/hall-ui/records/ai-studio.md +36 -0
  145. package/modules/hall-ui/records/blockers-people.md +38 -0
  146. package/modules/lifecycle/db-claims.js +32 -4
  147. package/modules/lifecycle/db-goals.js +18 -5
  148. package/modules/lifecycle/db-tasks.js +15 -6
  149. package/modules/lifecycle/done-when.js +23 -1
  150. package/modules/lifecycle/lifecycle.js +5 -0
  151. package/modules/lifecycle/migrations/lifecycle_017_notes.sql +46 -0
  152. package/modules/lifecycle/module.json +2 -1
  153. package/modules/lifecycle/notes.js +219 -0
  154. package/modules/lifecycle/page-notice.js +124 -0
  155. package/modules/lifecycle/page-tweak-artist.js +18 -1
  156. package/modules/lifecycle/publish-reconciler.js +67 -20
  157. package/modules/lifecycle/routes/claims.js +5 -2
  158. package/modules/lifecycle/routes/goals.js +3 -1
  159. package/modules/lifecycle/routes/notes.js +91 -0
  160. package/modules/lifecycle/routes/project-settings.js +43 -35
  161. package/modules/lifecycle/routes/task-route-helpers.js +21 -0
  162. package/modules/lifecycle/routes/task-write-routes.js +21 -3
  163. package/modules/lifecycle/routes/tasks.js +12 -12
  164. package/modules/lifecycle/task-needs-gate.js +70 -0
  165. package/modules/market-watch/CLAUDE.md +15 -0
  166. package/modules/market-watch/db.js +340 -0
  167. package/modules/market-watch/key.js +58 -0
  168. package/modules/market-watch/migrations/market_watch_001_tables.sql +249 -0
  169. package/modules/market-watch/migrations/market_watch_002_run.sql +46 -0
  170. package/modules/market-watch/module.json +26 -0
  171. package/modules/market-watch/pollers/hub-seed.js +54 -0
  172. package/modules/market-watch/pollers/weekly-run.js +100 -0
  173. package/modules/market-watch/research.js +350 -0
  174. package/modules/market-watch/run.js +245 -0
  175. package/modules/market-watch/seed/market-data.json +38 -0
  176. package/modules/market-watch/seed/partners-data.json +497 -0
  177. package/modules/market-watch/seed.js +252 -0
  178. package/modules/market-watch/store.js +230 -0
  179. package/modules/memory/routes/memory.js +14 -2
  180. package/modules/memory/routes/search.js +8 -2
  181. package/modules/platform-identity/account-logins.js +192 -0
  182. package/modules/platform-identity/migrations/platform_identity_034_account_logins.sql +96 -0
  183. package/modules/platform-identity/platform-identity.js +5 -4
  184. package/modules/platform-identity/routes/my-projects.js +6 -0
  185. package/modules/platform-identity/routes/profile.js +18 -0
  186. package/modules/platform-identity/routes/public-profile.js +10 -1
  187. package/modules/platform-identity/routes/sso.js +26 -1
  188. package/modules/platform-identity/tests/platform-identity.mjs +2 -1
  189. package/modules/provisioning/credential-preflight.js +13 -3
  190. package/modules/provisioning/pollers/app-liveness.js +25 -5
  191. package/modules/provisioning/routes/provisioning.js +1 -1
  192. package/modules/provisioning/starter-bundles.js +6 -2
  193. package/modules/public-landing/public/account.html +10 -2
  194. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg +0 -0
  195. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
  196. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
  197. package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +1 -1
  198. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp +0 -0
  199. package/modules/public-landing/public/assets/world/r2-chrome-blob-one-cut.webp.json +1 -1
  200. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg +0 -0
  201. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
  202. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
  203. package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +1 -1
  204. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg +0 -0
  205. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
  206. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
  207. package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +1 -1
  208. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp +0 -0
  209. package/modules/public-landing/public/assets/world/r3-frost-bead-cut.webp.json +1 -1
  210. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp +0 -0
  211. package/modules/public-landing/public/assets/world/r3-frost-pair-cut.webp.json +1 -1
  212. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp +0 -0
  213. package/modules/public-landing/public/assets/world/r3-gold-blob-cut.webp.json +1 -1
  214. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp +0 -0
  215. package/modules/public-landing/public/assets/world/r3-gold-pair-cut.webp.json +1 -1
  216. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp +0 -0
  217. package/modules/public-landing/public/assets/world/r3-obsidian-blob-cut.webp.json +1 -1
  218. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp +0 -0
  219. package/modules/public-landing/public/assets/world/r3-obsidian-pair-cut.webp.json +1 -1
  220. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg +0 -0
  221. package/modules/public-landing/public/assets/world/r3-space-nebula.jpg.json +1 -1
  222. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg +0 -0
  223. package/modules/public-landing/public/assets/world/r4-card-chrome.jpg.json +1 -1
  224. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg +0 -0
  225. package/modules/public-landing/public/assets/world/r4-card-nebula.jpg.json +1 -1
  226. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg +0 -0
  227. package/modules/public-landing/public/assets/world/r5-life-1-primordial-sea.jpg.json +1 -1
  228. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp +0 -0
  229. package/modules/public-landing/public/assets/world/r5-life-2-first-cells-cut.webp.json +1 -1
  230. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg +0 -0
  231. package/modules/public-landing/public/assets/world/r5-life-2-first-cells.jpg.json +1 -1
  232. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp +0 -0
  233. package/modules/public-landing/public/assets/world/r5-life-3-genome-cut.webp.json +1 -1
  234. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg +0 -0
  235. package/modules/public-landing/public/assets/world/r5-life-3-genome.jpg.json +1 -1
  236. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp +0 -0
  237. package/modules/public-landing/public/assets/world/r5-life-4-membrane-cut.webp.json +1 -1
  238. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg +0 -0
  239. package/modules/public-landing/public/assets/world/r5-life-4-membrane.jpg.json +1 -1
  240. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp +0 -0
  241. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system-cut.webp.json +1 -1
  242. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg +0 -0
  243. package/modules/public-landing/public/assets/world/r5-life-5-nervous-system.jpg.json +1 -1
  244. package/modules/public-landing/public/community.html +1 -1
  245. package/modules/public-landing/public/connections.html +2 -2
  246. package/modules/public-landing/public/guild.html +1 -1
  247. package/modules/public-landing/public/invitations.html +2 -2
  248. package/modules/public-landing/public/projects.html +5 -5
  249. package/modules/raise/views/nda.html +2 -0
  250. package/modules/specialities/db.js +32 -1
  251. package/modules/specialities/routes/specialities.js +10 -6
  252. package/modules/status-ui/public/index.html +1 -1
  253. package/package-lock.json +2 -2
  254. package/package.json +1 -1
  255. package/release-notes.json +230 -0
  256. package/scripts/bongos/autobongos-tweak-lane.js +46 -1
  257. package/scripts/bongos/backfill-subagent-rewards.js +2 -2
  258. package/scripts/bongos/claim.js +22 -1
  259. package/scripts/bongos/db-backup-nightly.sh +29 -0
  260. package/scripts/bongos/deploy-divergence.js +7 -0
  261. package/scripts/bongos/doc-cli-guard.js +6 -0
  262. package/scripts/bongos/fitness.js +3 -2
  263. package/scripts/bongos/gen-diagrams.js +3 -3
  264. package/scripts/bongos/government-walk.js +3 -0
  265. package/scripts/bongos/lib.sh +4 -5
  266. package/scripts/bongos/migration-namespace.js +13 -1
  267. package/scripts/bongos/plain-cards.js +4 -0
  268. package/scripts/bongos/provision-github-setup.js +3 -1
  269. package/scripts/bongos/provision-units.js +6 -1
  270. package/scripts/bongos/publish-manifest.js +3 -0
  271. package/scripts/bongos/release.js +2 -0
  272. package/scripts/bongos/run-unit-tests.js +268 -82
  273. package/scripts/bongos/seed-tasks.example.json +56 -0
  274. package/scripts/bongos/seed-tasks.js +222 -0
  275. package/scripts/bongos/seed-verify-criteria.js +1 -2
  276. package/scripts/bongos/ship-finish.js +2 -0
  277. package/scripts/bongos/ship-resume.js +2 -0
  278. package/scripts/bongos/strand-lease.js +250 -0
  279. package/scripts/bongos/strand-watch.js +26 -5
  280. package/scripts/bongos/version-literal-guard.js +2 -2
  281. package/scripts/discord/post.js +4 -3
  282. package/scripts/gds/seed-tasks.js +7 -0
  283. package/scripts/gds/{build-bongos.js → strand-lease.js} +3 -3
  284. package/scripts/hall-preview/server.js +21 -0
  285. package/src/bongos/auth-config.js +29 -1
  286. package/src/bongos/auth-discord.js +3 -3
  287. package/src/bongos/auth-github.js +3 -6
  288. package/src/bongos/auth-google.js +217 -0
  289. package/src/bongos/device-approval.js +140 -0
  290. package/src/bongos/llm-pricing.js +17 -1
  291. package/src/bongos/metrics.js +48 -2
  292. package/src/bongos/middleware/rate-limit.js +30 -11
  293. package/src/bongos/module-scope-map.js +12 -1
  294. package/src/bongos/optimizer.js +15 -1
  295. package/src/bongos/payout-approvals.js +342 -0
  296. package/src/bongos/payout-gates.js +364 -0
  297. package/src/bongos/prelaunch-gate.js +7 -9
  298. package/src/bongos/prelaunch-switch.js +20 -0
  299. package/src/bongos/route-rank-check.js +7 -0
  300. package/src/bongos/routes/auth-google.js +246 -0
  301. package/src/bongos/routes/auth.js +38 -1
  302. package/src/bongos/routes/backup.js +33 -9
  303. package/src/bongos/routes/builders.js +57 -30
  304. package/src/bongos/routes/github.js +9 -0
  305. package/src/bongos/routes/me.js +18 -0
  306. package/src/bongos/routes/my-payouts.js +133 -0
  307. package/src/bongos/routes/payout-approvals.js +312 -0
  308. package/src/bongos/routes/payout-gates.js +179 -0
  309. package/src/bongos/routes.js +15 -1
  310. package/src/bongos/secret-box.js +18 -3
  311. package/src/bongos/serve-internal.js +47 -19
  312. package/src/bongos/sign-in-pages.js +138 -0
  313. package/src/bongos/task-needs.js +146 -0
  314. package/src/bongos-downloads.js +18 -1
  315. package/src/instance-config.js +28 -0
  316. package/src/module-api.js +14 -1
  317. package/tests/access_holders.mjs +214 -0
  318. package/tests/account_logins.mjs +326 -0
  319. package/tests/account_logins_db.mjs +161 -0
  320. package/tests/ai_studio_billing.mjs +253 -0
  321. package/tests/ai_studio_generate.mjs +282 -0
  322. package/tests/ai_studio_keys.mjs +159 -0
  323. package/tests/ai_studio_requests.mjs +319 -0
  324. package/tests/auth_backchannel_logout_route.mjs +201 -0
  325. package/tests/auto_satisfy_criteria.mjs +10 -1
  326. package/tests/autobongos_tweak_lane.mjs +144 -0
  327. package/tests/autobongos_tweak_pin_identity.mjs +137 -0
  328. package/tests/backfill_subagent_rewards.mjs +17 -1
  329. package/tests/backup_trigger_lock.mjs +119 -0
  330. package/tests/blockers_people.mjs +198 -0
  331. package/tests/bounded_rate_maps.mjs +184 -0
  332. package/tests/claimable_blocker_status.mjs +1 -1
  333. package/tests/claims_batch_routes.mjs +421 -0
  334. package/tests/config_read_cache.mjs +171 -0
  335. package/tests/copy_desk_page_editor.mjs +12 -0
  336. package/tests/cost_write_guard.mjs +200 -0
  337. package/tests/craft_achievements.mjs +33 -10
  338. package/tests/criterion_goal_attach.mjs +1 -1
  339. package/tests/db_backup_nightly.mjs +73 -1
  340. package/tests/deploy_divergence_line.mjs +7 -0
  341. package/tests/effective_visibility_predicate.mjs +12 -0
  342. package/tests/fitness.mjs +19 -0
  343. package/tests/fixtures/seed-tasks/bongos-v1-idea-routing.json +256 -0
  344. package/tests/fixtures/seed-tasks/bv1-profiles.json +592 -0
  345. package/tests/fixtures/seed-tasks/bv2-ideator-surface.json +373 -0
  346. package/tests/fixtures/seed-tasks/fake-api.mjs +80 -0
  347. package/tests/github_one_trip.mjs +34 -0
  348. package/tests/github_repo_visibility.mjs +20 -0
  349. package/tests/goal_achievement.mjs +30 -1
  350. package/tests/goal_achievement_reward.mjs +205 -0
  351. package/tests/goal_sort_staleness.mjs +2 -1
  352. package/tests/goal_tier.mjs +11 -1
  353. package/tests/google_fonts_nonblocking.mjs +84 -0
  354. package/tests/google_sign_in.mjs +401 -0
  355. package/tests/government_board_expiry.mjs +94 -0
  356. package/tests/government_board_membership.mjs +4 -1
  357. package/tests/government_protected_surfaces.mjs +1 -1
  358. package/tests/government_routes.mjs +1 -1
  359. package/tests/government_seed.mjs +1 -0
  360. package/tests/hall_ai_studio.mjs +347 -0
  361. package/tests/hall_page_gate_map.mjs +3 -0
  362. package/tests/hall_studio_home.mjs +61 -2
  363. package/tests/home_attention_cards.mjs +1 -1
  364. package/tests/human_signal.mjs +141 -0
  365. package/tests/install_script_reader.mjs +51 -0
  366. package/tests/integration_fixture_ids.mjs +82 -0
  367. package/tests/invite_expiry_db.mjs +13 -1
  368. package/tests/lib_sh_resolution.mjs +0 -4
  369. package/tests/market_watch_data.mjs +244 -0
  370. package/tests/market_watch_data_db.mjs +308 -0
  371. package/tests/market_watch_module.mjs +114 -0
  372. package/tests/market_watch_run.mjs +503 -0
  373. package/tests/metrics.mjs +124 -0
  374. package/tests/migration_namespace.mjs +14 -0
  375. package/tests/module_api.mjs +2 -0
  376. package/tests/module_loader.mjs +1 -1
  377. package/tests/notes.mjs +182 -0
  378. package/tests/own_scope_guard.mjs +5 -0
  379. package/tests/page_tweak_marker_sql.mjs +76 -0
  380. package/tests/page_tweak_no_block.mjs +135 -0
  381. package/tests/page_tweak_notice.mjs +103 -0
  382. package/tests/payout_approvals.mjs +253 -0
  383. package/tests/payout_approvals_db.mjs +106 -0
  384. package/tests/payout_gates.mjs +322 -0
  385. package/tests/payout_gates_db.mjs +113 -0
  386. package/tests/planning_session_skill.mjs +13 -3
  387. package/tests/project_settings_page.mjs +29 -5
  388. package/tests/project_settings_spend_cap_route.mjs +235 -0
  389. package/tests/promotion_sweep.mjs +29 -1
  390. package/tests/provision.mjs +3 -2
  391. package/tests/provisioning_app_status.mjs +18 -0
  392. package/tests/provisioning_credential_preflight.mjs +53 -0
  393. package/tests/provisioning_env_manifest_edit_delete.mjs +223 -0
  394. package/tests/publish_reconciler_overlap.mjs +60 -0
  395. package/tests/rank_change_broadcast_port.mjs +151 -0
  396. package/tests/seed_tasks.mjs +176 -0
  397. package/tests/seed_verify_criteria.mjs +2 -6
  398. package/tests/site_classified_once.mjs +142 -0
  399. package/tests/speciality_db_shape.mjs +23 -0
  400. package/tests/speciality_session_skills.mjs +48 -2
  401. package/tests/strand_lease.mjs +249 -0
  402. package/tests/strand_watch.mjs +10 -0
  403. package/tests/task_criteria_routes.mjs +275 -0
  404. package/tests/task_criteria_unlink_db.mjs +123 -0
  405. package/tests/task_needs.mjs +233 -0
  406. package/tests/task_needs_db.mjs +110 -0
  407. package/tests/unit_runner_serial.mjs +266 -43
  408. package/tests/version_literals.mjs +5 -7
  409. package/tests/welcome_boot.mjs +16 -5
  410. package/tests/welcome_boot_browser.mjs +36 -4
  411. package/docs/recipes/bongos-cli-release.md +0 -66
  412. package/scripts/bongos/backfill-disciplines.js +0 -144
  413. package/scripts/bongos/backfill-session-earnings.js +0 -123
  414. package/scripts/bongos/backfill-session-types.js +0 -87
  415. package/scripts/bongos/build-bongos.js +0 -94
  416. package/scripts/bongos/cleanup-orphans.js +0 -74
  417. package/scripts/bongos/seed-bongos-v1-idea-routing-tasks.js +0 -152
  418. package/scripts/bongos/seed-bv1-profiles-tasks.js +0 -135
  419. package/scripts/bongos/seed-bv2-ideator-surface-tasks.js +0 -390
  420. package/scripts/bongos/smoke-batch-claim.sh +0 -238
  421. package/scripts/bongos/smoke-batch-release.sh +0 -316
  422. package/scripts/bongos/smoke-claim-consistency.sh +0 -222
  423. package/scripts/bongos/smoke-dependencies.sh +0 -143
  424. package/scripts/gds/backfill-disciplines.js +0 -7
  425. package/scripts/gds/backfill-session-earnings.js +0 -7
  426. package/scripts/gds/backfill-session-types.js +0 -7
  427. package/scripts/gds/cleanup-orphans.js +0 -7
  428. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +0 -6
  429. package/scripts/gds/seed-bv1-profiles-tasks.js +0 -6
  430. package/scripts/gds/seed-bv2-ideator-surface-tasks.js +0 -6
  431. package/scripts/gds/smoke-batch-claim.sh +0 -8
  432. package/scripts/gds/smoke-batch-release.sh +0 -8
  433. package/scripts/gds/smoke-claim-consistency.sh +0 -8
  434. package/scripts/gds/smoke-dependencies.sh +0 -8
  435. package/tests/smoke_dependencies_witness.mjs +0 -46
@@ -0,0 +1,193 @@
1
+ /* modules/hall-ui/public/ai-studio.css — the studio's AI pages,
2
+ /builders/ai-studio (task 1004921, goal 1000136).
3
+
4
+ Built 1:1 on option C of the AI Studio options canvas, the owner's pick: the
5
+ three steps, the waiting page, the result with its request to change and
6
+ make again, and the balance. It rides studio.css: the room, its night and
7
+ day tokens (--st-*) and the glass action rows are the studio's own, and this
8
+ sheet spends only those tokens, never a colour of its own. Where it differs
9
+ from the canvas, and why, is in modules/hall-ui/records/ai-studio.md. */
10
+
11
+ .ais-page { position: relative; z-index: 1; width: min(580px, 100%); display: flex; flex-direction: column; gap: 22px; }
12
+ .ais[data-view="result"] .ais-page { width: 100%; }
13
+ .ais-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
14
+
15
+ .ais-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
16
+ .ais-quiet, .ais-note { margin: 0; font-size: 17px; line-height: 1.5; color: var(--st-ink-soft); }
17
+ .ais-soft { color: var(--st-ink-soft); }
18
+ .ais-faint { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--st-ink-faint); }
19
+ .ais-dim { font-size: 13px; color: var(--st-ink-dim); white-space: nowrap; }
20
+ .ais-grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21
+ .ais-wrap { white-space: normal; }
22
+ .ais-head { font-family: var(--st-mono); font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--st-ink-faint); }
23
+ .ais-back { align-self: flex-start; display: inline-flex; align-items: center; min-height: 32px; }
24
+ .ais [data-head]:focus { outline: none; }
25
+ .ais [data-head]:focus-visible { outline: 2px solid var(--st-focus); outline-offset: 4px; }
26
+
27
+ /* The step line: back, then "1 Pick ✓ 2 Describe 3 Make". */
28
+ .ais-bar { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
29
+ .ais-marks { margin-left: auto; display: flex; gap: 18px; font-size: 13px; }
30
+ .ais-mark--done { color: var(--st-link); }
31
+ .ais-mark--now { color: var(--st-ink); font-weight: 500; }
32
+ .ais-mark--later { color: var(--st-ink-dim); }
33
+
34
+ .ais-ask { margin: 20px 0 0; font-size: 44px; font-weight: 200; letter-spacing: -.03em; line-height: 1.1; color: var(--st-ink); }
35
+ .ais-ask label { cursor: text; }
36
+
37
+ /* Step 1: the drop zone and the one-line file rows. */
38
+ .ais-drop {
39
+ display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
40
+ min-height: 120px; padding: 16px; box-sizing: border-box; text-align: center;
41
+ border-radius: 18px; border: 1.5px dashed var(--st-rule); color: var(--st-ink-soft); font-size: 14px;
42
+ }
43
+ .ais-drop--over { border-color: var(--st-focus); background: var(--st-glass); }
44
+ .ais-link {
45
+ display: inline-flex; align-items: center; min-height: 24px; min-width: 24px; padding: 0; border: 0; background: none;
46
+ font: inherit; color: var(--st-link); text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
47
+ }
48
+ .ais-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
49
+ .ais-row {
50
+ display: flex; align-items: center; gap: 14px; min-height: 48px; padding: 0 18px; box-sizing: border-box;
51
+ border-radius: 16px; background: var(--st-glass); border: 1px solid var(--st-glass-edge); font-size: 14px; color: var(--st-ink);
52
+ }
53
+ .ais-row--summary { min-height: 56px; }
54
+ .ais-thumb { flex: none; width: 28px; height: 28px; border-radius: 7px; object-fit: cover; background: var(--st-track); }
55
+ .ais-thumb--pdf { display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: var(--st-link); }
56
+ .ais-remove {
57
+ min-height: 24px; min-width: 24px; padding: 0 2px; border: 0; background: none; cursor: pointer;
58
+ font: inherit; font-size: 13px; color: var(--st-ink-dim);
59
+ }
60
+ .ais-remove:hover { color: var(--st-ink); }
61
+ .ais-err-inline { font-size: 13px; color: var(--st-danger); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 45%; }
62
+
63
+ /* Buttons: the studio's accent pill and its quiet ghost. */
64
+ .ais-go { display: flex; align-items: center; gap: 16px; }
65
+ .ais-go--wrap { flex-wrap: wrap; gap: 10px; }
66
+ .ais-btn {
67
+ display: inline-flex; align-items: center; justify-content: center; height: 48px; padding: 0 26px; border-radius: 999px;
68
+ border: 0; background: var(--st-accent); color: var(--st-on-accent); font: inherit; font-size: 15px; font-weight: 500; cursor: pointer;
69
+ }
70
+ .ais-btn:disabled { opacity: .5; cursor: default; }
71
+ .ais-ghost {
72
+ display: inline-flex; align-items: center; justify-content: center; height: 44px; padding: 0 18px; border-radius: 999px;
73
+ border: 0; background: var(--st-close); color: var(--st-ink); font: inherit; font-size: 14px; text-decoration: none; cursor: pointer;
74
+ }
75
+ .ais a.ais-ghost:hover { color: var(--st-ink); border-color: var(--st-focus); }
76
+ .ais-btn:focus-visible, .ais-ghost:focus-visible, .ais-link:focus-visible, .ais-remove:focus-visible,
77
+ .ais-chip:focus-visible, .ais-pick:focus-visible, .ais-back:focus-visible { outline: 2px solid var(--st-focus); outline-offset: 3px; }
78
+
79
+ /* Step 2: the request box (also the result's "Your request"). */
80
+ .ais-field {
81
+ width: 100%; box-sizing: border-box; min-height: 96px; padding: 16px 18px; resize: vertical;
82
+ border-radius: 18px; background: var(--st-glass); border: 1px solid var(--st-panel-edge);
83
+ color: var(--st-ink); font: inherit; font-size: 15px; line-height: 1.5; font-weight: 300;
84
+ }
85
+ .ais-field--tall { min-height: 160px; font-size: 16px; }
86
+ .ais-field::placeholder { color: var(--st-ink-dim); }
87
+ .ais-field:focus-visible { outline: 2px solid var(--st-focus); outline-offset: 2px; }
88
+
89
+ /* Step 3: the two pay cards, the studio's glass action rows made tall. */
90
+ .ais-cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
91
+ .ais .ais-card { min-height: 150px; justify-content: flex-start; padding-top: 22px; font: inherit; }
92
+ .ais .ais-card--ours { background: var(--st-glass); border-color: var(--st-glass-edge); }
93
+ .ais .ais-card:disabled { opacity: .55; cursor: default; }
94
+ .ais .ais-card[aria-busy="true"] { border-color: var(--st-focus); }
95
+ .ais-card__line { font-size: 13.5px; line-height: 1.45; color: var(--st-ink-soft); }
96
+ .ais-card__foot { margin-top: 10px; font-size: 13px; color: var(--st-ink-dim); }
97
+
98
+ .ais-err { margin: 0; font-size: 14px; line-height: 1.5; color: var(--st-danger); }
99
+ .ais-err[hidden] { display: none; }
100
+
101
+ /* The waiting page: the clock, the three lines, and the lamp turned up. */
102
+ .ais-wait { margin-top: 70px; display: flex; flex-direction: column; gap: 18px; }
103
+ .ais-clock { margin: 0; font-family: var(--st-mono); font-size: 56px; font-weight: 200; letter-spacing: -.03em; line-height: 1; color: var(--st-ink); font-variant-numeric: tabular-nums; }
104
+ .ais-wait > .ais-soft { margin: -10px 0 0; }
105
+ .ais-checks { list-style: none; margin: 0; padding: 0; width: min(420px, 100%); }
106
+ .ais-check { display: flex; align-items: center; gap: 12px; min-height: 40px; border-top: 1px solid var(--st-track); font-size: 14px; color: var(--st-ink); }
107
+ .ais-check:first-child { border-top: 0; }
108
+ .ais-check__mark { width: 22px; flex: none; color: var(--st-link); }
109
+ .ais-check--now .ais-check__mark::before {
110
+ content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%;
111
+ background: var(--st-accent); box-shadow: 0 0 0 4px var(--st-resume);
112
+ }
113
+ .ais-check--later { color: var(--st-ink-dim); }
114
+ /* By day the room's lamp is off; while a request runs it is on in either sky,
115
+ so "the lamp stays on until it's done" holds at noon too. */
116
+ .ais[data-making="on"] .st-glow { opacity: 1; transform: scale(1.35); background: radial-gradient(circle, var(--st-glow) 0%, var(--st-glow) 20%, var(--st-glow-out) 65%); }
117
+ .ais[data-making="on"] .st-lamp-shade { box-shadow: 0 18px 40px var(--st-glow); }
118
+
119
+ /* The result: the picture on the left, the words, the request and the receipt
120
+ on the right. The canvas draws it over the bare floor, so the window steps
121
+ back. */
122
+ .ais[data-view="result"] .st-window,
123
+ .ais[data-view="result"] .st-glow,
124
+ .ais[data-view="result"] .st-lamp-stem,
125
+ .ais[data-view="result"] .st-lamp-shade,
126
+ .ais[data-view="result"] .st-mug,
127
+ .ais[data-view="result"] .st-leaf { display: none; }
128
+ .ais-result { display: flex; gap: 40px; align-items: flex-start; }
129
+ .ais-result__art { width: min(640px, 55%); flex: none; display: flex; flex-direction: column; gap: 12px; }
130
+ .ais-result__words { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 16px; padding-top: 44px; }
131
+ .ais-big { display: block; width: 100%; height: 520px; object-fit: cover; border-radius: 16px; background: var(--st-track); }
132
+ .ais-big--none { display: flex; align-items: center; justify-content: center; height: 240px; background: var(--st-glass); border: 1px solid var(--st-glass-edge); box-sizing: border-box; }
133
+ .ais-thumbs { display: flex; align-items: center; gap: 10px; }
134
+ .ais-pick { width: 96px; height: 64px; padding: 0; border: 0; border-radius: 10px; overflow: hidden; background: none; cursor: pointer; }
135
+ .ais-pick img { display: block; width: 100%; height: 100%; object-fit: cover; }
136
+ .ais-pick--on { outline: 2px solid var(--st-accent); outline-offset: 0; }
137
+ .ais-reply p { margin: 0 0 12px; font-size: 15px; line-height: 1.6; color: var(--st-ink-sub); font-weight: 300; }
138
+ .ais-reply b { color: var(--st-ink); font-weight: 500; }
139
+ .ais-again { display: flex; flex-direction: column; gap: 8px; }
140
+ .ais-receipt, .ais-topup {
141
+ display: flex; flex-direction: column; padding: 10px 20px; border-radius: 22px;
142
+ background: var(--st-glass); border: 1px solid var(--st-glass-edge);
143
+ }
144
+ .ais-line { display: flex; align-items: center; gap: 14px; min-height: 40px; border-top: 1px solid var(--st-track); font-size: 14px; color: var(--st-ink); }
145
+ .ais-line:first-child, .ais-head + .ais-line { border-top: 0; }
146
+ .ais-line a { color: var(--st-link); display: inline-flex; align-items: center; min-height: 24px; }
147
+
148
+ /* The balance. */
149
+ .ais-balance { display: flex; flex-direction: column; gap: 24px; margin-top: 20px; }
150
+ .ais-figure { margin: 0; display: flex; align-items: baseline; gap: 16px; font-weight: 400; font-size: 17px; }
151
+ .ais-big-num { font-family: var(--st-mono); font-size: 56px; font-weight: 200; letter-spacing: -.03em; line-height: 1; color: var(--st-ink); font-variant-numeric: tabular-nums; }
152
+ .ais-topup { gap: 10px; padding: 18px 20px; background: none; border: 0; padding-left: 0; padding-right: 0; }
153
+ .ais-chips { display: flex; gap: 8px; flex-wrap: wrap; }
154
+ .ais-chip {
155
+ display: inline-flex; align-items: center; height: 36px; padding: 0 16px; border-radius: 999px; cursor: pointer;
156
+ border: 1px solid var(--st-chip-edge); background: none; color: var(--st-ink); font: inherit; font-size: 13.5px;
157
+ }
158
+ .ais-chip[aria-pressed="true"] { background: var(--st-resume); border-color: var(--st-resume-edge); }
159
+ .ais-other { display: flex; align-items: center; gap: 12px; }
160
+ .ais-other input {
161
+ width: 120px; height: 40px; padding: 0 12px; box-sizing: border-box; border-radius: 12px;
162
+ border: 1px solid var(--st-panel-edge); background: var(--st-glass); color: var(--st-ink); font: inherit;
163
+ }
164
+ .ais-ledger { display: flex; flex-direction: column; margin-top: 8px; }
165
+ .ais-ledger > .ais-head { margin-bottom: 4px; }
166
+ .ais-all { display: flex; flex-direction: column; }
167
+ .ais-date { width: 64px; flex: none; font-family: var(--st-mono); font-size: 12px; color: var(--st-ink-dim); }
168
+ .ais-detail { white-space: nowrap; font-size: 12.5px; }
169
+ .ais-num { font-family: var(--st-mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
170
+ .ais-tone-ok { color: var(--st-link); }
171
+ .ais-tone-dim { color: var(--st-ink-dim); }
172
+
173
+ @media (max-width: 1100px) {
174
+ .ais-result { flex-direction: column; gap: 20px; }
175
+ .ais-result__art { width: 100%; }
176
+ .ais-result__words { padding-top: 0; width: 100%; }
177
+ }
178
+ /* On a phone the studio scales its window into the top right and stands the
179
+ desk on the floor at the bottom; the words start below the window and end
180
+ above the plant, so no line is read over the drawing. */
181
+ @media (max-width: 760px) {
182
+ .studio.ais { padding-bottom: 240px; }
183
+ .ais-page { gap: 18px; }
184
+ .ais-ask { margin-top: 196px; font-size: 32px; }
185
+ .ais-marks { margin-left: 0; width: 100%; gap: 14px; }
186
+ .ais-cards { grid-template-columns: minmax(0, 1fr); }
187
+ .ais .ais-card { min-height: 120px; }
188
+ .ais-wait { margin-top: 210px; }
189
+ .ais-balance { margin-top: 210px; }
190
+ .ais-big { height: auto; aspect-ratio: 4 / 3; }
191
+ .ais-detail { display: none; }
192
+ .ais-err-inline { max-width: 40%; }
193
+ }
@@ -0,0 +1,98 @@
1
+ <!doctype html>
2
+ <!-- data-artist="on": the studio's mode marker, as on studio.html. These pages
3
+ are rooms of the studio, so entering them is still entering the mode. -->
4
+ <html lang="en" data-artist="on">
5
+ <head>
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ <title>Studio — {{worldName}}</title>
9
+ <meta name="description" content="Make something with AI in the studio: bring sketches, pictures or a PDF, say what you want, and get an answer and pictures back.">
10
+ <link rel="icon" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><text x='16' y='24' font-size='24' text-anchor='middle' font-family='sans-serif'>⌂</text></svg>">
11
+ <link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
12
+ <link rel="stylesheet" href="/builders/studio.css?v=2026-10-09-day">
13
+ <link rel="stylesheet" href="/builders/ai-studio.css?v=2026-10-29-ais1">
14
+ </head>
15
+ <!-- THE STUDIO'S AI PAGES (task 1004921, goal 1000136; ADR 0392). Built 1:1 on
16
+ the owner's pick, option C of the AI Studio options canvas ("Three steps:
17
+ pick, describe, make"), plus the owner's addition: the results page lets
18
+ the request be changed and made again. One page, four views, each a FULL
19
+ page in the studio's own room (never a dialog):
20
+ ?step=pick|describe|make the three steps
21
+ ?request=N the waiting page, then the result
22
+ ?view=balance what is left, add money, every charge
23
+ data-page="ai-studio" is the page's own id (page-inventory.js); studio.css
24
+ names it beside "studio" on the room's rules, so the room, its tokens and
25
+ its two skies apply unchanged. The words and rules are
26
+ ai-studio-lib.js; the record is modules/hall-ui/records/ai-studio.md. A key
27
+ is NEVER asked for here: it is entered only in Settings. -->
28
+ <body data-page="ai-studio" data-page-title="Studio" data-fullscreen-switch>
29
+
30
+ <div class="app">
31
+ <aside class="app-sidebar" id="app-sidebar" aria-label="Primary"></aside>
32
+ <div class="app-scrim" id="app-scrim" hidden></div>
33
+ <div class="app-body">
34
+ <header class="app-topbar" id="app-topbar"></header>
35
+ <div class="app-content">
36
+
37
+ <main id="hall-main" class="studio ais" data-view="step">
38
+ <!-- The studio's room, drawn as studio.html draws it. -->
39
+ <div class="st-room" aria-hidden="true">
40
+ <div class="st-window">
41
+ <span class="st-moon"></span>
42
+ <span class="st-star st-star--1"></span>
43
+ <span class="st-star st-star--2"></span>
44
+ <span class="st-star st-star--3"></span>
45
+ <span class="st-star st-star--4"></span>
46
+ <span class="st-star st-star--5"></span>
47
+ <span class="st-cloud st-cloud--1"></span>
48
+ <span class="st-cloud st-cloud--2"></span>
49
+ <span class="st-tower st-tower--1"></span>
50
+ <span class="st-tower st-tower--2"></span>
51
+ <span class="st-tower st-tower--3"></span>
52
+ <span class="st-tower st-tower--4"></span>
53
+ <span class="st-tower st-tower--5"></span>
54
+ <span class="st-light st-light--1"></span>
55
+ <span class="st-light st-light--2"></span>
56
+ <span class="st-light st-light--3"></span>
57
+ <span class="st-light st-light--4"></span>
58
+ <span class="st-light st-light--5"></span>
59
+ <span class="st-light st-light--6"></span>
60
+ <span class="st-light st-light--7"></span>
61
+ <span class="st-mullion"></span>
62
+ </div>
63
+ <div class="st-floor"></div>
64
+ <div class="st-sunpatch"></div>
65
+ <div class="st-glow"></div>
66
+ <div class="st-lamp-stem"></div>
67
+ <div class="st-lamp-shade"></div>
68
+ <div class="st-mug"></div>
69
+ <div class="st-leaf st-leaf--1"></div>
70
+ <div class="st-leaf st-leaf--2"></div>
71
+ </div>
72
+
73
+ <!-- The view, painted by ai-studio.js. The page's one <h1> is each
74
+ view's own question or figure. -->
75
+ <div class="ais-page" id="ais-page">
76
+ <p class="ais-quiet">Opening…</p>
77
+ </div>
78
+ <input type="file" id="ais-file" class="ais-file" multiple accept="image/png,image/jpeg,image/gif,image/webp,application/pdf" tabindex="-1" aria-hidden="true">
79
+ </main>
80
+
81
+ <footer class="app-foot" id="app-foot"></footer>
82
+ </div>
83
+ </div>
84
+ </div>
85
+
86
+ <div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
87
+
88
+ <script src="/builders/dom-utils.js?v=2026-10-25-escape"></script>
89
+ <script src="/builders/shell-trail.js?v=2026-10-08-city-tab"></script>
90
+ <script src="/builders/craft-mode.js?v=2026-10-09-living3"></script>
91
+ <script src="/builders/shell.js?v=2026-10-25-escape"></script>
92
+ <script src="/builders/palette.js" defer></script>
93
+ <script src="/builders/tweak-editor-lib.js?v=2026-09-28-tw23"></script>
94
+ <script src="/builders/studio-lib.js?v=2026-10-09-day"></script>
95
+ <script src="/builders/ai-studio-lib.js?v=2026-10-29-ais1"></script>
96
+ <script src="/builders/ai-studio.js?v=2026-10-29-ais1"></script>
97
+ </body>
98
+ </html>