@bongos/core 1.18.0 → 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 +1740 -640
- 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 +5 -3
- 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 +11 -2
- 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/0142-project-context-is-prose-only.md +41 -0
- package/docs/adr/0143-onboarding-repo-picker-oauth-scope.md +35 -0
- 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 +15 -2
- package/docs/api/openapi.json +2648 -483
- package/docs/api-reference.md +73 -13
- 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 +15 -7
- 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/packaging-the-core.md +13 -0
- 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/upgrading-the-core.md +5 -2
- 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/039_newcomer_friendly_column.sql +5 -0
- package/migrations/102_remove_box_first_provision_approval.sql +4 -0
- package/migrations/core_192_github_oauth_tokens.sql +33 -0
- 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/my-projects.html +78 -0
- package/modules/hall-ui/public/my-projects.js +142 -0
- 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/scouting.html +45 -0
- package/modules/hall-ui/public/scouting.js +73 -0
- 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/modules/status-ui/public/explore.html +54 -0
- package/modules/status-ui/public/explore.js +67 -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 +252 -62
- 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 -21
- 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/lint-migrations.js +102 -0
- package/scripts/gds/login.js +58 -11
- package/scripts/gds/mirror-redact.js +5 -0
- package/scripts/gds/package-core.js +263 -4
- package/scripts/gds/paste-token.js +7 -1
- package/scripts/gds/preflight.js +126 -0
- package/scripts/gds/provision.js +268 -19
- package/scripts/gds/publish-manifest.js +22 -1
- package/scripts/gds/reauth.js +7 -3
- package/scripts/gds/regen-instance-docs.js +47 -0
- package/scripts/gds/run-unit-tests.js +42 -16
- 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 +72 -5
- package/scripts/gds/shell.js +5 -3
- package/scripts/gds/ship.js +433 -59
- 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 +271 -7
- package/scripts/migrate.sh +10 -0
- package/scripts/status-mirror-sync.js +114 -84
- package/src/bongos/api-errors.js +1 -0
- package/src/bongos/auth.js +809 -107
- package/src/bongos/db-kernel.js +27 -0
- package/src/bongos/db.js +105 -0
- package/src/bongos/github-repos.js +93 -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 +312 -13
- package/src/bongos/routes/backup.js +58 -2
- package/src/bongos/routes/github.js +90 -0
- package/src/bongos/routes/instance.js +15 -3
- package/src/bongos/routes/me.js +35 -1
- package/src/bongos/routes.js +2 -0
- package/src/bongos/serve-internal.js +84 -15
- package/src/branding.js +49 -2
- package/src/instance-config.js +46 -0
- package/src/module-api.js +140 -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 +41 -23
- 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/github_repos_helpers.mjs +91 -0
- package/tests/github_token_store.mjs +121 -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 +198 -0
- package/tests/idp_federation.mjs +100 -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/migrations_forward_safe.mjs +86 -0
- package/tests/module_api.mjs +1 -1
- 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/package_core.mjs +246 -1
- 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 +289 -7
- package/tests/pruned_lockfile_integrity.mjs +79 -0
- 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 +140 -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 +393 -5
- package/tests/web_admission_status.mjs +162 -0
- package/tests/write_validation_gaps.mjs +110 -0
- package/.gitignore +0 -91
- package/docs/adr/0139-platform-history-migration-to-cloudbongos.md +0 -94
- package/docs/adr/0140-cloudbongos-standalone-reprovision.md +0 -43
- package/scripts/hall-preview/fixtures/access-requests.json +0 -20
- package/scripts/hall-preview/fixtures/achievements.json +0 -76
- package/scripts/hall-preview/fixtures/analytics__builder.json +0 -251
- package/scripts/hall-preview/fixtures/audit-log.json +0 -68
- package/scripts/hall-preview/fixtures/blockers__detail.json +0 -12
- package/scripts/hall-preview/fixtures/box__me.json +0 -5
- package/scripts/hall-preview/fixtures/boxes__cost-ledger.json +0 -69
- package/scripts/hall-preview/fixtures/builders__active-claims.json +0 -1
- package/scripts/hall-preview/fixtures/builders__directory.json +0 -81
- package/scripts/hall-preview/fixtures/builders__roster.json +0 -48
- package/scripts/hall-preview/fixtures/goals.json +0 -502
- package/scripts/hall-preview/fixtures/goals__25.json +0 -96
- package/scripts/hall-preview/fixtures/goals__26.json +0 -67
- package/scripts/hall-preview/fixtures/goals__3.json +0 -103
- package/scripts/hall-preview/fixtures/goals__35.json +0 -49
- package/scripts/hall-preview/fixtures/goals__conflicts.json +0 -154
- package/scripts/hall-preview/fixtures/goals__detail.json +0 -96
- package/scripts/hall-preview/fixtures/goals__inbox.json +0 -5
- package/scripts/hall-preview/fixtures/goals__requests.json +0 -3
- package/scripts/hall-preview/fixtures/grades__by-builder.json +0 -32
- package/scripts/hall-preview/fixtures/inbox.json +0 -330
- package/scripts/hall-preview/fixtures/inbox__detail.json +0 -15
- package/scripts/hall-preview/fixtures/instance.json +0 -124
- package/scripts/hall-preview/fixtures/leaderboard.json +0 -184
- package/scripts/hall-preview/fixtures/me.json +0 -476
- package/scripts/hall-preview/fixtures/me__art-key__own.json +0 -6
- package/scripts/hall-preview/fixtures/me__event-sound-prefs.json +0 -209
- package/scripts/hall-preview/fixtures/me__recent-ships.json +0 -304
- package/scripts/hall-preview/fixtures/me__render.json +0 -5
- package/scripts/hall-preview/fixtures/me__skill-prefs.json +0 -143
- package/scripts/hall-preview/fixtures/me__sound-prefs.json +0 -67
- package/scripts/hall-preview/fixtures/me__wandering.json +0 -43
- package/scripts/hall-preview/fixtures/override-requests.json +0 -15
- package/scripts/hall-preview/fixtures/provisioning__fleet.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__fleet__cost-ledger.json +0 -1
- package/scripts/hall-preview/fixtures/provisioning__instances.json +0 -1
- package/scripts/hall-preview/fixtures/public__analytics__ecosystem.json +0 -516
- package/scripts/hall-preview/fixtures/public__bounty-table.json +0 -37
- package/scripts/hall-preview/fixtures/public__cost-summary.json +0 -742
- package/scripts/hall-preview/fixtures/public__estimation-drift.json +0 -41
- package/scripts/hall-preview/fixtures/public__grades.json +0 -50
- package/scripts/hall-preview/fixtures/public__progress.json +0 -124
- package/scripts/hall-preview/fixtures/public__recent-shipped.json +0 -426
- package/scripts/hall-preview/fixtures/public__repo-health.json +0 -160
- package/scripts/hall-preview/fixtures/public__repo-info.json +0 -5
- package/scripts/hall-preview/fixtures/security__docs.json +0 -10
- package/scripts/hall-preview/fixtures/security__reports.json +0 -31
- package/scripts/hall-preview/fixtures/sessions__search.json +0 -9
- package/scripts/hall-preview/fixtures/tasks.json +0 -2420
- package/scripts/hall-preview/fixtures/tasks__claimable.json +0 -2555
- package/scripts/hall-preview/fixtures/tasks__detail.json +0 -111
- package/scripts/hall-preview/fixtures/tasks__peer-votes__feed.json +0 -330
- package/scripts/hall-preview/fixtures/versions.json +0 -89
|
@@ -29,6 +29,13 @@
|
|
|
29
29
|
--font-mono:"Fira Code",ui-monospace,SFMono-Regular,Menlo,monospace;
|
|
30
30
|
}
|
|
31
31
|
*{box-sizing:border-box;margin:0;padding:0;}
|
|
32
|
+
/* The `hidden` attribute must always win. Several blocks below set an explicit
|
|
33
|
+
`display` via a class (.field→block, .row2→grid); an author rule like that
|
|
34
|
+
silently defeats the user-agent [hidden] rule, so `el.hidden = true` fails to
|
|
35
|
+
hide them. The Home step (task 1002228) toggles el.hidden to switch between the
|
|
36
|
+
adopt-picker / fresh-name / manual sub-panels — without this they ALL render at
|
|
37
|
+
once. Make hidden authoritative for the whole page. */
|
|
38
|
+
[hidden]{display:none !important;}
|
|
32
39
|
html{scroll-behavior:smooth;}
|
|
33
40
|
body{
|
|
34
41
|
font-family:var(--font-body); color:var(--ink);
|
|
@@ -75,11 +82,6 @@ body{
|
|
|
75
82
|
.exit-wizard kbd{font-family:var(--font-mono);font-size:10px;line-height:1;background:rgba(42,31,23,0.08);border-radius:4px;padding:2px 5px;color:var(--ink-faint);}
|
|
76
83
|
.who{display:flex;align-items:center;gap:10px;font-size:14px;font-weight:600;color:var(--ink-soft);min-height:34px;}
|
|
77
84
|
.who img{width:30px;height:30px;border-radius:50%;border:2px solid #fff;box-shadow:0 2px 8px rgba(42,31,23,0.12);}
|
|
78
|
-
.who a{color:var(--accent-deep);text-decoration:none;font-weight:700;}
|
|
79
|
-
.who a:hover{text-decoration:underline;}
|
|
80
|
-
/* switch to a different GitHub account from inside the wizard (task 2098) */
|
|
81
|
-
.who .switch-acct{font-size:12px;font-weight:600;color:var(--ink-faint);padding-left:10px;margin-left:2px;border-left:1px solid rgba(42,31,23,0.16);}
|
|
82
|
-
.who .switch-acct:hover{color:var(--accent-deep);}
|
|
83
85
|
|
|
84
86
|
/* ── layout ── */
|
|
85
87
|
.wrap{
|
|
@@ -195,10 +197,6 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
195
197
|
.ghbtn:hover{background:#1b1f24;transform:translateY(-1px);}
|
|
196
198
|
.ghbtn:active{transform:translateY(0) scale(.98);}
|
|
197
199
|
.ghbtn .gh{width:18px;height:18px;fill:currentColor;}
|
|
198
|
-
.ghcreate{display:none;margin-bottom:18px;}
|
|
199
|
-
.ghcreate.on{display:block;}
|
|
200
|
-
.ghcreate-note{font-size:13px;font-weight:500;color:var(--ink-faint);line-height:1.5;margin-top:9px;max-width:52ch;}
|
|
201
|
-
.ghcreate-note strong{color:var(--ink-soft);}
|
|
202
200
|
.steps .ghbtn{font-size:14px;padding:9px 16px;margin-top:10px;}
|
|
203
201
|
|
|
204
202
|
/* buttons */
|
|
@@ -327,6 +325,16 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
327
325
|
@media (prefers-reduced-motion:reduce){
|
|
328
326
|
*,*::before,*::after{animation:none !important;transition:none !important;}
|
|
329
327
|
}
|
|
328
|
+
/* GitHub repo picker (task 1002099) */
|
|
329
|
+
.linklike{background:none;border:0;padding:0;margin-left:12px;color:var(--accent-deep);font:inherit;font-size:13px;cursor:pointer;text-decoration:underline;}
|
|
330
|
+
#ghConnect .btn{margin-top:4px;}
|
|
331
|
+
.ghlist{margin-top:8px;max-height:220px;overflow-y:auto;border:1px solid var(--line,#e7d8c4);border-radius:10px;background:var(--bg-deep,#fff);}
|
|
332
|
+
.ghlist:empty{display:none;}
|
|
333
|
+
.ghrow{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:0;border-bottom:1px solid rgba(42,31,23,0.06);padding:9px 12px;font:inherit;font-size:13.5px;color:var(--ink,#2a1f17);cursor:pointer;}
|
|
334
|
+
.ghrow:last-child{border-bottom:0;}
|
|
335
|
+
.ghrow:hover{background:#fff9f2;}
|
|
336
|
+
.ghrow[aria-selected=true]{background:#fff3e6;box-shadow:inset 3px 0 0 var(--accent,#f97316);font-weight:600;}
|
|
337
|
+
.ghrow .priv{margin-left:auto;font-size:11px;font-weight:600;color:var(--ink-faint,#9b8a78);background:rgba(42,31,23,0.06);border-radius:5px;padding:1px 6px;}
|
|
330
338
|
</style>
|
|
331
339
|
</head>
|
|
332
340
|
<body>
|
|
@@ -363,7 +371,11 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
363
371
|
<section class="panel" id="panel-gate" aria-labelledby="gate-h">
|
|
364
372
|
<h1 id="gate-h">Create a project</h1>
|
|
365
373
|
<p class="lede">Your own <strong data-brand-product-inline>Cloud Bongos</strong> project: its own repository, its own home on the web, and a hall of AI builders who do the building. You set the direction; agents lay down the code. Sign in with GitHub so the project belongs to <em>you</em> from the very first beat.</p>
|
|
366
|
-
|
|
374
|
+
<!-- The wizard's own sign-in opts into repo scope (read:user + public_repo) up
|
|
375
|
+
front (&repos=1) — anyone here intends to create a project, which needs repo
|
|
376
|
+
access, so we ask once at sign-in instead of a second "Connect" step at Home.
|
|
377
|
+
Hall + CLI sign-in stay identity-only (ADR 0143 least-privilege default). -->
|
|
378
|
+
<a class="btn big" id="signin" href="/api/bongos/auth/web/start?return=/create&repos=1">
|
|
367
379
|
<svg class="gh" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
|
|
368
380
|
Sign in with GitHub
|
|
369
381
|
</a>
|
|
@@ -405,7 +417,31 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
405
417
|
</button>
|
|
406
418
|
</div>
|
|
407
419
|
<div class="reassure" id="adoptNote">Adopting never overwrites your files: you get a conflict pre-flight first, nothing is written until you accept, and your existing backlog (issues, TODOs) is imported as real tasks.</div>
|
|
408
|
-
|
|
420
|
+
|
|
421
|
+
<!-- GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099.
|
|
422
|
+
Progressive enhancement: when the signed-in user grants repo access we let
|
|
423
|
+
them PICK a repo (adopt) or NAME one we auto-create (fresh). Without that
|
|
424
|
+
access — not granted yet, or the server can't store the token — we fall back
|
|
425
|
+
to the manual owner/repo inputs below (#manualHome), which stay authoritative. -->
|
|
426
|
+
<div id="ghConnect" class="reassure">
|
|
427
|
+
<p id="ghConnectMsg"> </p>
|
|
428
|
+
<button type="button" class="btn" id="ghConnectBtn">Allow repo access</button>
|
|
429
|
+
<button type="button" class="linklike" id="ghManualToggle">or enter it manually</button>
|
|
430
|
+
</div>
|
|
431
|
+
<div id="ghBusy" class="hint" hidden>Reading your GitHub repositories…</div>
|
|
432
|
+
<div id="ghAdopt" class="field" hidden>
|
|
433
|
+
<span>Pick one of your repositories</span>
|
|
434
|
+
<input type="text" id="ghSearch" placeholder="Search your repos…" autocomplete="off">
|
|
435
|
+
<div id="ghList" class="ghlist" role="listbox" aria-label="Your repositories"></div>
|
|
436
|
+
<div class="hint" id="ghAdoptHint"> </div>
|
|
437
|
+
</div>
|
|
438
|
+
<div id="ghFresh" class="field" hidden>
|
|
439
|
+
<span>New repository name</span>
|
|
440
|
+
<input type="text" id="ghNewName" placeholder="mercury" autocomplete="off" maxlength="100">
|
|
441
|
+
<div class="hint" id="ghFreshHint">We’ll create an empty repo at <code id="ghFreshPreview" style="font-family:var(--font-mono)">github.com/you/mercury</code>.</div>
|
|
442
|
+
</div>
|
|
443
|
+
|
|
444
|
+
<div class="row2" id="manualHome">
|
|
409
445
|
<label class="field"><span>GitHub owner <small>(user or org)</small></span>
|
|
410
446
|
<input type="text" id="f-owner" placeholder="acme" autocomplete="off" maxlength="60">
|
|
411
447
|
</label>
|
|
@@ -413,13 +449,6 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
413
449
|
<input type="text" id="f-repo" placeholder="mercury" autocomplete="off" maxlength="120">
|
|
414
450
|
</label>
|
|
415
451
|
</div>
|
|
416
|
-
<div class="ghcreate" id="ghCreate">
|
|
417
|
-
<a class="ghbtn" id="ghCreateBtn" href="https://github.com/new" target="_blank" rel="noopener">
|
|
418
|
-
<svg class="gh" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
|
|
419
|
-
Create this repo on GitHub
|
|
420
|
-
</a>
|
|
421
|
-
<p class="ghcreate-note">Opens GitHub with the name already filled in — just click <strong>Create repository</strong> and leave it empty, then come back and press Next. Already made it? Just press Next.</p>
|
|
422
|
-
</div>
|
|
423
452
|
<div class="hint" id="h-home"> </div>
|
|
424
453
|
<div class="nav">
|
|
425
454
|
<button type="button" class="btn ghost" data-back="1">← Back</button>
|
|
@@ -566,10 +595,6 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
566
595
|
if (owner) u.searchParams.set('owner', owner);
|
|
567
596
|
return u.toString();
|
|
568
597
|
}
|
|
569
|
-
function updateGhCreateHref() {
|
|
570
|
-
var a = $('ghCreateBtn');
|
|
571
|
-
if (a) a.href = githubNewRepoUrl(state.owner, state.repo);
|
|
572
|
-
}
|
|
573
598
|
function esc(s) {
|
|
574
599
|
return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) {
|
|
575
600
|
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
|
|
@@ -595,6 +620,7 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
595
620
|
saveDraft();
|
|
596
621
|
var h = $(panels[step]).querySelector('h1');
|
|
597
622
|
if (h) { h.setAttribute('tabindex', '-1'); h.focus({ preventScroll: false }); }
|
|
623
|
+
if (step === 2) { syncHome(); ensureRepoAccess(); }
|
|
598
624
|
if (step === 4) renderReview();
|
|
599
625
|
}
|
|
600
626
|
|
|
@@ -622,7 +648,6 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
622
648
|
if (!state.repoTouched) {
|
|
623
649
|
state.repo = deriveRepo(state.name);
|
|
624
650
|
$('f-repo').value = state.repo;
|
|
625
|
-
updateGhCreateHref();
|
|
626
651
|
}
|
|
627
652
|
var h = $('h-name');
|
|
628
653
|
if (state.slug) { h.innerHTML = 'its handle on the platform: <code>' + esc(state.slug) + '</code>'; h.className = 'hint'; }
|
|
@@ -636,18 +661,143 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
636
661
|
$('c-green').setAttribute('aria-pressed', String(mode === 'greenfield'));
|
|
637
662
|
$('c-adopt').setAttribute('aria-pressed', String(mode === 'adopt'));
|
|
638
663
|
$('adoptNote').classList.toggle('on', mode === 'adopt');
|
|
639
|
-
// The "create the repo on GitHub" button only makes sense when starting fresh —
|
|
640
|
-
// an adopted repo already exists.
|
|
641
|
-
$('ghCreate').classList.toggle('on', mode === 'greenfield');
|
|
642
|
-
updateGhCreateHref();
|
|
643
664
|
saveDraft();
|
|
665
|
+
syncHome();
|
|
644
666
|
}
|
|
645
667
|
$('c-green').addEventListener('click', function () { setMode('greenfield'); });
|
|
646
668
|
$('c-adopt').addEventListener('click', function () { setMode('adopt'); });
|
|
647
669
|
setMode(state.mode);
|
|
648
670
|
|
|
649
|
-
|
|
650
|
-
|
|
671
|
+
/* ── GitHub-integrated repo picker (adopt) + auto-create (fresh) — task 1002099 / ADR 0143.
|
|
672
|
+
Progressive enhancement: probe GET /github/repos once we reach step 2.
|
|
673
|
+
200 → we hold repo access → show the picker (adopt) / name field (fresh);
|
|
674
|
+
403 → offer to grant repo access (a ?repos=1 re-sign-in);
|
|
675
|
+
503 (server can't store the token) or any error → the manual inputs.
|
|
676
|
+
#manualHome (the classic owner/repo fields) is the always-safe fallback. ── */
|
|
677
|
+
var repoAccess = null; // null=unknown/loading · true · 'need-connect' · 'unavailable' · 'manual'
|
|
678
|
+
var repoList = []; // the user's repos (from the probe) — feeds the picker + the fresh-name clash hint
|
|
679
|
+
var ghProbed = false;
|
|
680
|
+
|
|
681
|
+
function isManualHome() { return repoAccess === 'manual' || repoAccess === 'unavailable'; }
|
|
682
|
+
function validRepoName(s) { return /^[A-Za-z0-9._-]{1,100}$/.test(String(s || '')); }
|
|
683
|
+
function myLogin() { return (me && me.github_login) || 'you'; }
|
|
684
|
+
|
|
685
|
+
function connectRepos(e) {
|
|
686
|
+
if (e) e.preventDefault();
|
|
687
|
+
// Same-tab navigation so the sessionStorage draft round-trips back to step 2.
|
|
688
|
+
window.location.assign(API + '/auth/web/start?return=/create&repos=1');
|
|
689
|
+
}
|
|
690
|
+
$('ghConnectBtn').addEventListener('click', connectRepos);
|
|
691
|
+
$('ghManualToggle').addEventListener('click', function () { repoAccess = 'manual'; syncHome(); $('f-owner').focus(); });
|
|
692
|
+
|
|
693
|
+
function syncHome() {
|
|
694
|
+
var need = repoAccess === 'need-connect';
|
|
695
|
+
var ok = repoAccess === true;
|
|
696
|
+
var adopt = state.mode === 'adopt';
|
|
697
|
+
$('ghBusy').hidden = !!repoAccess; // busy only while still probing (null)
|
|
698
|
+
$('ghConnect').classList.toggle('on', need); // .reassure box: shown via .on (not hidden — .reassure sets display:none)
|
|
699
|
+
$('ghAdopt').hidden = !(ok && adopt);
|
|
700
|
+
$('ghFresh').hidden = !(ok && !adopt);
|
|
701
|
+
$('manualHome').hidden = !isManualHome();
|
|
702
|
+
if (need) {
|
|
703
|
+
$('ghConnectMsg').textContent = adopt
|
|
704
|
+
? 'You’re signed in — creating your project needs one more GitHub permission. Allow repo access to pick the repository to adopt.'
|
|
705
|
+
: 'You’re signed in — creating your project needs one more GitHub permission. Allow repo access and we’ll create the empty repo for you.';
|
|
706
|
+
}
|
|
707
|
+
if (ok && adopt) initAdoptPicker();
|
|
708
|
+
if (ok && !adopt) syncFresh();
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function syncFresh() {
|
|
712
|
+
// Fresh + access: the repo is created under the signed-in account. Seed owner for
|
|
713
|
+
// the review/target now; the create response confirms the real full_name.
|
|
714
|
+
state.owner = myLogin();
|
|
715
|
+
$('ghNewName').value = state.repo || '';
|
|
716
|
+
updateFreshPreview();
|
|
717
|
+
}
|
|
718
|
+
function updateFreshPreview() {
|
|
719
|
+
var hint = $('ghFreshHint');
|
|
720
|
+
var clash = state.repo && repoList.some(function (r) { return String(r.name).toLowerCase() === state.repo.toLowerCase(); });
|
|
721
|
+
if (state.repo && !validRepoName(state.repo)) {
|
|
722
|
+
hint.className = 'hint err'; hint.textContent = 'Use letters, numbers, and . _ - (1–100 chars).';
|
|
723
|
+
} else if (clash) {
|
|
724
|
+
hint.className = 'hint err'; hint.innerHTML = 'You already have a repo named <strong>' + esc(state.repo) + '</strong> — pick another name, or adopt it instead.';
|
|
725
|
+
} else {
|
|
726
|
+
hint.className = 'hint'; hint.innerHTML = 'We’ll create an empty repo at <code style="font-family:var(--font-mono)">github.com/' + esc(myLogin()) + '/' + esc(state.repo || 'name') + '</code>.';
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
$('ghNewName').addEventListener('input', function () { state.repo = this.value.trim(); updateFreshPreview(); saveDraft(); });
|
|
730
|
+
|
|
731
|
+
// The adopt picker behaves like a standard combobox (owner design review, task
|
|
732
|
+
// 1002247): the dropdown is open only while the visitor is choosing. Selecting a
|
|
733
|
+
// repo fills the search box with its full_name and collapses the list; focusing or
|
|
734
|
+
// typing reopens it.
|
|
735
|
+
function openRepoList() { $('ghList').hidden = false; renderRepoList(); }
|
|
736
|
+
function closeRepoList() { $('ghList').hidden = true; }
|
|
737
|
+
function renderRepoList() {
|
|
738
|
+
var q = ($('ghSearch').value || '').trim().toLowerCase();
|
|
739
|
+
var sel = state.owner && state.repo ? (state.owner + '/' + state.repo) : '';
|
|
740
|
+
// When the box just shows the current selection verbatim, list everything (so the
|
|
741
|
+
// visitor can switch) instead of filtering down to the one selected repo.
|
|
742
|
+
var effectiveQ = q === sel.toLowerCase() ? '' : q;
|
|
743
|
+
var rows = repoList.filter(function (r) { return !effectiveQ || String(r.full_name).toLowerCase().indexOf(effectiveQ) >= 0; }).slice(0, 100);
|
|
744
|
+
$('ghList').innerHTML = rows.length
|
|
745
|
+
? rows.map(function (r) {
|
|
746
|
+
return '<button type="button" class="ghrow" role="option" data-full="' + esc(r.full_name) + '" aria-selected="' + (r.full_name === sel) + '">' +
|
|
747
|
+
'<span>' + esc(r.full_name) + '</span>' + (r.private ? '<span class="priv">Private</span>' : '') + '</button>';
|
|
748
|
+
}).join('')
|
|
749
|
+
: '<div class="hint" style="padding:10px 12px">No repositories match “' + esc(effectiveQ) + '”.</div>';
|
|
750
|
+
}
|
|
751
|
+
// Fill the search box with the current selection (if any) and collapse the list;
|
|
752
|
+
// with nothing chosen yet, open it so the visitor sees their repos right away.
|
|
753
|
+
function initAdoptPicker() {
|
|
754
|
+
var sel = state.owner && state.repo ? state.owner + '/' + state.repo : '';
|
|
755
|
+
// Only treat it as a confirmed pick if it's actually one of the visitor's repos.
|
|
756
|
+
// owner/repo are auto-derived from the project name, so a bare derived value must
|
|
757
|
+
// NOT masquerade as a chosen repo — that would collapse the list onto a repo that
|
|
758
|
+
// may not even exist.
|
|
759
|
+
var picked = sel && repoList.some(function (r) { return String(r.full_name).toLowerCase() === sel.toLowerCase(); });
|
|
760
|
+
var h = $('ghAdoptHint');
|
|
761
|
+
if (picked) {
|
|
762
|
+
$('ghSearch').value = sel;
|
|
763
|
+
h.className = 'hint ok'; h.innerHTML = 'Adopting <strong>' + esc(sel) + '</strong>.';
|
|
764
|
+
closeRepoList();
|
|
765
|
+
} else {
|
|
766
|
+
$('ghSearch').value = '';
|
|
767
|
+
h.className = 'hint'; h.innerHTML = ' ';
|
|
768
|
+
openRepoList();
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
$('ghSearch').addEventListener('focus', function () { this.select(); openRepoList(); });
|
|
772
|
+
$('ghSearch').addEventListener('input', openRepoList);
|
|
773
|
+
$('ghList').addEventListener('click', function (ev) {
|
|
774
|
+
var row = ev.target.closest('.ghrow'); if (!row) return;
|
|
775
|
+
var full = row.getAttribute('data-full'); var slash = full.indexOf('/');
|
|
776
|
+
state.owner = full.slice(0, slash); state.repo = full.slice(slash + 1);
|
|
777
|
+
state.ownerTouched = true; state.repoTouched = true; // a real pick — don't let name-derive clobber it
|
|
778
|
+
saveDraft();
|
|
779
|
+
$('ghSearch').value = full; // pull the choice into the search box …
|
|
780
|
+
var h = $('ghAdoptHint'); h.className = 'hint ok'; h.innerHTML = 'Adopting <strong>' + esc(full) + '</strong>.';
|
|
781
|
+
closeRepoList(); // … and collapse the dropdown (typical UX)
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
function ensureRepoAccess() {
|
|
785
|
+
if (ghProbed && repoAccess !== null) return; // already known this session
|
|
786
|
+
if (isManualHome()) return; // user chose manual — don't nag
|
|
787
|
+
repoAccess = null; syncHome(); // show "reading your repos…"
|
|
788
|
+
fetch(API + '/github/repos', { credentials: 'same-origin' })
|
|
789
|
+
.then(function (res) {
|
|
790
|
+
ghProbed = true;
|
|
791
|
+
if (res.status === 200) return res.json().then(function (d) { repoList = (d && d.repos) || []; repoAccess = true; });
|
|
792
|
+
if (res.status === 403 || res.status === 401) { repoAccess = 'need-connect'; return; }
|
|
793
|
+
repoAccess = 'unavailable'; return; // 503 or anything else → manual fallback
|
|
794
|
+
})
|
|
795
|
+
.catch(function () { ghProbed = true; repoAccess = 'unavailable'; })
|
|
796
|
+
.then(syncHome);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
$('f-owner').addEventListener('input', function () { state.owner = this.value.trim(); state.ownerTouched = true; saveDraft(); });
|
|
800
|
+
$('f-repo').addEventListener('input', function () { state.repo = this.value.trim(); state.repoTouched = true; saveDraft(); });
|
|
651
801
|
|
|
652
802
|
$('f-slug').addEventListener('input', function () {
|
|
653
803
|
state.slugTouched = true;
|
|
@@ -675,7 +825,17 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
675
825
|
return true;
|
|
676
826
|
}
|
|
677
827
|
if (step === 2) {
|
|
678
|
-
|
|
828
|
+
var homeErr = function (msg) { $('h-home').textContent = msg; $('h-home').className = 'hint err'; return false; };
|
|
829
|
+
if (repoAccess === 'need-connect') return homeErr('Allow GitHub repo access to pick or create your repository — or choose “enter it manually”.');
|
|
830
|
+
if (repoAccess === true && state.mode !== 'adopt') {
|
|
831
|
+
// Fresh with access: just the new repo NAME (owner is the signed-in account).
|
|
832
|
+
if (!validRepoName(state.repo)) return homeErr('Name the new repository (letters, numbers, and . _ -).');
|
|
833
|
+
} else {
|
|
834
|
+
// Adopt (picker or manual) and the manual fallback: need a concrete owner + repo.
|
|
835
|
+
if (!state.owner || !state.repo) {
|
|
836
|
+
return homeErr(state.mode === 'adopt' && repoAccess === true ? 'Pick one of your repositories.' : 'Both owner and repository name are needed.');
|
|
837
|
+
}
|
|
838
|
+
}
|
|
679
839
|
$('h-home').innerHTML = ' '; $('h-home').className = 'hint';
|
|
680
840
|
return true;
|
|
681
841
|
}
|
|
@@ -725,20 +885,58 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
725
885
|
return 'Couldn’t file the request: ' + (err && err.message ? err.message : 'something went sideways. Try again.');
|
|
726
886
|
}
|
|
727
887
|
|
|
888
|
+
/* Fresh + repo access: auto-create the empty GitHub repo NOW (the commit moment),
|
|
889
|
+
then hand its real full_name to provisioning. No-op for adopt / manual / no-access.
|
|
890
|
+
Idempotent across a retry — once created we reuse the stashed full_name so a second
|
|
891
|
+
click doesn't trip GitHub's 422 "name already exists". Errors set err.gotoHome so
|
|
892
|
+
the caller bounces the user back to the Home step to fix the name / reconnect. */
|
|
893
|
+
function ensureFreshRepo() {
|
|
894
|
+
if (state.mode === 'adopt' || repoAccess !== true) return Promise.resolve();
|
|
895
|
+
if (state.repoAutoCreated && state.owner && state.repo) return Promise.resolve();
|
|
896
|
+
return fetch(API + '/github/repos', {
|
|
897
|
+
method: 'POST', credentials: 'same-origin',
|
|
898
|
+
headers: { 'Content-Type': 'application/json' },
|
|
899
|
+
body: JSON.stringify({ name: state.repo })
|
|
900
|
+
}).then(function (res) {
|
|
901
|
+
return res.json().catch(function () { return {}; }).then(function (data) {
|
|
902
|
+
if (res.status === 401 || res.status === 403) {
|
|
903
|
+
repoAccess = 'need-connect';
|
|
904
|
+
var e0 = new Error('reconnect'); e0.gotoHome = true;
|
|
905
|
+
e0.homeMsg = 'Your GitHub authorization expired — reconnect on the Home step to create the repo.';
|
|
906
|
+
throw e0;
|
|
907
|
+
}
|
|
908
|
+
if (!res.ok) {
|
|
909
|
+
var e = new Error((data.error && (data.error.message || data.error.code)) || ('HTTP ' + res.status));
|
|
910
|
+
e.data = data;
|
|
911
|
+
if (data.error && data.error.code === 'name_taken') { e.gotoHome = true; e.homeMsg = data.error.message; }
|
|
912
|
+
throw e;
|
|
913
|
+
}
|
|
914
|
+
var full = data.repo && data.repo.full_name;
|
|
915
|
+
if (full && full.indexOf('/') > 0) {
|
|
916
|
+
state.owner = full.slice(0, full.indexOf('/'));
|
|
917
|
+
state.repo = full.slice(full.indexOf('/') + 1);
|
|
918
|
+
}
|
|
919
|
+
state.repoAutoCreated = true; saveDraft();
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
|
|
728
924
|
$('doCreate').addEventListener('click', function () {
|
|
729
925
|
var btn = this;
|
|
730
926
|
var alertBox = $('createAlert');
|
|
731
927
|
alertBox.classList.remove('on');
|
|
732
928
|
btn.disabled = true; btn.textContent = 'Raising it into the sky…';
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
929
|
+
ensureFreshRepo().then(function () {
|
|
930
|
+
return fetch(API + '/provisioning/instances', {
|
|
931
|
+
method: 'POST', credentials: 'same-origin',
|
|
932
|
+
headers: { 'Content-Type': 'application/json' },
|
|
933
|
+
body: JSON.stringify({
|
|
934
|
+
slug: state.slug,
|
|
935
|
+
hosting_shape: 'standalone',
|
|
936
|
+
domain: state.domain || undefined,
|
|
937
|
+
target_ref: state.owner + '/' + state.repo
|
|
938
|
+
})
|
|
939
|
+
});
|
|
742
940
|
}).then(function (res) {
|
|
743
941
|
if (res.status === 401) { window.location.assign(API + '/auth/web/start?return=/create'); throw new Error('signing in'); }
|
|
744
942
|
return res.json().catch(function () { return {}; }).then(function (data) {
|
|
@@ -761,9 +959,17 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
761
959
|
startProgress(data.instance && data.instance.id);
|
|
762
960
|
}).catch(function (err) {
|
|
763
961
|
if (String(err && err.message) === 'signing in') return;
|
|
962
|
+
btn.disabled = false; btn.textContent = 'Create my project';
|
|
963
|
+
if (err && err.gotoHome) {
|
|
964
|
+
// A repo-creation problem (name taken / reconnect) — bounce back to the Home
|
|
965
|
+
// step with the reason, so the user fixes it where the repo is chosen.
|
|
966
|
+
show(2);
|
|
967
|
+
$('h-home').textContent = err.homeMsg || 'Please revisit the repository step.';
|
|
968
|
+
$('h-home').className = 'hint err';
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
764
971
|
alertBox.textContent = friendlyCreateError(err);
|
|
765
972
|
alertBox.classList.add('on');
|
|
766
|
-
btn.disabled = false; btn.textContent = 'Create my project';
|
|
767
973
|
});
|
|
768
974
|
});
|
|
769
975
|
|
|
@@ -786,8 +992,10 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
786
992
|
var ghIcon = '<svg class="gh" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>';
|
|
787
993
|
steps.push(adopt
|
|
788
994
|
? '<li data-onboard-step="github-repo"><b>Layer onto your existing repo</b><p>In your repo run <code style="font-family:var(--font-mono)">bongos init --adopt</code>. It shows a conflict pre-flight and writes <em>nothing</em> until you accept — your files and history stay yours, and your existing backlog is imported. Commit and push.</p></li>'
|
|
789
|
-
:
|
|
790
|
-
'<
|
|
995
|
+
: (state.repoAutoCreated
|
|
996
|
+
? '<li data-onboard-step="github-repo"><b>Your empty repo is ready</b><p>We created ' + repoLabel + ' on GitHub for you — empty and waiting. The scaffold lands there when the build runs; nothing for you to do here.</p></li>'
|
|
997
|
+
: '<li data-onboard-step="github-repo"><b>Create the empty GitHub repo</b><p>Do this first — the build needs the repo to exist. Click below (GitHub opens with the name already filled in), press <strong>Create repository</strong>, and leave it completely empty. Seeing “repository not found” above? That just means the repo isn’t created yet — make it here.</p>' +
|
|
998
|
+
'<a class="ghbtn" href="' + esc(ghNewUrl) + '" target="_blank" rel="noopener">' + ghIcon + 'Create ' + repoLabel + ' on GitHub</a></li>'));
|
|
791
999
|
if (!state.domain) {
|
|
792
1000
|
steps.push('<li><b>Add a domain you own</b><p>Sign-in on your new instance needs a real domain. When you have one, come back here or ask your hall — the address gets wired in minutes.</p></li>');
|
|
793
1001
|
}
|
|
@@ -917,31 +1125,14 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
917
1125
|
if (e.key === 'Escape') { e.preventDefault(); exitWizard(); }
|
|
918
1126
|
});
|
|
919
1127
|
|
|
920
|
-
/* ── switch GitHub account from inside the wizard (task 2098) ── you are not
|
|
921
|
-
locked to the account you entered with: sign out of the Cloud Bongos session,
|
|
922
|
-
then restart GitHub sign-in so the wizard reloads under whichever account you
|
|
923
|
-
pick. (To land on a *different* GitHub account, switch accounts on GitHub's
|
|
924
|
-
side; this un-locks our session so the next sign-in is honored.) */
|
|
925
|
-
function switchAccount(e) {
|
|
926
|
-
if (e) e.preventDefault();
|
|
927
|
-
var back = API + '/auth/web/start?return=/create';
|
|
928
|
-
fetch(API + '/auth/logout', { method: 'POST', credentials: 'same-origin' })
|
|
929
|
-
.then(function () { window.location.assign(back); })
|
|
930
|
-
.catch(function () { window.location.assign(back); });
|
|
931
|
-
}
|
|
932
|
-
|
|
933
1128
|
/* ── boot: who am I? ── (task 2094: the wizard shows the signed-in identity
|
|
934
1129
|
ONLY — never a link into cloud bongos's own builders hall. A project
|
|
935
|
-
creator enters a hall from their own project's landing, not from here.
|
|
936
|
-
task 2098: + a "switch account" action so you're not locked in.) ── */
|
|
1130
|
+
creator enters a hall from their own project's landing, not from here.) ── */
|
|
937
1131
|
function renderWho() {
|
|
938
1132
|
var w = $('who');
|
|
939
1133
|
if (me) {
|
|
940
1134
|
w.innerHTML = (me.avatar_url ? '<img src="' + esc(me.avatar_url) + '" alt="">' : '') +
|
|
941
|
-
'<span>' + esc(me.github_login || 'signed in') + '</span>'
|
|
942
|
-
'<a href="#" class="switch-acct" id="switchAcct">switch account</a>';
|
|
943
|
-
var sw = $('switchAcct');
|
|
944
|
-
if (sw) sw.addEventListener('click', switchAccount);
|
|
1135
|
+
'<span>' + esc(me.github_login || 'signed in') + '</span>';
|
|
945
1136
|
} else {
|
|
946
1137
|
w.innerHTML = '';
|
|
947
1138
|
}
|
|
@@ -957,7 +1148,6 @@ input[type=text].bad{border-color:var(--err);}
|
|
|
957
1148
|
if (!state.ownerTouched && !state.owner && me && me.github_login) {
|
|
958
1149
|
state.owner = me.github_login;
|
|
959
1150
|
$('f-owner').value = state.owner;
|
|
960
|
-
updateGhCreateHref();
|
|
961
1151
|
saveDraft();
|
|
962
1152
|
}
|
|
963
1153
|
// returning after a create? resume watching that instance instead of a blank wizard
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Cloud Bongos — landing gate (interactive)
|
|
2
|
+
|
|
3
|
+
`index.html` is the Cloud Bongos landing experience — a small state machine over one
|
|
4
|
+
self-contained page (`space.css` + `space.js` for the space side; the download scene + its
|
|
5
|
+
drag physics live in the inline `<script>`), built from **drawn ATLA-style sprites**
|
|
6
|
+
(`sprites/*.png` — a `> cloud bongos` terminal, an enter key, a search bar, and download tiles)
|
|
7
|
+
refracting the backdrop through SVG displacement maps.
|
|
8
|
+
|
|
9
|
+
## The flow (tasks 1721, 1722)
|
|
10
|
+
|
|
11
|
+
Four body-class views: `view-entry` → `view-space` → `view-download` / `view-detail`.
|
|
12
|
+
|
|
13
|
+
1. **Entry — type `bongos`, in space** (`#entry`, `view-entry`). Every visit lands here: the
|
|
14
|
+
`> cloud ▊` terminal floating in the **space sky** (deep-blue → sunrise gradient, drifting
|
|
15
|
+
clouds), *not* the temple world. Typing `bongos` is the ritual on every visit; the enter key
|
|
16
|
+
lights, and pressing enter flashes through into the circles. Driven by `space.js`
|
|
17
|
+
(`entryKey` / `enterSite`), reusing the terminal + enter CSS.
|
|
18
|
+
2. **Space — the circles** (`#space` / `#space-canvas`, `view-space`). A pannable, zoomable sky
|
|
19
|
+
of project orbs, sized by number of builders, moving as a **living gravity cluster** — every
|
|
20
|
+
orb attracts every other by its mass (∝ size³), so the field swirls, bodies sling past one
|
|
21
|
+
another, and a small orb is sometimes briefly caught circling a big one like a moon (task
|
|
22
|
+
1733; see "The gravity" below). Project data is **inlined** in `space.js` (`PROJECTS`) — Caddy
|
|
23
|
+
404s `*.json` on staging — so swap in a real registry by changing `PROJECTS` + `layout()`.
|
|
24
|
+
- **Drag** empty sky to pan · **scroll** to zoom (toward the cursor).
|
|
25
|
+
- **Hover** an orb for an info card; **click** it to dive in.
|
|
26
|
+
- **Space bar** opens a search scoped to the orbs **currently in view** (client-side match
|
|
27
|
+
over name/tagline/tags now; the Claude-backed answer is a dormant seam, `aiAnswer()`, per
|
|
28
|
+
the "interaction now, AI wired next" decision).
|
|
29
|
+
- **Click empty sky** drops a new project circle.
|
|
30
|
+
3. **Download — Cloud Bongos' install page** (`#land` in `.stage`, `view-download`). Clicking the
|
|
31
|
+
Cloud Bongos orb zooms **straight** into the search + download-tiles scene over the
|
|
32
|
+
temple-world backdrop — **no type-`bongos` gate in between** (that already happened at entry).
|
|
33
|
+
`space.js` fires `cb:show-download`; the inline script reveals `#land` and runs its drag.
|
|
34
|
+
4. **Detail — other projects** (`#detail`, `view-detail`). Clicking any non-self orb opens a
|
|
35
|
+
themed "full story — coming soon" page with a link out to its live site.
|
|
36
|
+
|
|
37
|
+
**ESC** rises from the download or detail page back to the circles (`space.js` → `cb:hide-download`).
|
|
38
|
+
|
|
39
|
+
## The download scene's elastic-tether drag (task 1534)
|
|
40
|
+
|
|
41
|
+
Every download sprite (search bar, tiles, wordmark) is draggable. Grab one and it resists like
|
|
42
|
+
it's anchored; pull past the threshold and it snaps free, hovers, then drifts slowly home and
|
|
43
|
+
re-docks, carrying a faint idle bob at rest. The physics is scoped to `.stage`, so it never
|
|
44
|
+
grabs the entry terminal (which `space.js` owns). **This scene is separate from the space
|
|
45
|
+
gravity below — the download interaction is unchanged by task 1733.**
|
|
46
|
+
|
|
47
|
+
## The space gravity — a living n-body cluster (task 1733)
|
|
48
|
+
|
|
49
|
+
The project orbs on the **space** view (`view-space`) are a real gravitational simulation, all
|
|
50
|
+
in `space.js`. Each orb is a body with **mass ∝ size³** (more builders → bigger → heavier →
|
|
51
|
+
pulls harder), so the sky behaves like planets, suns and the occasional fleeting moon rather
|
|
52
|
+
than a fixed scatter. Under the hood:
|
|
53
|
+
|
|
54
|
+
- **Softened Newtonian gravity**, every pair, so a close pass *slings* instead of blowing up
|
|
55
|
+
(no singularities).
|
|
56
|
+
- A **fixed-timestep leapfrog integrator** (`physStep`) for accurate, energy-stable motion; the
|
|
57
|
+
frame loop (`tick` → `render`) interpolates between steps for smoothness.
|
|
58
|
+
- **Soft collisions** so discs bounce rather than overlap; a **soft containment well** plus a
|
|
59
|
+
**band thermostat** keep the swirl bounded and lively *forever* — energy is free to ebb and
|
|
60
|
+
flow inside a band, and only a runaway collapse or blow-up gets a gentle nudge back.
|
|
61
|
+
- Net drift is removed each step, so the cluster stays centred on screen (and stays put when a
|
|
62
|
+
visitor adds a new orb, which is flung into the swirl).
|
|
63
|
+
|
|
64
|
+
Verified stable over a 60-minute headless simulation (no NaN, never off-screen, never
|
|
65
|
+
interpenetrating). It replaced the earlier "drift around fixed anchors" motion.
|
|
66
|
+
|
|
67
|
+
### Tuning the gravity
|
|
68
|
+
|
|
69
|
+
All knobs live in the `GRAV` block near the top of `space.js`:
|
|
70
|
+
|
|
71
|
+
| You want… | Edit (in `GRAV`) |
|
|
72
|
+
|--------------------------------------|---------------------------------------------------|
|
|
73
|
+
| Livelier / faster swirl | `SWIRL` ↑ (or `THERMO_LO` ↑) |
|
|
74
|
+
| Calmer, slower motion | `SWIRL` ↓ / `THERMO_LO` ↓ |
|
|
75
|
+
| Tighter cluster (less panning) | `CONTAIN_R` ↓ |
|
|
76
|
+
| Stronger pull between orbs | `G` ↑ |
|
|
77
|
+
| Fewer hard slingshots on near-misses | `SOFTEN` ↑ |
|
|
78
|
+
| Bouncier contacts (→ elastic) | `REST` → 1 |
|
|
79
|
+
| Sharper size→mass contrast | lower `R_REF`, or raise the `massFor` exponent |
|
|
80
|
+
|
|
81
|
+
Turn it off (freeze the orbs): comment out `initOrbits()` in `layout()` and the
|
|
82
|
+
`requestAnimationFrame(tick)` at the bottom of the IIFE — pan, zoom, hover, dive, search and the
|
|
83
|
+
table all keep working.
|
|
84
|
+
|
|
85
|
+
> **Live:** password-locked at **staging.cloudbongos.com** (the future landing page, parked
|
|
86
|
+
> for review). Setup + the password live in [`docs/recipes/cloudbongos-staging-gate.md`](../../../docs/recipes/cloudbongos-staging-gate.md).
|
|
87
|
+
> Branding (logo coin / wordmark / mascot / code-glyphs) is still being finished and is
|
|
88
|
+
> intentionally untouched here.
|
|
89
|
+
|
|
90
|
+
## Preview it locally
|
|
91
|
+
|
|
92
|
+
The page links to art one folder up (`../world/assets/…`), so it must be served from the
|
|
93
|
+
**`brand/cloud-bongos/`** folder — not from `gate/` itself, or those paths break.
|
|
94
|
+
|
|
95
|
+
**Easiest (Claude Code preview):** start the `gate-preview` server in `.claude/launch.json`,
|
|
96
|
+
then open `http://127.0.0.1:8137/gate/index.html`.
|
|
97
|
+
|
|
98
|
+
**From a terminal** (repo root): `python3 -m http.server --directory brand/cloud-bongos 8137`,
|
|
99
|
+
then open <http://127.0.0.1:8137/gate/index.html>.
|
|
100
|
+
|
|
101
|
+
Use a Chromium browser (Chrome/Edge) — the live-glass refraction relies on `backdrop-filter`
|
|
102
|
+
with an SVG displacement map. Safari ignores the displacement and falls back to a plain
|
|
103
|
+
frost, which still looks fine.
|
|
104
|
+
|
|
105
|
+
## Tuning the drag
|
|
106
|
+
|
|
107
|
+
All behaviour is in the single `<script>` at the bottom of `index.html`, which opens with a
|
|
108
|
+
commented **TUNING** block. Common tweaks:
|
|
109
|
+
|
|
110
|
+
| You want… | Edit (in the TUNING block) |
|
|
111
|
+
|------------------------------------------|-----------------------------------|
|
|
112
|
+
| Harder / easier to pull a pane free | `THRESHOLD` — ↑ harder, ↓ easier |
|
|
113
|
+
| How far a tap can move before it's a drag | `DEADZONE` — px |
|
|
114
|
+
| Freed panes wait longer before returning | `HOVER` — milliseconds |
|
|
115
|
+
| Slower, more drifty return | `DRIFT_MAXV` — ↓ slower |
|
|
116
|
+
| Wider, more wandering return path | `WMAG` ↑ and/or `TURN` ↓ |
|
|
117
|
+
| More / less idle "breathing" | `BOB_X`, `BOB_Y` (px) — `0` = off |
|
|
118
|
+
|
|
119
|
+
### Which elements are draggable
|
|
120
|
+
|
|
121
|
+
The drag targets **`.mark`** (the wordmark) + every **`.el`** sprite pane (terminal, enter,
|
|
122
|
+
search, tiles). To add one, give it the `el` class (or push it into the `els` array); to
|
|
123
|
+
exclude one, filter it out of `els`.
|
|
124
|
+
|
|
125
|
+
### Why it does not fight the other animations
|
|
126
|
+
|
|
127
|
+
The drag only ever applies `transform: translate(…)` to each pane, and it owns that property
|
|
128
|
+
exclusively — so the float/reveal animations were replaced by the drag's own idle bob, and
|
|
129
|
+
the enter key's reveal uses opacity + blur only (no transform). The **scene** transforms
|
|
130
|
+
(the dive's scale/translate) live on the parent `.gate`/`.land` containers, so they compose
|
|
131
|
+
with the per-pane drag instead of clobbering it. When a scene settles, `measure()` re-runs
|
|
132
|
+
so a freshly-revealed pane drags from the right home.
|
|
133
|
+
|
|
134
|
+
### Turn the drag off
|
|
135
|
+
|
|
136
|
+
Delete the second `<script>` IIFE (the drag) — the type→dive interaction and all the art
|
|
137
|
+
keep working untouched.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|