@bongos/core 1.18.3 → 1.18.18
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 +1575 -285
- package/.claude/skills/builder-box/SKILL.md +6 -0
- package/.claude/skills/builder-sequence/SKILL.md +97 -0
- package/.claude/skills/builder-ship/SKILL.md +8 -2
- package/.claude/skills/builder-start/SKILL.md +11 -0
- package/.claude/skills/builder-sync/SKILL.md +41 -0
- package/.claude/skills/fix-task/SKILL.md +64 -0
- package/.claude/skills/goal-create/SKILL.md +158 -0
- package/.claude/skills/goal-review/SKILL.md +3 -1
- package/.claude/skills/idea-triage/SKILL.md +14 -8
- package/.claude/skills/merge-mode/SKILL.md +2 -2
- package/.claude/skills/new-project/SKILL.md +1 -0
- package/.claude/skills/planning-session/SKILL.md +45 -18
- package/.env.local.example +4 -3
- package/README.md +4 -2
- package/bin/bongos.js +1 -0
- package/clients/bongos-client/README.md +2 -2
- package/clients/bongos-client/bongos-client.global.js +82 -18
- package/clients/bongos-client/index.cjs +82 -18
- package/clients/bongos-client/index.d.ts +131 -29
- package/clients/bongos-client/index.mjs +82 -18
- package/config/branding.neutral.json +6 -1
- package/config/governance.neutral.json +21 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
- package/docs/adr/0090-metic-task-authoring.md +1 -1
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
- package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
- package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
- package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
- package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
- package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
- package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
- package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
- package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
- package/docs/adr/0152-metic-task-abandonment.md +67 -0
- package/docs/adr/0153-sequential-chain-runner.md +51 -0
- package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
- package/docs/adr/README.md +10 -0
- package/docs/api/openapi.json +843 -17
- package/docs/api-reference.md +23 -10
- package/docs/architecture.md +4 -2
- package/docs/branding-contract.md +3 -1
- package/docs/canonical-permissions.md +21 -8
- package/docs/file-map.md +8 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
- package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
- package/docs/onboarding/diagrams/assertions.json +4 -7
- package/docs/onboarding/drachmae-and-karma.md +3 -3
- package/docs/onboarding/primer.md +17 -16
- package/docs/onboarding/slash-commands.md +124 -0
- package/docs/recipes/builder-box-lifecycle.md +23 -0
- package/docs/recipes/devbox-app-release.md +14 -4
- package/docs/recipes/instance-first-run.md +16 -0
- package/docs/recipes/local-dev.md +81 -0
- package/docs/recipes/ops-gotchas.md +19 -1
- package/docs/recipes/overnight-builder.md +1 -1
- package/docs/recipes/parallel-goal-waves.md +174 -0
- package/docs/recipes/ship-and-regrade.md +2 -2
- package/docs/recipes/standalone-live-docs.md +48 -0
- package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
- package/migrations/003_pms.sql +6 -7
- package/migrations/006_pms_v2.sql +3 -31
- package/migrations/core_193_task_needs_rebase.sql +28 -0
- package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
- package/migrations/core_195_idea_triage_provenance.sql +57 -0
- package/migrations/core_196_session_reward_topup.sql +69 -0
- package/modules/autonomy/pollers/routine-timers.js +9 -8
- package/modules/builder-settings/wandering-prefs.js +61 -18
- package/modules/dev-box/app/README.md +73 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
- package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
- package/modules/dev-box/app/assets/tray/win-off.png +0 -0
- package/modules/dev-box/app/assets/tray/win-on.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
- package/modules/dev-box/app/build-resources/icon.png +0 -0
- package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
- package/modules/dev-box/app/electron-builder.yml +95 -0
- package/modules/dev-box/app/package-lock.json +5291 -0
- package/modules/dev-box/app/package.json +30 -0
- package/modules/dev-box/app/renderer/app.js +319 -0
- package/modules/dev-box/app/renderer/index.html +45 -0
- package/modules/dev-box/app/renderer/styles.css +246 -0
- package/modules/dev-box/app/renderer/theme.generated.css +16 -0
- package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
- package/modules/dev-box/app/scripts/gen-brand.js +138 -0
- package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
- package/modules/dev-box/app/scripts/gen-icons.js +286 -0
- package/modules/dev-box/app/scripts/vendor-client.js +23 -0
- package/modules/dev-box/app/src/box-controller.js +287 -0
- package/modules/dev-box/app/src/brand.generated.json +13 -0
- package/modules/dev-box/app/src/brand.js +16 -0
- package/modules/dev-box/app/src/config.js +19 -0
- package/modules/dev-box/app/src/gds-client.js +90 -0
- package/modules/dev-box/app/src/main.js +610 -0
- package/modules/dev-box/app/src/pairing.js +57 -0
- package/modules/dev-box/app/src/preload.js +29 -0
- package/modules/dev-box/app/src/session-store.js +58 -0
- package/modules/dev-box/app/src/ssh-setup.js +569 -0
- package/modules/dev-box/app/src/task-picker.js +70 -0
- package/modules/dev-box/app/src/tray.js +99 -0
- package/modules/dev-box/app/src/updater.js +55 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
- package/modules/dev-box/app/test/unit.mjs +526 -0
- package/modules/dev-box/box-access.js +121 -4
- package/modules/dev-box/boxes.js +20 -0
- package/modules/dev-box/module.json +1 -1
- package/modules/dev-box/routes/box.js +87 -3
- package/modules/economy/credits.js +116 -25
- package/modules/economy/reward.js +8 -0
- package/modules/economy/streak.js +2 -1
- package/modules/governance/CLAUDE.md +15 -0
- package/modules/governance/catalog.js +419 -0
- package/modules/governance/config.js +174 -0
- package/modules/governance/db.js +125 -0
- package/modules/governance/migrations/governance_001_tables.sql +81 -0
- package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
- package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
- package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
- package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
- package/modules/governance/module.json +10 -0
- package/modules/governance/protected-surfaces.js +88 -0
- package/modules/governance/protected-surfaces.json +80 -0
- package/modules/governance/rank-roles.js +83 -0
- package/modules/governance/resolver.js +221 -0
- package/modules/governance/routes/governance.js +89 -0
- package/modules/governance/routes/role-sync.js +49 -0
- package/modules/governance/session-scopes.js +127 -0
- package/modules/governance/session-scopes.json +38 -0
- package/modules/hall-ui/public/atlas.css +117 -0
- package/modules/hall-ui/public/atlas.html +3 -114
- package/modules/hall-ui/public/brand-apply.js +34 -6
- package/modules/hall-ui/public/builders.js +187 -219
- package/modules/hall-ui/public/diagrams.html +2 -0
- package/modules/hall-ui/public/dom-utils.js +27 -0
- package/modules/hall-ui/public/drachmae.html +2 -0
- package/modules/hall-ui/public/drachmae.js +54 -1
- package/modules/hall-ui/public/gate.css +98 -0
- package/modules/hall-ui/public/gate.html +3 -95
- package/modules/hall-ui/public/goal-inbox.js +4 -1
- package/modules/hall-ui/public/goals-page.js +626 -114
- package/modules/hall-ui/public/goals.css +79 -1
- package/modules/hall-ui/public/goals.html +38 -11
- package/modules/hall-ui/public/hall-widgets.js +62 -52
- package/modules/hall-ui/public/harbor.css +123 -0
- package/modules/hall-ui/public/harbor.html +3 -120
- package/modules/hall-ui/public/index.html +11 -4
- package/modules/hall-ui/public/instances-panel.js +4 -1
- package/modules/hall-ui/public/modules.css +63 -0
- package/modules/hall-ui/public/modules.html +3 -60
- package/modules/hall-ui/public/new-project-wizard.js +7 -3
- package/modules/hall-ui/public/not-ready.html +2 -0
- package/modules/hall-ui/public/pair.css +73 -0
- package/modules/hall-ui/public/pair.html +3 -70
- package/modules/hall-ui/public/palette.js +302 -0
- package/modules/hall-ui/public/primer.css +13 -0
- package/modules/hall-ui/public/primer.html +2 -0
- package/modules/hall-ui/public/profile.html +2 -0
- package/modules/hall-ui/public/ranks.html +2 -0
- package/modules/hall-ui/public/roadmap.css +179 -0
- package/modules/hall-ui/public/roadmap.html +9 -172
- package/modules/hall-ui/public/roadmap.js +329 -316
- package/modules/hall-ui/public/sessions.css +16 -0
- package/modules/hall-ui/public/sessions.html +3 -13
- package/modules/hall-ui/public/settings.html +2 -0
- package/modules/hall-ui/public/settings.js +4 -4
- package/modules/hall-ui/public/shell.js +143 -18
- package/modules/hall-ui/public/style.css +231 -39
- package/modules/hall-ui/public/task-detail.js +347 -26
- package/modules/hall-ui/public/task.html +6 -1
- package/modules/hall-ui/public/watch.html +2 -0
- package/modules/hall-ui/public/work.html +8 -6
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/ideas/inbox.js +61 -11
- package/modules/ideas/routes/inbox.js +23 -0
- package/modules/lifecycle/claim-eligibility.js +72 -0
- package/modules/lifecycle/db.js +519 -139
- package/modules/lifecycle/done-when.js +18 -3
- package/modules/lifecycle/github-push.js +19 -2
- package/modules/lifecycle/goal-advisory.js +114 -0
- package/modules/lifecycle/goal-authz.js +62 -0
- package/modules/lifecycle/lifecycle.js +9 -0
- package/modules/lifecycle/publish-reconciler.js +109 -6
- package/modules/lifecycle/routes/claims.js +68 -23
- package/modules/lifecycle/routes/done-when.js +110 -15
- package/modules/lifecycle/routes/goals.js +8 -38
- package/modules/lifecycle/routes/tasks.js +38 -6
- package/modules/lifecycle/ship-card.js +6 -0
- package/modules/onboarding/onboarding-state.js +1 -1
- package/modules/platform-identity/CLAUDE.md +15 -0
- package/modules/platform-identity/hub-device.js +147 -0
- package/modules/platform-identity/hub-keys.js +151 -0
- package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
- package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
- package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
- package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
- package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
- package/modules/platform-identity/module.json +18 -0
- package/modules/platform-identity/platform-identity.js +531 -0
- package/modules/platform-identity/pollers/code-sweep.js +43 -0
- package/modules/platform-identity/routes/my-projects.js +140 -0
- package/modules/platform-identity/routes/projects.js +107 -0
- package/modules/platform-identity/routes/scouting.js +35 -0
- package/modules/platform-identity/routes/sso.js +402 -0
- package/modules/platform-identity/tests/platform-identity.mjs +388 -0
- package/modules/platform-identity/ui/.gitkeep +0 -0
- package/modules/security/routes/reports.js +10 -0
- package/modules/sessions/db.js +166 -21
- package/modules/sessions/module.json +1 -1
- package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
- package/modules/sessions/routes/sessions.js +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/anim/idle/frame_00.webp +0 -0
- package/public-landing/assets/anim/idle/frame_01.webp +0 -0
- package/public-landing/assets/anim/idle/frame_02.webp +0 -0
- package/public-landing/assets/anim/idle/frame_03.webp +0 -0
- package/public-landing/assets/anim/idle/frame_04.webp +0 -0
- package/public-landing/assets/anim/idle/frame_05.webp +0 -0
- package/public-landing/assets/anim/idle/frame_06.webp +0 -0
- package/public-landing/assets/anim/idle/frame_07.webp +0 -0
- package/public-landing/assets/anim/idle/frame_08.webp +0 -0
- package/public-landing/assets/anim/idle/frame_09.webp +0 -0
- package/public-landing/assets/anim/idle/frame_10.webp +0 -0
- package/public-landing/assets/anim/idle/frame_11.webp +0 -0
- package/public-landing/assets/anim/idle/frame_12.webp +0 -0
- package/public-landing/assets/anim/idle/frame_13.webp +0 -0
- package/public-landing/assets/anim/idle/frame_14.webp +0 -0
- package/public-landing/assets/anim/idle/frame_15.webp +0 -0
- package/public-landing/assets/anim/idle/frame_16.webp +0 -0
- package/public-landing/assets/anim/idle/frame_17.webp +0 -0
- package/public-landing/assets/anim/idle/frame_18.webp +0 -0
- package/public-landing/assets/anim/idle/frame_19.webp +0 -0
- package/public-landing/assets/anim/idle/frame_20.webp +0 -0
- package/public-landing/assets/anim/idle/frame_21.webp +0 -0
- package/public-landing/assets/anim/idle/frame_22.webp +0 -0
- package/public-landing/assets/anim/idle/frame_23.webp +0 -0
- package/public-landing/assets/anim/idle/frame_24.webp +0 -0
- package/public-landing/assets/anim/idle/frame_25.webp +0 -0
- package/public-landing/assets/anim/idle/frame_26.webp +0 -0
- package/public-landing/assets/anim/idle/frame_27.webp +0 -0
- package/public-landing/assets/anim/idle/frame_28.webp +0 -0
- package/public-landing/assets/anim/idle/frame_29.webp +0 -0
- package/public-landing/assets/anim/idle/frame_30.webp +0 -0
- package/public-landing/assets/anim/idle/frame_31.webp +0 -0
- package/public-landing/assets/anim/idle/frame_32.webp +0 -0
- package/public-landing/assets/anim/idle/frame_33.webp +0 -0
- package/public-landing/assets/anim/idle/frame_34.webp +0 -0
- package/public-landing/assets/anim/idle/frame_35.webp +0 -0
- package/public-landing/assets/anim/idle/frame_36.webp +0 -0
- package/public-landing/assets/anim/idle/frame_37.webp +0 -0
- package/public-landing/assets/anim/idle/frame_38.webp +0 -0
- package/public-landing/assets/anim/idle/frame_39.webp +0 -0
- package/public-landing/assets/anim/idle/frame_40.webp +0 -0
- package/public-landing/assets/anim/idle/frame_41.webp +0 -0
- package/public-landing/assets/anim/idle/frame_42.webp +0 -0
- package/public-landing/assets/anim/idle/frame_43.webp +0 -0
- package/public-landing/create.html +51 -58
- package/public-landing/gate/README.md +137 -0
- package/public-landing/gate/dispmaps/bar.png +0 -0
- package/public-landing/gate/dispmaps/flat.png +0 -0
- package/public-landing/gate/dispmaps/key.png +0 -0
- package/public-landing/gate/index.html +587 -0
- package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
- package/public-landing/gate/previews/off-the-boats.jpg +0 -0
- package/public-landing/gate/space.css +799 -0
- package/public-landing/gate/space.js +1826 -0
- package/public-landing/gate/sprites/enter.png +0 -0
- package/public-landing/gate/sprites/search.png +0 -0
- package/public-landing/gate/sprites/terminal-blank.png +0 -0
- package/public-landing/gate/sprites/tile.png +0 -0
- package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
- package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
- package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
- package/public-landing/world/assets/plates/scene-establishing.png +0 -0
- package/scripts/gds/abandon.js +6 -4
- package/scripts/gds/api.js +10 -5
- package/scripts/gds/api.ps1 +26 -0
- package/scripts/gds/api.sh +6 -0
- package/scripts/gds/audit-ships.js +7 -1
- package/scripts/gds/backfill-sessions.js +78 -18
- package/scripts/gds/backup.js +23 -1
- package/scripts/gds/box-connect-lib.js +124 -31
- package/scripts/gds/box-sync.js +66 -0
- package/scripts/gds/box.js +225 -53
- package/scripts/gds/cf-tunnel.js +145 -6
- package/scripts/gds/claim.js +34 -3
- package/scripts/gds/cli-lib.js +161 -27
- package/scripts/gds/code.js +6 -2
- package/scripts/gds/deploy-divergence.js +209 -0
- package/scripts/gds/dev-lib.js +309 -0
- package/scripts/gds/dev.js +322 -0
- package/scripts/gds/doctor.js +90 -61
- package/scripts/gds/fetch-art-key.js +1 -1
- package/scripts/gds/fetch-sound-prefs.js +2 -2
- package/scripts/gds/fitness.js +228 -12
- package/scripts/gds/gds-db-backup.service +16 -1
- package/scripts/gds/gds-db-offsite.service +9 -1
- package/scripts/gds/gen-api-client.js +1 -1
- package/scripts/gds/gen-api-docs.js +36 -14
- package/scripts/gds/gen-diagrams.js +45 -28
- package/scripts/gds/gen-file-map.js +2 -1
- package/scripts/gds/gen-freshness.js +32 -0
- package/scripts/gds/gen-repo-map.js +3 -2
- package/scripts/gds/gen-session-index.js +14 -5
- package/scripts/gds/hooks/pre-push.js +2 -2
- package/scripts/gds/init.js +60 -3
- package/scripts/gds/install-git-hooks.js +1 -1
- package/scripts/gds/key-card.js +15 -6
- package/scripts/gds/key-status.js +1 -1
- package/scripts/gds/linkify-refs.js +35 -9
- package/scripts/gds/login.js +16 -1
- package/scripts/gds/paste-token.js +7 -1
- package/scripts/gds/preflight.js +126 -0
- package/scripts/gds/provision.js +123 -12
- package/scripts/gds/publish-manifest.js +7 -1
- package/scripts/gds/reauth.js +7 -3
- package/scripts/gds/regen-instance-docs.js +47 -0
- package/scripts/gds/run-unit-tests.js +4 -2
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
- package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
- package/scripts/gds/sequence.js +425 -0
- package/scripts/gds/session-cost.js +10 -1
- package/scripts/gds/setup.js +31 -5
- package/scripts/gds/shell.js +5 -3
- package/scripts/gds/ship.js +319 -29
- package/scripts/gds/smoke-gds.js +139 -8
- package/scripts/gds/start.js +171 -22
- package/scripts/gds/status.js +1 -1
- package/scripts/gds/triage.js +10 -9
- package/scripts/gds/upgrade.js +124 -2
- package/scripts/status-mirror-sync.js +114 -84
- package/src/bongos/api-errors.js +1 -0
- package/src/bongos/auth.js +447 -102
- package/src/bongos/db-kernel.js +27 -0
- package/src/bongos/db.js +39 -0
- package/src/bongos/module-scope-map.js +27 -1
- package/src/bongos/permission-path-check.js +136 -102
- package/src/bongos/repo-info.js +47 -11
- package/src/bongos/route-rank-check.js +429 -46
- package/src/bongos/routes/_helpers.js +12 -1
- package/src/bongos/routes/auth.js +219 -2
- package/src/bongos/routes/backup.js +58 -2
- package/src/bongos/routes/me.js +35 -1
- package/src/bongos/serve-internal.js +84 -15
- package/src/branding.js +32 -0
- package/src/instance-config.js +30 -0
- package/src/module-api.js +112 -1
- package/src/platform-server.js +86 -9
- package/tests/abandon_task.mjs +59 -3
- package/tests/api_cli_flags.mjs +53 -0
- package/tests/auth_page_gate.mjs +13 -0
- package/tests/backfill_sessions.mjs +127 -1
- package/tests/backup_cli.mjs +54 -0
- package/tests/bongos_box_connect.mjs +77 -0
- package/tests/box_access.mjs +130 -1
- package/tests/box_credential.mjs +125 -0
- package/tests/box_host_keys.mjs +24 -0
- package/tests/box_infra_resolve.mjs +149 -0
- package/tests/box_scope_session.mjs +6 -2
- package/tests/box_sync.mjs +55 -0
- package/tests/box_task_scope.mjs +99 -0
- package/tests/branding.mjs +12 -0
- package/tests/cf_ruleset_preflight.mjs +142 -0
- package/tests/cf_tunnel.mjs +37 -0
- package/tests/claim_gate_rebase.mjs +98 -0
- package/tests/clawback_confirmed_backlog.mjs +103 -0
- package/tests/cli_lib_formatters.mjs +20 -0
- package/tests/confirm_attribution.mjs +30 -46
- package/tests/credit_grant.mjs +198 -10
- package/tests/criterion_authoring_gate.mjs +272 -0
- package/tests/criterion_progress.mjs +33 -1
- package/tests/dev_lib.mjs +253 -0
- package/tests/devbox_artifact_gate.mjs +75 -0
- package/tests/devbox_dmg_backdrop.mjs +137 -0
- package/tests/devbox_icons.mjs +304 -0
- package/tests/devbox_installer_brand.mjs +232 -0
- package/tests/devbox_key_register.mjs +234 -0
- package/tests/docs_openapi_route.mjs +110 -0
- package/tests/doctor_hooks.mjs +141 -0
- package/tests/extract_json.mjs +140 -0
- package/tests/fitness.mjs +89 -0
- package/tests/gen_freshness.mjs +96 -0
- package/tests/goal_advisory.mjs +251 -0
- package/tests/goal_criterion_confirm_ui.mjs +269 -0
- package/tests/goal_routes.mjs +59 -4
- package/tests/goal_tier.mjs +12 -3
- package/tests/governance_catalog.mjs +129 -0
- package/tests/governance_claim_eligibility.mjs +262 -0
- package/tests/governance_config.mjs +187 -0
- package/tests/governance_ownership_scope.mjs +410 -0
- package/tests/governance_page_gates.mjs +324 -0
- package/tests/governance_parity.mjs +336 -0
- package/tests/governance_principals.mjs +232 -0
- package/tests/governance_protected_surfaces.mjs +208 -0
- package/tests/governance_require_permission.mjs +223 -0
- package/tests/governance_resolver.mjs +84 -0
- package/tests/governance_role_sync.mjs +231 -0
- package/tests/governance_seed.mjs +127 -0
- package/tests/governance_session_scope.mjs +434 -0
- package/tests/governance_vanilla_boot.mjs +203 -0
- package/tests/grade_attribution.mjs +7 -7
- package/tests/hall_audit.mjs +223 -0
- package/tests/hall_nav.mjs +191 -0
- package/tests/hall_palette.mjs +206 -0
- package/tests/hall_signout.mjs +124 -0
- package/tests/hook_user_agents.mjs +10 -0
- package/tests/idea_triage.mjs +162 -0
- package/tests/idp_device_exchange.mjs +93 -0
- package/tests/init.mjs +51 -0
- package/tests/instance_config.mjs +65 -0
- package/tests/instance_mismatch_guard.mjs +23 -6
- package/tests/instance_release_config.mjs +104 -0
- package/tests/linkify_refs.mjs +15 -2
- package/tests/module_contributions.mjs +55 -0
- package/tests/module_loader.mjs +10 -5
- package/tests/module_scope_active_claims.mjs +94 -0
- package/tests/needs_rebase.mjs +92 -0
- package/tests/one_active_claim_per_session.mjs +76 -0
- package/tests/override_attribution.mjs +10 -8
- package/tests/override_request_ownership.mjs +8 -4
- package/tests/parse_cookie_decode.mjs +42 -0
- package/tests/pay_on_land.mjs +129 -0
- package/tests/platform_boot.mjs +100 -1
- package/tests/post_login_landing.mjs +42 -0
- package/tests/preflight_checks.mjs +72 -0
- package/tests/provision.mjs +132 -7
- package/tests/publish_branch_route.mjs +53 -0
- package/tests/publish_reconciler.mjs +187 -2
- package/tests/repo_info_binding.mjs +248 -0
- package/tests/reward_gate.mjs +11 -2
- package/tests/reward_mode_cost_plus_only.mjs +116 -0
- package/tests/reward_mode_surfacing.mjs +168 -0
- package/tests/route_permission_check.mjs +301 -0
- package/tests/route_rank_check.mjs +254 -12
- package/tests/route_validation.mjs +30 -0
- package/tests/sequence.mjs +267 -0
- package/tests/session_digest.mjs +44 -0
- package/tests/session_index.mjs +18 -6
- package/tests/session_records.mjs +39 -1
- package/tests/session_reward_on_land.mjs +381 -0
- package/tests/session_reward_reconcile.mjs +229 -0
- package/tests/ship_api_client_pathspec.mjs +100 -0
- package/tests/ship_base_flag.mjs +93 -0
- package/tests/ship_ci_deploy.mjs +80 -3
- package/tests/ship_upstream_deletion.mjs +57 -0
- package/tests/smoke_target.mjs +233 -0
- package/tests/start_env_guard.mjs +87 -0
- package/tests/start_rebase_warning.mjs +103 -0
- package/tests/status_mirror_sync.mjs +122 -0
- package/tests/stop_refcheck.mjs +19 -1
- package/tests/task_goal_link.mjs +15 -6
- package/tests/upgrade.mjs +139 -0
- package/tests/web_admission_status.mjs +162 -0
- package/tests/write_validation_gaps.mjs +110 -0
package/scripts/gds/upgrade.js
CHANGED
|
@@ -194,6 +194,115 @@ function regenerateApiArtifacts({ instanceDir, coreRoot }, run = spawnSync, fsIm
|
|
|
194
194
|
return { ok: true, ran };
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
// The instance's GITIGNORED WHOLE-FILE navigation docs (ADR 0110). On the monorepo these
|
|
198
|
+
// regenerate at deploy (deploy-prod.sh) + box-fetch and are gitignored so no branch ever diffs
|
|
199
|
+
// them. STANDALONE instances (ADR 0108) never got that step: their bespoke deploy regenerated
|
|
200
|
+
// nothing and init/upgrade only did the API docs, so a fresh instance shipped with an empty docs/
|
|
201
|
+
// and nothing kept the index live (task 1002314, the owner's "docs didn't transfer from primea").
|
|
202
|
+
// This is the standalone sibling of deploy-prod.sh's regen: run the generator(s) against the
|
|
203
|
+
// INSTANCE root, best-effort + LOUD — a broken generator must surface (::ERROR::) but must NEVER
|
|
204
|
+
// fail the deploy/bump (a stale nav doc is tolerable; a failed deploy is not — ADR 0110 §2
|
|
205
|
+
// "accepted staleness").
|
|
206
|
+
//
|
|
207
|
+
// SCOPE — deliberately just session-index (the one gitignored whole-file doc that is INSTANCE
|
|
208
|
+
// content). Excluded on purpose:
|
|
209
|
+
// • repo-map.md — CORE-scoped: gen-repo-map writes to resolveCoreRoot() (the platform code map),
|
|
210
|
+
// not the instance. A pure standalone instance runs core from node_modules and has ~no code of
|
|
211
|
+
// its own to map, so an instance-level repo-map is empty/meaningless; the core ships its own.
|
|
212
|
+
// (An instance-scoped map for BROWNFIELD/adopted repos is a separate enhancement — task 1001655.)
|
|
213
|
+
// • file-map.md + API docs — TRACKED/committed (seeded at init, refreshed at ship/upgrade);
|
|
214
|
+
// regenerating them on the box would perpetually dirty the tree that deploy.sh `git reset
|
|
215
|
+
// --hard`es. file-map is also HYBRID (hand-written prose + generated sections, ADR 0110) so it
|
|
216
|
+
// cannot leave git; seeding it at standup is a follow-up (needs a scaffolded file-map.md).
|
|
217
|
+
// • diagrams + atlas.json — NOT instance content: they are CORE-scoped generated assets that
|
|
218
|
+
// live under resolveCoreRoot(). They are handled separately by healDocAssets() below, because
|
|
219
|
+
// an upgrade is precisely what destroys them (task 1002441).
|
|
220
|
+
const NAV_WHOLE_FILE_GENERATORS = ['gen-session-index.js'];
|
|
221
|
+
function regenerateNavDocs({ instanceDir, coreRoot, generators = NAV_WHOLE_FILE_GENERATORS }, run = spawnSync, fsImpl = fs) {
|
|
222
|
+
const env = { ...process.env, CLOUDBONGOS_INSTANCE_ROOT: instanceDir };
|
|
223
|
+
const ran = [];
|
|
224
|
+
const failed = [];
|
|
225
|
+
for (const gen of generators) {
|
|
226
|
+
const script = path.join(coreRoot, 'scripts', 'gds', gen);
|
|
227
|
+
if (!fsImpl.existsSync(script)) { failed.push({ gen, reason: `not found in core (${coreRoot})` }); continue; }
|
|
228
|
+
const r = run(process.execPath, [script], { cwd: instanceDir, env, stdio: 'inherit' });
|
|
229
|
+
if (!r || r.error || r.status !== 0) {
|
|
230
|
+
// LOUD per ADR 0110 §2 — journald greps ::ERROR:: so a broken generator alarms.
|
|
231
|
+
failed.push({ gen, reason: r && r.error ? r.error.message : `exited ${r && r.status}` });
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
ran.push(gen);
|
|
235
|
+
}
|
|
236
|
+
return { ok: failed.length === 0, ran, failed };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// The CORE-scoped generated doc assets that back two builders'-hall surfaces:
|
|
240
|
+
//
|
|
241
|
+
// modules/hall-ui/public/atlas.json → the Repo Atlas (/builders/atlas)
|
|
242
|
+
// docs/onboarding/diagrams/<n>.svg+.png → the system maps (/builders/diagrams)
|
|
243
|
+
//
|
|
244
|
+
// Both are GITIGNORED (.gitignore: `modules/hall-ui/public/atlas.json`,
|
|
245
|
+
// `docs/onboarding/diagrams/*.svg|*.png` — ADR 0122 / task 1002027) and both are generated INTO
|
|
246
|
+
// the vendored core root. So an upgrade DESTROYS them: npmInstall replaces node_modules wholesale
|
|
247
|
+
// and the new tarball carries only the .mmd sources. Nothing else puts them back —
|
|
248
|
+
// • packaging does not render (package-core.js has no render step, and the renders are
|
|
249
|
+
// gitignored so a git checkout has none to copy), and
|
|
250
|
+
// • a standalone instance's pull-deploy typically short-circuits on an unchanged git SHA, which
|
|
251
|
+
// an upgrade does not move — so its regen hooks never fire.
|
|
252
|
+
// Result before this healer: /builders/atlas 404'd and the diagrams page showed broken images
|
|
253
|
+
// after every `bongos upgrade`, until some unrelated commit happened to land (task 1002441).
|
|
254
|
+
//
|
|
255
|
+
// Both generators resolve their own output dir from __dirname, so running the CORE's copy always
|
|
256
|
+
// writes into coreRoot regardless of cwd. Idempotent by design — each asset is regenerated only
|
|
257
|
+
// when actually absent, so this is also safe to call from a deploy loop.
|
|
258
|
+
//
|
|
259
|
+
// Best-effort + LOUD, per ADR 0110 §2 "accepted staleness": a stale diagram is tolerable, a failed
|
|
260
|
+
// upgrade is not. render-diagrams.sh additionally needs a system Chromium (ADR 0122); where none is
|
|
261
|
+
// installed it fails and we say so via ::ERROR:: rather than aborting the bump.
|
|
262
|
+
const DOC_ASSET_GENERATORS = {
|
|
263
|
+
atlas: { rel: path.join('scripts', 'gds', 'gen-atlas.js'), kind: 'node' },
|
|
264
|
+
diagrams: { rel: path.join('scripts', 'render-diagrams.sh'), kind: 'bash' },
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
// Which of the two asset groups are missing under coreRoot. Exported for testing.
|
|
268
|
+
function missingDocAssets(coreRoot, fsImpl = fs) {
|
|
269
|
+
const missing = [];
|
|
270
|
+
if (!fsImpl.existsSync(path.join(coreRoot, 'modules', 'hall-ui', 'public', 'atlas.json'))) {
|
|
271
|
+
missing.push('atlas');
|
|
272
|
+
}
|
|
273
|
+
const diagramDir = path.join(coreRoot, 'docs', 'onboarding', 'diagrams');
|
|
274
|
+
let sources = [];
|
|
275
|
+
try {
|
|
276
|
+
sources = fsImpl.readdirSync(diagramDir).filter((f) => f.endsWith('.mmd'));
|
|
277
|
+
} catch { sources = []; } // no diagram dir in this core → nothing to render
|
|
278
|
+
const unrendered = sources.some((src) => {
|
|
279
|
+
const base = path.join(diagramDir, src.replace(/\.mmd$/, ''));
|
|
280
|
+
return !fsImpl.existsSync(`${base}.svg`) || !fsImpl.existsSync(`${base}.png`);
|
|
281
|
+
});
|
|
282
|
+
if (unrendered) missing.push('diagrams');
|
|
283
|
+
return missing;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function healDocAssets({ coreRoot }, run = spawnSync, fsImpl = fs) {
|
|
287
|
+
const missing = missingDocAssets(coreRoot, fsImpl);
|
|
288
|
+
if (missing.length === 0) return { ok: true, ran: [], failed: [], missing: [] };
|
|
289
|
+
const ran = [];
|
|
290
|
+
const failed = [];
|
|
291
|
+
for (const group of missing) {
|
|
292
|
+
const gen = DOC_ASSET_GENERATORS[group];
|
|
293
|
+
const script = path.join(coreRoot, gen.rel);
|
|
294
|
+
if (!fsImpl.existsSync(script)) { failed.push({ group, reason: `not found in core (${gen.rel})` }); continue; }
|
|
295
|
+
const argv = gen.kind === 'bash' ? ['bash', [script]] : [process.execPath, [script]];
|
|
296
|
+
const r = run(argv[0], argv[1], { cwd: coreRoot, stdio: 'inherit' });
|
|
297
|
+
if (!r || r.error || r.status !== 0) {
|
|
298
|
+
failed.push({ group, reason: r && r.error ? r.error.message : `exited ${r && r.status}` });
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
ran.push(group);
|
|
302
|
+
}
|
|
303
|
+
return { ok: failed.length === 0, ran, failed, missing };
|
|
304
|
+
}
|
|
305
|
+
|
|
197
306
|
function restartService({ service, restartCmd }, run = spawnSync) {
|
|
198
307
|
if (restartCmd) {
|
|
199
308
|
const parts = restartCmd.split(/\s+/);
|
|
@@ -587,7 +696,20 @@ async function runUpgrade(opts, deps = {}) {
|
|
|
587
696
|
const regen = (deps.regenerateApiArtifacts || regenerateApiArtifacts)({ instanceDir, coreRoot }, run);
|
|
588
697
|
if (regen.ok) log(` ✓ regenerated API docs + typed client from core ${targetVersion}`);
|
|
589
698
|
else err(` ! API-artifact regen incomplete (${regen.reason}) — ran ${regen.ran.join(', ') || 'nothing'}; the next ship's fitness gate refreshes them.`);
|
|
590
|
-
|
|
699
|
+
// 5c. regenerate the whole-file navigation docs (repo-map + session-index) from the new
|
|
700
|
+
// core against the instance root (ADR 0110 / task 1002314). Best-effort + LOUD: a broken
|
|
701
|
+
// generator alarms via ::ERROR:: but never fails the bump.
|
|
702
|
+
const nav = (deps.regenerateNavDocs || regenerateNavDocs)({ instanceDir, coreRoot }, run);
|
|
703
|
+
if (nav.ok) log(` ✓ regenerated navigation docs (${nav.ran.join(', ')}) from core ${targetVersion}`);
|
|
704
|
+
else err(` ! ::ERROR:: navigation-doc regen incomplete — ran ${nav.ran.join(', ') || 'nothing'}; failed ${nav.failed.map((f) => `${f.gen} (${f.reason})`).join(', ')}. The next deploy retries.`);
|
|
705
|
+
// 5d. re-generate the CORE-scoped doc assets this very upgrade just wiped — the Repo Atlas
|
|
706
|
+
// data file + the onboarding diagram renders (task 1002441). See healDocAssets() for why
|
|
707
|
+
// nothing else puts them back. Best-effort + LOUD, same contract as 5c.
|
|
708
|
+
const heal = (deps.healDocAssets || healDocAssets)({ coreRoot }, run);
|
|
709
|
+
if (heal.missing.length === 0) log(' • doc assets intact (atlas + diagram renders present)');
|
|
710
|
+
else if (heal.ok) log(` ✓ regenerated doc assets wiped by the core swap (${heal.ran.join(', ')})`);
|
|
711
|
+
else err(` ! ::ERROR:: doc-asset regen incomplete — ran ${heal.ran.join(', ') || 'nothing'}; failed ${heal.failed.map((f) => `${f.group} (${f.reason})`).join(', ')}. /builders/atlas or /builders/diagrams may be broken until the next deploy retries (diagram renders need a system Chromium — ADR 0122).`);
|
|
712
|
+
} else log(' • doc regen skipped (--skip-regen-docs)');
|
|
591
713
|
|
|
592
714
|
// 6. restart.
|
|
593
715
|
const rs = restartService({ service: opts.service, restartCmd: opts.restartCmd }, run);
|
|
@@ -700,7 +822,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
700
822
|
module.exports = {
|
|
701
823
|
runUpgrade, parseArgs, main, rollback,
|
|
702
824
|
versionFromTgzPath, versionFromDep, readInstalledCoreVersion, readPinnedCoreVersion, writePin, writeRegistryPin, restorePin,
|
|
703
|
-
vendorTarball, gitTreeClean, preflightModules, npmInstall, runMigrate, regenerateApiArtifacts, restartService, recordLedger, pollHealth,
|
|
825
|
+
vendorTarball, gitTreeClean, preflightModules, npmInstall, runMigrate, regenerateApiArtifacts, regenerateNavDocs, NAV_WHOLE_FILE_GENERATORS, missingDocAssets, healDocAssets, DOC_ASSET_GENERATORS, restartService, recordLedger, pollHealth,
|
|
704
826
|
readManifest, resolveReferenceManifest, verifyInstalledPin, // task 1002216 (audit H8) — integrity-pin verification
|
|
705
827
|
CORE_PKG, ARTIFACT,
|
|
706
828
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// scripts/status-mirror-sync.js — publish the status surface to the off-box status
|
|
3
|
-
// mirror (
|
|
3
|
+
// mirror (a separate repo → a static Pages host → the instance's status domain).
|
|
4
4
|
//
|
|
5
5
|
// SOURCE PATH (BV1.R84 / task 1635): the status dashboard moved from public-status/
|
|
6
6
|
// to modules/status-ui/public/ when the status surface became a module (a web
|
|
@@ -14,19 +14,28 @@
|
|
|
14
14
|
// (that's how #726's reorg + #731's theming never showed up). This makes the
|
|
15
15
|
// publish deterministic and CI-driven.
|
|
16
16
|
//
|
|
17
|
+
// CONFIG (task 1002510 — no host identity is baked in here; ADR 0062 §3):
|
|
18
|
+
// domains.publicOrigin — the origin the mirror calls cross-origin
|
|
19
|
+
// (window.STATUS_API_BASE), and the site label the
|
|
20
|
+
// availability banner names as up/down.
|
|
21
|
+
// domains.statusDataUrl — the off-box prober's status.json URL the availability
|
|
22
|
+
// banner reads. EMPTY ⇒ this instance runs no off-box
|
|
23
|
+
// mirror, and the publish REFUSES rather than shipping a
|
|
24
|
+
// page whose banner points nowhere.
|
|
25
|
+
//
|
|
17
26
|
// DESIGN: status.js + style.css + cursors/ are byte-identical between the
|
|
18
27
|
// droplet copy and the mirror (#737 parameterized the one differing constant via
|
|
19
28
|
// window.STATUS_API_BASE), so they are PURE COPIES. Only index.html carries the
|
|
20
29
|
// three off-box additions, injected here at stable anchors:
|
|
21
|
-
// 1. <script>window.STATUS_API_BASE=
|
|
22
|
-
// 2. <div id="offbox-status">…</div>
|
|
23
|
-
// 3. the availability-banner driver <script> (reads
|
|
30
|
+
// 1. <script>window.STATUS_API_BASE = <domains.publicOrigin></script> (head)
|
|
31
|
+
// 2. <div id="offbox-status">…</div> (after <body>)
|
|
32
|
+
// 3. the availability-banner driver <script> (reads domains.statusDataUrl) (before status.js)
|
|
24
33
|
// If any anchor is missing the script THROWS — a silent mis-sync is worse than
|
|
25
34
|
// a failed run.
|
|
26
35
|
//
|
|
27
36
|
// USAGE:
|
|
28
37
|
// node scripts/status-mirror-sync.js --repo-dir <path-to-mirror-checkout> [--push]
|
|
29
|
-
// --repo-dir : a checkout of
|
|
38
|
+
// --repo-dir : a checkout of the status-mirror repo (its `main` branch).
|
|
30
39
|
// --push : commit + push the result. Without it the files are written
|
|
31
40
|
// and `git status` is printed for inspection (dry-ish run).
|
|
32
41
|
//
|
|
@@ -42,52 +51,36 @@ const SRC = path.join(REPO_ROOT, 'modules', 'status-ui', 'public');
|
|
|
42
51
|
const { branding, clientBranding } = require('../src/branding');
|
|
43
52
|
|
|
44
53
|
// Stamp instance-identity tokens into the mirror HTML. The off-box mirror is
|
|
45
|
-
// served by
|
|
46
|
-
// must reproduce serve-internal.applyBrandTokens (task 1705, ADR 0062 §3), else
|
|
47
|
-
// mirror would render literal {{worldName}}/{{currency}} placeholders. KEEP IN SYNC
|
|
48
|
-
// with src/bongos/serve-internal.js applyBrandTokens.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
+
// served by a static Pages host, NOT the branding-injecting Node server — so this
|
|
55
|
+
// script must reproduce serve-internal.applyBrandTokens (task 1705, ADR 0062 §3), else
|
|
56
|
+
// the mirror would render literal {{worldName}}/{{currency}} placeholders. KEEP IN SYNC
|
|
57
|
+
// with src/bongos/serve-internal.js applyBrandTokens. `brand` is the client-safe pack
|
|
58
|
+
// and `publicOrigin` the resolved origin — both injected, never read ambiently, so the
|
|
59
|
+
// transform stays pure and testable.
|
|
60
|
+
function brandTokens(html, brand = {}, publicOrigin = '') {
|
|
61
|
+
const world = (brand.identity && brand.identity.worldName) || '';
|
|
62
|
+
const product = (brand.identity && brand.identity.productName) || '';
|
|
63
|
+
const cur = (brand.currency && brand.currency.label) || 'credits';
|
|
54
64
|
const Cur = cur ? cur.charAt(0).toUpperCase() + cur.slice(1) : cur;
|
|
55
|
-
let origin = '';
|
|
56
|
-
try { origin = branding().domains.publicOrigin || ''; } catch (_) { /* neutral */ }
|
|
57
65
|
return html
|
|
58
66
|
.split('{{worldName}}').join(world)
|
|
59
67
|
.split('{{productName}}').join(product)
|
|
60
68
|
.split('{{Currency}}').join(Cur)
|
|
61
69
|
.split('{{currency}}').join(cur)
|
|
62
|
-
.split('{{publicOrigin}}').join(
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function arg(name) {
|
|
66
|
-
const i = process.argv.indexOf(name);
|
|
67
|
-
return i >= 0 ? process.argv[i + 1] : null;
|
|
68
|
-
}
|
|
69
|
-
const repoDir = arg('--repo-dir');
|
|
70
|
-
const doPush = process.argv.includes('--push');
|
|
71
|
-
if (!repoDir) {
|
|
72
|
-
console.error('usage: node scripts/status-mirror-sync.js --repo-dir <mirror-checkout> [--push]');
|
|
73
|
-
process.exit(2);
|
|
74
|
-
}
|
|
75
|
-
if (!fs.existsSync(path.join(repoDir, 'CNAME'))) {
|
|
76
|
-
console.error(`refusing: ${repoDir} does not look like the status mirror (no CNAME). Clone lars589/amazonprimea-status first.`);
|
|
77
|
-
process.exit(2);
|
|
70
|
+
.split('{{publicOrigin}}').join(publicOrigin || '');
|
|
78
71
|
}
|
|
79
72
|
|
|
80
73
|
// ---- the three off-box index.html injections -------------------------------
|
|
81
74
|
|
|
82
|
-
const
|
|
75
|
+
const headInject = (apiBase) =>
|
|
83
76
|
` <!-- #737: off-box mirror runs cross-origin against the droplet. -->\n` +
|
|
84
|
-
` <script>window.STATUS_API_BASE =
|
|
77
|
+
` <script>window.STATUS_API_BASE = ${JSON.stringify(apiBase)};</script>\n`;
|
|
85
78
|
|
|
86
79
|
// The client-safe branding pack, so status.js reads the instance currency label
|
|
87
80
|
// on the mirror exactly as it does on the droplet (serve-internal injects the same
|
|
88
81
|
// global there). Without this, status.js would fall back to the neutral 'credits'.
|
|
89
|
-
const
|
|
90
|
-
` <script>window.__BRANDING__ = ${JSON.stringify(
|
|
82
|
+
const brandingInject = (brand) =>
|
|
83
|
+
` <script>window.__BRANDING__ = ${JSON.stringify(brand)};</script>\n`;
|
|
91
84
|
|
|
92
85
|
const BANNER_DIV =
|
|
93
86
|
`\n<!-- Off-box availability banner (ADR 0029) — injected by scripts/status-mirror-sync.js.\n` +
|
|
@@ -95,11 +88,17 @@ const BANNER_DIV =
|
|
|
95
88
|
` prober's status.json from this repo's status-data branch, no droplet dependency. -->\n` +
|
|
96
89
|
`<div id="offbox-status" role="status" aria-live="polite"></div>\n`;
|
|
97
90
|
|
|
98
|
-
|
|
91
|
+
// The banner names the site it is reporting on. Derived from the configured origin
|
|
92
|
+
// so no hostname is baked in; a non-URL origin falls back to the raw string.
|
|
93
|
+
function siteLabel(origin) {
|
|
94
|
+
try { return new URL(origin).host; } catch { return String(origin || ''); }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const bannerDriver = (statusDataUrl, label) => `<!-- Off-box availability banner driver (ADR 0029) — loaded before status.js so
|
|
99
98
|
it lights up even if the dashboard script or its cross-origin fetches fail. -->
|
|
100
99
|
<script>
|
|
101
100
|
(function () {
|
|
102
|
-
var OFFBOX_URL =
|
|
101
|
+
var OFFBOX_URL = ${JSON.stringify(statusDataUrl)};
|
|
103
102
|
var el = document.getElementById('offbox-status');
|
|
104
103
|
if (!el) return;
|
|
105
104
|
function fmtUtc(iso) {
|
|
@@ -113,8 +112,8 @@ const BANNER_DRIVER = `<!-- Off-box availability banner driver (ADR 0029) — lo
|
|
|
113
112
|
.then(function (res) { if (!res.ok) throw new Error('HTTP ' + res.status); return res.json(); })
|
|
114
113
|
.then(function (data) {
|
|
115
114
|
var cur = data && data.current, status = cur && cur.status, when = fmtUtc(cur && cur.t);
|
|
116
|
-
if (status === 'up') setState('up', '\\uD83D\\uDFE2
|
|
117
|
-
else if (status === 'down') setState('down', '\\uD83D\\uDD34
|
|
115
|
+
if (status === 'up') setState('up', '\\uD83D\\uDFE2 ${label} is operational \\u2014 checked ' + when);
|
|
116
|
+
else if (status === 'down') setState('down', '\\uD83D\\uDD34 ${label} is DOWN \\u2014 checked ' + when);
|
|
118
117
|
else setState('unknown', 'status data is momentarily unavailable');
|
|
119
118
|
})
|
|
120
119
|
.catch(function () { setState('unknown', 'status data is momentarily unavailable'); });
|
|
@@ -134,59 +133,90 @@ function injectOnce(haystack, anchor, insertion, where) {
|
|
|
134
133
|
return haystack.slice(0, idx + anchor.length) + insertion + haystack.slice(idx + anchor.length);
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
// Pure: droplet index.html + resolved config → the mirror's index.html. No disk, no
|
|
137
|
+
// network, no ambient branding read — everything the output depends on is a parameter.
|
|
138
|
+
function buildMirrorIndex({ srcHtml, apiBase, statusDataUrl, brand }) {
|
|
139
|
+
if (!statusDataUrl) {
|
|
140
|
+
throw new Error('domains.statusDataUrl is empty — the off-box availability banner would point nowhere. Set domains.statusDataUrl (the prober\'s status.json URL) in the branding config, or do not publish a mirror for this instance.');
|
|
141
|
+
}
|
|
142
|
+
let html = String(srcHtml == null ? '' : srcHtml);
|
|
139
143
|
if (html.includes('offbox-status')) {
|
|
140
144
|
throw new Error('modules/status-ui/public/index.html already contains offbox markup — the source should be the droplet (no-banner) copy. Aborting.');
|
|
141
145
|
}
|
|
142
|
-
html = injectOnce(html, '</head>',
|
|
146
|
+
html = injectOnce(html, '</head>', headInject(apiBase) + brandingInject(brand), 'before');
|
|
143
147
|
html = injectOnce(html, '<body>', BANNER_DIV, 'after');
|
|
144
148
|
// Insert the driver right before the main status.js script tag.
|
|
145
149
|
const scriptAnchor = '<script src="/status.js';
|
|
146
|
-
html = injectOnce(html, scriptAnchor,
|
|
147
|
-
// Stamp the instance branding tokens LAST —
|
|
150
|
+
html = injectOnce(html, scriptAnchor, bannerDriver(statusDataUrl, siteLabel(apiBase)), 'before');
|
|
151
|
+
// Stamp the instance branding tokens LAST — the Pages host won't run the server's
|
|
148
152
|
// injection, so the mirror must resolve {{worldName}}/{{currency}}/… itself.
|
|
149
|
-
|
|
150
|
-
return html;
|
|
153
|
+
return brandTokens(html, brand, apiBase);
|
|
151
154
|
}
|
|
152
155
|
|
|
153
|
-
// ----
|
|
156
|
+
// ---- CLI -------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
if (require.main === module) {
|
|
159
|
+
const arg = (name) => {
|
|
160
|
+
const i = process.argv.indexOf(name);
|
|
161
|
+
return i >= 0 ? process.argv[i + 1] : null;
|
|
162
|
+
};
|
|
163
|
+
const repoDir = arg('--repo-dir');
|
|
164
|
+
const doPush = process.argv.includes('--push');
|
|
165
|
+
if (!repoDir) {
|
|
166
|
+
console.error('usage: node scripts/status-mirror-sync.js --repo-dir <mirror-checkout> [--push]');
|
|
167
|
+
process.exit(2);
|
|
168
|
+
}
|
|
169
|
+
if (!fs.existsSync(path.join(repoDir, 'CNAME'))) {
|
|
170
|
+
console.error(`refusing: ${repoDir} does not look like the status mirror (no CNAME). Clone the status-mirror repo first.`);
|
|
171
|
+
process.exit(2);
|
|
172
|
+
}
|
|
154
173
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
const b = branding();
|
|
175
|
+
|
|
176
|
+
// ---- copy the verbatim assets + the transformed index ----------------------
|
|
177
|
+
|
|
178
|
+
const copyFile = (rel) => {
|
|
179
|
+
fs.copyFileSync(path.join(SRC, rel), path.join(repoDir, rel));
|
|
180
|
+
console.error(` copied ${rel}`);
|
|
181
|
+
};
|
|
182
|
+
const copyDir = (rel) => {
|
|
183
|
+
const from = path.join(SRC, rel), to = path.join(repoDir, rel);
|
|
184
|
+
if (!fs.existsSync(from)) return;
|
|
185
|
+
fs.rmSync(to, { recursive: true, force: true });
|
|
186
|
+
fs.cpSync(from, to, { recursive: true });
|
|
187
|
+
console.error(` copied ${rel}/`);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
console.error('[status-mirror-sync] building mirror from modules/status-ui/public/ …');
|
|
191
|
+
const indexHtml = buildMirrorIndex({
|
|
192
|
+
srcHtml: fs.readFileSync(path.join(SRC, 'index.html'), 'utf8'),
|
|
193
|
+
apiBase: b.domains.publicOrigin,
|
|
194
|
+
statusDataUrl: b.domains.statusDataUrl,
|
|
195
|
+
brand: clientBranding(),
|
|
196
|
+
});
|
|
197
|
+
fs.writeFileSync(path.join(repoDir, 'index.html'), indexHtml);
|
|
198
|
+
console.error(' wrote index.html (with off-box injections)');
|
|
199
|
+
copyFile('status.js');
|
|
200
|
+
copyFile('style.css');
|
|
201
|
+
copyDir('cursors');
|
|
202
|
+
|
|
203
|
+
// ---- commit + (optionally) push -------------------------------------------
|
|
204
|
+
|
|
205
|
+
const git = (args) => execFileSync('git', ['-C', repoDir, ...args], { encoding: 'utf8' });
|
|
206
|
+
git(['add', 'index.html', 'status.js', 'style.css', 'cursors']);
|
|
207
|
+
const status = git(['status', '--porcelain']);
|
|
208
|
+
if (!status.trim()) {
|
|
209
|
+
console.error('[status-mirror-sync] mirror already up to date — nothing to publish.');
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
console.error('[status-mirror-sync] changes staged:\n' + status);
|
|
213
|
+
if (!doPush) {
|
|
214
|
+
console.error('[status-mirror-sync] dry run (no --push). Review the checkout, then re-run with --push.');
|
|
215
|
+
process.exit(0);
|
|
216
|
+
}
|
|
217
|
+
git(['commit', '-m', 'chore(status): sync off-box mirror from modules/status-ui/public/ (#737)']);
|
|
218
|
+
git(['push', 'origin', 'HEAD:main']);
|
|
219
|
+
console.error(`[status-mirror-sync] published. The Pages host rebuilds ${b.domains.statusOrigin || 'the mirror'} in ~1 min.`);
|
|
165
220
|
}
|
|
166
221
|
|
|
167
|
-
|
|
168
|
-
fs.writeFileSync(path.join(repoDir, 'index.html'), buildIndexHtml());
|
|
169
|
-
console.error(' wrote index.html (with off-box injections)');
|
|
170
|
-
copyFile('status.js');
|
|
171
|
-
copyFile('style.css');
|
|
172
|
-
copyDir('cursors');
|
|
173
|
-
|
|
174
|
-
// ---- commit + (optionally) push -------------------------------------------
|
|
175
|
-
|
|
176
|
-
function git(args) {
|
|
177
|
-
return execFileSync('git', ['-C', repoDir, ...args], { encoding: 'utf8' });
|
|
178
|
-
}
|
|
179
|
-
git(['add', 'index.html', 'status.js', 'style.css', 'cursors']);
|
|
180
|
-
const status = git(['status', '--porcelain']);
|
|
181
|
-
if (!status.trim()) {
|
|
182
|
-
console.error('[status-mirror-sync] mirror already up to date — nothing to publish.');
|
|
183
|
-
process.exit(0);
|
|
184
|
-
}
|
|
185
|
-
console.error('[status-mirror-sync] changes staged:\n' + status);
|
|
186
|
-
if (!doPush) {
|
|
187
|
-
console.error('[status-mirror-sync] dry run (no --push). Review the checkout, then re-run with --push.');
|
|
188
|
-
process.exit(0);
|
|
189
|
-
}
|
|
190
|
-
git(['commit', '-m', 'chore(status): sync off-box mirror from modules/status-ui/public/ (#737)']);
|
|
191
|
-
git(['push', 'origin', 'HEAD:main']);
|
|
192
|
-
console.error('[status-mirror-sync] published. GitHub Pages rebuilds status.amazonprimea.com in ~1 min.');
|
|
222
|
+
module.exports = { buildMirrorIndex, injectOnce, brandTokens };
|
package/src/bongos/api-errors.js
CHANGED
|
@@ -66,6 +66,7 @@ const OVERRIDES = Object.freeze({
|
|
|
66
66
|
// --- forbidden: 403 (rank/ownership, not "missing" or "bad input") ---
|
|
67
67
|
forbidden: 'forbidden',
|
|
68
68
|
rank_forbidden: 'forbidden',
|
|
69
|
+
permission_forbidden: 'forbidden',
|
|
69
70
|
archon_approval_required: 'forbidden',
|
|
70
71
|
archon_required_for_protected_scope: 'forbidden',
|
|
71
72
|
metic_required_for_ownership: 'forbidden',
|