@bongos/core 1.19.1073 → 1.19.1075
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 +404 -549
- package/.claude/skills/feedback/SKILL.md +2 -2
- package/bin/bongos.js +1 -3
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -60
- package/clients/bongos-client/index.cjs +4 -60
- package/clients/bongos-client/index.d.ts +5 -90
- package/clients/bongos-client/index.mjs +4 -60
- package/config/branding.neutral.json +1 -5
- package/config/modules.neutral.json +2 -3
- package/config/scheduled-routines.json +0 -2
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +1 -0
- package/docs/adr/0285-a-shared-box-holds-about-twelve-projects-per-gb-and-memory-is-the-wall.md +1 -0
- package/docs/adr/0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md +1 -1
- package/docs/adr/0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md +1 -1
- package/docs/adr/0341-the-page-is-the-unit-of-tweak-mode.md +2 -0
- package/docs/adr/0345-we-host-every-projects-hall-and-its-app-deploys-where-the-owner-chooses.md +94 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +175 -1665
- package/docs/api-reference.md +9 -41
- package/docs/architecture.md +16 -1
- package/docs/branding-contract.md +0 -3
- package/docs/copy-inventory.md +454 -479
- package/docs/copy-registry.json +746 -978
- package/docs/file-map.md +5 -34
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +13 -1
- package/docs/onboarding/diagrams/04-architecture.mmd +11 -22
- package/docs/onboarding/diagrams/README.md +3 -3
- package/docs/onboarding/diagrams/assertions.json +2 -22
- package/docs/onboarding/primer.md +9 -28
- package/docs/page-inventory.json +4 -1
- package/docs/page-readings.json +1032 -1077
- package/docs/recipes/render-pilot.md +29 -10
- package/migrations/core_257_module_store_registry.sql +87 -0
- package/migrations/core_258_drop_dev_box_tables.sql +55 -0
- package/modules/agents/module.json +1 -0
- package/modules/autonomy/module.json +1 -0
- package/modules/builder-settings/module.json +1 -0
- package/modules/builder-settings/render-prefs.js +4 -5
- package/modules/copy-desk/docx.js +78 -5
- package/modules/copy-desk/module.json +1 -0
- package/modules/copy-desk/routes/copy-desk.js +10 -10
- package/modules/copy-desk/tests/copy_docx.mjs +107 -1
- package/modules/copy-desk/tests/fixtures/word-docx.mjs +30 -0
- package/modules/discord/module.json +1 -0
- package/modules/discord/ship-broadcast.js +3 -3
- package/modules/economy/credits.js +2 -2
- package/modules/economy/module.json +1 -0
- package/modules/economy/routes/credits.js +1 -2
- package/modules/government/catalog.js +13 -17
- package/modules/government/migrations/government_019_retire_box_permissions.sql +33 -0
- package/modules/government/module.json +1 -0
- package/modules/government/protected-surfaces.json +3 -11
- package/modules/government/resolver.js +3 -46
- package/modules/government/routes/government.js +0 -2
- package/modules/government/session-scopes.js +43 -83
- package/modules/government/session-scopes.json +8 -18
- package/modules/grading/module.json +1 -0
- package/modules/hall-ui/module.json +1 -0
- package/modules/hall-ui/public/board-lib.js +2 -2
- package/modules/hall-ui/public/builders.js +29 -40
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/collab.js +1 -1
- package/modules/hall-ui/public/diagrams.html +3 -3
- package/modules/hall-ui/public/dom-utils.js +1 -1
- package/modules/hall-ui/public/gate.js +2 -2
- package/modules/hall-ui/public/gate.states.json +1 -1
- package/modules/hall-ui/public/hall-render.js +43 -79
- package/modules/hall-ui/public/index.html +5 -1
- package/modules/hall-ui/public/modules.js +1 -0
- package/modules/hall-ui/public/oversight.css +5 -5
- package/modules/hall-ui/public/palette.js +0 -11
- package/modules/hall-ui/public/primer.js +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings-sessions.js +1 -1
- package/modules/hall-ui/public/settings.css +0 -1
- package/modules/hall-ui/public/settings.html +4 -33
- package/modules/hall-ui/public/settings.js +3 -33
- package/modules/hall-ui/public/settings.states.json +2 -2
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/style.css +10 -13
- package/modules/hall-ui/public/task.html +4 -1
- package/modules/hall-ui/public/task.js +36 -1
- package/modules/hall-ui/public/tweak-editor-lib.js +18 -1
- package/modules/hall-ui/public/tweak-editor.css +16 -0
- package/modules/hall-ui/public/tweak-editor.html +26 -3
- package/modules/hall-ui/public/tweak-editor.js +32 -1
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/hall-ui/records/tweak-editor.md +1 -0
- package/modules/ideas/module.json +1 -0
- package/modules/ideas/projection.js +1 -1
- package/modules/lifecycle/db-claim-reads.js +1 -58
- package/modules/lifecycle/db-ship.js +4 -9
- package/modules/lifecycle/db.js +0 -4
- package/modules/lifecycle/github-push.js +12 -14
- package/modules/lifecycle/kickoff-checklist.js +0 -4
- package/modules/lifecycle/lifecycle.js +0 -8
- package/modules/lifecycle/module.json +1 -0
- package/modules/lifecycle/publish-reconciler.js +10 -10
- package/modules/lifecycle/routes/tasks.js +13 -15
- package/modules/lifecycle/ship-card.js +1 -1
- package/modules/lifecycle/task-visuals.js +2 -2
- package/modules/memory/module.json +1 -0
- package/modules/memory/routes/memory.js +2 -2
- package/modules/npm-release/module.json +1 -0
- package/modules/onboarding/module.json +1 -0
- package/modules/onboarding/onboarding-state.js +17 -36
- package/modules/onboarding/routes/access-requests.js +3 -3
- package/modules/platform-identity/module.json +1 -0
- package/modules/platform-identity/platform-identity.js +13 -5
- package/modules/platform-identity/routes/sso.js +5 -4
- package/modules/platform-identity/tests/platform-identity.mjs +17 -3
- package/modules/provisioning/capacity.js +1 -1
- package/modules/provisioning/module.json +1 -0
- package/modules/provisioning/provisioning.js +6 -5
- package/modules/provisioning/routes/provisioning.js +4 -4
- package/modules/provisioning/starter-bundles.js +5 -25
- package/modules/public-landing/module.json +1 -0
- package/modules/public-landing/public/assets/cosmos.css +1 -1
- package/modules/public-landing/public/contact.html +1 -1
- package/modules/public-landing/public/privacy.html +1 -1
- package/modules/public-landing/public/projects.html +101 -32
- package/modules/public-landing/public/projects.probes.json +2 -2
- package/modules/public-landing/public/projects.states.json +4 -3
- package/modules/public-landing/public/terms.html +1 -1
- package/modules/security/module.json +1 -0
- package/modules/sessions/db.js +1 -1
- package/modules/sessions/module.json +1 -0
- package/modules/specialities/module.json +1 -0
- package/modules/status-ui/module.json +1 -0
- package/modules/ui-design/module.json +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +84 -0
- package/scripts/gds/artifact-format.js +203 -0
- package/scripts/gds/artifact-staleness.js +2 -2
- package/scripts/gds/audit-authorship.sh +1 -13
- package/scripts/gds/backfill-task-rewards.js +5 -5
- package/scripts/gds/claim.js +0 -15
- package/scripts/gds/claude-materialize.js +2 -2
- package/scripts/gds/cli-lib.js +15 -15
- package/scripts/gds/codemod-rename-src-gds.js +1 -1
- package/scripts/gds/context-pack.js +5 -7
- package/scripts/gds/diagram-facts.js +12 -23
- package/scripts/gds/do-api.js +13 -80
- package/scripts/gds/doc-cli-guard.js +2 -0
- package/scripts/gds/doctor.js +4 -4
- package/scripts/gds/feedback-latest.js +139 -9
- package/scripts/gds/fitness-checks-identity.js +2 -7
- package/scripts/gds/fitness-checks-packaging.js +4 -4
- package/scripts/gds/fitness-checks-write-validation.js +4 -0
- package/scripts/gds/fitness-ratchets.js +5 -5
- package/scripts/gds/fitness.js +10 -10
- package/scripts/gds/gen-api-client.js +4 -4
- package/scripts/gds/gen-api-docs.js +1 -1
- package/scripts/gds/gen-diagrams.js +49 -71
- package/scripts/gds/gen-repo-map.js +13 -14
- package/scripts/gds/gen-session-index.js +8 -8
- package/scripts/gds/http-api-client.js +12 -19
- package/scripts/gds/init.js +1 -1
- package/scripts/gds/leak-scan-allowlist.js +1 -1
- package/scripts/gds/lint-infra-exec.js +1 -1
- package/scripts/gds/local-preview-lib.js +8 -39
- package/scripts/gds/local-preview.js +2 -15
- package/scripts/gds/migration-namespace.js +3 -3
- package/scripts/gds/module-artifact.js +212 -0
- package/scripts/gds/module.js +95 -6
- package/scripts/gds/package-core.js +5 -116
- package/scripts/gds/plain-cards.js +1 -1
- package/scripts/gds/provision-config.js +2 -2
- package/scripts/gds/provision-net.js +2 -3
- package/scripts/gds/provision.js +9 -9
- package/scripts/gds/publish-manifest.js +1 -2
- package/scripts/gds/push-path-brief.js +10 -10
- package/scripts/gds/regen-instance-docs.js +1 -1
- package/scripts/gds/rename-history-check.js +1 -1
- package/scripts/gds/run-unit-tests.js +2 -16
- package/scripts/gds/sandbox-stage.js +39 -341
- package/scripts/gds/session-digest-build.js +2 -2
- package/scripts/gds/ship-deploy-target.js +13 -13
- package/scripts/gds/ship-flow.js +7 -7
- package/scripts/gds/ship-land.js +9 -10
- package/scripts/gds/ship-merge.js +4 -4
- package/scripts/gds/ship-preflight-steps.js +4 -4
- package/scripts/gds/ship-regen.js +15 -49
- package/scripts/gds/ship.js +13 -33
- package/scripts/gds/skill-preflight.js +9 -8
- package/scripts/gds/start.js +0 -15
- package/scripts/hall-preview/README.md +5 -5
- package/scripts/hall-preview/server.js +6 -6
- package/scripts/render-diagrams.sh +1 -1
- package/src/bongos/api-errors.js +1 -1
- package/src/bongos/api-prefix.js +4 -4
- package/src/bongos/auth-github.js +2 -3
- package/src/bongos/auth.js +51 -126
- package/src/bongos/db-kernel.js +2 -3
- package/src/bongos/db.js +5 -28
- package/src/bongos/module-scope-map.js +14 -29
- package/src/bongos/module-store.js +141 -0
- package/src/bongos/platform-visibility-gate.js +1 -1
- package/src/bongos/route-rank-check.js +3 -16
- package/src/bongos/routes/auth.js +0 -116
- package/src/bongos/routes/builders.js +5 -15
- package/src/bongos/routes/instance.js +8 -14
- package/src/bongos/routes/me.js +7 -23
- package/src/bongos/routes/modules.js +83 -0
- package/src/bongos/routes/security.js +3 -3
- package/src/bongos/routes.js +7 -2
- package/src/bongos/serve-internal.js +5 -6
- package/src/bongos-downloads.js +1 -6
- package/src/branding.js +2 -2
- package/src/build-info.js +4 -6
- package/src/instance-config.js +2 -2
- package/src/module-api.js +13 -6
- package/src/module-loader/catalog.js +3 -0
- package/src/module-loader/loader.js +4 -4
- package/src/module-loader/manifest-schema.js +16 -8
- package/src/module-seams.js +2 -3
- package/src/modules.js +42 -14
- package/tests/agents_spend_guard.mjs +1 -1
- package/tests/api_alias_caller_ratchet.mjs +1 -1
- package/tests/api_alias_exceptions.mjs +1 -1
- package/tests/api_client.mjs +1 -16
- package/tests/api_path_404.mjs +1 -1
- package/tests/auth_page_gate.mjs +10 -10
- package/tests/backfill_task_rewards.mjs +1 -1
- package/tests/canonical_profile_url.mjs +1 -3
- package/tests/claim_action.mjs +4 -1
- package/tests/claim_from_task_and_home.mjs +127 -0
- package/tests/{box_ship_permissions.mjs → cli_allowlist_permissions.mjs} +5 -5
- package/tests/cli_sessions.mjs +1 -1
- package/tests/consumer_layout_boot.mjs +2 -0
- package/tests/context_pack.mjs +13 -13
- package/tests/copy_desk_page_docx.mjs +33 -2
- package/tests/copy_inventory.mjs +7 -7
- package/tests/core_upgrade_runner.mjs +6 -6
- package/tests/credit_grant.mjs +2 -2
- package/tests/criterion_suggest.mjs +1 -1
- package/tests/deploy_divergence_line.mjs +11 -11
- package/tests/design_tokens_sync.mjs +3 -2
- package/tests/diagram_facts_offset.mjs +1 -1
- package/tests/do_api.mjs +106 -0
- package/tests/feedback_latest.mjs +122 -0
- package/tests/fitness.mjs +44 -42
- package/tests/fitness_ratchets.mjs +2 -2
- package/tests/gate_approvals.mjs +0 -1
- package/tests/github_push_land_proof.mjs +1 -1
- package/tests/go_live.mjs +3 -3
- package/tests/goal_advisory.mjs +3 -3
- package/tests/goal_suggest.mjs +3 -3
- package/tests/government_abuse_matrix.mjs +21 -19
- package/tests/government_ownership_scope.mjs +33 -35
- package/tests/government_parity.mjs +2 -2
- package/tests/government_protected_surfaces.mjs +56 -37
- package/tests/government_require_permission.mjs +3 -3
- package/tests/government_seed.mjs +37 -4
- package/tests/government_session_scope.mjs +92 -366
- package/tests/hall_audit.mjs +1 -1
- package/tests/hall_error_envelope.mjs +4 -0
- package/tests/hall_landing_boot.mjs +4 -1
- package/tests/hall_palette.mjs +1 -16
- package/tests/hall_record_world.mjs +6 -0
- package/tests/hall_tweak_editor.mjs +52 -1
- package/tests/helpers.mjs +1 -1
- package/tests/host_topology_skips.mjs +3 -4
- package/tests/html_comment_nesting.mjs +137 -0
- package/tests/infra_exec_paths.mjs +9 -10
- package/tests/init.mjs +4 -5
- package/tests/instance_manifest.mjs +18 -25
- package/tests/kickoff_checklist.mjs +1 -1
- package/tests/lib_sh_resolution.mjs +0 -221
- package/tests/local_preview.mjs +0 -12
- package/tests/migration_namespace.mjs +6 -6
- package/tests/module-scope-map.mjs +9 -9
- package/tests/module_api.mjs +2 -2
- package/tests/module_catalog.mjs +1 -1
- package/tests/module_cli.mjs +20 -20
- package/tests/module_contributions.mjs +6 -6
- package/tests/module_loader.mjs +6 -6
- package/tests/module_manifest.mjs +26 -17
- package/tests/module_route_rank.mjs +2 -2
- package/tests/module_store_publish.mjs +307 -0
- package/tests/module_store_publish_route.mjs +121 -0
- package/tests/module_store_registry_migration.mjs +70 -0
- package/tests/modules.mjs +56 -26
- package/tests/modules_route_wiring.mjs +1 -1
- package/tests/onboarding_route_signals.mjs +21 -31
- package/tests/onboarding_state.mjs +35 -49
- package/tests/paste_token_session_store.mjs +1 -1
- package/tests/permission_path.mjs +0 -3
- package/tests/platform_boot.mjs +1 -2
- package/tests/platform_visibility_gate.mjs +1 -1
- package/tests/profile_route.mjs +1 -6
- package/tests/project_modules_ui.mjs +17 -17
- package/tests/projects_hub.mjs +5 -5
- package/tests/projects_hub_app_step.mjs +138 -0
- package/tests/projects_hub_module_picker.mjs +77 -76
- package/tests/projects_hub_pre_uat.mjs +4 -5
- package/tests/provision.mjs +7 -7
- package/tests/provisioning_capacity.mjs +1 -1
- package/tests/provisioning_recommendations.mjs +2 -1
- package/tests/provisioning_starter_bundles.mjs +0 -22
- package/tests/publish_branch_route.mjs +11 -19
- package/tests/publish_manifest.mjs +2 -3
- package/tests/publish_reconciler.mjs +8 -8
- package/tests/push_path_brief.mjs +10 -9
- package/tests/rank_tier_single_source.mjs +1 -13
- package/tests/regrade_eligibility.mjs +1 -1
- package/tests/rename_history_restraint.mjs +1 -1
- package/tests/repo_map.mjs +12 -13
- package/tests/runner_drift.mjs +3 -21
- package/tests/sandbox_stage.mjs +57 -390
- package/tests/seam_wiring_guard.mjs +11 -11
- package/tests/search_isolation.mjs +3 -3
- package/tests/session_records.mjs +1 -1
- package/tests/session_rename_fallback.mjs +1 -22
- package/tests/session_start_freshness.mjs +3 -3
- package/tests/session_token_hash_db.mjs +1 -1
- package/tests/ship_card.mjs +1 -1
- package/tests/ship_ci_deploy.mjs +17 -17
- package/tests/ship_error_shape.mjs +1 -1
- package/tests/ship_premerge.mjs +1 -1
- package/tests/ship_resume.mjs +1 -1
- package/tests/skill_preflight.mjs +2 -2
- package/tests/skip_is_not_pass.mjs +1 -1
- package/tests/task_visual_slots.mjs +31 -0
- package/tests/terms_acceptance.mjs +2 -2
- package/tests/upgrade.mjs +4 -4
- package/tests/watch_sealed_floor.mjs +0 -1
- package/tests/wizard_draft_resume.mjs +2 -2
- package/tests/wizard_intent_resume.mjs +21 -10
- package/tests/wizard_preselect_why.mjs +18 -18
- package/docs/onboarding/browser-terminal-guide.md +0 -73
- package/docs/recipes/managed-settings-remote-control.md +0 -416
- package/modules/dev-box/CLAUDE.md +0 -15
- package/modules/dev-box/box-access.js +0 -623
- package/modules/dev-box/box-credential.js +0 -94
- package/modules/dev-box/box-onboard.js +0 -486
- package/modules/dev-box/boxes.js +0 -1038
- package/modules/dev-box/db.js +0 -39
- package/modules/dev-box/module.json +0 -19
- package/modules/dev-box/routes/box.js +0 -1223
- package/scripts/gds/box-auth-check.js +0 -160
- package/scripts/gds/box-infra.js +0 -321
- package/scripts/gds/box-sync.js +0 -216
- package/scripts/gds/box.js +0 -1332
- package/scripts/gds/cf-tunnel.js +0 -558
- package/scripts/gds/smoke-box.sh +0 -150
- package/scripts/gds/tree-preflight.js +0 -241
- package/src/bongos/app-pair.js +0 -172
- package/tests/app_pair.mjs +0 -168
- package/tests/box_access.mjs +0 -578
- package/tests/box_auth_check.mjs +0 -114
- package/tests/box_code_staleness.mjs +0 -129
- package/tests/box_connect_e2e.mjs +0 -196
- package/tests/box_cost.mjs +0 -70
- package/tests/box_credential.mjs +0 -125
- package/tests/box_dns_repoint.mjs +0 -153
- package/tests/box_env.mjs +0 -64
- package/tests/box_host_keys.mjs +0 -126
- package/tests/box_infra_resolve.mjs +0 -246
- package/tests/box_onboard.mjs +0 -317
- package/tests/box_scope_session.mjs +0 -119
- package/tests/box_sweep_docs.mjs +0 -119
- package/tests/box_sync.mjs +0 -55
- package/tests/box_sync_scope_report.mjs +0 -126
- package/tests/box_task_scope.mjs +0 -169
- package/tests/box_task_scope_pause.mjs +0 -66
- package/tests/box_terminal_ssrf.mjs +0 -96
- package/tests/boxes.mjs +0 -1585
- package/tests/cf_ruleset_preflight.mjs +0 -142
- package/tests/cf_tunnel.mjs +0 -496
- package/tests/docs_scrubber_damage.mjs +0 -111
- package/tests/module_scope_active_claims.mjs +0 -94
- package/tests/ship_api_client_pathspec.mjs +0 -100
- package/tests/tree_preflight.mjs +0 -243
|
@@ -1197,14 +1197,9 @@
|
|
|
1197
1197
|
// unchanged. Deep links activate their group first, so scrollIntoView lands on
|
|
1198
1198
|
// a visible section.
|
|
1199
1199
|
|
|
1200
|
-
// The Dev box group (box panel, desktop app, pairing) exists only where the
|
|
1201
|
-
// dev-box module runs — a vanilla instance has no boxes to manage, so the
|
|
1202
|
-
// whole group (rail entry included) stays out rather than showing an empty
|
|
1203
|
-
// shell. RAIL_GROUPS derives from the items so a #dev-box anchor no-ops too.
|
|
1204
1200
|
const RAIL_ITEMS = [
|
|
1205
1201
|
{ id: 'account', label: 'Account' },
|
|
1206
1202
|
{ id: 'access', label: 'Access & keys' },
|
|
1207
|
-
...(window.OTB.moduleOn('dev-box') ? [{ id: 'devbox', label: 'Dev box' }] : []),
|
|
1208
1203
|
{ id: 'preferences', label: 'Preferences' },
|
|
1209
1204
|
{ id: 'sound', label: 'Sound' },
|
|
1210
1205
|
// task 1004296 — every project's version and its update; settings-software-update.js.
|
|
@@ -1213,7 +1208,7 @@
|
|
|
1213
1208
|
const RAIL_GROUPS = RAIL_ITEMS.map((i) => i.id).concat('extensions');
|
|
1214
1209
|
let rail = null;
|
|
1215
1210
|
|
|
1216
|
-
// task 2172 — stable per-panel anchors (/settings#cli, /settings#
|
|
1211
|
+
// task 2172 — stable per-panel anchors (/settings#cli, /settings#voices, …)
|
|
1217
1212
|
// so skills and docs can deep-link a panel without depending on internal
|
|
1218
1213
|
// section ids. #art-key predates the map and IS its section id (the hall's
|
|
1219
1214
|
// "Add your key" action + the CLI nudge target it) — kept verbatim.
|
|
@@ -1225,7 +1220,6 @@
|
|
|
1225
1220
|
'disciplines': 'craft-scroll',
|
|
1226
1221
|
'cli': 'cli-scroll',
|
|
1227
1222
|
'art-key': 'art-key',
|
|
1228
|
-
'dev-box-app': 'boxapp-scroll',
|
|
1229
1223
|
'interaction': 'interaction-scroll',
|
|
1230
1224
|
'wandering': 'wandering-scroll',
|
|
1231
1225
|
'rendering': 'render-scroll',
|
|
@@ -1341,19 +1335,12 @@
|
|
|
1341
1335
|
// DISPLAY NAME — the label beside your work (task 1669); seeded from /me.
|
|
1342
1336
|
setupDisplayName(builder);
|
|
1343
1337
|
|
|
1344
|
-
// DEV BOX APP — revealed once we know the viewer is a real builder,
|
|
1345
|
-
// and only where the dev-box module runs (the group's rail entry is gated
|
|
1346
|
-
// the same way above — task 2172).
|
|
1347
|
-
if (window.OTB.moduleOn('dev-box')) {
|
|
1348
|
-
$('#boxapp-scroll').hidden = false;
|
|
1349
|
-
loadDevboxLatestVersion(); // #924: best-effort "latest version: X" courtesy line
|
|
1350
|
-
}
|
|
1351
1338
|
// CONNECTIONS — Discord (hidden unless the server has Discord configured).
|
|
1352
1339
|
setupConnections(me && me.discord ? me.discord : null);
|
|
1353
1340
|
// CLI ACCESS — re-issue a CLI bearer from this browser session.
|
|
1354
1341
|
setupCliAccess();
|
|
1355
1342
|
// MODULE PANELS — render any Settings panels modules contributed via the
|
|
1356
|
-
// seam (BV1.R42). None today; ready for
|
|
1343
|
+
// seam (BV1.R42). None today; ready for discord/art once they leave core.
|
|
1357
1344
|
mountContributedPanels();
|
|
1358
1345
|
// Reveal the Extensions rail entry only when a module actually contributed:
|
|
1359
1346
|
// the kit rail re-renders from the item list, then re-marks the active group.
|
|
@@ -1383,27 +1370,10 @@
|
|
|
1383
1370
|
// the `needs` art_key item that drives the covered/action-needed banner.
|
|
1384
1371
|
await loadArtKey(me);
|
|
1385
1372
|
// Every section has now loaded/revealed — land any panel-anchor deep link
|
|
1386
|
-
// (/settings#cli, #
|
|
1373
|
+
// (/settings#cli, #voices, …) on its visible section.
|
|
1387
1374
|
applyHash();
|
|
1388
1375
|
}
|
|
1389
1376
|
|
|
1390
|
-
// #924: show the current published Dev Box app version next to the download
|
|
1391
|
-
// buttons, read from the same public endpoint the app polls (/downloads/devbox/
|
|
1392
|
-
// version → config/devbox-app.json). Best-effort: a fetch failure just leaves the
|
|
1393
|
-
// courtesy line hidden — it must never break the settings page.
|
|
1394
|
-
async function loadDevboxLatestVersion() {
|
|
1395
|
-
try {
|
|
1396
|
-
const r = await fetch('/downloads/devbox/version', { headers: { Accept: 'application/json' } });
|
|
1397
|
-
if (!r.ok) return;
|
|
1398
|
-
const v = await r.json();
|
|
1399
|
-
if (v && v.version) {
|
|
1400
|
-
const el = $('#boxapp-latest');
|
|
1401
|
-
el.textContent = `Latest version: v${v.version}.`;
|
|
1402
|
-
el.hidden = false;
|
|
1403
|
-
}
|
|
1404
|
-
} catch (_) { /* best-effort courtesy line — never break the page */ }
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
1377
|
wireRail();
|
|
1408
1378
|
load();
|
|
1409
1379
|
})();
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
"surface": "hall-ui",
|
|
5
5
|
"stub": { "prefix": "/builders/" },
|
|
6
6
|
"modeQuery": false,
|
|
7
|
-
"ignoreRequests": ["/api/(gds|bongos)/"
|
|
8
|
-
"ignoreConsole": ["/api/(gds|bongos)/", "
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/"],
|
|
8
|
+
"ignoreConsole": ["/api/(gds|bongos)/", "\\b401\\b", "\\b404\\b", "Unauthorized", "Not Found", "load failed", "Password field"],
|
|
9
9
|
"states": {
|
|
10
10
|
"account": { "auth": true, "actions": [["wait", 900]], "expect": { "visible": ["#settings-h1", "#display-name-input", "#craft-chips", "#privacy-rows"] } },
|
|
11
11
|
"access": { "auth": true, "url": "/settings#access", "actions": [["wait", 900]], "expect": { "visible": ["#cli-reissue-btn", "#sessions-list", "#artkey-card"] } },
|
|
@@ -189,7 +189,7 @@
|
|
|
189
189
|
<script src="/builders/approval-queue.js"></script>
|
|
190
190
|
<!-- The page names and the draft body (the tweak editor's pure rules), then
|
|
191
191
|
the studio's own. -->
|
|
192
|
-
<script src="/builders/tweak-editor-lib.js?v=2026-09-28-
|
|
192
|
+
<script src="/builders/tweak-editor-lib.js?v=2026-09-28-tw23"></script>
|
|
193
193
|
<script src="/builders/studio-lib.js?v=2026-09-28-tw16"></script>
|
|
194
194
|
<script src="/builders/studio.js?v=2026-09-28-tw16"></script>
|
|
195
195
|
</body>
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
--z-drawer: 150;
|
|
231
231
|
/* A confirm dialog is the one thing that must sit above the drawer: it is
|
|
232
232
|
asking a question the drawer's content cannot answer. Added by task 1003307
|
|
233
|
-
because
|
|
233
|
+
because two pages had each guessed a bare number for exactly this
|
|
234
234
|
(200 and 50), which is what a missing layer looks like. */
|
|
235
235
|
--z-modal: 160;
|
|
236
236
|
--z-diagram-full: 9999;
|
|
@@ -1303,7 +1303,6 @@ html[data-fullscreen="on"] .fullscreen-toggle {
|
|
|
1303
1303
|
.stat-tile:first-child { border-left: 0; }
|
|
1304
1304
|
.stat-tile__label,
|
|
1305
1305
|
.gate-stat__label,
|
|
1306
|
-
.harbor-stat__label,
|
|
1307
1306
|
.watch-stat__label {
|
|
1308
1307
|
font-family: var(--label-face);
|
|
1309
1308
|
font-size: var(--label-size);
|
|
@@ -1313,7 +1312,6 @@ html[data-fullscreen="on"] .fullscreen-toggle {
|
|
|
1313
1312
|
}
|
|
1314
1313
|
.stat-tile__num,
|
|
1315
1314
|
.gate-stat__value,
|
|
1316
|
-
.harbor-stat__value,
|
|
1317
1315
|
.watch-stat__num {
|
|
1318
1316
|
font-family: var(--font-display);
|
|
1319
1317
|
font-size: clamp(26px, 2.6vw, 34px);
|
|
@@ -2433,11 +2431,6 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
|
|
|
2433
2431
|
.setup__tab:first-child { padding-left: 0; }
|
|
2434
2432
|
.setup__tab:hover { color: var(--ink); }
|
|
2435
2433
|
.setup__tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--accent); }
|
|
2436
|
-
.setup__tab-tag { font-family: var(--label-face); font-size: 10.5px; letter-spacing: var(--label-space); text-transform: var(--label-case); margin-left: 6px; color: var(--ink-faint); }
|
|
2437
|
-
.setup__tab-tag--rec { color: var(--ok); }
|
|
2438
|
-
.setup__pane { display: none; }
|
|
2439
|
-
.setup[data-config="desktop"] .setup__pane--desktop { display: block; }
|
|
2440
|
-
.setup[data-config="online"] .setup__pane--online { display: block; }
|
|
2441
2434
|
.setup__steps { margin: 8px 0; padding-left: 20px; font-size: 13.5px; }
|
|
2442
2435
|
.setup__steps li { margin: 6px 0; }
|
|
2443
2436
|
/* The setup panel's prose links ("Git", "Claude Code", "primer") take the
|
|
@@ -3512,6 +3505,11 @@ a.stat-tile:hover .stat-tile__sub { color: var(--ink-soft); }
|
|
|
3512
3505
|
.next-up__title { font-weight: 400; font-size: 14px; color: var(--ink); }
|
|
3513
3506
|
.next-up__title:hover { color: var(--accent-ink); }
|
|
3514
3507
|
.next-up__meta { font-family: var(--font-mono); font-size: 11.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
|
|
3508
|
+
/* task 1003459: the row's Claim button reuses .task__claim's pill (the
|
|
3509
|
+
claimable card's own accent fill, style.css ~2769) rather than a second
|
|
3510
|
+
definition — align-self keeps it from stretching to the column's full
|
|
3511
|
+
width, which flex's default cross-axis stretch would otherwise do. */
|
|
3512
|
+
.next-up__item .task__claim { align-self: flex-start; margin-top: 4px; }
|
|
3515
3513
|
.next-up__foot { margin: 14px 0 18px; font-size: 13px; }
|
|
3516
3514
|
|
|
3517
3515
|
/* ---------- jump palette (task 2178) ----------
|
|
@@ -3638,16 +3636,16 @@ html.palette-open { overflow: hidden; }
|
|
|
3638
3636
|
state is a HAIRLINE in its own colour with no fill, and a scope is a quiet
|
|
3639
3637
|
mono chip. Neither is pressable, so neither takes the accent.
|
|
3640
3638
|
|
|
3641
|
-
These live here because
|
|
3642
|
-
.gov-pill, .
|
|
3643
|
-
|
|
3639
|
+
These live here because several pages had already invented them separately —
|
|
3640
|
+
.gov-pill, .gate-pill, .badge, .mod-chip — each re-spelling the label voice
|
|
3641
|
+
as literals. The shell had no neutral pill to take: .chip below is
|
|
3644
3642
|
the accent-tinted FILTER chip, and it means "press me".
|
|
3645
3643
|
|
|
3646
3644
|
The state colours are the hall's fixed verification vocabulary, never the
|
|
3647
3645
|
world's warm accent states (ADR 0196 §2): a status must not re-tint when an
|
|
3648
3646
|
instance re-brands. */
|
|
3649
3647
|
/* The names below are the SAME pill, found by the task 1003307 audit:
|
|
3650
|
-
government,
|
|
3648
|
+
government, gate and watch each invented one because the shell had
|
|
3651
3649
|
none to take (modules had one too; its rows take .fact-pill by name since
|
|
3652
3650
|
task 1003472). They are aliased rather than renamed because renaming would
|
|
3653
3651
|
mean editing the JS row builders, and a class name is not what was wrong —
|
|
@@ -3655,7 +3653,6 @@ html.palette-open { overflow: hidden; }
|
|
|
3655
3653
|
in their own sheets. */
|
|
3656
3654
|
.fact-pill,
|
|
3657
3655
|
.gov-pill,
|
|
3658
|
-
.harbor-pill,
|
|
3659
3656
|
.gate-pill,
|
|
3660
3657
|
.badge {
|
|
3661
3658
|
display: inline-flex;
|
|
@@ -69,6 +69,9 @@
|
|
|
69
69
|
<script src="/builders/brand-apply.js?v=2026-06-19-r56" defer></script>
|
|
70
70
|
<script src="/builders/md-reader.js" defer></script>
|
|
71
71
|
<script src="/builders/hall-visual.js?v=2026-09-16-visual1" defer></script>
|
|
72
|
-
|
|
72
|
+
<!-- task 1003459: the hall's ONE claim/release action (task 1003458) — this
|
|
73
|
+
page's Claim it button consumes it rather than a second hand-rolled POST. -->
|
|
74
|
+
<script src="/builders/claim-action.js?v=2026-09-26-claimaction1" defer></script>
|
|
75
|
+
<script src="/builders/task.js?v=2026-09-28-taskclaim" defer></script>
|
|
73
76
|
</body>
|
|
74
77
|
</html>
|
|
@@ -142,6 +142,15 @@
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
// task 1003459 — the hall's ONE claim action (task 1003458), consumed here so
|
|
146
|
+
// a task's own page can claim it directly instead of only handing over the
|
|
147
|
+
// copyable `/builder-claim N` string. `load` is hoisted below; reusing it as
|
|
148
|
+
// the refresh means a successful (or 409-refused) claim re-renders the whole
|
|
149
|
+
// record from the server's own state, the same idiom every other write here
|
|
150
|
+
// already follows.
|
|
151
|
+
const { makeClaimAction } = window.OTBClaimAction;
|
|
152
|
+
const claimAction = makeClaimAction({ postJSON, toast, API, refresh: load });
|
|
153
|
+
|
|
145
154
|
// task 759: run a lifecycle action (ship / confirm), then reload so the page
|
|
146
155
|
// re-renders at the new status. On failure, surface the server's refusal and
|
|
147
156
|
// re-enable the button. `load` is hoisted below.
|
|
@@ -711,7 +720,16 @@
|
|
|
711
720
|
const ownsLastClaim = !!(viewer && lastClaim && lastClaim.github_login &&
|
|
712
721
|
lastClaim.github_login === viewer.github_login);
|
|
713
722
|
let lifecycle = '';
|
|
714
|
-
|
|
723
|
+
// task 1003459 — the same door the Work board and Goals page already open.
|
|
724
|
+
// `ready` is the one status the claim gate can actually admit (backlog
|
|
725
|
+
// needs a promote first, blocked waits on a dependency, and both already
|
|
726
|
+
// say so in the lifecycle rail above) — every other refusal (rank, an
|
|
727
|
+
// owed rebase, a module/touches conflict, …) is still possible and still
|
|
728
|
+
// surfaces, because claimAction.claim() carries the same friendlyClaimError
|
|
729
|
+
// switch the board uses, not a second guess at it here.
|
|
730
|
+
if (t.status === 'ready') {
|
|
731
|
+
lifecycle = `<button class="td-btn td-btn--primary" type="button" id="claim-btn">Claim it</button>`;
|
|
732
|
+
} else if (t.status === 'confirmed' && (isSupervisor || ownsLastClaim)) {
|
|
715
733
|
lifecycle = `<button class="td-btn td-btn--primary" type="button" id="ship-btn">Ship it</button>`;
|
|
716
734
|
} else if (t.status === 'completed') {
|
|
717
735
|
lifecycle = rank === 'archon'
|
|
@@ -823,6 +841,23 @@
|
|
|
823
841
|
});
|
|
824
842
|
}
|
|
825
843
|
|
|
844
|
+
const claimBtn = $('#claim-btn');
|
|
845
|
+
if (claimBtn) {
|
|
846
|
+
claimBtn.addEventListener('click', async () => {
|
|
847
|
+
if (claimBtn.disabled) return;
|
|
848
|
+
claimBtn.disabled = true;
|
|
849
|
+
claimBtn.textContent = '…';
|
|
850
|
+
const out = await claimAction.claim(t.id);
|
|
851
|
+
// A redirect to sign-in is already navigating away; re-enabling here
|
|
852
|
+
// would just invite a click that can't land (task.js's own pattern,
|
|
853
|
+
// runLifecycle above).
|
|
854
|
+
if (!out.ok && !out.redirected) {
|
|
855
|
+
claimBtn.disabled = false;
|
|
856
|
+
claimBtn.textContent = 'Claim it';
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
|
|
826
861
|
const shipBtn = $('#ship-btn');
|
|
827
862
|
if (shipBtn) {
|
|
828
863
|
shipBtn.addEventListener('click', () => {
|
|
@@ -107,6 +107,23 @@
|
|
|
107
107
|
return `uploaded · ${n} ${n === 1 ? 'line' : 'lines'} from your doc`;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// A refused upload, as the panel says it (task 1004354): a headline naming
|
|
111
|
+
// what happened, the next step in plain words, and whether a fresh download
|
|
112
|
+
// is part of that step. The server's own what_this_means sits between them.
|
|
113
|
+
const REDOWNLOAD = 'Or download this page again, make your changes in the new file, and upload that.';
|
|
114
|
+
const UPLOAD_REFUSALS = Object.freeze({
|
|
115
|
+
wrong_page: { title: 'This file is a different page.', next: `Pick the file you downloaded from this page and upload it again. ${REDOWNLOAD}`, download: true },
|
|
116
|
+
reading_moved: { title: 'This page changed after you downloaded it.', next: 'Download this page again, copy your changes into the new file, and upload that.', download: true },
|
|
117
|
+
structure_changed: { title: 'Some lines in your file moved.', next: `Put the lines listed here back the way they were, one paragraph per line, and upload again. ${REDOWNLOAD}`, download: true },
|
|
118
|
+
not_a_docx: { title: 'That file is not a Word file.', next: 'Upload the .docx you downloaded here. From Google Docs, choose File, then Download, then Microsoft Word (.docx).', download: false },
|
|
119
|
+
upload_too_large: { title: 'That file is too big.', next: `Take out any pictures you pasted in and upload it again. ${REDOWNLOAD}`, download: true },
|
|
120
|
+
page_not_held: { title: 'Someone else is writing this page now.', next: 'Reload the editor to see who holds it. Your file is still on your computer.', download: false },
|
|
121
|
+
page_in_flight: { title: 'This page has already been submitted.', next: 'Reload the editor. Its words are frozen until it ships or is sent back.', download: false },
|
|
122
|
+
});
|
|
123
|
+
function uploadRefusal(code) {
|
|
124
|
+
return UPLOAD_REFUSALS[code] || { title: 'Your file was not saved.', next: `Try the upload again. ${REDOWNLOAD}`, download: true };
|
|
125
|
+
}
|
|
126
|
+
|
|
110
127
|
// A page's name as the artist reads it ("Home", "Projects"). The inventory's
|
|
111
128
|
// title is the page's <title>, and on the apex that is a branding template
|
|
112
129
|
// ("{{productName}}: {{tagline}}"), which is not a name. So a templated title
|
|
@@ -131,7 +148,7 @@
|
|
|
131
148
|
return PAGE_ID_RE.test(id) ? id : null;
|
|
132
149
|
}
|
|
133
150
|
|
|
134
|
-
const api = { NOTES, sectionsOf, isChanged, noteFor, draftBody, changedCount, counterText, initialValues, rowsFor, liveUrl, uploadedLabel, displayTitle, pageIdFrom };
|
|
151
|
+
const api = { NOTES, sectionsOf, isChanged, noteFor, draftBody, changedCount, counterText, initialValues, rowsFor, liveUrl, uploadedLabel, uploadRefusal, displayTitle, pageIdFrom };
|
|
135
152
|
if (typeof window !== 'undefined') window.OTBTweakEditor = api;
|
|
136
153
|
if (typeof module !== 'undefined' && module.exports) module.exports = api;
|
|
137
154
|
})();
|
|
@@ -404,6 +404,22 @@ html:not([data-fullscreen="on"]) .tw-bar { top: calc(var(--topbar-h, 56px) + 12p
|
|
|
404
404
|
.tw-stage .tw-linkish:focus-visible { outline: 2px solid var(--tw-accent); outline-offset: 2px; }
|
|
405
405
|
.tw-done__error { margin: 0; font-size: 14px; line-height: 1.5; color: var(--tw-link); }
|
|
406
406
|
|
|
407
|
+
/* A REFUSED UPLOAD (task 1004354). Not on the artboard, which has no failing
|
|
408
|
+
state: the "is in" panel's own glass and scrim, so a refusal is as
|
|
409
|
+
unmissable as a submit. It scrolls inside itself on a short phone rather
|
|
410
|
+
than hide its buttons below the window. */
|
|
411
|
+
.tw-refused .tw-done__panel { max-height: calc(100vh - 32px); overflow-y: auto; }
|
|
412
|
+
.tw-refused__list {
|
|
413
|
+
margin: 0;
|
|
414
|
+
padding-left: 18px;
|
|
415
|
+
font-size: 14px;
|
|
416
|
+
line-height: 1.5;
|
|
417
|
+
color: var(--tw-ink-soft);
|
|
418
|
+
}
|
|
419
|
+
.tw-refused__list li { margin: 2px 0; overflow-wrap: anywhere; }
|
|
420
|
+
.tw-refused__list[hidden] { display: none; }
|
|
421
|
+
.tw-refused__next { margin: 0; font-size: 15px; line-height: 1.5; color: var(--tw-ink); }
|
|
422
|
+
|
|
407
423
|
/* PHONE WIDTH (not on the artboard, which is 1440 wide). The bar stops being
|
|
408
424
|
one pill and becomes a glass card of two rows: where you are and how far,
|
|
409
425
|
then the four doors, wrapping. The paper takes the width, and each margin
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
12
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
13
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
14
|
-
<link rel="stylesheet" href="/builders/tweak-editor.css?v=2026-09-28-
|
|
14
|
+
<link rel="stylesheet" href="/builders/tweak-editor.css?v=2026-09-28-tw23">
|
|
15
15
|
</head>
|
|
16
16
|
<!-- THE TWEAK EDITOR (task 1004321 / BV2.TW10, goal 1000095; ADR 0341 D4 and
|
|
17
17
|
D11). docs/design/mocks/tweak-mode/Editor.dc.html is the master design:
|
|
@@ -93,6 +93,29 @@
|
|
|
93
93
|
<div class="tw-picks" id="tw-picks" hidden></div>
|
|
94
94
|
</div>
|
|
95
95
|
</div>
|
|
96
|
+
|
|
97
|
+
<!-- A refused upload (task 1004354): the "is in" panel's glass over the
|
|
98
|
+
whole window, so it cannot scroll away. What happened, the lines
|
|
99
|
+
it names, and what to do. The notice on the paper stays after it
|
|
100
|
+
closes. -->
|
|
101
|
+
<div class="tw-done tw-refused" id="tw-refused" hidden>
|
|
102
|
+
<div class="tw-done__panel" role="alertdialog" aria-modal="true" aria-labelledby="tw-refused-title" aria-describedby="tw-refused-what">
|
|
103
|
+
<div class="tw-done__head">
|
|
104
|
+
<span class="tw-next__label">nothing was saved</span>
|
|
105
|
+
<h2 class="tw-done__title" id="tw-refused-title" tabindex="-1">Your file was not saved.</h2>
|
|
106
|
+
<p class="tw-done__sub" id="tw-refused-what"></p>
|
|
107
|
+
</div>
|
|
108
|
+
<ul class="tw-refused__list" id="tw-refused-list" hidden></ul>
|
|
109
|
+
<div class="tw-next">
|
|
110
|
+
<span class="tw-next__label">what to do</span>
|
|
111
|
+
<p class="tw-refused__next" id="tw-refused-next"></p>
|
|
112
|
+
</div>
|
|
113
|
+
<div class="tw-done__acts">
|
|
114
|
+
<button class="tw-take" id="tw-refused-download" type="button">download this page again</button>
|
|
115
|
+
<button class="tw-linkish" id="tw-refused-close" type="button">close</button>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
96
119
|
</main>
|
|
97
120
|
|
|
98
121
|
<footer class="app-foot" id="app-foot"></footer>
|
|
@@ -105,7 +128,7 @@
|
|
|
105
128
|
<script src="/builders/shell.js?v=2026-09-28-archive"></script>
|
|
106
129
|
<script src="/builders/palette.js" defer></script>
|
|
107
130
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
108
|
-
<script src="/builders/tweak-editor-lib.js?v=2026-09-28-
|
|
109
|
-
<script src="/builders/tweak-editor.js?v=2026-09-28-
|
|
131
|
+
<script src="/builders/tweak-editor-lib.js?v=2026-09-28-tw23"></script>
|
|
132
|
+
<script src="/builders/tweak-editor.js?v=2026-09-28-tw23"></script>
|
|
110
133
|
</body>
|
|
111
134
|
</html>
|
|
@@ -244,6 +244,34 @@
|
|
|
244
244
|
const msg = (d && d.what_this_means) || errMessage(data) || fallback;
|
|
245
245
|
const items = refusalItems(d || {});
|
|
246
246
|
notice(`<p>${escapeHtml(msg)}</p>${items.length ? `<ul>${items.map((i) => `<li>${escapeHtml(i)}</li>`).join('')}</ul>` : ''}`);
|
|
247
|
+
return { msg, items };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// A refused UPLOAD also opens the panel over the whole window (task
|
|
251
|
+
// 1004354): an artist uploads from the bar, often far down the page, where a
|
|
252
|
+
// notice at the top of the paper is off screen. It names what happened and
|
|
253
|
+
// the next step; the paper's notice stays after it closes.
|
|
254
|
+
function showRefused(data, said) {
|
|
255
|
+
const code = data && data.error ? data.error.code : null;
|
|
256
|
+
const r = lib.uploadRefusal(code);
|
|
257
|
+
$('tw-refused-title').textContent = r.title;
|
|
258
|
+
$('tw-refused-what').textContent = said.msg;
|
|
259
|
+
const list = $('tw-refused-list');
|
|
260
|
+
list.innerHTML = said.items.map((i) => `<li>${escapeHtml(i)}</li>`).join('');
|
|
261
|
+
list.hidden = !said.items.length;
|
|
262
|
+
$('tw-refused-next').textContent = r.next;
|
|
263
|
+
$('tw-refused-download').hidden = !r.download;
|
|
264
|
+
$('tw-bar').inert = true;
|
|
265
|
+
$('tw-paper').inert = true;
|
|
266
|
+
$('tw-refused').hidden = false;
|
|
267
|
+
$('tw-refused-title').focus();
|
|
268
|
+
}
|
|
269
|
+
function closeRefused() {
|
|
270
|
+
if ($('tw-refused').hidden) return;
|
|
271
|
+
$('tw-refused').hidden = true;
|
|
272
|
+
$('tw-bar').inert = false;
|
|
273
|
+
$('tw-paper').inert = false;
|
|
274
|
+
$('tw-upload').focus();
|
|
247
275
|
}
|
|
248
276
|
|
|
249
277
|
// Leaving with an unsaved change: one last save that outlives the page.
|
|
@@ -294,7 +322,7 @@
|
|
|
294
322
|
btn.disabled = false;
|
|
295
323
|
if (!r.ok) {
|
|
296
324
|
btn.textContent = 'upload .docx';
|
|
297
|
-
refusal(r.data, 'The file could not be read. Nothing was saved.');
|
|
325
|
+
showRefused(r.data, refusal(r.data, 'The file could not be read. Nothing was saved.'));
|
|
298
326
|
return;
|
|
299
327
|
}
|
|
300
328
|
notice('');
|
|
@@ -403,6 +431,7 @@
|
|
|
403
431
|
document.addEventListener('focusout', (ev) => {
|
|
404
432
|
if (ev.target && ev.target.classList && ev.target.classList.contains('tw-line')) flush();
|
|
405
433
|
});
|
|
434
|
+
document.addEventListener('keydown', (ev) => { if (ev.key === 'Escape') closeRefused(); });
|
|
406
435
|
window.addEventListener('resize', () => { document.querySelectorAll('textarea.tw-line').forEach(fit); });
|
|
407
436
|
|
|
408
437
|
document.addEventListener('click', async (ev) => {
|
|
@@ -411,6 +440,8 @@
|
|
|
411
440
|
if (t.closest('#tw-upload')) { $('tw-file').click(); return; }
|
|
412
441
|
if (t.closest('#tw-submit')) { submit(); return; }
|
|
413
442
|
if (t.closest('#tw-take')) { takeNext(); return; }
|
|
443
|
+
if (t.closest('#tw-refused-close')) { closeRefused(); return; }
|
|
444
|
+
if (t.closest('#tw-refused-download')) { closeRefused(); download(); return; }
|
|
414
445
|
if (t.closest('#tw-claim')) {
|
|
415
446
|
const b = t.closest('#tw-claim');
|
|
416
447
|
b.disabled = true;
|
|
@@ -606,7 +606,7 @@
|
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
// Editors and the Claude desktop/CLI app autolink any bare "#NNN" in a session
|
|
609
|
-
// transcript to the
|
|
609
|
+
// transcript to the checkout's GitHub remote (…/issues/NNN), which 404s because
|
|
610
610
|
// our records number tasks separately from GitHub. So the scroll we hand the
|
|
611
611
|
// builder must never carry a bare "#NNN": write "task NNN" + the clickable hall
|
|
612
612
|
// URL, and strip "#NNN" out of the (free-text) task description too.
|
|
@@ -25,6 +25,7 @@ The paper is paper and the room is the room whatever the hall's theme: the stage
|
|
|
25
25
|
- **A focused line gets a hairline accent ring** beside the artboard's warm wash (the hall's focus rule, `tests/hall_audit.mjs` §10).
|
|
26
26
|
- **"pick another" opens the other pages in place** as chips under the actions (the studio artboard's own "pick another"), where the editor artboard linked to the studio, whose flow panel is TW16's.
|
|
27
27
|
- **Boxes grow to their words** rather than the artboard's rows 1 or 2.
|
|
28
|
+
- **A refused upload opens a panel** (task 1004354, `#tw-refused`): the "is in" panel's glass and scrim over the whole window, a headline per refusal (`lib.uploadRefusal`), the server's words, the lines it names, "what to do", and "download this page again" or close (Escape too). An artist uploads from the bar, often far down the page, where the paper's notice was off screen. The notice stays on the paper after the panel closes. The kit has no file-upload action, so the panel is proven in `tests/hall_tweak_editor.mjs` and by shots of a real browser at 1440 and 390, not by a states.json state.
|
|
28
29
|
- **Not on the artboard at all:** the phone layout (the bar becomes a two-row glass card, notes drop under their lines), the shell's full-screen button top right, the read-only and refusal notices on the paper, the chrome view (the switch off), and light mode.
|
|
29
30
|
|
|
30
31
|
## The proof
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"key": "ideas",
|
|
3
3
|
"title": "Ideas",
|
|
4
4
|
"description": "The idea inbox (capture, triage, criterion-proposal ratification) and the blockers queue — the methodology surfaces that feed the backlog. A core-domain module carved out of the GDS core in BV1.R78 (ADR 0093 §1); default-on because every instance captures ideas and tracks what's stuck on its owner. Registers the `ideas.capture` kernel PORT the discord #ideas inbound resolves (ADR 0093 §5 — retiring the temporary `captureIdea` doorway leak).",
|
|
5
|
+
"version": "1.0.0",
|
|
5
6
|
"coreVersion": "^1.8.0",
|
|
6
7
|
"default": true,
|
|
7
8
|
"maintenance": {
|
|
@@ -50,7 +50,7 @@ const IDEA_COLS = IDEA_COL_NAMES.join(', ');
|
|
|
50
50
|
//
|
|
51
51
|
// THE DOOR IS READ OFF THE SESSION, not claimed in the body. A web cookie is the
|
|
52
52
|
// hall (the ideas form, the sky's composer), a device-flow token is the CLI
|
|
53
|
-
// (capture.js, spark.js), anything else (a
|
|
53
|
+
// (capture.js, spark.js), anything else (a program on the port) is
|
|
54
54
|
// the API — so a filer cannot say they came through a door they did not. The one
|
|
55
55
|
// value a body may ADD is 'planning': a planning session's capture is a CLI
|
|
56
56
|
// filing no session can tell apart, so capture.js --via planning names it. The
|
|
@@ -34,61 +34,6 @@ async function getActiveClaimsForBuilder(builderId) {
|
|
|
34
34
|
return rows;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// Task-scoped dev box (goal 1000051 / R92, ADR 0148 §2). The set-union of the
|
|
38
|
-
// module KEYS a builder's active claims put in scope: each active claim's task →
|
|
39
|
-
// its goal → goal.scope_modules (the ADR 0086 scope wall), unioned + deduped
|
|
40
|
-
// across all the builder's active claims. This is the "what code does this
|
|
41
|
-
// builder's current work need" signal the dev-box source-access resolver
|
|
42
|
-
// (modules/dev-box/box-access.js, wired in R93/R94) maps to git sparse-checkout
|
|
43
|
-
// globs via the doorway `moduleScopeMap`. Returns [] when the builder holds no
|
|
44
|
-
// active claim, or when every claimed task carries no goal / an empty
|
|
45
|
-
// scope_modules — the box then falls back to BASE-only (the pre-existing Bongos
|
|
46
|
-
// instance). KEYS only; glob resolution is the box module's job (it reaches
|
|
47
|
-
// moduleScopeMap through the doorway, never a core-internal require — the
|
|
48
|
-
// R90/ADR-0148 boundary). Honours the #538 deps.pool test seam
|
|
49
|
-
// (NODE_ENV==='test' only), like the goals reads above.
|
|
50
|
-
async function moduleScopeForActiveClaims(builderId, deps = {}) {
|
|
51
|
-
const activePool = (deps.pool && process.env.NODE_ENV === 'test') ? deps.pool : pool;
|
|
52
|
-
const id = Number(builderId);
|
|
53
|
-
if (!Number.isInteger(id)) {
|
|
54
|
-
throw new Error('moduleScopeForActiveClaims: builderId must be numeric');
|
|
55
|
-
}
|
|
56
|
-
const { rows } = await activePool.query(
|
|
57
|
-
`SELECT DISTINCT m AS module_key
|
|
58
|
-
FROM claims c
|
|
59
|
-
JOIN tasks t ON t.id = c.task_id
|
|
60
|
-
JOIN goals g ON g.id = t.goal_id
|
|
61
|
-
CROSS JOIN LATERAL unnest(g.scope_modules) AS m
|
|
62
|
-
WHERE c.builder_id = $1 AND c.released_at IS NULL
|
|
63
|
-
ORDER BY m`,
|
|
64
|
-
[id]
|
|
65
|
-
);
|
|
66
|
-
return rows.map((r) => r.module_key);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Task 1002729 — the companion signal moduleScopeForActiveClaims cannot carry.
|
|
70
|
-
// That query INNER JOINs goals and unnests scope_modules, so it returns [] for
|
|
71
|
-
// BOTH "this builder holds no claim" and "this builder holds claims whose goals
|
|
72
|
-
// declare no scope_modules". Those must not be treated alike: the first is a
|
|
73
|
-
// genuinely unscoped box (BASE-only is right), the second is a builder actively
|
|
74
|
-
// working who would be handed a box with no modules/ at all. Live evidence for
|
|
75
|
-
// why this matters: 247 of 248 source grants on the cloudbongos fleet resolved to
|
|
76
|
-
// BASE, including an Archon holding 7 active claims — every one of those claims
|
|
77
|
-
// sat on a goal with scope_modules = {}. Counts CLAIMS, deliberately not joining
|
|
78
|
-
// goals, so it stays true regardless of how the goal wall is (or isn't) declared.
|
|
79
|
-
async function activeClaimCountForBuilder(builderId, deps = {}) {
|
|
80
|
-
const activePool = (deps.pool && process.env.NODE_ENV === 'test') ? deps.pool : pool;
|
|
81
|
-
const id = Number(builderId);
|
|
82
|
-
if (!Number.isInteger(id)) {
|
|
83
|
-
throw new Error('activeClaimCountForBuilder: builderId must be numeric');
|
|
84
|
-
}
|
|
85
|
-
const { rows } = await activePool.query(
|
|
86
|
-
`SELECT count(*)::int AS n FROM claims WHERE builder_id = $1 AND released_at IS NULL`,
|
|
87
|
-
[id]
|
|
88
|
-
);
|
|
89
|
-
return rows.length ? Number(rows[0].n) : 0;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
37
|
// task 1642 — every active claim bound to a given CLI session. "Active" is the
|
|
93
38
|
// claims-table convention (released_at IS NULL); there is NO `status` column on
|
|
94
39
|
// claims (a common misread — the task's status lives on `tasks`). Keyed on
|
|
@@ -159,7 +104,7 @@ async function getLastClaimHolder(taskId) {
|
|
|
159
104
|
// reading it.
|
|
160
105
|
//
|
|
161
106
|
// `deps.pool` is the family's test-only pool seam (task 538), honoured ONLY under
|
|
162
|
-
// NODE_ENV==='test' (the same line
|
|
107
|
+
// NODE_ENV==='test' (the same line the family's other reads use), so
|
|
163
108
|
// tests/grade_diff_hash.mjs can drive the lift with a fake row instead of a
|
|
164
109
|
// real Postgres (task 1003490). Production callers pass the task id alone.
|
|
165
110
|
async function getTaskGrade(taskId, deps = {}) {
|
|
@@ -217,12 +162,10 @@ async function getTaskSessionLogs(taskId) {
|
|
|
217
162
|
}
|
|
218
163
|
|
|
219
164
|
module.exports = {
|
|
220
|
-
activeClaimCountForBuilder,
|
|
221
165
|
getActiveClaimsForBuilder,
|
|
222
166
|
getActiveClaimsForSession,
|
|
223
167
|
getLastClaimHolder,
|
|
224
168
|
getTaskClaims,
|
|
225
169
|
getTaskGrade,
|
|
226
170
|
getTaskSessionLogs,
|
|
227
|
-
moduleScopeForActiveClaims,
|
|
228
171
|
};
|
|
@@ -224,17 +224,17 @@ async function resolveClaim({ claimId, builderId, outcome, notesMd, valueSummary
|
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
// Task #1048 (ADR 0046 follow-up): record the builder's sandbox self-approval
|
|
227
|
-
// as a durable fact on the task. When a
|
|
227
|
+
// as a durable fact on the task. When a builder reviews a staged
|
|
228
228
|
// game change on their sandbox and approves shipping it (TTY 'y', or an
|
|
229
229
|
// explicit --approved re-run on the dominant non-TTY path), ship.js threads
|
|
230
230
|
// { stamp, url, method } through this resolve call. We stamp `by` + `at`
|
|
231
231
|
// SERVER-SIDE (never trust the client for identity or time) and persist the
|
|
232
232
|
// blob to tasks.sandbox_review. Only on a 'shipped' resolve carrying a
|
|
233
|
-
// payload — laptop ships, non-game diffs,
|
|
233
|
+
// payload — laptop ships, non-game diffs, --skip-stage,
|
|
234
234
|
// and un-approved re-runs send nothing, leaving the column NULL.
|
|
235
235
|
if (outcome === 'shipped' && sandboxReview && typeof sandboxReview === 'object' && sandboxReview.stamp) {
|
|
236
236
|
// Sanitize the client-supplied fields (defense in depth): the builder's
|
|
237
|
-
//
|
|
237
|
+
// machine controls stamp/url/method, so clamp lengths, whitelist `method`, and
|
|
238
238
|
// accept only an https:// URL. This keeps a forged/oversized value — or a
|
|
239
239
|
// future stored-XSS string like a `javascript:` URL rendered in the hall —
|
|
240
240
|
// out of the persisted record. `by`/`at` stay SERVER-stamped (never
|
|
@@ -672,11 +672,6 @@ async function shipTask({ taskId, builderId, landAssurance }, deps = {}) {
|
|
|
672
672
|
console.log('[gds] graduation broadcast post-ship failed:', e && e.message);
|
|
673
673
|
}
|
|
674
674
|
}
|
|
675
|
-
if (rankGraduation) {
|
|
676
|
-
await seams.emitAsync('builder.box-reconcile-needed', {
|
|
677
|
-
builderId: actualShipperId, rank: 'thetes', status: rankGraduation.status, actor: 'auto-graduation:#692',
|
|
678
|
-
}).catch(() => {});
|
|
679
|
-
}
|
|
680
675
|
await recordShipAssurance({ insertAuditLog, taskId, builderId: actualShipperId, assurance: shipAssuranceValue, log });
|
|
681
676
|
return {
|
|
682
677
|
...shipRow,
|
|
@@ -1103,7 +1098,7 @@ async function confirmTask({ taskId, builderId }, deps = {}) {
|
|
|
1103
1098
|
// first-class way to KILL a task that is no longer relevant. The only routes to
|
|
1104
1099
|
// status='abandoned' were offboarding a builder (offboardBuilder, which seals
|
|
1105
1100
|
// each open claim) and a raw SQL UPDATE — so stale/moot tasks sat in 'ready' as
|
|
1106
|
-
// claimable noise (the
|
|
1101
|
+
// claimable noise (the teardown chores #819/#822/#827 and the dup tasks
|
|
1107
1102
|
// #907/#926 that other sessions had already shipped, all retired 2026-06-13).
|
|
1108
1103
|
// This is the missing transition.
|
|
1109
1104
|
//
|
package/modules/lifecycle/db.js
CHANGED
|
@@ -203,14 +203,12 @@ const {
|
|
|
203
203
|
} = require('./db-overrides.js');
|
|
204
204
|
const { applyGrade } = require('./db-grade.js');
|
|
205
205
|
const {
|
|
206
|
-
activeClaimCountForBuilder,
|
|
207
206
|
getActiveClaimsForBuilder,
|
|
208
207
|
getActiveClaimsForSession,
|
|
209
208
|
getLastClaimHolder,
|
|
210
209
|
getTaskClaims,
|
|
211
210
|
getTaskGrade,
|
|
212
211
|
getTaskSessionLogs,
|
|
213
|
-
moduleScopeForActiveClaims,
|
|
214
212
|
} = require('./db-claim-reads.js');
|
|
215
213
|
const {
|
|
216
214
|
claimTask,
|
|
@@ -333,8 +331,6 @@ module.exports = {
|
|
|
333
331
|
getClaimPublishedSha, // task 1547 — read the published tip for the reconcile gate
|
|
334
332
|
shippedTasksByPublishedSha, // task 1004090 / BV2.R15 — the reverse read, for removal attribution
|
|
335
333
|
getActiveClaimsForBuilder,
|
|
336
|
-
moduleScopeForActiveClaims, // goal 1000051 / R92 — dev-box task-scoped source access (ADR 0148 §2)
|
|
337
|
-
activeClaimCountForBuilder, // task 1002729 — distinguishes "no claim" from "claim with an empty goal wall"
|
|
338
334
|
getActiveClaimsForSession,
|
|
339
335
|
getLastClaimHolder, // --regrade ownership guard (#678)
|
|
340
336
|
getTaskGrade, // V4.R08 — diff-hash reuse check before grading
|