@bongos/core 1.24.79 → 1.24.81
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.
- package/.bongos-core.json +554 -394
- package/.claude/skills/ask-for-help/SKILL.md +1 -1
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/design/SKILL.md +1 -1
- package/.claude/skills/goal-create/SKILL.md +1 -1
- package/.claude/skills/planning-session/SKILL.md +1 -1
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +8 -0
- package/clients/bongos-client/index.cjs +8 -0
- package/clients/bongos-client/index.d.ts +11 -0
- package/clients/bongos-client/index.mjs +8 -0
- package/docs/adr/0274-one-kernel-three-role-packs.md +2 -2
- package/docs/adr/0399-the-visor-is-glass-over-the-scene-and-owns-no-camera.md +91 -0
- package/docs/adr/0400-a-chain-reserves-work-and-each-sub-quest-is-still-claimed-alone.md +109 -0
- package/docs/adr/0401-one-options-menu-opens-every-settings-screen-in-a-frame.md +53 -0
- package/docs/adr/0402-helm-is-the-halls-look-and-the-hall-is-dark-only.md +142 -0
- package/docs/adr/README.md +4 -0
- package/docs/api/openapi.json +195 -3
- package/docs/api-reference.md +8 -4
- package/docs/architecture.md +7 -3
- package/docs/copy-inventory.md +393 -378
- package/docs/copy-registry.json +722 -578
- package/docs/design/characters/character-sprites-source.webp +0 -0
- package/docs/file-map.md +7 -8
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +5 -0
- package/docs/onboarding/slash-commands.md +1 -1
- package/docs/packs/{engineer.md → artisan.md} +5 -5
- package/docs/packs/artist.md +50 -4
- package/docs/page-inventory.json +16 -7
- package/docs/page-readings.json +3184 -3338
- package/docs/{packs/ideator.md → recipes/ideation-playbook.md} +5 -48
- package/migrations/core_296_crafts_artisan_artist.sql +72 -0
- package/migrations/core_297_builder_character.sql +30 -0
- package/modules/copy-desk/proposals.js +1 -1
- package/modules/economy/credits-by-craft.js +29 -15
- package/modules/hall-ui/public/ai-studio.html +6 -4
- package/modules/hall-ui/public/ai-studio.states.json +1 -0
- package/modules/hall-ui/public/atlas.html +5 -5
- package/modules/hall-ui/public/atlas.js +3 -1
- package/modules/hall-ui/public/atlas.states.json +1 -0
- package/modules/hall-ui/public/blockers.html +5 -5
- package/modules/hall-ui/public/board-room.html +4 -4
- package/modules/hall-ui/public/board-room.states.json +1 -0
- package/modules/hall-ui/public/characters/artisan.png +0 -0
- package/modules/hall-ui/public/characters/artist.png +0 -0
- package/modules/hall-ui/public/characters/patron.png +0 -0
- package/modules/hall-ui/public/city.css +3 -4
- package/modules/hall-ui/public/city.html +9 -9
- package/modules/hall-ui/public/city.js +17 -56
- package/modules/hall-ui/public/city.states.json +7 -32
- package/modules/hall-ui/public/collab.html +4 -4
- package/modules/hall-ui/public/collab.states.json +1 -0
- package/modules/hall-ui/public/commands.html +4 -4
- package/modules/hall-ui/public/commands.states.json +1 -0
- package/modules/hall-ui/public/controls.css +63 -11
- package/modules/hall-ui/public/copy-desk.html +4 -4
- package/modules/hall-ui/public/copy-desk.states.json +1 -0
- package/modules/hall-ui/public/craft-mode.js +258 -64
- package/modules/hall-ui/public/deploy.html +4 -4
- package/modules/hall-ui/public/deploy.states.json +1 -0
- package/modules/hall-ui/public/diagram-viewer.js +2 -1
- package/modules/hall-ui/public/dom-utils.js +1 -1
- package/modules/hall-ui/public/goal-map.html +9 -6
- package/modules/hall-ui/public/goals.html +5 -5
- package/modules/hall-ui/public/goals.states.json +1 -0
- package/modules/hall-ui/public/government.html +4 -4
- package/modules/hall-ui/public/government.states.json +1 -0
- package/modules/hall-ui/public/hall-render.js +3 -1
- package/modules/hall-ui/public/home-city-draw.js +3 -3
- package/modules/hall-ui/public/home-city.css +4 -0
- package/modules/hall-ui/public/home-city.js +17 -9
- package/modules/hall-ui/public/home-gallery.js +8 -1
- package/modules/hall-ui/public/home-idea-box.css +2 -2
- package/modules/hall-ui/public/home-idea-box.js +3 -3
- package/modules/hall-ui/public/idea.html +5 -5
- package/modules/hall-ui/public/idea.states.json +1 -0
- package/modules/hall-ui/public/ideas.html +5 -5
- package/modules/hall-ui/public/ideas.states.json +1 -0
- package/modules/hall-ui/public/index-founding.states.json +1 -0
- package/modules/hall-ui/public/index-genesis-decide.states.json +1 -0
- package/modules/hall-ui/public/index-genesis-demo.states.json +1 -0
- package/modules/hall-ui/public/index-genesis.states.json +1 -0
- package/modules/hall-ui/public/index.html +11 -7
- package/modules/hall-ui/public/index.states.json +1 -0
- package/modules/hall-ui/public/market-watch-item.html +4 -4
- package/modules/hall-ui/public/market-watch-item.states.json +1 -0
- package/modules/hall-ui/public/market-watch-rules.html +4 -4
- package/modules/hall-ui/public/market-watch-rules.states.json +1 -0
- package/modules/hall-ui/public/market-watch.html +6 -9
- package/modules/hall-ui/public/market-watch.js +22 -45
- package/modules/hall-ui/public/market-watch.states.json +1 -0
- package/modules/hall-ui/public/modules.html +4 -4
- package/modules/hall-ui/public/modules.states.json +1 -0
- package/modules/hall-ui/public/money.html +4 -4
- package/modules/hall-ui/public/money.states.json +1 -0
- package/modules/hall-ui/public/my-agents.html +4 -4
- package/modules/hall-ui/public/my-agents.states.json +1 -0
- package/modules/hall-ui/public/options-menu.js +409 -0
- package/modules/hall-ui/public/paintbrush.js +3 -3
- package/modules/hall-ui/public/palette.js +11 -13
- package/modules/hall-ui/public/primer.html +5 -5
- package/modules/hall-ui/public/primer.states.json +1 -0
- package/modules/hall-ui/public/profile-crafts.js +1 -1
- package/modules/hall-ui/public/profile-roles.js +23 -19
- package/modules/hall-ui/public/profile.css +1 -1
- package/modules/hall-ui/public/profile.html +19 -18
- package/modules/hall-ui/public/profile.js +19 -18
- package/modules/hall-ui/public/profile.states.json +5 -4
- package/modules/hall-ui/public/project-settings.html +4 -4
- package/modules/hall-ui/public/roster.html +4 -4
- package/modules/hall-ui/public/roster.js +3 -3
- package/modules/hall-ui/public/roster.states.json +1 -0
- package/modules/hall-ui/public/settings.css +24 -4
- package/modules/hall-ui/public/settings.html +21 -17
- package/modules/hall-ui/public/settings.js +44 -44
- package/modules/hall-ui/public/settings.states.json +1 -0
- package/modules/hall-ui/public/shell-game.css +110 -0
- package/modules/hall-ui/public/shell-game.js +316 -3
- package/modules/hall-ui/public/shell.js +15 -66
- package/modules/hall-ui/public/sky-interaction.js +7 -0
- package/modules/hall-ui/public/speciality-tools.js +1 -2
- package/modules/hall-ui/public/street-card.states.json +1 -0
- package/modules/hall-ui/public/street-inside.js +3 -4
- package/modules/hall-ui/public/street.css +1 -5
- package/modules/hall-ui/public/street.html +6 -10
- package/modules/hall-ui/public/street.js +8 -59
- package/modules/hall-ui/public/street.states.json +7 -32
- package/modules/hall-ui/public/studio.html +5 -5
- package/modules/hall-ui/public/studio.states.json +1 -0
- package/modules/hall-ui/public/style.css +197 -112
- package/modules/hall-ui/public/task-detail.js +5 -4
- package/modules/hall-ui/public/task.html +5 -5
- package/modules/hall-ui/public/task.states.json +1 -0
- package/modules/hall-ui/public/thinking.css +10 -0
- package/modules/hall-ui/public/thinking.html +9 -6
- package/modules/hall-ui/public/thinking.states.json +1 -0
- package/modules/hall-ui/public/tweak-editor.html +5 -5
- package/modules/hall-ui/public/tweak-editor.js +5 -1
- package/modules/hall-ui/public/tweak-editor.states.json +1 -0
- package/modules/hall-ui/public/update-pill.js +91 -2
- package/modules/hall-ui/public/visor.css +80 -0
- package/modules/hall-ui/public/visor.js +316 -0
- package/modules/hall-ui/public/watch-repo-invite.js +159 -0
- package/modules/hall-ui/public/watch.html +6 -5
- package/modules/hall-ui/public/watch.js +17 -2
- package/modules/hall-ui/public/watch.states.json +1 -0
- package/modules/hall-ui/public/welcome-boot.js +15 -6
- package/modules/hall-ui/public/work-founding.states.json +1 -0
- package/modules/hall-ui/public/work.html +5 -5
- package/modules/hall-ui/public/work.states.json +1 -0
- package/modules/hall-ui/records/builders-roster.md +2 -2
- package/modules/hall-ui/records/craft-mode.md +13 -11
- package/modules/hall-ui/records/game-mode.md +2 -2
- package/modules/hall-ui/records/governor-street.md +1 -1
- package/modules/hall-ui/records/home-city.md +3 -1
- package/modules/hall-ui/records/market-watch-settings.md +2 -0
- package/modules/hall-ui/records/options-menu.md +15 -0
- package/modules/hall-ui/records/profile-roles.md +11 -11
- package/modules/hall-ui/records/sky.md +3 -3
- package/modules/hall-ui/records/start-screen.md +25 -0
- package/modules/hall-ui/records/tweak-editor.md +1 -1
- package/modules/hall-ui/records/update-pill.md +12 -0
- package/modules/hall-ui/records/visor.md +23 -0
- package/modules/hall-ui/records/welcome-tower.md +5 -5
- package/modules/hall-ui/specimens/components.states.json +2 -1
- package/modules/ideas/ideator-stats.js +3 -1
- package/modules/ideas/inbox.js +2 -2
- package/modules/lifecycle/activity.js +1 -1
- package/modules/lifecycle/cascade.js +4 -4
- package/modules/lifecycle/goal-spec-task.js +1 -1
- package/modules/lifecycle/help-requests.js +19 -15
- package/modules/lifecycle/kickoff-checklist.js +3 -3
- package/modules/lifecycle/kickoff-seed.js +1 -1
- package/modules/lifecycle/migrations/lifecycle_021_crafts_artisan_artist.sql +29 -0
- package/modules/lifecycle/mingle.js +4 -4
- package/modules/lifecycle/page-tweak-write.js +1 -1
- package/modules/lifecycle/routes/task-write-routes.js +3 -1
- package/modules/lifecycle/routes/tasks.js +3 -3
- package/modules/lifecycle/ship-card.js +2 -3
- package/modules/lifecycle/task-classifier.js +39 -29
- package/modules/lifecycle/tests/cascade.mjs +7 -7
- package/modules/onboarding/founding-mode.js +3 -0
- package/modules/onboarding/genesis-home.js +21 -1
- package/modules/onboarding/routes/onboarding.js +2 -0
- package/modules/page-notes/notes.js +3 -2
- package/modules/page-notes/split.js +1 -1
- package/modules/platform-identity/craft-rollup.js +35 -7
- package/modules/platform-identity/migrations/platform_identity_036_crafts_artisan_artist.sql +45 -0
- package/modules/platform-identity/platform-identity.js +2 -2
- package/modules/platform-identity/routes/community-leaderboard.js +2 -1
- package/modules/platform-identity/routes/community-search.js +2 -1
- package/modules/platform-identity/routes/sso.js +2 -1
- package/modules/platform-identity/tests/platform-identity.mjs +6 -6
- package/modules/public-landing/public/community.html +3 -5
- package/modules/public-landing/public/index.html +1 -1
- package/modules/public-landing/public/projects.html +1 -1
- package/modules/specialities/migrations/specialities_004_crafts_artisan_artist.sql +30 -0
- package/modules/specialities/routes/specialities.js +2 -2
- package/modules/status-ui/public/status.js +1 -1
- package/modules/ui-design/kit/fixtures/community-leaderboard.json +10 -10
- package/modules/ui-design/kit/fixtures/community-search.json +2 -2
- package/modules/ui-design/kit/fixtures/scouting-recruiter.json +1 -1
- package/modules/ui-design/public/brand.html +2 -2
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +76 -0
- package/scripts/bongos/autobongos-loop.js +1 -1
- package/scripts/bongos/discipline-modes.json +7 -12
- package/scripts/bongos/fitness.js +1 -1
- package/scripts/bongos/gen-hall-sitemap.js +7 -7
- package/scripts/bongos/grade-smoke.js +2 -2
- package/scripts/bongos/init.js +2 -2
- package/scripts/bongos/newcomer-floor.config.json +1 -2
- package/scripts/bongos/newcomer-floor.js +4 -3
- package/scripts/bongos/newcomer-floor.templates.json +10 -12
- package/scripts/bongos/newcomer-floor.test.js +47 -38
- package/scripts/bongos/role-pack-guard.js +5 -4
- package/scripts/bongos/seed-tasks.example.json +3 -3
- package/scripts/bongos/setup.js +20 -107
- package/scripts/bongos/start.js +2 -2
- package/scripts/bongos/task.js +5 -4
- package/scripts/bongos/triage.js +1 -1
- package/scripts/bongos/worktree.js +16 -4
- package/scripts/hall-preview/README.md +2 -3
- package/scripts/setup-builder.js +6 -46
- package/src/bongos/auth-admission.js +8 -8
- package/src/bongos/craft-mode.js +2 -0
- package/src/bongos/db.js +39 -1
- package/src/bongos/github-repos.js +78 -0
- package/src/bongos/module-scope-map.js +22 -0
- package/src/bongos/role-stats.js +27 -11
- package/src/bongos/routes/github.js +100 -2
- package/src/bongos/routes/me.js +33 -0
- package/src/bongos/serve-internal.js +33 -11
- package/src/crafts.js +66 -0
- package/src/hall-helm.js +79 -0
- package/src/module-api.js +6 -1
- package/src/module-loader/manifest-schema.js +16 -0
- package/src/modules.js +2 -2
- package/src/role-responsibilities.js +6 -5
- package/tests/acclaim_feed_evidence_db.mjs +1 -1
- package/tests/activity_rollup_as_of.mjs +1 -1
- package/tests/api_alias_caller_ratchet.mjs +3 -3
- package/tests/application_lifecycle.mjs +1 -1
- package/tests/artist_review.mjs +1 -1
- package/tests/artist_review_goal.mjs +1 -1
- package/tests/blocker_hall_live_proof.mjs +1 -1
- package/tests/blocker_tasks_named_db.mjs +2 -2
- package/tests/canonical_profile_url.mjs +1 -1
- package/tests/cap_newcomer_tasks.mjs +13 -13
- package/tests/character_creation.mjs +294 -0
- package/tests/claim_gate_open_blocker.mjs +2 -2
- package/tests/claim_gate_rebase.mjs +6 -6
- package/tests/claude_materialize.mjs +1 -1
- package/tests/clawback_confirmed_backlog.mjs +3 -3
- package/tests/collab_page.mjs +8 -9
- package/tests/collab_self_settling.mjs +2 -2
- package/tests/community_leaderboard_route.mjs +13 -5
- package/tests/community_proof_db.mjs +3 -0
- package/tests/community_search_route.mjs +7 -6
- package/tests/conductor.mjs +1 -1
- package/tests/conductor_main_e2e.mjs +8 -8
- package/tests/copy_desk_flags_db.mjs +1 -1
- package/tests/copy_desk_page_approve.mjs +2 -2
- package/tests/copy_desk_page_claim.mjs +2 -2
- package/tests/copy_desk_page_next.mjs +1 -1
- package/tests/copy_desk_page_release.mjs +1 -1
- package/tests/copy_desk_page_submit.mjs +2 -2
- package/tests/core_258_box_session_claims_db.mjs +1 -1
- package/tests/craft_mode.mjs +48 -34
- package/tests/craft_mode_home.mjs +20 -20
- package/tests/craft_mode_looks.mjs +16 -15
- package/tests/craft_mode_nav.mjs +31 -29
- package/tests/craft_review_mode.mjs +46 -41
- package/tests/crafts_vocabulary.mjs +70 -0
- package/tests/cross_discipline_priority_direction.mjs +5 -5
- package/tests/design_reference.mjs +1 -1
- package/tests/fitness.mjs +7 -11
- package/tests/funded_project_pays_proof_db.mjs +1 -1
- package/tests/genesis_home.mjs +21 -1
- package/tests/github_chip.mjs +3 -3
- package/tests/github_repo_invite.mjs +379 -0
- package/tests/goal_criterion_confirm_ui.mjs +1 -1
- package/tests/goal_invite_consent.mjs +1 -1
- package/tests/goal_map_page.mjs +2 -2
- package/tests/goal_sort_staleness.mjs +1 -1
- package/tests/goal_spec_task.mjs +1 -1
- package/tests/goal_spec_task_db.mjs +3 -3
- package/tests/grade_engine.mjs +2 -2
- package/tests/grader_no_artifact.mjs +1 -1
- package/tests/grader_prompt_fencing.mjs +1 -1
- package/tests/grader_prompt_window_bound.mjs +1 -1
- package/tests/grader_reader_lens.mjs +2 -2
- package/tests/grader_severity_gate.mjs +1 -1
- package/tests/grader_unbacked_score.mjs +1 -1
- package/tests/hall_approval_queue.mjs +1 -1
- package/tests/hall_board_world.mjs +2 -2
- package/tests/hall_builders_page_pass.mjs +3 -2
- package/tests/hall_city.mjs +16 -30
- package/tests/hall_controls.mjs +52 -4
- package/tests/hall_fullscreen.mjs +27 -3
- package/tests/hall_helm.mjs +187 -0
- package/tests/hall_kit_charts.mjs +1 -1
- package/tests/hall_landing_boot.mjs +1 -1
- package/tests/hall_my_agents.mjs +16 -16
- package/tests/hall_nav.mjs +22 -15
- package/tests/hall_options_menu.mjs +247 -0
- package/tests/hall_oversight_world.mjs +1 -1
- package/tests/hall_palette.mjs +8 -9
- package/tests/hall_profile_world.mjs +3 -3
- package/tests/hall_record_world.mjs +6 -4
- package/tests/hall_settings_world.mjs +2 -1
- package/tests/hall_sitemap.mjs +6 -5
- package/tests/hall_start_screen.mjs +307 -0
- package/tests/hall_street.mjs +15 -28
- package/tests/hall_street_inside.mjs +17 -9
- package/tests/hall_studio_world.mjs +3 -3
- package/tests/hall_topbar_320.mjs +4 -2
- package/tests/hall_visor.mjs +224 -0
- package/tests/help_requests.mjs +47 -15
- package/tests/helpers.mjs +4 -4
- package/tests/home_city.mjs +6 -4
- package/tests/home_city_widget.mjs +33 -14
- package/tests/home_gallery_widget.mjs +4 -4
- package/tests/home_idea_box.mjs +6 -6
- package/tests/hub_community_page.mjs +3 -3
- package/tests/hub_craft_rollup.mjs +75 -36
- package/tests/hub_recent_ships.mjs +3 -2
- package/tests/idea_cascade.mjs +2 -2
- package/tests/idea_credit_streams_db.mjs +1 -1
- package/tests/idea_detail_page.mjs +1 -1
- package/tests/idea_ideate_full.mjs +5 -2
- package/tests/idea_spark_hall.mjs +1 -1
- package/tests/init.mjs +3 -3
- package/tests/instance_manifest.mjs +2 -2
- package/tests/kickoff_checklist.mjs +1 -1
- package/tests/leaderboard_roles.mjs +34 -25
- package/tests/lifecycle_claim_ladder_refs.mjs +55 -0
- package/tests/lightbulb.mjs +14 -10
- package/tests/main_discipline.mjs +8 -8
- package/tests/markdown_line_endings.mjs +1 -1
- package/tests/market_watch_pages.mjs +52 -74
- package/tests/me_streak_leaderboard_queries.mjs +3 -3
- package/tests/migration_allocation.mjs +1 -1
- package/tests/mingle.mjs +36 -21
- package/tests/module-scope-map.mjs +22 -2
- package/tests/module_api.mjs +1 -0
- package/tests/module_contributions.mjs +13 -13
- package/tests/module_manifest.mjs +29 -0
- package/tests/module_skills_hook.mjs +2 -2
- package/tests/modules.mjs +14 -7
- package/tests/nav_permission_atoms.mjs +2 -1
- package/tests/needs_rebase.mjs +1 -1
- package/tests/newcomer_restock.mjs +13 -13
- package/tests/page_notes_panel.mjs +22 -22
- package/tests/page_tweak_no_block.mjs +1 -1
- package/tests/paintbrush.mjs +7 -7
- package/tests/privacy_matrix.mjs +1 -0
- package/tests/profile_activity.mjs +20 -23
- package/tests/profile_earnings.mjs +1 -1
- package/tests/profile_nudge_prefs.mjs +4 -4
- package/tests/profile_role_headline.mjs +73 -46
- package/tests/profile_role_stats.mjs +55 -45
- package/tests/profile_rollup_consent.mjs +19 -6
- package/tests/profile_route.mjs +12 -12
- package/tests/profile_ui_cross_project.mjs +4 -4
- package/tests/project_invite_suggestions.mjs +2 -2
- package/tests/promote_goal_id.mjs +1 -1
- package/tests/publish_manifest.mjs +1 -1
- package/tests/rank_floor_wiring.mjs +1 -1
- package/tests/regrade_actual_minutes.mjs +1 -1
- package/tests/removal_proposal.mjs +2 -2
- package/tests/reward_gate.mjs +4 -4
- package/tests/reward_mode_cost_plus_only.mjs +1 -1
- package/tests/role_responsibilities.mjs +18 -12
- package/tests/role_stats_db.mjs +17 -16
- package/tests/scouting_rollup_fanout.mjs +5 -5
- package/tests/seed_tasks.mjs +5 -2
- package/tests/session_earnings_mirror_db.mjs +1 -1
- package/tests/session_reward_on_land_db.mjs +1 -1
- package/tests/session_reward_reconcile_db.mjs +2 -2
- package/tests/sessions_kit_pager.mjs +1 -1
- package/tests/settings_art_key_absent.mjs +2 -2
- package/tests/settings_main_role.mjs +21 -20
- package/tests/setup_flow.mjs +3 -3
- package/tests/setup_smoke.mjs +20 -0
- package/tests/ship_card.mjs +6 -6
- package/tests/specialities.mjs +16 -4
- package/tests/speciality_db_shape.mjs +6 -6
- package/tests/speciality_injection.mjs +17 -17
- package/tests/speciality_offer_ui.mjs +5 -5
- package/tests/speciality_offered.mjs +6 -5
- package/tests/speciality_session_skills.mjs +7 -7
- package/tests/speciality_skills.mjs +11 -11
- package/tests/speciality_walkthrough_ui.mjs +2 -2
- package/tests/sso_checkin_identity_spoof.mjs +2 -1
- package/tests/task_classifier_vocab.mjs +10 -0
- package/tests/task_cli.mjs +11 -3
- package/tests/task_criteria_unlink_db.mjs +2 -2
- package/tests/task_discipline_required.mjs +38 -16
- package/tests/task_goal_required.mjs +4 -4
- package/tests/task_needs_db.mjs +1 -1
- package/tests/tweak_replaces_artist_review.mjs +1 -1
- package/tests/update_pill.mjs +153 -2
- package/tests/upkeep_home.mjs +1 -1
- package/tests/v3_c1_options_proof.mjs +145 -0
- package/tests/visual_review.mjs +3 -3
- package/tests/watch_applications_queue.mjs +8 -5
- package/tests/watch_sealed_floor.mjs +3 -1
- package/tests/welcome_boot.mjs +12 -9
- package/tests/welcome_boot_browser.mjs +13 -13
- package/tests/worktree_helper.mjs +16 -1
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/* watch-repo-invite.js — the GitHub repository half of an invite, for the Gate on /watch.
|
|
2
|
+
*
|
|
3
|
+
* A hall invite admits someone to THIS hall. It never puts the project's repository on
|
|
4
|
+
* their GitHub: that is a separate invite, sent with the owner's own GitHub account and
|
|
5
|
+
* accepted by the person on GitHub. This file holds the pieces of that second door so
|
|
6
|
+
* watch.js (at its line cap) only wires them:
|
|
7
|
+
* • formFieldsHtml() / explainerHtml() / readForm() — the "also invite to the
|
|
8
|
+
* repository" tick in the invite box, and the words under it
|
|
9
|
+
* • inviteToRepo() — POST /github/repo-invite; the form runs it AFTER the hall invite
|
|
10
|
+
* landed, so a GitHub refusal never undoes the admission
|
|
11
|
+
* • showRepoNote() — the form's result, kept where the owner can read it after the
|
|
12
|
+
* queue redraws
|
|
13
|
+
* • rowButtonHtml() / gateGithubStep() — one admitted row's GitHub status, in place:
|
|
14
|
+
* on the repository, waiting for them to accept, or not on it
|
|
15
|
+
*
|
|
16
|
+
* Access is always read-only (owner decision, 2026-11-04): a builder ships through the
|
|
17
|
+
* server's own publish and needs no write access, so there is no access choice at all.
|
|
18
|
+
* The server holds the same line (POST /github/repo-invite allows only 'pull').
|
|
19
|
+
*
|
|
20
|
+
* It is a factory over the page's own helpers, so it makes no request of its own that the
|
|
21
|
+
* page's sign-in bounce and error envelope do not already cover.
|
|
22
|
+
*/
|
|
23
|
+
(function () {
|
|
24
|
+
'use strict';
|
|
25
|
+
|
|
26
|
+
// A real GitHub username (the rule the server applies), so the repository button never
|
|
27
|
+
// shows for a Google-only member's stand-in name.
|
|
28
|
+
const GH_LOGIN_RE = /^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$/;
|
|
29
|
+
|
|
30
|
+
// The one word for this access level, so every sentence says it the same way.
|
|
31
|
+
const READ_ONLY = 'read-only';
|
|
32
|
+
|
|
33
|
+
function make({ api, API, postJson, $ }) {
|
|
34
|
+
function formFieldsHtml() {
|
|
35
|
+
return (
|
|
36
|
+
'<div class="ov-field">' +
|
|
37
|
+
`<label class="ov-field__l"><input type="checkbox" id="gate-invite-repo" checked> Also invite them to the project’s GitHub repository (${READ_ONLY} — they can see the code, not change it)</label>` +
|
|
38
|
+
'</div>'
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The sentences under the form: what each invite does, and where the result lands.
|
|
43
|
+
function explainerHtml() {
|
|
44
|
+
return (
|
|
45
|
+
'<p class="ov-form__why">The hall invite lets them sign in here. The GitHub invite is separate: GitHub emails them, and the repository only shows on their GitHub after they accept it (github.com/notifications). Neither changes their rank.</p>' +
|
|
46
|
+
'<p class="ov-form__why" id="gate-invite-note" role="status"></p>'
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Reads the form's tick: { want }. There is no access choice; it is always read-only.
|
|
51
|
+
function readForm(form) {
|
|
52
|
+
const tick = form.querySelector('#gate-invite-repo');
|
|
53
|
+
return { want: !!(tick && tick.checked) };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Resolves { ok, text, signin } and never throws except for a signed-out 401, which
|
|
57
|
+
// postJson has already bounced to sign-in. The words say nothing about the hall
|
|
58
|
+
// invite: this runs from the form (after one) and from a row (with none).
|
|
59
|
+
async function inviteToRepo(login) {
|
|
60
|
+
try {
|
|
61
|
+
// No access level is sent: the server offers read-only and nothing else.
|
|
62
|
+
const out = await postJson('/github/repo-invite', { github_login: login });
|
|
63
|
+
if (out.state === 'already_collaborator') {
|
|
64
|
+
return { ok: true, text: `@${login} already has access to the GitHub repository.` };
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, text: `GitHub repository invite sent to @${login} (${READ_ONLY}). They must accept it: GitHub emails them, or they can open github.com/notifications.` };
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if (err && err.kind === '401') throw err;
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
signin: !!(err && err.code === 'repo_scope_required'),
|
|
72
|
+
text: `The GitHub repository invite did not go through: ${(err && err.message) || err}`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Writes a result into an element. A sign-in link is added only when GitHub access is
|
|
78
|
+
// what is missing; it opens the same GitHub sign-in with the repository permission asked
|
|
79
|
+
// for. Used by the form's note and by a row's status line alike.
|
|
80
|
+
function paint(el, res) {
|
|
81
|
+
if (!el) return;
|
|
82
|
+
el.textContent = res.text;
|
|
83
|
+
if (res.signin) {
|
|
84
|
+
const a = document.createElement('a');
|
|
85
|
+
a.href = `${API}/auth/web/start?return=${encodeURIComponent('/watch')}&repos=1`;
|
|
86
|
+
a.textContent = ' Reconnect GitHub with repository access, then try again.';
|
|
87
|
+
el.appendChild(a);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// The form's result. When the repository step failed, the owner is told the hall
|
|
92
|
+
// invite still stands, because the form sent that one first.
|
|
93
|
+
function showRepoNote(res) {
|
|
94
|
+
paint($('#gate-invite-note'), res.ok ? res : { ...res, text: `The hall invite went through. ${res.text}` });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// The button an admitted row offers, and the span its answer is written into.
|
|
98
|
+
function rowButtonHtml(r, ghost) {
|
|
99
|
+
return GH_LOGIN_RE.test(String(r.github_login || ''))
|
|
100
|
+
? ghost(`data-gate-gh data-gh-mode="check" data-login="${String(r.github_login).replace(/[^A-Za-z0-9-]/g, '')}"`, 'GitHub repository')
|
|
101
|
+
: '';
|
|
102
|
+
}
|
|
103
|
+
// The span a row's answer is written into: drawn only where the button is.
|
|
104
|
+
function rowStateHtml(r) {
|
|
105
|
+
return r.status === 'invited' && !r.expired && GH_LOGIN_RE.test(String(r.github_login || ''))
|
|
106
|
+
? '<span class="ov-row__when" data-gh-state role="status"></span>'
|
|
107
|
+
: '';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// One row's GitHub status, in place; and a button to send (or send again) read-only access.
|
|
111
|
+
async function gateGithubStep(btn) {
|
|
112
|
+
const login = btn.getAttribute('data-login');
|
|
113
|
+
const mode = btn.getAttribute('data-gh-mode') || 'check';
|
|
114
|
+
const row = btn.closest('.ov-row');
|
|
115
|
+
const out = row && row.querySelector('[data-gh-state]');
|
|
116
|
+
const say = (t) => paint(out, { ok: true, text: t });
|
|
117
|
+
try {
|
|
118
|
+
if (mode === 'send') {
|
|
119
|
+
const sent = await inviteToRepo(login);
|
|
120
|
+
paint(out, sent);
|
|
121
|
+
if (sent.ok) { // a failed send stays a send, so the retry is one click
|
|
122
|
+
btn.textContent = 'Check GitHub again';
|
|
123
|
+
btn.setAttribute('data-gh-mode', 'check');
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const res = await api.request('GET', `${API}/github/repo-invite?github_login=${encodeURIComponent(login)}`);
|
|
128
|
+
if (res.status === 401) { window.location.assign(`${API}/auth/web/start`); throw { kind: '401' }; }
|
|
129
|
+
const s = res.data || {};
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
const env = s.error && typeof s.error === 'object' ? s.error : null;
|
|
132
|
+
paint(out, { ok: false, signin: !!(env && env.code === 'repo_scope_required'), text: (env && env.message) || 'Could not read the GitHub repository. Try again in a moment.' });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (s.state === 'collaborator') {
|
|
136
|
+
say('On the GitHub repository.');
|
|
137
|
+
btn.textContent = 'Check GitHub again';
|
|
138
|
+
} else if (s.state === 'pending') {
|
|
139
|
+
say('GitHub invite sent, waiting for them to accept it.');
|
|
140
|
+
btn.textContent = 'Send the invite again';
|
|
141
|
+
btn.setAttribute('data-gh-mode', 'send');
|
|
142
|
+
} else {
|
|
143
|
+
say('Not on the GitHub repository.');
|
|
144
|
+
btn.textContent = `Send ${READ_ONLY} repository invite`;
|
|
145
|
+
btn.setAttribute('data-gh-mode', 'send');
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
if (err && err.kind === '401') throw err;
|
|
149
|
+
say((err && err.message) || 'Could not reach GitHub. Try again in a moment.');
|
|
150
|
+
} finally {
|
|
151
|
+
btn.disabled = false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return { formFieldsHtml, explainerHtml, readForm, inviteToRepo, showRepoNote, rowButtonHtml, rowStateHtml, gateGithubStep };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
window.OTBWatchRepoInvite = { make };
|
|
159
|
+
})();
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
12
12
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
13
13
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
14
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-
|
|
14
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm">
|
|
15
15
|
<!-- The oversight family's sheet (task 1003469): the figure band, the group
|
|
16
16
|
head, the row, the form. Then the page's own: severities, the report
|
|
17
17
|
reader, the grade trend. The attention tiles + tabs come from style.css's
|
|
@@ -269,20 +269,21 @@
|
|
|
269
269
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
270
270
|
chrome exists before the page script runs. -->
|
|
271
271
|
<script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
|
|
272
|
-
<script src="/builders/shell-game.js?v=2026-11-
|
|
272
|
+
<script src="/builders/shell-game.js?v=2026-11-11-helm"></script>
|
|
273
273
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
274
|
-
<script src="/builders/craft-mode.js?v=2026-11-
|
|
275
|
-
<script src="/builders/shell.js?v=2026-11-
|
|
274
|
+
<script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
|
|
275
|
+
<script src="/builders/shell.js?v=2026-11-11-helm"></script>
|
|
276
276
|
<script src="/builders/hall-dialog.js"></script>
|
|
277
277
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
278
278
|
<script src="/builders/palette.js" defer></script>
|
|
279
279
|
<!-- shared component kit (window.OTBKit) — tabs, ledger, pager (task 2166). -->
|
|
280
280
|
<script src="/builders/hall-kit.js"></script>
|
|
281
|
-
<script src="/builders/task-detail.js?v=2026-
|
|
281
|
+
<script src="/builders/task-detail.js?v=2026-11-10-options"></script>
|
|
282
282
|
<script src="/builders/brand-apply.js?v=2026-06-19-r56"></script>
|
|
283
283
|
<!-- task 1005049: the two tabs' scripts, booted by watch.js when their tab first opens. -->
|
|
284
284
|
<script src="/builders/sessions.js?v=2026-11-05-tab"></script>
|
|
285
285
|
<script src="/builders/gate.js?v=2026-11-05-tab"></script>
|
|
286
|
+
<script src="/builders/watch-repo-invite.js?v=2026-11-04-repoinvite"></script>
|
|
286
287
|
<script src="/builders/watch.js?v=2026-11-05-tabs"></script>
|
|
287
288
|
</body>
|
|
288
289
|
</html>
|
|
@@ -142,7 +142,9 @@
|
|
|
142
142
|
if (!res.ok) {
|
|
143
143
|
// the envelope (ADR 0116) nests the sentence under `error`; older handlers answer flat
|
|
144
144
|
const env = data.error && typeof data.error === 'object' ? data.error : null;
|
|
145
|
-
|
|
145
|
+
const e = new Error((env && env.message) || data.message || (typeof data.error === 'string' ? data.error : '') || `${path} → ${res.status}`);
|
|
146
|
+
if (env && env.code) e.code = env.code; // the repo invite branches on repo_scope_required
|
|
147
|
+
throw e;
|
|
146
148
|
}
|
|
147
149
|
return data;
|
|
148
150
|
}
|
|
@@ -276,6 +278,10 @@
|
|
|
276
278
|
const ghost = (attrs, label, danger = false) =>
|
|
277
279
|
`<button type="button" class="btn-ghost${danger ? ' btn-ghost--danger' : ''}" ${attrs}>${label}</button>`;
|
|
278
280
|
|
|
281
|
+
// The GitHub repository half of an invite (watch-repo-invite.js): a separate door from
|
|
282
|
+
// the hall invite, and always read-only.
|
|
283
|
+
const repoInvite = window.OTBWatchRepoInvite.make({ api, API, postJson, $ });
|
|
284
|
+
|
|
279
285
|
// =========================================================================
|
|
280
286
|
// 1. GATE — access requests (pending)
|
|
281
287
|
// =========================================================================
|
|
@@ -299,8 +305,10 @@
|
|
|
299
305
|
'<label class="ov-field__l" for="gate-invite-login">Invite by GitHub username</label>' +
|
|
300
306
|
'<input type="text" id="gate-invite-login" name="github_login" autocomplete="off" placeholder="e.g. octocat" maxlength="40">' +
|
|
301
307
|
'</div>' +
|
|
308
|
+
repoInvite.formFieldsHtml() + // the GitHub repository is a separate door
|
|
302
309
|
'<button type="submit" class="btn-accent">Invite</button>' +
|
|
303
310
|
`<p class="ov-form__why">${escapeHtml(why)}</p>` +
|
|
311
|
+
repoInvite.explainerHtml() +
|
|
304
312
|
'</form>'
|
|
305
313
|
);
|
|
306
314
|
}
|
|
@@ -337,11 +345,14 @@
|
|
|
337
345
|
const login = ((input && input.value) || '').trim().replace(/^@/, '');
|
|
338
346
|
if (!login) { toast('A GitHub username is needed.'); return; }
|
|
339
347
|
const btn = form.querySelector('button[type="submit"]');
|
|
348
|
+
const repo = repoInvite.readForm(form);
|
|
340
349
|
if (btn) btn.disabled = true;
|
|
341
350
|
try {
|
|
342
351
|
const r = await postJson('/access-requests/invite', { github_login: login });
|
|
343
352
|
toast(r.already_invited ? `@${login} is already invited.` : `@${login} invited — their sign-in gets in.`);
|
|
353
|
+
const repoResult = repo.want ? await repoInvite.inviteToRepo(login) : null;
|
|
344
354
|
await loadGate();
|
|
355
|
+
if (repoResult) repoInvite.showRepoNote(repoResult);
|
|
345
356
|
} catch (err) {
|
|
346
357
|
if (err && err.kind === '401') return;
|
|
347
358
|
if (btn) btn.disabled = false;
|
|
@@ -493,7 +504,9 @@
|
|
|
493
504
|
// the only move, so the row offers none.
|
|
494
505
|
if (r.expired) return '';
|
|
495
506
|
if (r.status === 'invited') {
|
|
496
|
-
|
|
507
|
+
// The GitHub repository is its own door: check where this person stands on it, and
|
|
508
|
+
// send (or re-send) a read-only invite. A Google-only member has no GitHub name.
|
|
509
|
+
return repoInvite.rowButtonHtml(r, ghost) + ghost(`data-gate-action="dismissed" data-gate-from="invited" data-id="${id}"`, 'Rescind', true);
|
|
497
510
|
}
|
|
498
511
|
if (r.status === 'dismissed') return '';
|
|
499
512
|
return ghost(`data-gate-action="invited" data-id="${id}"`, 'Invite')
|
|
@@ -533,6 +546,7 @@
|
|
|
533
546
|
vouchedHandleHtml(r, !!profile) +
|
|
534
547
|
`<span class="ov-row__when">Asked ${escapeHtml(fmtDate(r.created_at))}</span>` +
|
|
535
548
|
decided +
|
|
549
|
+
repoInvite.rowStateHtml(r) +
|
|
536
550
|
'</div>' +
|
|
537
551
|
'</div>' +
|
|
538
552
|
(actions ? `<div class="ov-row__right"><div class="ov-row__actions">${actions}</div></div>` : '') +
|
|
@@ -638,6 +652,7 @@
|
|
|
638
652
|
if (requests.length) {
|
|
639
653
|
wireActions(target, '[data-gate-bulk]', (btn) =>
|
|
640
654
|
inviteAll(String(btn.getAttribute('data-ids') || '').split(',').filter(Boolean)), 'Could not invite');
|
|
655
|
+
wireActions(target, '[data-gate-gh]', repoInvite.gateGithubStep, 'Could not check GitHub');
|
|
641
656
|
wireActions(target, '[data-gate-action]', async (btn) => {
|
|
642
657
|
const id = btn.getAttribute('data-id');
|
|
643
658
|
const status = btn.getAttribute('data-gate-action');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "Watch — the attention board behind requireGovernmentPage. The SEALED state (a viewer below the gate) is a real render, not an error page, so it is a state here. Written with the re-skin (task 1003307) so this page is MEASURED at three widths in both modes rather than looked at once.",
|
|
3
3
|
"page": "/builders/watch",
|
|
4
|
+
"modes": ["dark"],
|
|
4
5
|
"_storage": "The hall asks a first-visit question (the session mode picker, craft-mode.js) over every page; seeding \"already asked\" renders the page a returning builder sees (task 1005080).",
|
|
5
6
|
"storage": { "session": { "hall-craft-asked": "1" } },
|
|
6
7
|
"surface": "hall-ui",
|
|
@@ -10,8 +10,9 @@
|
|
|
10
10
|
// hall underneath.
|
|
11
11
|
//
|
|
12
12
|
// Rules:
|
|
13
|
-
// - A signed-in builder sees it once per LOCAL day
|
|
14
|
-
//
|
|
13
|
+
// - A signed-in builder sees it once per LOCAL day. A fresh sign-in (the sign-in click leaves a
|
|
14
|
+
// flag in localStorage that the return visit consumes) opens on the game's start screen
|
|
15
|
+
// instead (task 1005143, shell-game.js); without that file it is greeted here as before. Storage that
|
|
15
16
|
// throws cannot remember, so such a browser is never shown it (it would replay on every visit).
|
|
16
17
|
// - A visitor who is not signed in sees the Welcome on Home, every visit, with a "Sign in with
|
|
17
18
|
// GitHub" button in place of the role choices. Only on Home, never over a deep link (#/task/N, #/idea/N).
|
|
@@ -73,11 +74,12 @@
|
|
|
73
74
|
|
|
74
75
|
// ---------- the roles (the owner's mapping) ----------
|
|
75
76
|
// `mode` is the craft mode the pick sets; `href` null means stay on Home.
|
|
77
|
+
// The game's three characters (task 1005141): Owner became Patron, and the
|
|
78
|
+
// ideator's and the artist's doors are one Artist door (the studio).
|
|
76
79
|
var ROLES = [
|
|
77
|
-
{ id: '
|
|
78
|
-
{ id: '
|
|
79
|
-
{ id: '
|
|
80
|
-
{ id: 'engineer', label: 'Engineer', room: 'Home', href: null, mode: 'building', dot: '#60a5fa' },
|
|
80
|
+
{ id: 'patron', label: 'Patron', room: 'City', href: '/city', mode: 'patron', dot: 'var(--accent)' },
|
|
81
|
+
{ id: 'artist', label: 'Artist', room: 'Studio', href: '/studio', mode: 'artist', dot: '#f472b6' },
|
|
82
|
+
{ id: 'artisan', label: 'Artisan', room: 'Home', href: null, mode: 'artisan', dot: '#60a5fa' },
|
|
81
83
|
];
|
|
82
84
|
function rolesFor(craft) {
|
|
83
85
|
return ROLES.filter(function (r) { return !craft || typeof craft.offered !== 'function' || craft.offered(r.mode); });
|
|
@@ -382,6 +384,13 @@
|
|
|
382
384
|
} catch (_) { return false; }
|
|
383
385
|
shown = true;
|
|
384
386
|
var c = craft();
|
|
387
|
+
// A fresh sign-in opens on the game's start screen instead (task 1005143, shell-game.js): the
|
|
388
|
+
// same still behind it, and the craft picker asked once the world is showing.
|
|
389
|
+
var game = window.OTBShellGame;
|
|
390
|
+
if (fresh && game && typeof game.start === 'function' && game.start({
|
|
391
|
+
name: projectName(window.__BRANDING__), art: artFor(timeOfDay(now)),
|
|
392
|
+
done: function () { if (c && typeof c.onAccess === 'function') c.onAccess(access, builder); },
|
|
393
|
+
})) return true;
|
|
385
394
|
if (c && typeof c.markAsked === 'function') c.markAsked();
|
|
386
395
|
show(builder);
|
|
387
396
|
return true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "Project founding mode (task 1004422) on an ordinary hall page: the founding band above the topbar and today's nav items asleep, rendered from a /me that says founding (kit fixture me-founding.json, the real server shaper's output at stage strategize). The page itself is work.states.json's; only the identity differs. The no-founding case is every other hall states file.",
|
|
3
3
|
"page": "/builders/work",
|
|
4
|
+
"modes": ["dark"],
|
|
4
5
|
"_storage": "The hall asks a first-visit question (the session mode picker, craft-mode.js) over every page; seeding \"already asked\" renders the page a returning builder sees (task 1005080).",
|
|
5
6
|
"storage": { "session": { "hall-craft-asked": "1" } },
|
|
6
7
|
"surface": "hall-ui",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="icon" href="/modules/ui-design/public/brand/favicon.svg" type="image/svg+xml">
|
|
9
9
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link rel="stylesheet" href="/builders/style.css?v=2026-
|
|
11
|
+
<link rel="stylesheet" href="/builders/style.css?v=2026-11-11-helm">
|
|
12
12
|
<!-- Page-local styles (task 2170) — extracted from the old inline <style>
|
|
13
13
|
block per the hall placement rules; shared pager/count-pill styles now
|
|
14
14
|
live in style.css's hall-kit section. -->
|
|
@@ -172,10 +172,10 @@
|
|
|
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
174
|
<script src="/builders/dom-utils.js?v=2026-11-05-numbers"></script>
|
|
175
|
-
<script src="/builders/shell-game.js?v=2026-11-
|
|
175
|
+
<script src="/builders/shell-game.js?v=2026-11-11-helm"></script>
|
|
176
176
|
<script src="/builders/shell-trail.js?v=2026-11-05-numbers"></script>
|
|
177
|
-
<script src="/builders/craft-mode.js?v=2026-11-
|
|
178
|
-
<script src="/builders/shell.js?v=2026-11-
|
|
177
|
+
<script src="/builders/craft-mode.js?v=2026-11-10-visor"></script>
|
|
178
|
+
<script src="/builders/shell.js?v=2026-11-11-helm"></script>
|
|
179
179
|
<script src="/builders/hall-dialog.js"></script>
|
|
180
180
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
181
181
|
<script src="/builders/palette.js" defer></script>
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
<script src="/builders/mine-lens.js" defer></script>
|
|
193
193
|
<!-- the Completed tab's project-wide momentum card (window.OTBWorkSummary), carved out of work.js. -->
|
|
194
194
|
<script src="/builders/work-summary.js" defer></script>
|
|
195
|
-
<script src="/builders/task-detail.js?v=2026-
|
|
195
|
+
<script src="/builders/task-detail.js?v=2026-11-10-options" defer></script>
|
|
196
196
|
<script src="/builders/brand-apply.js?v=2026-06-19-r56" defer></script>
|
|
197
197
|
<script src="/builders/bulk-toolbar.js" defer></script>
|
|
198
198
|
<script src="/builders/work.js?v=2026-09-30-bulktoolbar" defer></script>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_": "The hall's Work Board through modules/ui-design/kit/render.js (task 1003304). Written with the re-skin so the board's four tabs and its selection state are measured at 1440/390/320 in both modes, not just looked at. The populated look is the hall-preview harness (scripts/hall-preview/server.js); this file is the FLOORS.",
|
|
3
3
|
"page": "/builders/work",
|
|
4
|
+
"modes": ["dark"],
|
|
4
5
|
"_storage": "The hall asks a first-visit question (the session mode picker, craft-mode.js) over every page; seeding \"already asked\" renders the page a returning builder sees (task 1005080).",
|
|
5
6
|
"storage": { "session": { "hall-craft-asked": "1" } },
|
|
6
7
|
"surface": "hall-ui",
|
|
@@ -11,12 +11,12 @@ Pinned by `tests/hall_nav.mjs` (the Community group's middle id is `roster`) and
|
|
|
11
11
|
|
|
12
12
|
## The roles (task 1004437, WA6.RP07)
|
|
13
13
|
|
|
14
|
-
Owner decision (b), 2026-09-30: the leaderboard gets BOTH a column naming each builder's roles and the Everyone / Engineers / Artists / Ideators toggle above it. The approved mock is `docs/design/mocks/profile-roles/` (`?state=board`, `?state=board-artists`).
|
|
14
|
+
Owner decision (b), 2026-09-30: the leaderboard gets BOTH a column naming each builder's roles and the Everyone / Engineers / Artists / Ideators toggle above it (Everyone / Artisans / Artists since task 1005141, `roster.js` `ROLE_CHIPS`). The approved mock is `docs/design/mocks/profile-roles/` (`?state=board`, `?state=board-artists`).
|
|
15
15
|
|
|
16
16
|
- **The roster now reads `GET /public/leaderboard`,** the list the status page reads, which carries each row's `roles` (`src/bongos/role-stats.js` `readRolesForBuilders`: the profile's own main/shown rules, two reads for the whole page) and, since this task, `karma`. The hall and the public page cannot rank a role differently. The authed `/leaderboard` is unchanged and no longer read by the hall.
|
|
17
17
|
- **Roles column:** one pill per role in `roles.shown`, the main one a step stronger. `shown` is the main role plus every craft the builder has EARNED in, so it is evidence of work, not only a declared preference.
|
|
18
18
|
- **The toggle** keeps the builders a craft is shown for and ranks them by the credits that craft earned (`roles.credits_by_craft`, in the row: ADR 0255). The place column becomes the place inside that craft, the credits header says "Credits as artist", and the karma/rank/tokens lenses still apply on top.
|
|
19
|
-
- **Tokens only where they apply.** A builder with no recorded AI session (an artist in the studio
|
|
19
|
+
- **Tokens only where they apply.** A builder with no recorded AI session (an artist in the studio or in the room) reads a dash, and the cell's tooltip says no AI sessions were recorded, instead of a 0 and a "0 tokens per credit" figure that read as "did nothing".
|
|
20
20
|
- **Home's Standing card** reads the same list and adds "#N as an artist" beside "#N on the leaderboard" when the place inside the builder's main role differs from the overall one (`hall-render.js` `rolePlaceText`).
|
|
21
21
|
- **The status page** names each builder's roles under their name, on that page's own palette (`status.js` `renderRoles`).
|
|
22
22
|
|
|
@@ -4,10 +4,12 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
4
4
|
|
|
5
5
|
## What it is
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
7
|
+
> **Renamed by task 1005141.** The four modes are three now: Building is **Artisan** (`artisan`), Artistry and Ideating are one **Artist** (`artist`), Governing is **Patron** (`patron`). A mode stored under an old id is read as the new one (`LEGACY_MODES`). Lines below that name the old modes are the record of what was built.
|
|
8
|
+
|
|
9
|
+
- On entering the hall, once per browser session, a signed-in builder is asked **"What are you doing now?"**: Artisan, Artist or Patron (Building, Artistry, Ideating or Governing until task 1005141). A fifth choice, **Legacy mode** (2026-10-01: the hall exactly as it was), was removed in task 1004567 (owner, 2026-10-04: "builder has all those tabs anyways"); a browser that still has `legacy` stored reads it as no mode, because `valid()` ignores any id that is not a mode. The approved prototype is the design canvas linked on the task; the doors carry its four scenes (the work desk, the night room, the sky, the governor city).
|
|
10
|
+
- The answer is ONE attribute, `html[data-craft="artisan|artist|patron"]`, readable by every hall page. Every change also fires `otb:craft` on `document` with `{ detail: { mode } }`, so a page can react without polling.
|
|
11
|
+
- The top bar carries a switch with all three; pressing one changes the mode without a reload. Under 1180px it drops the words; at phone width only the current mode shows (or a "Choose your mode" button when there is none), and tapping it opens the picker.
|
|
12
|
+
- Artist is pre-selected for a builder whose `main_discipline` is `artist` (or, with no main role, whose first craft is).
|
|
11
13
|
|
|
12
14
|
## The rules an edit here must keep
|
|
13
15
|
|
|
@@ -24,13 +26,13 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
24
26
|
## The nav follows the mode (task 1004493)
|
|
25
27
|
|
|
26
28
|
- **Each craft has a named tab list**, `MODE_TABS` in `craft-mode.js`, by NAV id. `ALWAYS_TABS` is the owner's list of tabs no mode may hide (2026-10-01: Builders, NAV id `roster`, first), and every mode's list is `ALWAYS_TABS` plus its own. No mode has no entry, so it shows every tab, as before.
|
|
27
|
-
- **Government shows only in
|
|
29
|
+
- **Government shows only in Patron**, which leads with City and folds its other tabs under More (`MODE_LEAD`). Artisan is Goals, Goal map, Work, Blockers, Your thinking, Studio, Market Watch; Artist is Studio, Goals, Your thinking, Goal map, Market Watch (`MODE_TABS`). The prototype names rooms that do not exist yet (Store, Page reviews, Treasury); a list names only real NAV items, and `tests/craft_mode_nav.mjs` requires every NAV item to sit in some mode.
|
|
28
30
|
- **The mode only ever takes away, and never through `hidden`.** The access gate owns `hidden`; `applyNav()` marks what the mode leaves out with `[data-craft-off]`, which `style.css` hides. So a mode can never show a tab the gate hid, and switching mode just moves the attribute. A group head goes too once nothing under it shows.
|
|
29
31
|
- **Two callers.** `apply()` runs it on every mode change (live, no reload), and `shell.js` `applyAccess` runs it right after its gate loop, so a later `/me` answer (a promotion, a permission) brings a head back with its tabs. Hidden tabs still open by their URL; nothing is enforced (ADR 0016).
|
|
30
32
|
|
|
31
33
|
## Each mode's look (task 1004495)
|
|
32
34
|
|
|
33
|
-
- **
|
|
35
|
+
- **Two modes wear a look; Artisan and no mode wear none.** Artist and Patron each set `--craft` (where you are) and `--craft-on` (text on it) on `html[data-craft="<mode>"]`, with a dark twin on `html[data-theme="dark"][data-craft="<mode>"]` that also darkens the ground and tints the glass. Values and contrast are the direction's, `docs/design/craft-mode-direction.md`. No rule in `style.css` names `artisan`, and none matches any mode at all; `tests/craft_mode_looks.mjs` pins both, and re-measures every colour pair.
|
|
34
36
|
- **The accent stays the action colour.** `--craft` paints only the switch's current pill, the current tab (tint, icon, label, marker) and the top bar's hairline.
|
|
35
37
|
- **Two pieces are drawn by `craft-mode.js` `applyLook()`, on every mode change:** the eyebrow beside `#topbar-title` (`LOOKS`: "the studio · night", "the sky", "the city"; hidden at <=640px, where it overflowed phones) and the scene plate under `.app-sidebar__brand` (40px closed rail, 64px open). The plate's markup IS `artHtml(mode)`, the picker's door art, exported rather than copied; light mode recolours it to each scene's day (the city is the dark one through `invert(1) hue-rotate(180deg)`). It does not animate.
|
|
36
38
|
- **Always-present tabs widened** (owner, 2026-10-03): `ALWAYS_TABS` is Builders, Collab and Profile, so every mode keeps the You and Community groups.
|
|
@@ -38,7 +40,7 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
38
40
|
|
|
39
41
|
## The paintbrush (task 1004497)
|
|
40
42
|
|
|
41
|
-
- **
|
|
43
|
+
- **Artist carries the palette and the paintbrush** (and the lightbulb, below): the palette (a feedback doc, `page-notes.js`, record `page-notes.md`) and the paintbrush (`paintbrush.js`). Both are `TOOLS` entries in `craft-mode.js` and load their own script on first press.
|
|
42
44
|
- **The paintbrush edits the page's own words where they stand, as a REAL wording change** (owner, 2026-10-04): it is the copy desk's page round, the same one the tweak editor and the studio's own words write (ADR 0341). Pressing it reads `GET /copy-desk/pages/builders:<page>/draft`; a page nobody holds is OFFERED, never taken silently (taking it is the copy desk's artists-only claim, and the page shows as being tweaked while held). Typing saves the whole draft; "Review" lists every change as was/now; "Send for approval" submits the round. It never writes `page-notes` (owner: kept separate from the feedback docs).
|
|
43
45
|
- **Only a leaf element inside `<main>` whose words are one reading line becomes editable.** Shared chrome, a line with a `{…}` hole, controls (`button`, form fields, `code`), and anything hidden stay as they are; the bar counts the lines it cannot reach and links to the tweak editor for them. A click on edited words inside a link does not navigate.
|
|
44
46
|
- **Nobody else's view changes, and neither does yours once editing ends**: "Stop editing" and "Send" both put the page's own words back. The draft stays on the round.
|
|
@@ -47,20 +49,20 @@ Covers: every shelled hall page (`craft-mode.js`, `shell.js`, `style.css`), and
|
|
|
47
49
|
|
|
48
50
|
### Removing a line, and the artist review alongside (task 1004696)
|
|
49
51
|
|
|
50
|
-
- **An artist can recommend removing a line** (owner, 2026-10-09: pages carry superfluous subtitles and text). The line the artist is in shows in the bar with **Remove this line**; emptying a line's words and leaving it does the same. A removed line shows the page's own words struck through and faded, is no longer typed into but stays focusable, and **Keep this line** puts it back. Review lists it as its own "Remove" row and says it goes to an engineer. It is saved as `{ key, remove: true }` (the copy desk's rule, `modules/copy-desk/CLAUDE.md`), so the send files an
|
|
52
|
+
- **An artist can recommend removing a line** (owner, 2026-10-09: pages carry superfluous subtitles and text). The line the artist is in shows in the bar with **Remove this line**; emptying a line's words and leaving it does the same. A removed line shows the page's own words struck through and faded, is no longer typed into but stays focusable, and **Keep this line** puts it back. Review lists it as its own "Remove" row and says it goes to an engineer. It is saved as `{ key, remove: true }` (the copy desk's rule, `modules/copy-desk/CLAUDE.md`), so the send files an artisan task to take it out.
|
|
51
53
|
- **The artist review is one press away**: **Artist review** in the editing bar saves the words and opens the palette's sheet (`page-notes.js`, loaded on demand like a tool) over the page; editing carries on when it closes. Once the words are sent, the bar asks "Review how this page looks too?" with **Start an artist review** (closes the bar, opens the sheet) and **Not now**. The paintbrush still writes no feedback doc itself: `tests/paintbrush.mjs` allows `page-notes.js` as the only page-notes name in the file.
|
|
52
54
|
|
|
53
55
|
## The lightbulb (task 1004498)
|
|
54
56
|
|
|
55
|
-
- **
|
|
56
|
-
- **Only the ideas remain** (owner, 2026-10-04). `POST /page-notes/ideas` splits the notes with the palette's AI split (
|
|
57
|
+
- **The lightbulb** (`lightbulb.js`, a `TOOLS` entry loaded on first press) was Ideating's one tool and is the Artist's third since task 1005141. Its button wears its own note glyph, not the mode's lightbulb, so it is never read as the Ideating pill beside it (owner, 2026-10-04). It is a watered-down palette: the same side sheet and `.pn` styles, text only, no uploads.
|
|
58
|
+
- **Only the ideas remain** (owner, 2026-10-04). `POST /page-notes/ideas` splits the notes with the palette's AI split (the notes wording, once the ideator's; one idea if the split cannot run) and files each idea under its author, its body ending in a link to the page. Nothing else is stored: no doc row, no reference doc. The split answers inside the request, so it gives up after 45 seconds and files the notes whole.
|
|
57
59
|
- **The panel lists the ideas already filed from this page** (`GET /page-notes/ideas?page_path=`): open and promoted ideas whose body carries the page's link, from the lightbulb (`](/page)`) or the palette (`](/page?note=`). That link is the only record of where an idea came from, so `notes.pageLinks` and the two idea bodies are pinned together in `tests/lightbulb.mjs`.
|
|
58
60
|
- **Unsent text waits in this browser only**, per page (`localStorage 'hall-lightbulb:<path>'`), and is forgotten once it files.
|
|
59
61
|
- `tests/lightbulb.mjs` runs the real routes and the real script over a small DOM.
|
|
60
62
|
|
|
61
63
|
## Artist review mode (task 1004686)
|
|
62
64
|
|
|
63
|
-
- **Review is a split pill** (owner, 2026-10-09): pressing Review still opens the feedback doc; hovering it with a mouse, or pressing its chevron, opens a menu: "Write feedback on this page", then the
|
|
65
|
+
- **Review is a split pill** (owner, 2026-10-09): pressing Review still opens the feedback doc; hovering it with a mouse, or pressing its chevron, opens a menu: "Write feedback on this page", then the experiences in the owner's order (Ideator, Governing, Building, Artistry experience when written; since task 1005141 three: Patron, Artisan, Artist experience), then "Stop reviewing" while a review is on. Hover is asked of the pointer (`pointerType === 'mouse'`), never `(hover: hover)`: a touch laptop can report no hover at all. On a phone (<=640px) the chevron folds away and a tap on Review opens the menu.
|
|
64
66
|
- **Picking one makes the hall wear that mode** (`html[data-craft]`, so its tabs, look, eyebrow and tallies follow) and stamps `html[data-craft-review]`. The artist's own mode stays Artistry: `sessionStorage['hall-craft-review']` holds the experience for the session only, and is ignored unless the mode is Artistry. Choosing any mode from the switch or the picker ends it. The artist keeps Review and Edit words; the experience's own tools follow them, marked `craft-tool--guest` so a phone under 360px can fold them away (three tools pushed 320px 36px sideways; Artistry alone overflows 4px there today, before and after).
|
|
65
67
|
- **The scribble wall** (`craft-review.js`, loaded on demand; `craft-review.css`, imported by `style.css`): a flexible box in the top bar's empty space where a pen tip scribbles six small doodles in the sky's hand (thinking.css: hairlines, stars, a dashed orbit, a constellation, a crescent, a shooting star, a looped scribble, sparks), each at its own spot and height, a new one every 5s of a 30s round and each up about 10s, so two or three show at once. **Ink alone** (owner, 2026-10-09, after a first cut of big painted colour tags: "small black white graffiti scribbling"): every mark is `--ink`, black on the light bar and white on the dark, with the sky's fainter ladder for trails and orbits; the test holds the wall section to that one token. No doodle is wider than 56px or taller than 24px; the two widest fold away on a wall under 58px (Governing at 1440px keeps about 60), all of them under 34px and on a phone. The wipe is two opposite `translateX` moves, so every motion is transform or opacity in CSS, and the kill switch leaves three doodles standing, finished, with no pen. A doodle not yet begun keeps its pen unseen (`gx-track` starts at opacity 0), or each waiting tip shows as a stray dot.
|
|
66
68
|
- **An @import lands before style.css's own rules**, so a rule in `craft-review.css` that restyles `.craft-tool` needs two classes, or `.craft-tool` silently wins (it did, for the reviewing wash and the guest fold, until measured).
|
|
@@ -7,7 +7,7 @@ Covers: every shelled hall page (`shell-game.js`, `shell.js`). Spec: `docs/specs
|
|
|
7
7
|
- **Game mode is the existing full-screen switch, made hall-wide. There is no second full-screen mode.** The switch was already on every page (task 1004430) but remembered per page, so a reader had to turn it on 33 times. Game mode is one `localStorage` key, `hall-game`; while it is `on`, `shell.js` `storedFullscreen()` answers yes for every page, whatever that page remembers. What hides, the corner button and the Escape hand-off are the shell's, unchanged.
|
|
8
8
|
- **`shell-game.js` holds the mode and nothing else**: `window.OTBShellGame` = `on()`, `set(bool)`, `hint()`. It stamps `html[data-game="on"]` for a sheet or script that wants to read the mode. `shell.js` reads it through a fallback object, so a page without the file is never in game mode. It is its own file because `shell.js` sits on the 1,500-line ratchet; the start screen and options menu (R03, R04) are expected to grow here, not in `shell.js`.
|
|
9
9
|
- **Load order**: `shell-game.js` before `shell-trail.js` / `craft-mode.js` / `shell.js`, loaded the same way (deferred or not) as the shell on that page. Test-pinned.
|
|
10
|
-
- **Leaving is for this page load only.** In game mode the corner button
|
|
10
|
+
- **Leaving is for this page load only.** In game mode the corner button brings the bars back (Escape did too until task 1005144; it opens the options menu now), and nothing is written: the next page opens without them again, and a page's own `hall-fullscreen:<page>` memory is never overwritten. Turning game mode off (`set(false)`) hands each page back what it remembered. `OTBShell.setFullscreen(null)` is the "re-read what should show" call `set()` uses.
|
|
11
11
|
- **No page may opt out.** `<body data-fullscreen-switch="off">` would keep that page's sidebar in game mode; the test fails on one. A new hall page needs `#app-topbar` and the `shell-game.js` tag, like the rest.
|
|
12
12
|
- **The "how to leave" line shows once per tab in game mode** (`sessionStorage 'hall-game-hint'`), not on every page load. Outside game mode the shell's rule is unchanged.
|
|
13
13
|
- **How it is turned on today**: `?game=on` / `?game=off` on any hall URL, or `OTBShellGame.set()`. Nothing in the hall's interface sets it yet; the start screen (R03) is where that lands.
|
|
@@ -15,6 +15,6 @@ Covers: every shelled hall page (`shell-game.js`, `shell.js`). Spec: `docs/specs
|
|
|
15
15
|
## For the tasks after this one
|
|
16
16
|
|
|
17
17
|
- A HUD or options menu that wants Escape must call `preventDefault()` on the press. `shell.js` `onFullscreenKey` waits one tick before leaving so a listener added after it still wins.
|
|
18
|
-
-
|
|
18
|
+
- Since R04 (task 1005144, ADR 0401) the last Escape in game mode opens the options menu (`shell-game.js` `onEscape`), and on the menu it closes it again. The corner button is still the way back to the bars.
|
|
19
19
|
|
|
20
20
|
Tests: `tests/hall_fullscreen.mjs` (the eight `game mode:` cases run the real `shell-game.js` + `shell.js`), and the script lists in `tests/hall_city.mjs`, `tests/hall_street.mjs`, `tests/hall_my_agents.mjs`, `tests/goal_map_page.mjs`.
|
|
@@ -29,7 +29,7 @@ Files: `street-inside.js` (`window.GovInside`, node-require-safe, pure): the pro
|
|
|
29
29
|
- **The lift and the flip.** The lift is one node kept across draws, so picking a floor slides it by a CSS transform transition; the chosen floor's block is two blocks that take turns (`flipA` / `flipB`), so it re-enters on every pick. Both are dead under reduced motion.
|
|
30
30
|
- **Change how this works** is present and honest: pressed, it says drafting an amendment from here is not built yet (task 1004530 wires it).
|
|
31
31
|
- **No "on the table here" list.** The prototype's list of the building's open matters was removed on the owner's direction (task 1004565): the floor desks carry every matter as an actionable row, so the list was duplication. Inside a building a matter is its desk row; the short card opens from the street's pins.
|
|
32
|
-
- **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower
|
|
32
|
+
- **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower artisan, studio artist, glass front UI; none or any other is a tower; the ideator's pavilion went with task 1005141), stage from the status (backlog and blocked a staked plot, ready a slab, active a scaffold, completed and confirmed built with a flag, shipped lit), label the kind; height from the estimate. Up to ten stand on the road, work in flight first; the rest are counted with a link to the goal. Each one opens its task.
|
|
33
33
|
- **Narrow.** Under 900 px the board becomes a column: the drawing in its own sideways strip (never scaled under 0.6, so a floor stays a 24 px target), then the panel.
|
|
34
34
|
|
|
35
35
|
Tests: `tests/hall_street_inside.mjs` runs the prototype's own `Component` beside `street-inside.js` on the prototype's sample floors and holds every building's section, panel bindings and every district equal to it in both modes, then the docket rules (no invented numbers) and the page in a vm (the persistent lift, the flip, the drawers, the amendment note, the card from a table row, back to the street, a district's tasks). The states file renders every building, a floor pick, the amendment note and a district.
|
|
@@ -87,6 +87,8 @@ the builder's Home. Steps 2–4 (the ideator's sky, the artist's gallery, the st
|
|
|
87
87
|
|
|
88
88
|
## v16 step 2 — the ideator's sky (task 1005059)
|
|
89
89
|
|
|
90
|
+
> **Not drawn since task 1005141.** The Ideating mode folded into Artist, so `home-city.js` `craft()` never answers `ideating` and every craft lands in the city; the sky is a door away (Your thinking). The branch and `skySvg` are kept so the sky can come back as its own view. What follows is the record of what step 2 built.
|
|
91
|
+
|
|
90
92
|
The mock is [`v16-ideating.html`](../../../docs/design/mocks/hall/home/v16-ideating.html). While the craft is
|
|
91
93
|
**Ideating** (`OTBCraftMode.current()`, redrawn on `otb:craft`) the same widget, from the same one read, draws
|
|
92
94
|
`home-city-draw.js` `skySvg` instead of the city. Every other craft keeps the builder's city untouched.
|
|
@@ -108,7 +110,7 @@ The mock is [`v16-ideating.html`](../../../docs/design/mocks/hall/home/v16-ideat
|
|
|
108
110
|
new idea (these two weeks) that is open, in no area, not the viewer's, and not yet voted on by them. In the
|
|
109
111
|
week an idea became work it falls into its tower; after that it lights a window there. The moon is the
|
|
110
112
|
version, its phase what the areas have shipped over every task under them (`version.tasks`).
|
|
111
|
-
- **The ladder**
|
|
113
|
+
- **The ladder** (in the dormant sky view) ranked the week's ideators: ideas filed, idea votes cast, and ideas of theirs that became work.
|
|
112
114
|
- **The read stays one and bounded.** `GET /home/city` adds these fields to the ideas list it already sent
|
|
113
115
|
(still newest first, at most 120 rows), plus idea votes per builder per week and a per-area task count.
|
|
114
116
|
The `ideas_votes` table is probed first, so a project with the ideas module off answers without votes.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Market Watch settings, the owner's Settings tab on /market-watch (task 1004938; a tab since task 1005045)
|
|
2
2
|
|
|
3
|
+
**Since task 1005144 (ADR 0401) the settings are an options menu entry, not a tab.** The menu opens `/market-watch?embed=1#settings` in its frame and the page shows `#mw-panel-settings` alone; a plain visit is the watch with no tab strip and no settings read, an old `/market-watch#settings` link `location.replace`s to `/settings?open=market-watch`, and `/market-watch-settings` 302s to the same entry (`RETIRED_TO_OPTIONS`). The owner check moved with it: the menu lists the entry for an archon, and the four routes stay the wall. The tab-era notes below are history; see `records/options-menu.md`.
|
|
4
|
+
|
|
3
5
|
**Since task 1005045 (owner decision 2026-11-03, idea 1001310) this is a tab, not a page.** The sidebar showed "Market Watch" twice — the page and these settings — so the settings page is gone and its markup is the `#mw-panel-settings` panel in `market-watch.html`. What that move settled:
|
|
4
6
|
|
|
5
7
|
- **Only the owner gets the strip.** `market-watch.js` adopts the shell's one `/me` read (`window.__hallReads`, no second request); for an archon it builds two kit tabs (`watch`, `settings`, `hash: true`) and calls `OTBMarketWatchSettings.load()`. Anyone else gets no tab strip at all, and their page never asks for the settings. An unreadable `/me` is not an owner. Cosmetic only: the four routes below are still the wall (ADR 0016).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# The options menu — Settings, and the six screens it opens (task 1005144, BONGOS-V3 R04; ADR 0401)
|
|
2
|
+
|
|
3
|
+
Every setting and configuration is reached from one vertical, grouped menu with a search box at the top. The menu IS `/settings`; the profile chip opens it and says "Options".
|
|
4
|
+
|
|
5
|
+
- **Two kinds of entry** (`options-menu.js` `MENU`). *Native* entries are Settings' own groups (`data-group` in `settings.html`): Account, Access and keys, Preferences, Sound, Software update, Extensions (only when a module contributed a panel). *Embedded* entries open an old page in an `<iframe>` of its address with `?embed=1`: Your agents (`/my-agents`), Project settings, Modules, Permissions and constitution (`/government`), Market Watch settings (`/market-watch#settings`) and Market Watch rules. A frame is created the first time its entry opens, never at boot.
|
|
6
|
+
- **Who sees an entry** is the rank key the old sidebar item used (`signed`, `member`, `government`, `archon`), plus a module gate (`market-watch`). Cosmetic: each framed page keeps its server page gate and its routes.
|
|
7
|
+
- **The search** (`search()`, pure) matches every typed word against a line's label, its `words`, its entry and its group. Each entry can list `anchors` (CLI access, How Claude talks to you, …) so a search lands on the exact place; Enter opens the first line, so the ranking puts a label hit first, then the exact place above the group that merely holds it.
|
|
8
|
+
- **Addresses.** `/settings#<entry>` or `/settings?open=<entry>#<anchor>`; a panel anchor (`#cli`, `#art-key`) still lands as before. The address follows what is open (`replaceState`), and `?from=` survives switches so closing returns.
|
|
9
|
+
- **Embedded pages** (`shell-game.js`, only inside a frame): `html[data-embed="on"]` hides the sidebar, scrim, foot and top bar; the full-screen switch is off; an unused Escape goes to the menu; a link to another page opens in the whole window. A link on the menu's own panels to an old page (Settings' "these moved to My agents" lines) opens that entry in place instead.
|
|
10
|
+
- **Old addresses** 302 to the menu (`serve-internal.js` `RETIRED_TO_OPTIONS`, the twin of `options-menu.js` `RETIRED`); `?embed=1` passes through, except for `/market-watch-settings`, which has no page left.
|
|
11
|
+
- **Game mode.** The last Escape on any page opens the menu (`/settings?from=…`); on the menu or in a frame it closes it. Outside game mode the menu is a page like any other.
|
|
12
|
+
- **Layout.** The rail is sticky beside the open screen and scrolls itself; a frame fills the column to the window's foot. Below 860px the menu stacks above the screen, and choosing an entry scrolls the screen up clear of the top bar.
|
|
13
|
+
- **Left the sidebar:** My agents, Project settings, Permissions, Modules (and their glyphs). The palette's agent rows open the menu; its Government rows are gone.
|
|
14
|
+
- **Tests:** `tests/hall_options_menu.mjs` (the catalogue, gates, search, addresses, both redirect maps, the embedded page, game-mode Escape); `tests/hall_fullscreen.mjs` (Escape in game mode); `tests/market_watch_pages.mjs` (the settings panel in the frame).
|
|
15
|
+
- **Known:** sounds are switched off (task 1004554), so the Sound entry shows its note, not a toggle.
|