@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
|
@@ -56,7 +56,7 @@ for (const fn of ['function ensureModsCatalog(', 'function renderMods(', 'functi
|
|
|
56
56
|
const CATALOG = {
|
|
57
57
|
core: ['memory', 'lifecycle', 'hall-ui'],
|
|
58
58
|
optional: [
|
|
59
|
-
{ key: '
|
|
59
|
+
{ key: 'npm-release', label: 'npm release', summary: 'Publishes each release of your project to npm.' },
|
|
60
60
|
{ key: 'discord', label: 'Discord', summary: 'Mirrors what ships into a Discord channel.' },
|
|
61
61
|
{ key: 'agents', label: 'Agents', summary: 'Lets AI builders claim and ship work on their own.' },
|
|
62
62
|
],
|
|
@@ -76,7 +76,7 @@ function parseRows(html) {
|
|
|
76
76
|
|
|
77
77
|
// Boot the region against a scripted catalog + detail channel and hand back the
|
|
78
78
|
// handles a test drives it with.
|
|
79
|
-
function boot({ selected = ['
|
|
79
|
+
function boot({ selected = ['npm-release'], source = 'chosen', catalog = CATALOG, catalogOk = true, patchAnswer } = {}) {
|
|
80
80
|
const requests = [];
|
|
81
81
|
const els = new Map();
|
|
82
82
|
const listeners = new Map();
|
|
@@ -156,14 +156,14 @@ function boot({ selected = ['dev-box'], source = 'chosen', catalog = CATALOG, ca
|
|
|
156
156
|
|
|
157
157
|
test('the band renders the optional catalog the server offered — a row and a sentence each', async () => {
|
|
158
158
|
// Arrange
|
|
159
|
-
const ui = boot({ selected: ['
|
|
159
|
+
const ui = boot({ selected: ['npm-release'] });
|
|
160
160
|
|
|
161
161
|
// Act
|
|
162
162
|
await ui.render();
|
|
163
163
|
|
|
164
164
|
// Assert
|
|
165
|
-
assert.deepEqual(ui.rows().map((r) => r.key), ['
|
|
166
|
-
assert.deepEqual(ui.rows().map((r) => r.label), ['
|
|
165
|
+
assert.deepEqual(ui.rows().map((r) => r.key), ['npm-release', 'discord', 'agents']);
|
|
166
|
+
assert.deepEqual(ui.rows().map((r) => r.label), ['npm release', 'Discord', 'Agents']);
|
|
167
167
|
for (const r of ui.rows()) assert.ok(r.summary.length > 20, `${r.label} says what it is for`);
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -171,11 +171,11 @@ test('what the project runs today is what is switched on — resolved by the ser
|
|
|
171
171
|
// A project that SKIPPED the picker reads as its own starter bundle, and the
|
|
172
172
|
// band must show that set rather than an empty one: the whole point of
|
|
173
173
|
// effectiveModules resolving `source: 'bundle'` on the way out.
|
|
174
|
-
const ui = boot({ selected: ['
|
|
174
|
+
const ui = boot({ selected: ['npm-release', 'discord'], source: 'bundle' });
|
|
175
175
|
|
|
176
176
|
await ui.render();
|
|
177
177
|
|
|
178
|
-
assert.deepEqual(ui.rows().filter((r) => r.on).map((r) => r.key), ['
|
|
178
|
+
assert.deepEqual(ui.rows().filter((r) => r.on).map((r) => r.key), ['npm-release', 'discord']);
|
|
179
179
|
assert.deepEqual(ui.rows().filter((r) => !r.on).map((r) => r.key), ['agents']);
|
|
180
180
|
});
|
|
181
181
|
|
|
@@ -185,7 +185,7 @@ test('the always-on core is COUNTED and stated, and is not a row anyone can swit
|
|
|
185
185
|
await ui.render();
|
|
186
186
|
|
|
187
187
|
assert.match(ui.slot(), /the same 3 core parts/, 'the clause names how many, from the server\'s own list');
|
|
188
|
-
assert.deepEqual(ui.rows().map((r) => r.key), ['
|
|
188
|
+
assert.deepEqual(ui.rows().map((r) => r.key), ['npm-release', 'discord', 'agents'], 'and no core key is on the band');
|
|
189
189
|
for (const key of CATALOG.core) {
|
|
190
190
|
assert.equal(ui.rows().some((r) => r.key === key), false, `${key} is not a choice`);
|
|
191
191
|
}
|
|
@@ -196,26 +196,26 @@ test('a toggle issues the write — the WHOLE list, in catalog order, on the own
|
|
|
196
196
|
const ui = boot({ selected: ['discord'] });
|
|
197
197
|
await ui.render();
|
|
198
198
|
|
|
199
|
-
// Act — switch
|
|
200
|
-
await ui.click('
|
|
199
|
+
// Act — switch npm release ON
|
|
200
|
+
await ui.click('npm-release');
|
|
201
201
|
|
|
202
202
|
// Assert
|
|
203
203
|
const patch = ui.requests.find((r) => r.method === 'PATCH');
|
|
204
204
|
assert.ok(patch, 'a PATCH was sent');
|
|
205
205
|
assert.equal(patch.url, '/api/bongos/provisioning/instances/18/detail');
|
|
206
|
-
assert.deepEqual(JSON.parse(patch.body), { modules: ['
|
|
206
|
+
assert.deepEqual(JSON.parse(patch.body), { modules: ['npm-release', 'discord'] },
|
|
207
207
|
'catalog order, exactly as the column stores it — never append order');
|
|
208
208
|
assert.equal(patch.credentials, 'same-origin', 'the cookie session is the auth — this page carries no token');
|
|
209
209
|
});
|
|
210
210
|
|
|
211
211
|
test('a toggle can REMOVE one too — the same list, one key shorter', async () => {
|
|
212
|
-
const ui = boot({ selected: ['
|
|
212
|
+
const ui = boot({ selected: ['npm-release', 'agents'] });
|
|
213
213
|
await ui.render();
|
|
214
214
|
|
|
215
215
|
await ui.click('agents');
|
|
216
216
|
|
|
217
217
|
const patch = ui.requests.find((r) => r.method === 'PATCH');
|
|
218
|
-
assert.deepEqual(JSON.parse(patch.body), { modules: ['
|
|
218
|
+
assert.deepEqual(JSON.parse(patch.body), { modules: ['npm-release'] });
|
|
219
219
|
});
|
|
220
220
|
|
|
221
221
|
test('switching the last one off sends an empty list — a real answer, not a skipped write', async () => {
|
|
@@ -243,8 +243,8 @@ test('the band repaints from the PLATFORM’S answer, and says the save changed
|
|
|
243
243
|
|
|
244
244
|
test('a refusal is SAID in the server’s own words, and the band goes back to what the row still holds', async () => {
|
|
245
245
|
const ui = boot({
|
|
246
|
-
selected: ['
|
|
247
|
-
patchAnswer: Promise.resolve({ ok: false, status: 400, _json: { error: { code: 'bad_modules', message: 'Unknown module "discrod" — the choices are:
|
|
246
|
+
selected: ['npm-release'],
|
|
247
|
+
patchAnswer: Promise.resolve({ ok: false, status: 400, _json: { error: { code: 'bad_modules', message: 'Unknown module "discrod" — the choices are: npm-release, discord, agents.' } } }),
|
|
248
248
|
});
|
|
249
249
|
await ui.render();
|
|
250
250
|
|
|
@@ -252,7 +252,7 @@ test('a refusal is SAID in the server’s own words, and the band goes back to w
|
|
|
252
252
|
|
|
253
253
|
assert.equal(ui.msg().className, 'projMsg err');
|
|
254
254
|
assert.match(ui.msg().textContent, /Unknown module "discrod"/);
|
|
255
|
-
assert.deepEqual(ui.rows().filter((r) => r.on).map((r) => r.key), ['
|
|
255
|
+
assert.deepEqual(ui.rows().filter((r) => r.on).map((r) => r.key), ['npm-release'],
|
|
256
256
|
'a refused write leaves the band showing the project’s real set');
|
|
257
257
|
});
|
|
258
258
|
|
|
@@ -269,7 +269,7 @@ test('a signed-out save offers a way back in rather than a dead end', async () =
|
|
|
269
269
|
});
|
|
270
270
|
|
|
271
271
|
test('a catalog that ANSWERED badly says so; nothing about the project is claimed to have changed', async () => {
|
|
272
|
-
const ui = boot({ selected: ['
|
|
272
|
+
const ui = boot({ selected: ['npm-release'], catalogOk: false });
|
|
273
273
|
|
|
274
274
|
await ui.render();
|
|
275
275
|
await ui.settle();
|
package/tests/projects_hub.mjs
CHANGED
|
@@ -707,14 +707,14 @@ test('the About answers travel on the create request, and an empty one is OMITTE
|
|
|
707
707
|
|
|
708
708
|
test('a renumbering of the wizard invalidates old drafts — the key carries the version', () => {
|
|
709
709
|
// task 1002772 renumbered once and bumped to -v2; task 1002334 renumbered again;
|
|
710
|
-
// task 1002339 (the module picker) is the third. A draft replayed under a
|
|
710
|
+
// task 1002339 (the module picker) is the third; task 1004351 (the app step) the fourth. A draft replayed under a
|
|
711
711
|
// different numbering lands on the wrong panel with the rail already marking
|
|
712
712
|
// the skipped steps done.
|
|
713
713
|
const key = (SCRIPT.match(/var DRAFT_KEY = '([^']+)'/) || [, ''])[1];
|
|
714
714
|
assert.match(key, /-v\d+$/, 'the draft key is versioned');
|
|
715
715
|
const panels = (SCRIPT.match(/var panels = \{([^}]*)\}/) || [, ''])[1];
|
|
716
716
|
const count = [...panels.matchAll(/\d+:\s*'panel-/g)].length;
|
|
717
|
-
assert.equal(count,
|
|
717
|
+
assert.equal(count, 10, 'gate + eight numbered steps + done — bump DRAFT_KEY when this changes');
|
|
718
718
|
});
|
|
719
719
|
|
|
720
720
|
test('every row lays the same five parts — the ledger has no ragged row', () => {
|
|
@@ -2133,9 +2133,9 @@ test('the wizard takes the world by scope: no card ground, the six-step strip as
|
|
|
2133
2133
|
assert.ok(at > -1, 'the #view-new block exists in cosmos.css');
|
|
2134
2134
|
const block = COSMOS.slice(at);
|
|
2135
2135
|
assert.match(block, /#view-new \.card\{background:none;border-radius:0;box-shadow:none;/, 'no card ground');
|
|
2136
|
-
//
|
|
2136
|
+
// eight tracks since task 1004351 added the App step (seven since 1002339); the count is the
|
|
2137
2137
|
// rail's own, so it moves with the panels map rather than being a magic number
|
|
2138
|
-
assert.match(block, /#view-new \.steps\{display:grid;grid-template-columns:repeat\(
|
|
2138
|
+
assert.match(block, /#view-new \.steps\{display:grid;grid-template-columns:repeat\(8,1fr\);/, 'the strip lays a track per numbered step');
|
|
2139
2139
|
assert.match(block, /#view-new \.steps li::before\{content:"";position:absolute;top:-4px;left:0;right:auto;width:7px;height:7px;/, 'the connector becomes the 7px dot');
|
|
2140
2140
|
assert.match(block, /#view-new \.steps li\.now::before\{background:var\(--accent\);border-color:var\(--accent\);outline:4px solid/, 'the lit step carries the accent and an outline halo');
|
|
2141
2141
|
assert.match(block, /#view-new \.panel h1\{font-weight:300;[^}]*text-transform:lowercase;/, 'the step title in the display voice, lowercase');
|
|
@@ -2182,7 +2182,7 @@ test('the wizard\'s own structures wear the world: hairline fields, cells of one
|
|
|
2182
2182
|
assert.match(block, /\.addrBig code\{display:block;font-family:var\(--font-display\);/, 'the address stands in the display voice');
|
|
2183
2183
|
assert.doesNotMatch(block, /linear-gradient/, 'no tinted plates');
|
|
2184
2184
|
assert.doesNotMatch(block, /box-shadow:(?!none)/, 'no box shadow in the wizard block');
|
|
2185
|
-
assert.match(HUB, /<div class="nav">\s*<button type="button" class="btn ghost" data-back="
|
|
2185
|
+
assert.match(HUB, /<div class="nav">\s*<button type="button" class="btn ghost" data-back="7">← Back<\/button>\s*<button type="button" class="btn big" id="doCreate">Create my project<\/button>/, 'the review\'s doors sit on one row, back then the primary');
|
|
2186
2186
|
assert.match(HUB, /<h2 class="stepsHead" id="doneStepsHead">Your steps — the parts only you can play<\/h2>/, 'the steps heading is the label face by class, not an inline style (the id is where a skipped invite step hands focus on, task 1002346)');
|
|
2187
2187
|
// what is enqueued is unchanged (ADR 0111): the filing body the control plane reads
|
|
2188
2188
|
assert.match(SCRIPT, /body: JSON\.stringify\(\{\s*slug: state\.slug,/, 'the filing still carries the slug first');
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// tests/projects_hub_app_step.mjs — the create wizard's "where your app runs" step,
|
|
2
|
+
// EXECUTED (task 1004351, ADR 0345).
|
|
3
|
+
//
|
|
4
|
+
// The step is a native radio group, so almost all of its behaviour is one rule: the
|
|
5
|
+
// review may only ever name a place the owner could actually pick. Render is listed
|
|
6
|
+
// but disabled until the connect flow lands (task 1004352), and "decide later" is the
|
|
7
|
+
// owner's ruling for the default. A static regex cannot tell a guard that works from
|
|
8
|
+
// one that is never consulted, so — as tests/projects_hub_module_picker.mjs does for
|
|
9
|
+
// the picker — this slices the block out of projects.html by its own sentinels and
|
|
10
|
+
// runs it in `vm` under a small DOM stub.
|
|
11
|
+
//
|
|
12
|
+
// Run: node --test --test-reporter=tap tests/projects_hub_app_step.mjs
|
|
13
|
+
|
|
14
|
+
import test from 'node:test';
|
|
15
|
+
import assert from 'node:assert/strict';
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import vm from 'node:vm';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
|
|
21
|
+
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
22
|
+
const HUB = fs.readFileSync(path.join(ROOT, 'modules', 'public-landing', 'public', 'projects.html'), 'utf8').replace(/\r\n/g, '\n');
|
|
23
|
+
|
|
24
|
+
const START = '/* the app step (task 1004351)';
|
|
25
|
+
const END = ' function renderReview() {';
|
|
26
|
+
const from = HUB.indexOf(START);
|
|
27
|
+
const to = HUB.indexOf(END, from);
|
|
28
|
+
assert.ok(from > -1, 'the app-step block opens with its sentinel comment');
|
|
29
|
+
assert.ok(to > from, 'the app-step block ends where renderReview begins');
|
|
30
|
+
const BLOCK = HUB.slice(from, to);
|
|
31
|
+
|
|
32
|
+
const PANEL = (HUB.match(/<section class="panel" id="panel-app"[\s\S]*?<\/section>/) || [''])[0];
|
|
33
|
+
|
|
34
|
+
// Two radios, built from the real markup so the harness cannot drift from the page.
|
|
35
|
+
function radiosFromMarkup(renderEnabled) {
|
|
36
|
+
return [...PANEL.matchAll(/<input type="radio" name="appPlatform" value="([a-z-]+)"([^>]*)>/g)].map((m) => ({
|
|
37
|
+
name: 'appPlatform',
|
|
38
|
+
value: m[1],
|
|
39
|
+
disabled: m[1] === 'render' ? !renderEnabled && /\sdisabled/.test(m[2]) : /\sdisabled/.test(m[2]),
|
|
40
|
+
checked: /\schecked/.test(m[2]),
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function load({ draft = {}, renderEnabled = false } = {}) {
|
|
45
|
+
const inputs = radiosFromMarkup(renderEnabled);
|
|
46
|
+
let changeHandler = null;
|
|
47
|
+
const saves = [];
|
|
48
|
+
const root = {
|
|
49
|
+
querySelector(sel) {
|
|
50
|
+
if (sel === '#appOpts') return { addEventListener: (ev, fn) => { if (ev === 'change') changeHandler = fn; } };
|
|
51
|
+
throw new Error('unexpected selector ' + sel);
|
|
52
|
+
},
|
|
53
|
+
querySelectorAll(sel) {
|
|
54
|
+
assert.equal(sel, '#appOpts input[name=appPlatform]');
|
|
55
|
+
return inputs;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const state = Object.assign({ appPlatform: 'later' }, draft);
|
|
59
|
+
const ctx = { root, state, saveDraft: () => saves.push(state.appPlatform) };
|
|
60
|
+
vm.createContext(ctx);
|
|
61
|
+
vm.runInContext(BLOCK + '\nthis.api = { appPlatformChoice, syncAppStep, appRow };', ctx);
|
|
62
|
+
return { ...ctx.api, inputs, state, saves, change: (value) => changeHandler({ target: inputs.find((i) => i.value === value) }) };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
test('the panel is real markup: Render listed but not pickable yet, Decide later the default', () => {
|
|
66
|
+
assert.ok(PANEL, '#panel-app exists');
|
|
67
|
+
assert.match(PANEL, /<input type="radio" name="appPlatform" value="render" disabled/, 'Render cannot be picked until task 1004352');
|
|
68
|
+
assert.match(PANEL, /<span class="soonTag">Coming soon<\/span>/, 'and says so in words, not by colour alone');
|
|
69
|
+
assert.match(PANEL, /<input type="radio" name="appPlatform" value="later" checked>/, 'Decide later is the default');
|
|
70
|
+
assert.match(PANEL, /We host your Builders' hall/, 'the step says the hall is ours to host (ADR 0345 D1), in the page\'s one spelling of it');
|
|
71
|
+
assert.match(PANEL, /<form data-next="8">/, 'Next leads to the review');
|
|
72
|
+
assert.match(PANEL, /data-back="6"/, 'Back returns to the address step');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('the step sits between Address and Review in the panels map and on the rail', () => {
|
|
76
|
+
assert.match(HUB, /6: 'panel-address', 7: 'panel-app', 8: 'panel-review', 9: 'panel-done'/);
|
|
77
|
+
assert.match(HUB, /<li data-step="7"><span class="snum">7<\/span><span class="slbl">App<\/span><\/li>/);
|
|
78
|
+
assert.match(HUB, /<li data-step="8"><span class="snum">8<\/span><span class="slbl">Create<\/span><\/li>/);
|
|
79
|
+
assert.match(HUB, /data-back="7">← Back<\/button>\n\s*<button type="button" class="btn big" id="doCreate">/, "the review's Back returns to the app step");
|
|
80
|
+
assert.match(HUB, /if \(step === 7\) syncAppStep\(\);\n\s*if \(step === 8\) renderReview\(\);/, 'entering the step repaints it from the draft');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('a fresh draft reads "decide later"', () => {
|
|
84
|
+
const w = load();
|
|
85
|
+
assert.equal(w.appPlatformChoice(), 'later');
|
|
86
|
+
assert.equal(w.appRow(), 'Not chosen yet — you can decide later');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('a draft that names Render while Render is not pickable still reads "decide later"', () => {
|
|
90
|
+
// The rule: the review never names a place the owner could not actually pick.
|
|
91
|
+
const w = load({ draft: { appPlatform: 'render' } });
|
|
92
|
+
assert.equal(w.appPlatformChoice(), 'later');
|
|
93
|
+
assert.equal(w.appRow(), 'Not chosen yet — you can decide later');
|
|
94
|
+
w.syncAppStep();
|
|
95
|
+
assert.deepEqual(w.inputs.filter((i) => i.checked).map((i) => i.value), ['later'], 'and the step shows Decide later checked');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('once Render is pickable, choosing it is what the review names', () => {
|
|
99
|
+
const w = load({ renderEnabled: true });
|
|
100
|
+
w.change('render');
|
|
101
|
+
assert.equal(w.state.appPlatform, 'render');
|
|
102
|
+
assert.deepEqual(w.saves, ['render'], 'the choice is saved to the draft');
|
|
103
|
+
assert.equal(w.appRow(), 'Render, on your own account');
|
|
104
|
+
w.syncAppStep();
|
|
105
|
+
assert.deepEqual(w.inputs.filter((i) => i.checked).map((i) => i.value), ['render']);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test('a change on a disabled radio is ignored, and an unknown or missing value reads "decide later"', () => {
|
|
109
|
+
const w = load();
|
|
110
|
+
w.change('render');
|
|
111
|
+
assert.equal(w.state.appPlatform, 'later', 'a disabled option never reaches the draft');
|
|
112
|
+
assert.deepEqual(w.saves, []);
|
|
113
|
+
for (const v of [undefined, '', 'vercel', 'x"]']) {
|
|
114
|
+
assert.equal(load({ draft: { appPlatform: v } }).appPlatformChoice(), 'later', `appPlatform=${JSON.stringify(v)}`);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('the review carries the hall row and the app row in place of the old Shape row', () => {
|
|
119
|
+
const render = HUB.slice(HUB.indexOf('function renderReview()'));
|
|
120
|
+
const rows = render.slice(0, render.indexOf("$('reviewList').innerHTML"));
|
|
121
|
+
assert.ok(rows.includes("['Builders\\' hall', 'Hosted by us, on the platform’s current release'],"), 'the hall row');
|
|
122
|
+
assert.match(rows, /\['App', appRow\(\)\]/);
|
|
123
|
+
assert.doesNotMatch(rows, /\['Shape',/, 'the Shape row is gone');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('the rail grid has one column per step, so adding a step never wraps the rail', () => {
|
|
127
|
+
// Adding the app step made the rail eight beats in a seven-column grid: at 1440 the
|
|
128
|
+
// Create beat wrapped onto a second row. The count lives in the shared sheet, so the
|
|
129
|
+
// two must be checked against each other, not each on its own.
|
|
130
|
+
const css = fs.readFileSync(path.join(ROOT, 'modules', 'public-landing', 'public', 'assets', 'cosmos.css'), 'utf8');
|
|
131
|
+
const cols = Number((css.match(/#view-new \.steps\{display:grid;grid-template-columns:repeat\((\d+),1fr\)/) || [])[1]);
|
|
132
|
+
const beats = [...HUB.matchAll(/<li[^>]*data-step="\d+"/g)].length;
|
|
133
|
+
assert.equal(cols, beats, 'the #view-new rail grid carries exactly one column per rail step');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('the hall is spelled one way on this page', () => {
|
|
137
|
+
assert.doesNotMatch(HUB, /Builders Hall/, 'no "Builders Hall" beside the page\'s own "Builders\' hall"');
|
|
138
|
+
});
|