@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
|
@@ -111,8 +111,12 @@ export function createClient(opts = {}) {
|
|
|
111
111
|
postAuthAppPairPoll: (args) => request("POST", "/auth/app-pair/poll", { hasBody: true }, args),
|
|
112
112
|
// POST /auth/app-pair/start — rank: public — POST /auth/app-pair/start
|
|
113
113
|
postAuthAppPairStart: (args) => request("POST", "/auth/app-pair/start", { hasBody: true }, args),
|
|
114
|
+
// POST /auth/backchannel-logout — rank: public — POST /auth/backchannel-logout
|
|
115
|
+
postAuthBackchannelLogout: (args) => request("POST", "/auth/backchannel-logout", { hasBody: true }, args),
|
|
114
116
|
// POST /auth/cli-token/issue — rank: any-builder — POST /auth/cli-token/issue
|
|
115
117
|
postAuthCliTokenIssue: (args) => request("POST", "/auth/cli-token/issue", { hasBody: true }, args),
|
|
118
|
+
// POST /auth/device/exchange — rank: public — POST /auth/device/exchange
|
|
119
|
+
postAuthDeviceExchange: (args) => request("POST", "/auth/device/exchange", { hasBody: true }, args),
|
|
116
120
|
// POST /auth/device/poll — rank: public — POST /auth/device/poll
|
|
117
121
|
postAuthDevicePoll: (args) => request("POST", "/auth/device/poll", { hasBody: true }, args),
|
|
118
122
|
// POST /auth/device/start — rank: public — POST /auth/device/start
|
|
@@ -129,6 +133,8 @@ export function createClient(opts = {}) {
|
|
|
129
133
|
postAuthRevoke: (args) => request("POST", "/auth/revoke", { hasBody: true }, args),
|
|
130
134
|
// POST /auth/revoke-all — rank: archon — POST /auth/revoke-all
|
|
131
135
|
postAuthRevokeAll: (args) => request("POST", "/auth/revoke-all", { hasBody: true }, args),
|
|
136
|
+
// GET /auth/web/admission-status — rank: public — GET /auth/web/admission-status
|
|
137
|
+
getAuthWebAdmissionStatus: (args) => request("GET", "/auth/web/admission-status", { hasBody: false }, args),
|
|
132
138
|
// GET /auth/web/callback — rank: public — GET /auth/web/callback
|
|
133
139
|
getAuthWebCallback: (args) => request("GET", "/auth/web/callback", { hasBody: false }, args),
|
|
134
140
|
// GET /auth/web/start — rank: public — GET /auth/web/start
|
|
@@ -177,6 +183,8 @@ export function createClient(opts = {}) {
|
|
|
177
183
|
getBoxManagedSettings: (args) => request("GET", "/box/managed-settings", { hasBody: false }, args),
|
|
178
184
|
// GET /box/me — rank: any-builder — GET /box/me
|
|
179
185
|
getBoxMe: (args) => request("GET", "/box/me", { hasBody: false }, args),
|
|
186
|
+
// GET /box/scope — rank: any-builder — GET /box/scope
|
|
187
|
+
getBoxScope: (args) => request("GET", "/box/scope", { hasBody: false }, args),
|
|
180
188
|
// GET /box/source-access — rank: any-builder — GET /box/source-access
|
|
181
189
|
getBoxSourceAccess: (args) => request("GET", "/box/source-access", { hasBody: false }, args),
|
|
182
190
|
// GET /box/ssh-key — rank: any-builder — GET /box/ssh-key
|
|
@@ -244,12 +252,6 @@ export function createClient(opts = {}) {
|
|
|
244
252
|
// POST /cost — rank: any-builder — POST /cost
|
|
245
253
|
postCost: (args) => request("POST", "/cost", { hasBody: true }, args),
|
|
246
254
|
},
|
|
247
|
-
"demo": {
|
|
248
|
-
// GET /demo/health — rank: public — GET /demo/health
|
|
249
|
-
getDemoHealth: (args) => request("GET", "/demo/health", { hasBody: false }, args),
|
|
250
|
-
// POST /demo/ping — rank: metic+archon — POST /demo/ping
|
|
251
|
-
postDemoPing: (args) => request("POST", "/demo/ping", { hasBody: true }, args),
|
|
252
|
-
},
|
|
253
255
|
"dependencies": {
|
|
254
256
|
// DELETE /dependencies — rank: archon — DELETE /dependencies
|
|
255
257
|
deleteDependencies: (args) => request("DELETE", "/dependencies", { hasBody: false }, args),
|
|
@@ -276,6 +278,12 @@ export function createClient(opts = {}) {
|
|
|
276
278
|
// POST /gate-approvals/{pr}/approve — rank: archon — POST /gate-approvals/:pr/approve
|
|
277
279
|
postGateApprovalsPrApprove: (args) => request("POST", "/gate-approvals/{pr}/approve", { hasBody: true }, args),
|
|
278
280
|
},
|
|
281
|
+
"github": {
|
|
282
|
+
// GET /github/repos — rank: any-builder — GET /github/repos
|
|
283
|
+
getGithubRepos: (args) => request("GET", "/github/repos", { hasBody: false }, args),
|
|
284
|
+
// POST /github/repos — rank: any-builder — POST /github/repos
|
|
285
|
+
postGithubRepos: (args) => request("POST", "/github/repos", { hasBody: true }, args),
|
|
286
|
+
},
|
|
279
287
|
"goals": {
|
|
280
288
|
// GET /goals — rank: any-builder — GET /goals
|
|
281
289
|
getGoals: (args) => request("GET", "/goals", { hasBody: false }, args),
|
|
@@ -343,6 +351,8 @@ export function createClient(opts = {}) {
|
|
|
343
351
|
getInboxId: (args) => request("GET", "/inbox/{id}", { hasBody: false }, args),
|
|
344
352
|
// PATCH /inbox/{id} — rank: metic+archon — PATCH /inbox/:id
|
|
345
353
|
patchInboxId: (args) => request("PATCH", "/inbox/{id}", { hasBody: true }, args),
|
|
354
|
+
// POST /inbox/{id}/ratify — rank: archon — POST /inbox/:id/ratify
|
|
355
|
+
postInboxIdRatify: (args) => request("POST", "/inbox/{id}/ratify", { hasBody: true }, args),
|
|
346
356
|
},
|
|
347
357
|
"instance": {
|
|
348
358
|
// GET /instance — rank: public — GET /instance
|
|
@@ -375,16 +385,6 @@ export function createClient(opts = {}) {
|
|
|
375
385
|
getMeAchievements: (args) => request("GET", "/me/achievements", { hasBody: false }, args),
|
|
376
386
|
// POST /me/anthropic-link — rank: any-builder — POST /me/anthropic-link
|
|
377
387
|
postMeAnthropicLink: (args) => request("POST", "/me/anthropic-link", { hasBody: true }, args),
|
|
378
|
-
// GET /me/art-key — rank: any-builder — GET /me/art-key
|
|
379
|
-
getMeArtKey: (args) => request("GET", "/me/art-key", { hasBody: false }, args),
|
|
380
|
-
// DELETE /me/art-key/own — rank: any-builder — DELETE /me/art-key/own
|
|
381
|
-
deleteMeArtKeyOwn: (args) => request("DELETE", "/me/art-key/own", { hasBody: false }, args),
|
|
382
|
-
// GET /me/art-key/own — rank: any-builder — GET /me/art-key/own
|
|
383
|
-
getMeArtKeyOwn: (args) => request("GET", "/me/art-key/own", { hasBody: false }, args),
|
|
384
|
-
// PUT /me/art-key/own — rank: any-builder — PUT /me/art-key/own
|
|
385
|
-
putMeArtKeyOwn: (args) => request("PUT", "/me/art-key/own", { hasBody: true }, args),
|
|
386
|
-
// POST /me/art-key/storage-init — rank: archon — POST /me/art-key/storage-init
|
|
387
|
-
postMeArtKeyStorageInit: (args) => request("POST", "/me/art-key/storage-init", { hasBody: true }, args),
|
|
388
388
|
// PATCH /me/disciplines — rank: any-builder — PATCH /me/disciplines
|
|
389
389
|
patchMeDisciplines: (args) => request("PATCH", "/me/disciplines", { hasBody: true }, args),
|
|
390
390
|
// GET /me/display-name — rank: any-builder — GET /me/display-name
|
|
@@ -429,6 +429,10 @@ export function createClient(opts = {}) {
|
|
|
429
429
|
getMemoryBfgBuildersBuilderIdFiles: (args) => request("GET", "/memory/bfg/builders/{builderId}/files", { hasBody: false }, args),
|
|
430
430
|
// POST /memory/builders/{builderId}/bfg-write — rank: bfg-principal — POST /memory/builders/:builderId/bfg-write
|
|
431
431
|
postMemoryBuildersBuilderIdBfgWrite: (args) => request("POST", "/memory/builders/{builderId}/bfg-write", { hasBody: true }, args),
|
|
432
|
+
// GET /memory/builders/{builderId}/file — rank: archon — GET /memory/builders/:builderId/file
|
|
433
|
+
getMemoryBuildersBuilderIdFile: (args) => request("GET", "/memory/builders/{builderId}/file", { hasBody: false }, args),
|
|
434
|
+
// GET /memory/builders/{builderId}/files — rank: archon — GET /memory/builders/:builderId/files
|
|
435
|
+
getMemoryBuildersBuilderIdFiles: (args) => request("GET", "/memory/builders/{builderId}/files", { hasBody: false }, args),
|
|
432
436
|
// DELETE /memory/file — rank: any-builder — DELETE /memory/file
|
|
433
437
|
deleteMemoryFile: (args) => request("DELETE", "/memory/file", { hasBody: true }, args),
|
|
434
438
|
// GET /memory/file — rank: any-builder — GET /memory/file
|
|
@@ -448,12 +452,38 @@ export function createClient(opts = {}) {
|
|
|
448
452
|
// GET /modules/submissions — rank: metic+archon — GET /modules/submissions
|
|
449
453
|
getModulesSubmissions: (args) => request("GET", "/modules/submissions", { hasBody: false }, args),
|
|
450
454
|
},
|
|
455
|
+
"myProjects": {
|
|
456
|
+
// GET /my-projects — rank: any-builder — GET /my-projects
|
|
457
|
+
getMyProjects: (args) => request("GET", "/my-projects", { hasBody: false }, args),
|
|
458
|
+
// POST /my-projects/{clientId}/leave — rank: any-builder — POST /my-projects/:clientId/leave
|
|
459
|
+
postMyProjectsClientIdLeave: (args) => request("POST", "/my-projects/{clientId}/leave", { hasBody: true }, args),
|
|
460
|
+
// GET /my-projects/invites — rank: any-builder — GET /my-projects/invites
|
|
461
|
+
getMyProjectsInvites: (args) => request("GET", "/my-projects/invites", { hasBody: false }, args),
|
|
462
|
+
// POST /my-projects/invites/{clientId}/accept — rank: any-builder — POST /my-projects/invites/:clientId/accept
|
|
463
|
+
postMyProjectsInvitesClientIdAccept: (args) => request("POST", "/my-projects/invites/{clientId}/accept", { hasBody: true }, args),
|
|
464
|
+
// POST /my-projects/invites/{clientId}/decline — rank: any-builder — POST /my-projects/invites/:clientId/decline
|
|
465
|
+
postMyProjectsInvitesClientIdDecline: (args) => request("POST", "/my-projects/invites/{clientId}/decline", { hasBody: true }, args),
|
|
466
|
+
// POST /my-projects/join — rank: any-builder — POST /my-projects/join
|
|
467
|
+
postMyProjectsJoin: (args) => request("POST", "/my-projects/join", { hasBody: true }, args),
|
|
468
|
+
},
|
|
451
469
|
"overrideRequests": {
|
|
452
470
|
// GET /override-requests — rank: archon — GET /override-requests
|
|
453
471
|
getOverrideRequests: (args) => request("GET", "/override-requests", { hasBody: false }, args),
|
|
454
472
|
// POST /override-requests/{id}/decide — rank: archon — POST /override-requests/:id/decide
|
|
455
473
|
postOverrideRequestsIdDecide: (args) => request("POST", "/override-requests/{id}/decide", { hasBody: true }, args),
|
|
456
474
|
},
|
|
475
|
+
"projects": {
|
|
476
|
+
// GET /projects — rank: archon — GET /projects
|
|
477
|
+
getProjects: (args) => request("GET", "/projects", { hasBody: false }, args),
|
|
478
|
+
// POST /projects — rank: archon — POST /projects
|
|
479
|
+
postProjects: (args) => request("POST", "/projects", { hasBody: true }, args),
|
|
480
|
+
// PATCH /projects/{id}/featured — rank: archon — PATCH /projects/:id/featured
|
|
481
|
+
patchProjectsIdFeatured: (args) => request("PATCH", "/projects/{id}/featured", { hasBody: true }, args),
|
|
482
|
+
// GET /projects/featured — rank: public — GET /projects/featured
|
|
483
|
+
getProjectsFeatured: (args) => request("GET", "/projects/featured", { hasBody: false }, args),
|
|
484
|
+
// POST /projects/invite — rank: archon — POST /projects/invite
|
|
485
|
+
postProjectsInvite: (args) => request("POST", "/projects/invite", { hasBody: true }, args),
|
|
486
|
+
},
|
|
457
487
|
"provisioning": {
|
|
458
488
|
// GET /provisioning/fleet — rank: archon — GET /provisioning/fleet
|
|
459
489
|
getProvisioningFleet: (args) => request("GET", "/provisioning/fleet", { hasBody: false }, args),
|
|
@@ -520,6 +550,10 @@ export function createClient(opts = {}) {
|
|
|
520
550
|
// GET /public/versions — rank: public — GET /public/versions
|
|
521
551
|
getPublicVersions: (args) => request("GET", "/public/versions", { hasBody: false }, args),
|
|
522
552
|
},
|
|
553
|
+
"scouting": {
|
|
554
|
+
// GET /scouting — rank: archon — GET /scouting
|
|
555
|
+
getScouting: (args) => request("GET", "/scouting", { hasBody: false }, args),
|
|
556
|
+
},
|
|
523
557
|
"search": {
|
|
524
558
|
// POST /search — rank: any-builder — POST /search
|
|
525
559
|
postSearch: (args) => request("POST", "/search", { hasBody: true }, args),
|
|
@@ -527,12 +561,26 @@ export function createClient(opts = {}) {
|
|
|
527
561
|
postSearchMark: (args) => request("POST", "/search/mark", { hasBody: true }, args),
|
|
528
562
|
},
|
|
529
563
|
"security": {
|
|
564
|
+
// GET /security/adr — rank: metic+archon — GET /security/adr
|
|
565
|
+
getSecurityAdr: (args) => request("GET", "/security/adr", { hasBody: false }, args),
|
|
530
566
|
// GET /security/docs — rank: archon — GET /security/docs
|
|
531
567
|
getSecurityDocs: (args) => request("GET", "/security/docs", { hasBody: false }, args),
|
|
532
568
|
// POST /security/docs — rank: archon — POST /security/docs
|
|
533
569
|
postSecurityDocs: (args) => request("POST", "/security/docs", { hasBody: true }, args),
|
|
534
570
|
// GET /security/docs/{slug} — rank: archon — GET /security/docs/:slug
|
|
535
571
|
getSecurityDocsSlug: (args) => request("GET", "/security/docs/{slug}", { hasBody: false }, args),
|
|
572
|
+
// GET /security/reports — rank: archon — GET /security/reports
|
|
573
|
+
getSecurityReports: (args) => request("GET", "/security/reports", { hasBody: false }, args),
|
|
574
|
+
// POST /security/reports — rank: metic+archon — POST /security/reports
|
|
575
|
+
postSecurityReports: (args) => request("POST", "/security/reports", { hasBody: true }, args),
|
|
576
|
+
// POST /security/reports/{id}/confirm — rank: archon — POST /security/reports/:id/confirm
|
|
577
|
+
postSecurityReportsIdConfirm: (args) => request("POST", "/security/reports/{id}/confirm", { hasBody: true }, args),
|
|
578
|
+
// POST /security/reports/{id}/dispute — rank: archon — POST /security/reports/:id/dispute
|
|
579
|
+
postSecurityReportsIdDispute: (args) => request("POST", "/security/reports/{id}/dispute", { hasBody: true }, args),
|
|
580
|
+
// POST /security/reports/{id}/fix — rank: archon — POST /security/reports/:id/fix
|
|
581
|
+
postSecurityReportsIdFix: (args) => request("POST", "/security/reports/{id}/fix", { hasBody: true }, args),
|
|
582
|
+
// POST /security/reports/{id}/link-fix — rank: archon — POST /security/reports/:id/link-fix
|
|
583
|
+
postSecurityReportsIdLinkFix: (args) => request("POST", "/security/reports/{id}/link-fix", { hasBody: true }, args),
|
|
536
584
|
},
|
|
537
585
|
"session": {
|
|
538
586
|
// POST /session/optimize — rank: any-builder — POST /session/optimize
|
|
@@ -548,6 +596,22 @@ export function createClient(opts = {}) {
|
|
|
548
596
|
// GET /sessions/search — rank: archon — GET /sessions/search
|
|
549
597
|
getSessionsSearch: (args) => request("GET", "/sessions/search", { hasBody: false }, args),
|
|
550
598
|
},
|
|
599
|
+
"sso": {
|
|
600
|
+
// POST /sso/activity/rollup — rank: public — POST /sso/activity/rollup
|
|
601
|
+
postSsoActivityRollup: (args) => request("POST", "/sso/activity/rollup", { hasBody: true }, args),
|
|
602
|
+
// GET /sso/authorize — rank: public — GET /sso/authorize
|
|
603
|
+
getSsoAuthorize: (args) => request("GET", "/sso/authorize", { hasBody: false }, args),
|
|
604
|
+
// POST /sso/device/poll — rank: public — POST /sso/device/poll
|
|
605
|
+
postSsoDevicePoll: (args) => request("POST", "/sso/device/poll", { hasBody: true }, args),
|
|
606
|
+
// POST /sso/device/start — rank: public — POST /sso/device/start
|
|
607
|
+
postSsoDeviceStart: (args) => request("POST", "/sso/device/start", { hasBody: true }, args),
|
|
608
|
+
// POST /sso/membership/check-in — rank: public — POST /sso/membership/check-in
|
|
609
|
+
postSsoMembershipCheckIn: (args) => request("POST", "/sso/membership/check-in", { hasBody: true }, args),
|
|
610
|
+
// GET /sso/pubkey — rank: public — GET /sso/pubkey
|
|
611
|
+
getSsoPubkey: (args) => request("GET", "/sso/pubkey", { hasBody: false }, args),
|
|
612
|
+
// POST /sso/token — rank: public — POST /sso/token
|
|
613
|
+
postSsoToken: (args) => request("POST", "/sso/token", { hasBody: true }, args),
|
|
614
|
+
},
|
|
551
615
|
"tasks": {
|
|
552
616
|
// GET /tasks — rank: any-builder — GET /tasks
|
|
553
617
|
getTasks: (args) => request("GET", "/tasks", { hasBody: false }, args),
|
|
@@ -557,7 +621,7 @@ export function createClient(opts = {}) {
|
|
|
557
621
|
getTasksId: (args) => request("GET", "/tasks/{id}", { hasBody: false }, args),
|
|
558
622
|
// PATCH /tasks/{id} — rank: metic+archon — PATCH /tasks/:id
|
|
559
623
|
patchTasksId: (args) => request("PATCH", "/tasks/{id}", { hasBody: true }, args),
|
|
560
|
-
// POST /tasks/{id}/abandon — rank: archon — POST /tasks/:id/abandon
|
|
624
|
+
// POST /tasks/{id}/abandon — rank: metic+archon — POST /tasks/:id/abandon
|
|
561
625
|
postTasksIdAbandon: (args) => request("POST", "/tasks/{id}/abandon", { hasBody: true }, args),
|
|
562
626
|
// POST /tasks/{id}/attest-gate — rank: any-builder — POST /tasks/:id/attest-gate
|
|
563
627
|
postTasksIdAttestGate: (args) => request("POST", "/tasks/{id}/attest-gate", { hasBody: true }, args),
|
|
@@ -611,7 +675,7 @@ export function createClient(opts = {}) {
|
|
|
611
675
|
postVersions: (args) => request("POST", "/versions", { hasBody: true }, args),
|
|
612
676
|
// GET /versions/{id}/done-when — rank: public — GET /versions/:id/done-when
|
|
613
677
|
getVersionsIdDoneWhen: (args) => request("GET", "/versions/{id}/done-when", { hasBody: false }, args),
|
|
614
|
-
// POST /versions/{id}/done-when — rank: archon — POST /versions/:id/done-when
|
|
678
|
+
// POST /versions/{id}/done-when — rank: metic+archon — POST /versions/:id/done-when
|
|
615
679
|
postVersionsIdDoneWhen: (args) => request("POST", "/versions/{id}/done-when", { hasBody: true }, args),
|
|
616
680
|
// GET /versions/{id}/progress — rank: public — GET /versions/:id/progress
|
|
617
681
|
getVersionsIdProgress: (args) => request("GET", "/versions/{id}/progress", { hasBody: false }, args),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_note": "Cloud Bongos vanilla brand pack — customer 0, the identity Cloud Bongos itself runs on
|
|
2
|
+
"_note": "Cloud Bongos vanilla brand pack — customer 0, the identity Cloud Bongos itself runs on. The neutral starter every instance resolves over. Light + joyful — 'playing in the clouds', where building software is laying down a beat (ADR 0064). The LOOK ships via theme.ui, injected by src/bongos/serve-internal.js (R57): a Lion-King sunrise backdrop, warm palette, Baloo 2 (display/wordmark) + Quicksand (interface) + Fira Code (code) type, and a bongo-pair favicon. To brand a NEW instance, copy this to config/branding.json and fill it in (docs/branding-fill-prompt.md). Authored by task 1216 / V4.R74. See docs/branding-contract.md.",
|
|
3
3
|
"identity": {
|
|
4
4
|
"productName": "Cloud Bongos",
|
|
5
5
|
"worldName": "Cloud Bongos",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"publicOrigin": "http://localhost:3000",
|
|
11
11
|
"buildersOrigin": "http://localhost:3000",
|
|
12
12
|
"statusOrigin": "http://localhost:3000",
|
|
13
|
+
"statusDataUrl": "",
|
|
13
14
|
"cookieDomain": "",
|
|
14
15
|
"oauthOrigin": "http://localhost:3000",
|
|
15
16
|
"devBoxBase": "",
|
|
@@ -17,12 +18,16 @@
|
|
|
17
18
|
"sandboxPrefix": "sandbox-",
|
|
18
19
|
"termPrefix": "term-"
|
|
19
20
|
},
|
|
21
|
+
"auth": {
|
|
22
|
+
"_note": "Cross-site identity (ADR 0141). idp=false → this instance owns its auth outright (its own GitHub app; the default + the self-hosted path). A HOSTED instance sets idp=true and gets its hub origin + client credentials from env (<PREFIX>_HUB_ORIGIN / _HUB_CLIENT_ID / _HUB_CLIENT_SECRET, written by provisioning) so web + CLI sign-in federate through the Cloud Bongos hub with no GitHub app of its own. Identity is federated; authority stays local.",
|
|
23
|
+
"idp": false
|
|
24
|
+
},
|
|
20
25
|
"repo": { "owner": "", "name": "" },
|
|
21
26
|
"db": { "database": null },
|
|
22
27
|
"configDir": "cloudbongos",
|
|
23
28
|
"firstAdmin": "",
|
|
24
29
|
"currency": { "label": "credits", "symbol": "" },
|
|
25
|
-
"reward": { "marginPct": 20, "usdPeg": 1 },
|
|
30
|
+
"reward": { "marginPct": 20, "usdPeg": 1, "mode": "cost-plus-and-estimate" },
|
|
26
31
|
"models": { "main": "opus", "subagentDefault": "opus", "subagentRoutine": "haiku" },
|
|
27
32
|
"theme": {
|
|
28
33
|
"palette": "",
|
|
@@ -56,5 +61,9 @@
|
|
|
56
61
|
"ctaLabel": "Try signing in again"
|
|
57
62
|
}
|
|
58
63
|
},
|
|
64
|
+
"landing": {
|
|
65
|
+
"_note": "Where a successful sign-in lands when no explicit ?return= / same-apex Referer was carried (auth.js postLoginLanding). Portable default '/builders' — the hall always exists. A platform-home instance points this at its own front door (cloudbongos.com → '/gate/', the orbs). Validated through the open-redirect allowlist; env override <PREFIX>_POST_LOGIN_LANDING. Task 1002240.",
|
|
66
|
+
"postLogin": "/builders"
|
|
67
|
+
},
|
|
59
68
|
"envPrefix": "CLOUDBONGOS"
|
|
60
69
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_note": "Neutral governance starter — the role TEMPLATES a fresh instance inherits (BV1.R96, ADR 0151). Resolved by modules/governance/config.js with the branding precedence: env override -> config/governance.json (instance) -> this file. TEMPLATES AND DEFAULTS ONLY. Live roles, grants, and per-builder assignments are DB rows (governance_roles / governance_role_permissions / governance_builder_roles), resolved server-side per request by resolver.js — putting a live grant here would make config a second source of authority truth and break ADR 0016. The four seeded rank-roles carry label + description only: their grants derive from catalog.js floors and are materialised by governance_002, so config may relabel a seeded role, never re-grant it. A CUSTOM role template may propose a `permissions` array, but a `system: true` key or a key the catalog does not define is stripped fail-closed — a config file is editable by anyone who can write the checkout, so it is not a trust boundary. Carries NO host identity: a vanilla instance boots sane from this file alone (proved by R102). To customise, copy to config/governance.json and edit there.",
|
|
3
|
+
"roles": {
|
|
4
|
+
"xenos": {
|
|
5
|
+
"label": "Xenos",
|
|
6
|
+
"description": "Seeded rank-role — the sandboxed entry rank. Own-work + public read."
|
|
7
|
+
},
|
|
8
|
+
"thetes": {
|
|
9
|
+
"label": "Thetes",
|
|
10
|
+
"description": "Seeded rank-role — graduated newcomer. Adds the general claim queue."
|
|
11
|
+
},
|
|
12
|
+
"metic": {
|
|
13
|
+
"label": "Metic",
|
|
14
|
+
"description": "Seeded rank-role — the trusted working rank. Adds review/triage/authoring."
|
|
15
|
+
},
|
|
16
|
+
"archon": {
|
|
17
|
+
"label": "Archon",
|
|
18
|
+
"description": "Seeded rank-role — top authority. Adds the admin + system (non-grantable) powers."
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -69,6 +69,30 @@ After shipping, the fix was adversarially red-teamed (a 4-dimension panel + per-
|
|
|
69
69
|
|
|
70
70
|
**Not yet done (finding `#7`, follow-up):** the permission-path pre-pass (layer 2) runs only client-side in `ship.js`; the server `/grade` and `/confirm` routes don't re-run it. Layer 3 is the server-side backstop today; re-running the pre-pass server-side (the server holds the live rank in `req.builder.rank`) would harden the cooperative path.
|
|
71
71
|
|
|
72
|
+
## Branch-protection status: re-verified 2026-07-24 (task [#1001840](https://cloudbongos.com/builders#/task/1001840))
|
|
73
|
+
|
|
74
|
+
The 2026-07-03 authority sweep reported that `main` had since gained live branch protection (required
|
|
75
|
+
checks + code-owner review, direct push blocked), which would have demoted `main-audit.js` from
|
|
76
|
+
*authoritative* to *defense-in-depth*. **That report was wrong.** Re-checked against the live GitHub
|
|
77
|
+
API — every probe agrees there is no protection on `main`:
|
|
78
|
+
|
|
79
|
+
| Probe | Result |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `GET /repos/:o/:r/branches/main` | `protected: false` |
|
|
82
|
+
| `GET /repos/:o/:r/branches/main/protection` | `404` (a *protected* branch returns `403` to a non-admin, not `404`) |
|
|
83
|
+
| `GET /repos/:o/:r/rulesets` | `[]` |
|
|
84
|
+
| `GET /repos/:o/:r/rules/branches/main` (effective rules; readable by non-admins) | `[]` |
|
|
85
|
+
| `.github/CODEOWNERS` | absent |
|
|
86
|
+
| PR #19, merged 2026-07-24 by a **non-admin** collaborator | `statusCheckRollup: []`, no review decision — a merge that required checks + code-owner review would forbid |
|
|
87
|
+
|
|
88
|
+
So §"The gap" ¶1 and the layer table above stand **as written**: the repo is still a personal-account
|
|
89
|
+
private repo with no protection available, and **layer 3 (`main-audit.js`) remains the authoritative
|
|
90
|
+
enforcement**, not a redundant second net. Option B (blocker
|
|
91
|
+
[#17](https://cloudbongos.com/builders#/blocker/17)) is still open and still the durable closure.
|
|
92
|
+
|
|
93
|
+
Treat this as the freshness stamp: re-run the probes above before asserting the claim has changed —
|
|
94
|
+
a plan upgrade or a new ruleset would flip it, and this section is what a future sweep should update.
|
|
95
|
+
|
|
72
96
|
## Notes
|
|
73
97
|
|
|
74
98
|
We did **not** take immediate action against Builder 25 — Lars was overseeing the session and the change itself was a legitimate bug fix. The point of this ADR is the *mechanism*, not the person: the system must make the bypass hard and visible regardless of intent.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0090 — Metic gains task authoring: create / promote / edit + dependency & criteria shaping
|
|
2
2
|
|
|
3
|
-
- **Status:** Accepted
|
|
3
|
+
- **Status:** Accepted — one line amended by [ADR 0152](<redacted>.md) (2026-07-27): `POST /tasks/:id/abandon`, listed below under "What stays Archon-only", moved to Metic+ alongside create/promote/edit, paired with an `abandoned → backlog` restore on `/promote`. The rest of this ADR stands.
|
|
4
4
|
- **Date:** 2026-06-26
|
|
5
5
|
- **Deciders:** Lars (Archon), Claude
|
|
6
6
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 0142 — Project context is prose-only; the structured host contract is branding
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted
|
|
4
|
+
- **Date:** 2026-07-13
|
|
5
|
+
- **Deciders:** Claude (acting builder, autonomous session under goal 1000042); owner to ratify. Presented the fork the audit named — build a structured neutral+instance+resolver for project context (mirroring branding), or keep project context prose-only — and chose prose-only.
|
|
6
|
+
- **Task:** [#1002224](https://example.com/builders#/task/1002224) (BONGOS-V1, goal 1000042 — *Harden the Cloud Bongos update pipeline*). Closes hardening item **H11** / finding **F7** of [`docs/audits/update-pipeline-audit.md`](../audits/update-pipeline-audit.md).
|
|
7
|
+
- **Builds on:** [ADR 0062](<redacted>.md) §7 (the core↔host split — CLAUDE.md is portable methodology; host identity lives beside it), the branding contract ([`docs/branding-contract.md`](../branding-contract.md), [`src/branding.js`](../../src/branding.js)), and the agent-doc stub (task 2121).
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
The audit's finding F7 asked a fair question: **branding** flows as a *structured* contract — `config/branding.neutral.json` (ships) ⊕ `config/branding.json` (publish-excluded) → a validated resolver ([`src/branding.js`](../../src/branding.js)) with env-override precedence and a client-safe projection — while **project context** flows only as *prose*: [`docs/project-context.template.md`](../project-context.template.md) ships (the scaffold `cloudbongos init` fills), `docs/project-context.md` (the instance's filled-in prose) is publish-excluded, plus the `CLAUDE.md`/`AGENTS.md` brand-free stub (task 2121) so a consumer's `node_modules` can't auto-load core project-memory.
|
|
12
|
+
|
|
13
|
+
So the two match at the **publish-boundary** level (a neutral template ships; the instance's filled-in copy is excluded) but NOT at the **structured-resolution** level: there is no runtime resolver, no required-field validation, and no env override for project context — code never reads a merged "project-context object." F7 framed closing that gap as a decision: introduce a parallel structured resolver, or explicitly document prose-only.
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
**Project context stays prose-only. We do NOT build a parallel structured neutral+instance+resolver for it.** The structured, code-read host contract is **branding** (and only branding). Project context is deliberately narrative — written for the *AI agents* who read it (product, vision, world, visual style), not for code to consume as fields.
|
|
18
|
+
|
|
19
|
+
Concretely, the contract is:
|
|
20
|
+
|
|
21
|
+
1. **Machine-readable host identity → branding.** Every instance-identity string code actually renders or injects (names, domains/origins, currency label, cookie/OAuth/dev-box hosts, theme, track set, the project name injected into LLM prompts) lives in the branding contract: `branding.neutral.json` (ships) ⊕ `branding.json` (excluded) → `resolveBranding()` with env precedence and fail-to-vanilla. If a new host string needs to be *code-read*, it goes in **branding**, not a new project-context resolver.
|
|
22
|
+
2. **Prose host context → project-context, unstructured.** Vision / world / visual-style narrative for agents lives in `docs/project-context.md` (instance, excluded) scaffolded from `docs/project-context.template.md` (ships). It is read by humans and agents, never parsed by code.
|
|
23
|
+
3. **The boundary is enforced at the publish layer, which already exists.** `isPublishable()` ships the neutral template and excludes the instance's filled copy ([`scripts/gds/publish-manifest.js`](../../scripts/gds/publish-manifest.js)); the `CLAUDE.md`/`AGENTS.md` stub stops a consumer auto-loading core project-memory. No runtime contract is needed because nothing at runtime consumes project context as data.
|
|
24
|
+
|
|
25
|
+
## Why prose-only over a structured resolver (the trade-off)
|
|
26
|
+
|
|
27
|
+
- **No consumer → YAGNI.** A structured resolver earns its keep only when *code* must read merged, validated fields with env precedence — exactly branding's job, which already exists. Nothing in the platform reads a "project-context object": it is documentation. Building a second resolver, schema, and validation layer for a thing only agents read is speculative infrastructure against the bootstrapped posture ([CLAUDE.md §4](../../CLAUDE.md)).
|
|
28
|
+
- **It matches the core↔host split as already drawn** ([ADR 0062](<redacted>.md) §7): CLAUDE.md is portable methodology; the host authors identity beside it — the *strings code reads* in branding (structured), the *prose agents read* in project-context (narrative). F7 is not a gap in that split; it is the split working as designed.
|
|
29
|
+
- **Redaction stays simple + correct.** Project-context prose flows through the same doc-redaction + publish-exclusion path as every other doc. A structured project-context file would add another schema the no-leak gate and the `init` flow must understand, for no functional gain.
|
|
30
|
+
- **One place to add a host string.** "Where does a new instance-identity value go?" has a single answer — branding — instead of a judgment call between two parallel contracts.
|
|
31
|
+
|
|
32
|
+
## When to revisit
|
|
33
|
+
|
|
34
|
+
Revisit if a concrete need appears for **code to read project-context as structured data** — e.g. the product runtime (not just agents) must branch on a world/vision field, or an automated flow must validate that an instance filled in required narrative before it can ship. At that point the value under question would really be a *branding* field (add it there), or a genuinely new structured need would justify its own resolver. Until such a consumer exists, prose-only is correct.
|
|
35
|
+
|
|
36
|
+
## Consequences
|
|
37
|
+
|
|
38
|
+
- **No new code.** No project-context resolver, schema, or env-override layer is added; `src/branding.js` carries a short pointer comment so the next person who wonders "why isn't there a project-context resolver?" finds this ADR at the natural place they'd add one.
|
|
39
|
+
- **Init unchanged.** `cloudbongos init` keeps scaffolding `docs/project-context.md` from the template as prose; there is nothing to validate at standup beyond the existing branding validation.
|
|
40
|
+
- **Publish boundary unchanged.** The template ships, the filled instance prose is excluded, the agent-doc stub stands — already true, now documented as the deliberate contract rather than an accidental asymmetry.
|
|
41
|
+
- **Audit H11 closed** without expanding the surface the update pipeline must keep neutral (which the sibling PROVE-NO-LEAK work — H4/H5/H6 — is separately hardening).
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 0143 — Onboarding repo picker & auto-create: broaden the OAuth scope (not a GitHub App), store a short-lived token
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted — built in task 1002099.
|
|
4
|
+
- **Date:** 2026-07-13
|
|
5
|
+
- **Deciders:** Lars (owner/Archon) chose the credential approach; Claude designed + built.
|
|
6
|
+
- **Task:** [#1002099](https://cloudbongos.com/builders#/task/1002099) · **Goal:** 35 (greenfield onboarding).
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
The onboarding wizard at `/create` ([public-landing/create.html](../../public-landing/create.html)) had the visitor **type `owner/repo` by hand** (adopt) and, for a fresh project, do a **manual** "New repository on github.com → leave it empty" step. Owner feedback: make it real — let the signed-in user **pick from their own repos** (adopt) and **auto-create the empty repo** (fresh).
|
|
11
|
+
|
|
12
|
+
Blocker: the wizard's GitHub sign-in requests only `read:user` ([auth.js `SCOPE`](../../src/bongos/auth.js)), which cannot list or create repos, and `completeWebFlow` discarded the OAuth token after reading the username. Two ways forward were weighed:
|
|
13
|
+
|
|
14
|
+
- **(A) Broaden the OAuth scope** and act as the user via their own token.
|
|
15
|
+
- **(B) A central "Cloud Bongos" GitHub App** the user installs (fine-grained `Administration:write` to create, `Metadata:read` to list).
|
|
16
|
+
|
|
17
|
+
The existing per-instance GitHub **App-manifest** flow ([ADR 0133](<redacted>.md)) is *not* reusable here — it builds a sign-in-only App with `default_permissions:{}`, one per provisioned instance, not a central repo-acting App.
|
|
18
|
+
|
|
19
|
+
## Decision
|
|
20
|
+
|
|
21
|
+
**Take (A) — broaden the scope — per the owner's explicit call**, accepting that it is less least-privilege than a GitHub App, in exchange for no install step and a single sign-in. Within (A):
|
|
22
|
+
|
|
23
|
+
1. **Scope = `public_repo`, not `repo`.** There is no OAuth scope for "create a repo only"; `repo` grants read/write to *all* the user's code (public **and** private) — a serious liability for a token we now persist on an internet-facing tier. `public_repo` lists/creates **public** repos with a much gentler consent screen and a far smaller blast radius. Cloud Bongos instances are open-source / capture-resistant by design, so public is the norm. **Accepted limitation:** private repos can't be listed/adopted or created; revisit to `repo` only if private support is needed.
|
|
24
|
+
2. **Opt-in per sign-in.** The scope is requested **only** by the wizard, via `?repos=1` on `/auth/web/start` (a `gds_oauth_repos` intent cookie carried to the callback). The builders'-hall web sign-in and the CLI Device Flow stay `read:user`. A single pure `scopeForWebFlow({repos})` is the one place the scope string is decided (unit-tested).
|
|
25
|
+
3. **Lazy consent.** The step-0 gate sign-in stays identity-only; repo access is requested at **step 2**, when the user reaches the picker/creator — more private, and the "grant access" path is the well-exercised normal path.
|
|
26
|
+
4. **Token persistence, contained.** The captured `public_repo` token is stored **encrypted** (secret-box, master key in server env only) in `github_oauth_tokens` (migration `core_192`), keyed to the builder, with a **short TTL (1h = one wizard sitting)** and a lazy expiry sweep on read. This lives in **core auth**, not the provisioning module: it is the auth system's *own* handshake token, not a feature's third-party API key (contrast the art module's Gemini key, [ADR 0102](<redacted>.md)), and the provisioning module's charter forbids holding tokens / calling cloud APIs ([ADR 0111](<redacted>.md) §2 / [ADR 0016](<redacted>.md)). Endpoints `GET/POST /github/repos` ([src/bongos/routes/github.js](../../src/bongos/routes/github.js)) read it back, `requireBuilder` + router-wide rate-limited.
|
|
27
|
+
5. **v1 = the user's own personal repos** (`affiliation=owner`), so `full_name` is unambiguously `login/repo` and org OAuth-policy complexity (an org can restrict/approve OAuth apps; repos silently omitted) is out of scope. Org/collaborator repos are a later enhancement.
|
|
28
|
+
6. **Progressive enhancement / graceful degrade.** If secret-box is **unconfigured** (`BUILDER_SECRET_KEY` unset), no token is ever stored: `GET /github/repos` returns `503 github_repos_unavailable` and the wizard **keeps the manual owner/repo inputs + the manual create-repo done-step** as the fallback. Onboarding never regresses.
|
|
29
|
+
|
|
30
|
+
## Consequences
|
|
31
|
+
|
|
32
|
+
- **New surface:** `scopeForWebFlow` + `captureRepoToken` in auth.js; `?repos=1` handling in the web routes; `github_oauth_tokens` (core_192) + `upsert/get/deleteGithubToken` in db.js; `src/bongos/github-repos.js` (raw-fetch `listUserRepos`/`createUserRepo`); `src/bongos/routes/github.js`; the wizard's picker/auto-create UI.
|
|
33
|
+
- **Security posture:** a stored `public_repo` token is a smaller honeypot than `repo`, and it is encrypted at rest, short-lived, and swept — but it *is* new liability the web tier didn't carry before. The 503-fallback means an instance that doesn't configure secret-box simply doesn't get the feature (no plaintext token is ever written).
|
|
34
|
+
- **Consent friction:** a returning user who signed in months ago has only `read:user`; the picker's `repo_scope_required` (403) prompts a one-click reconnect. The sessionStorage draft round-trips through the OAuth hop (same-tab), so no wizard state is lost.
|
|
35
|
+
- **Reversal path:** switching to `repo` (private support) is a one-line scope change; switching to a GitHub App later would supersede this ADR (append a new one, don't edit).
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# 0144 — Re-home the dev-box fleet onto the cloudbongos.com plane (native runners, local DB, isolated fleet tag)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted — Phases 1–3 built in task 1002239. **Phase 4 part (a) (stop legacy `cohost-box-*` runners) done in task 1002248** (2026-07-15); part (b) (disable dev-box on example.com) flagged to owner — not reachable from the cloudbongos control plane.
|
|
4
|
+
- **Date:** 2026-07-15
|
|
5
|
+
- **Deciders:** Lars (owner/Archon) chose "re-home properly, not a legacy band-aid" + pre-approved box spend; Claude designed + executed autonomously.
|
|
6
|
+
- **Task:** [#1002239](https://cloudbongos.com/builders#/task/1002239) · supersedes stale incident [#1002031](https://cloudbongos.com/builders#/task/1002031) · **Goal:** 1000025 (builder experience — hall, dev box, skills).
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
"Get the dev box up and running again for cloud bongos" surfaced a split that was invisible from the platform:
|
|
11
|
+
|
|
12
|
+
- **The dev-box feature was disabled on cloudbongos.com** — `config/modules.json` listed only `provisioning` + `platform-identity`, so `/api/gds/box/*` 404'd. The instance note said dev-box stays off "until box infra is confirmed present."
|
|
13
|
+
- **The live dev-box data plane was the *legacy* `example` Postgres** (on the co-hosting box), drained by the cloudbongos control plane's `cohost-box-*` systemd runners over an SSH DB tunnel ([ADR 0132](<redacted>.md)). Builder identities even diverged: `example-owner` is builder **1** in the example DB, **3** on cloudbongos.com.
|
|
14
|
+
- **The fleet was dormant** — all 9 boxes `destroyed`, control-plane timers green but idle (`ran=0`). So nothing was *broken*; the box capability simply lived on the old plane and was never brought onto the platform after the [ADR 0139] work-history migration.
|
|
15
|
+
|
|
16
|
+
The owner chose to **re-home the box feature onto the cloudbongos.com plane** (its own DB, its own domains) rather than revive a box on the legacy `example` infra. Feasibility was high: the box tables already exist in the cloudbongos DB, `cloudbongos.com` is a live Cloudflare zone on the same account the control plane already uses, the DO/CF tokens are already on the control plane, and box domains are branding-driven (`domains.devBoxBase`/`sshBoxBase`) — not hardcoded.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
Stand up a **cloudbongos-native box plane** alongside (not replacing) the legacy one, in four moves:
|
|
21
|
+
|
|
22
|
+
1. **Enable the feature (persisted).** `config/modules.json` → `dev-box: true`; `config/branding.json` → `domains.devBoxBase=cloudbongos.com`, `sshBoxBase=dev.cloudbongos.com`. **Persistence is by pushing to the instance `origin/main`, not a local commit** — `deploy.sh` (the ~3-min pull-deploy, ADR 0129) does `git reset --hard origin/main`, which silently reverts any local-only change. (Learned the hard way: a local commit was reset away within one deploy cycle.)
|
|
23
|
+
|
|
24
|
+
2. **Native lifecycle runners against the LOCAL DB.** Four systemd service+timer pairs (`cloudbongos-box-{intent-runner,idle-suspend,drift-reconcile,dormant-reclaim}`) modeled on the `cohost-box-*` units but pointed at the **local `cloudbongos` Postgres** (peer auth, `PGDATABASE=cloudbongos`, **no tunnel, no `DATABASE_URL`**). Box domain/zone come from env, not branding, for the CLI: `CLOUDFLARE_ZONE`, `BOX_TERMINAL_ZONE`, `BOX_DNS_ZONE`, `GDS_PUBLIC_ORIGIN` (all cloudbongos.com). Overrides live in `/etc/cloudbongos/cloudbongos-box.env`, layered over `/etc/cloudbongos/box.env` (which holds the tokens).
|
|
25
|
+
|
|
26
|
+
3. **Fleet isolation by a DISTINCT tag — the load-bearing safety decision.** Both planes share one DigitalOcean + one Cloudflare account. `boxes.js planDropletDrift` treats any fleet-tagged droplet **not in its own DB as a "zombie" and force-deletes it** (30-min grace). With a shared `otb-builder-box` tag, the legacy plane's hourly drift-reconcile would reap a cloudbongos box within ~30–90 min. So the native plane uses **`BOX_TAG=cloudbongos-builder-box`**. This is watertight because `cmdReconcileDrift` lists droplets `{tag: CONFIG.tag}`, and the sweeps act only on their own DB's rows — so each plane manages exactly its own fleet.
|
|
27
|
+
|
|
28
|
+
4. **Legacy plane untouched.** The `example` (cohost) plane keeps running, fully isolated by tag/DB. Retiring it (disable dev-box on example.com, stop the cohost tunnel/runners) is **Phase 4** — deferred to an explicit owner go-ahead because it is the one hard-to-reverse step and is unnecessary for the cloudbongos plane to work.
|
|
29
|
+
|
|
30
|
+
## Consequences
|
|
31
|
+
|
|
32
|
+
- cloudbongos.com now serves `/box/*` and provisions boxes on its own plane, at `term-<login>.cloudbongos.com` / `sandbox-<login>.cloudbongos.com`, tracked in the cloudbongos DB, isolated from the legacy fleet.
|
|
33
|
+
- **Verified end-to-end (2026-07-15):** web `POST /box/ensure` → intent in the cloudbongos DB → native `cloudbongos-box-intent-runner` drained it (`ran=1 ok=1`) → droplet `584756519 @ REDACTED_IP`, tunnel + DNS on cloudbongos.com, box `active`. Drift-reconcile confirmed `fleet tag=cloudbongos-builder-box: 0 droplets` before provisioning — proving isolation.
|
|
34
|
+
- Two planes now exist until Phase 4. That is intentional and safe (tag + DB isolation), but means dev-box is "on" in two places.
|
|
35
|
+
|
|
36
|
+
## Follow-ups (open)
|
|
37
|
+
|
|
38
|
+
1. **Box first-boot convergence — ROOT-CAUSED + fixed (workaround live; proper fix open, task 1002243).** Symptom: provisioned boxes reached `active` but `cloudflared`/terminal never came up (`term-…` = CF 530) and SSH keys weren't applied. Root cause: **`box.js` provisioned droplets with EMPTY user-data** (`/var/lib/cloud/instance/user-data.txt` = 0 bytes; cloud-init logged "No user-data found"). `box.js` renders the box cloud-init from `<REPO_ROOT>/infra/` (the 26 KB `builder-box-cloud-init.yaml` + ~12 gz+b64-inlined scripts), and `fileGzB64` **silently returns `''` on a missing file**, so a missing `infra/` yields empty user-data with no error. The R89 split moved `scripts/gds/` into the `@bongos/core` package but **kept `infra/` in the instance repo** — yet `box.js` still resolves `infra/` relative to *its own* location (the vendored core), where `infra/` **isn't shipped at all** (0 files). So every box on any vendored/installed instance booted with only DigitalOcean's default user-data. **Workaround applied (temporary):** populated the vendored core's `infra/` from the instance's `infra/` (`/home/lars/cloudbongos/node_modules/@bongos/core/infra/`); re-provision then rendered a 62 KB user-data and the box converged — `cloudflared` active, `term-example-owner.cloudbongos.com` → 200 (authed), builder SSH key baked + working. **Proper fix (task 1002243):** ship `infra/` in the core publish-manifest, OR make `box.js` resolve `infra/` from the instance root (like `core-node.sh`'s candidate-base search), AND make `fileGzB64`/the template render **fail loudly** instead of emitting empty user-data. The workaround is under `node_modules` and will be lost on the next `npm ci`/core reinstall until the proper fix lands.
|
|
39
|
+
2. **Cloudflare token scope.** Provision warned the ADR 0053 cookie-strip Transform Rule was **not** applied — `CLOUDFLARE_API_TOKEN` lacks "Transform Rules" edit scope on the cloudbongos.com zone. Add the scope (or apply the rule once in the dashboard) **before** other builders get boxes on `*.cloudbongos.com`, so platform cookies (`cookieDomain=<redacted> aren't sent to box subdomains.
|
|
40
|
+
3. **Cosmetic `otb-` prefix.** Tunnel names (`otb-term-<login>`) and the droplet name (`otb-box-<login>`) are still hardcoded in `box-onboard.js`/`box.js`. Harmless (fleet separation is by tag, and DNS is per-zone), but a branding leak worth parameterizing.
|
|
41
|
+
4. **Phase 4 — retire the legacy example plane** (owner decision) — **part (a) DONE in task 1002248 (2026-07-15).** Pre-checked read-only that the legacy fleet was empty (0 `otb-builder-box` droplets on DigitalOcean; cohost intent queue `ran=0`), then `systemctl disable --now` on the four `cohost-box-*` timers (intent-runner / idle-suspend / drift-reconcile / dormant-reclaim) on the control-plane host — now `disabled`/`inactive`; the native `cloudbongos-box-*` timers were left `enabled`/`active`. **Part (b) — disabling the dev-box module on example.com itself — NOT reachable from the control plane, flagged to owner:** example's web app + instance checkout are not co-located on the cloudbongos droplet (no local checkout, no ssh alias) and the local example GDS token is expired, so a durable module-disable needs owner access to example's own config/host. Harmless meanwhile: with the runners stopped there is no cost/security impact — worst case is a box request on the legacy instance that now hangs unfulfilled.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# 0144 — Federated single-logout: hub-initiated back-channel session revocation
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted — built in task 1002238.
|
|
4
|
+
- **Date:** 2026-07-15
|
|
5
|
+
- **Deciders:** Lars (owner/Archon) chose the back-channel approach; Claude designed + built.
|
|
6
|
+
- **Task:** [#1002238](https://cloudbongos.com/builders#/task/1002238) · **Goal:** 41 (cross-site identity). Follow-up to [ADR 0141](<redacted>.md).
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
Cross-site identity ([ADR 0141](<redacted>.md)) gave single sign-**on**: one hub login (cloudbongos.com) reaches every federated project's hall with no second GitHub sign-in. But sign-**off** stayed local. When a federated instance completes the SSO handshake it mints its **own** local session (`completeIdpFlow` → `createSession`) with its own cookie on its own domain. `POST /auth/logout` revokes only *that* instance's session + clears *that* apex cookie — so signing out of the hub left every federated project (e.g. demo) still signed in. Owner request (2026-07-14): make sign-out universal.
|
|
11
|
+
|
|
12
|
+
Three approaches were weighed (the task's options):
|
|
13
|
+
|
|
14
|
+
- **(a) Back-channel SLO** — on hub logout the hub server calls each entered instance's revoke endpoint (server-to-server).
|
|
15
|
+
- **(b) Front-channel SLO** — the browser is bounced through each instance's logout URL (classic OIDC front-channel).
|
|
16
|
+
- **(c) Soft sessions** — federated instances stop holding durable sessions and re-check the hub continuously.
|
|
17
|
+
|
|
18
|
+
## Decision
|
|
19
|
+
|
|
20
|
+
**Take (a) — back-channel single-logout — per the owner's explicit call.** It is the robust, browser-independent choice for a session-lifecycle security feature, and it reuses the federation machinery ADR 0141 already built.
|
|
21
|
+
|
|
22
|
+
1. **A hub-signed, purpose-tagged EdDSA logout token.** The hub mints (`platform-identity/hub-keys.js` `mintHubLogoutToken`) a compact Ed25519 JWT — the **same envelope + asymmetric key + ~120s TTL + audience-binding** as the login assertion (`mintHubAssertion`), so a token minted for instance A can't be replayed against instance B, and a compromised instance (holding only the public key) can't forge one. The payload carries **only** `{ iss, aud:<client_id>, sub:<github_id>, purpose:"backchannel-logout", iat, exp, jti }` — never identity, a rank, or a session token. The **`purpose` marker is load-bearing**: a login assertion has no `purpose` (rejected by the logout verifier) and a logout token has no `github_login` (rejected by the login verifier `verifyHubAssertion`), so the two token types are **mutually non-interchangeable** — a captured login assertion can't trigger a logout, and a logout token can't mint a session. The instance verifier (`auth.js verifyHubLogoutToken`) is the boundary-mirrored sibling of `verifyHubAssertion` (ADR 0091 §2), alg **hardcoded to Ed25519** (no algorithm-confusion), signature verified **before** any claim is trusted.
|
|
23
|
+
|
|
24
|
+
2. **Kernel-mediated seam event, so core stays module-agnostic.** `POST /auth/logout` (core) revokes the local session as before, then **emits** a `builder.logout` seam event (fire-and-forget). On a non-hub instance nothing listens → no-op. On the hub, the `platform-identity` module (enabled only there) reacts. Core never references the module (ADR 0083 one-way rule); the switchboard (`src/module-seams.js`) is the seam.
|
|
25
|
+
|
|
26
|
+
3. **The hub fans out; the instance revokes.** The module's listener looks up the builder's entered projects and POSTs a per-project logout token to each `{origin}/api/gds/auth/backchannel-logout`. That endpoint (core `auth.js`/`routes/auth.js`, **dormant unless the instance federates** — `idpConfigured()`, else a plain 404) verifies the token against the hub public key it already trusts (`/sso/pubkey`), resolves the builder by `github_id`, and calls `revokeAllSessionsForBuilder` — killing **all** of that builder's local sessions (web + CLI).
|
|
27
|
+
|
|
28
|
+
4. **Entered-instance list = memberships (ADR 0141 §3).** The hub uses `listMembershipsForAccount(github_id)` — the projects the builder is known to build on — as the fan-out target list, per the task's sanctioned V1 signal. **Over-notifying is safe:** an instance with no live session for that builder just revokes nothing (revoke is idempotent). A precise per-SSO-session entry ledger (notify *only* instances with a live federated session) is a deliberate follow-up, not V1.
|
|
29
|
+
|
|
30
|
+
5. **Best-effort, bounded, isolated fan-out.** The user's hub session is revoked **synchronously** (the part they experience); the cross-instance sweep runs server-side off the fire-and-forget event, each POST bounded by a 4s timeout, all under `Promise.allSettled` — a slow or down project can never wedge the sweep or the logout, and the fan-out never throws. **Accepted limitation:** if an instance is unreachable at logout time, its local session survives until its own TTL; a retry/queue is out of scope for V1 (logged, not retried).
|
|
31
|
+
|
|
32
|
+
6. **Anti-replay on the instance side.** A logout token's `jti` is honored **once** (`logoutTokenJtiSeenAndRecord`, symmetric with the CLI-assertion path): the first use revokes, a replay within the ~120s TTL is an idempotent no-op. Without this, a captured token would stay a repeatable "log this builder out" primitive for its whole life — it could keep killing sessions the builder legitimately creates *after* the token was minted (revoking already-dead sessions is otherwise harmless).
|
|
33
|
+
|
|
34
|
+
## Consequences
|
|
35
|
+
|
|
36
|
+
- **Trust boundary preserved (ADR 0016 / 0141).** The logout token, like every other hub→instance message, carries **identity only** (a subject to sign out) — never authority. The instance decides locally what "sign this github_id out" means (revoke its own sessions). Authority stays local.
|
|
37
|
+
- **Deploys to both sides.** The instance half (`/auth/backchannel-logout`, `verifyHubLogoutToken`, the `builder.logout` emit) ships in **core** (dormant on non-federated instances); the hub fan-out ships in the **platform-identity** module. So this go-live re-vendors **both** the hub (cloudbongos.com) and every federated instance (demo). Core `1.18.5 → 1.18.7` (the `1.18.6` cut on `main` is the unrelated task 1002241 `?return=` fix, carried along).
|
|
38
|
+
- **No new schema.** Reuses the existing `<redacted>` + `sso_clients` (origin) rows and the existing Ed25519 hub keypair. No migration.
|
|
39
|
+
- **Not front-channel (b):** modern third-party-cookie / iframe restrictions (Safari ITP, Chrome's trajectory) make browser-driven cross-site logout unreliable, and it doesn't complete if the tab closes mid-chain. Rejected for a security guarantee.
|
|
40
|
+
- **Not soft sessions (c):** re-checking the hub per-request adds latency to every request and makes a federated instance's sign-in fail whenever the hub is down (a hard runtime dependency) — too heavy for a bootstrapped setup.
|
|
41
|
+
- **V1 scope:** hub-initiated logout only. A federated instance's own logout does **not** yet propagate back to the hub + siblings (it has no client registry); that's a follow-up if wanted.
|
|
42
|
+
- **Known limitation — a membership-spoof presence oracle (security review, medium).** The fan-out targets a builder's `<redacted>`, and `POST /sso/membership/check-in` (ADR 0141 §3) trusts a caller-named `github_id` under any active `client_secret`. So a client-secret holder can assert a membership for an arbitrary `github_id` and thereafter receive a hub-signed logout callback naming that builder on each of their hub logouts — a cross-account presence/existence oracle. It is **contained** (the token is `aud`-bound to the attacker's own `client_id`, so it can't be replayed against the victim's real instances — no session compromise) and **gated** (an `sso_client` is registered only by the operator-run `provision.js`, never a public route, so today every secret-holder is an operator-provisioned, trusted instance — the only client is `demo`). The root cause predates this ADR; this feature newly turns it into an active signed callback. **The proper fix — bind the fan-out to evidence of a real federated session for that `github_id` (a per-SSO-session ledger), or prove user consent at check-in — is the deferred follow-up (task [#1002244](https://cloudbongos.com/builders#/task/1002244)); it must land before federation opens to untrusted third-party clients.**
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# 0145 — The Dev Box app becomes a branding-driven module (one source, per-instance builds)
|
|
2
|
+
|
|
3
|
+
- **Status:** Accepted — Phase 1 built in task [#1002255](https://cloudbongos.com/builders#/task/1002255). Downloads (1002257), CI + releases repo + signing (1002258), and end-to-end verify (1002256) follow.
|
|
4
|
+
- **Date:** 2026-07-15
|
|
5
|
+
- **Deciders:** Lars (owner) — "re-set up the dev box app so it's properly installable for cloudbongos; the design should not be linked to a specific project but to the Cloud Bongos design; it should live on cloudbongos and be maintained there as a module, and Example should borrow it."
|
|
6
|
+
- **Extends:** ADR 0045 (the Dev Box desktop app), ADR 0072 (app signing posture), ADR 0083 (module system), ADR 0004/0062 (brand discipline — no hardcoded host identity), [branding contract](../branding-contract.md).
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
The Dev Box desktop app (ADR 0045 — an Electron menu-bar/tray switch that pairs sign-in, flips the box on/off, and wires the local SSH + Claude-Desktop last mile) was **built for Example and lived outside the Cloud Bongos core**:
|
|
11
|
+
|
|
12
|
+
- Its source was only in the OTB monolith (`~/dev/Claude-OTB/devbox-app/`), never in the neutral core.
|
|
13
|
+
- It was **hardcoded to Example/OTB**: `src/brand.js` (`CIV_NAME: 'Example'`, `PRODUCT_NAME: 'OTB Dev Box'`, `example.com` origins), `appId com.offtheboats.devbox`, artifact names `OTB-Dev-Box-*`, the renderer's parchment/ancient-Greek theme (Cinzel/EB Garamond, tan `#ece0c2`) and an archaic "thy/thee" voice ("a gift of Hermes").
|
|
14
|
+
- cloudbongos already ships the *download-redirect server* (`src/devbox-downloads.js`) but with no `config/devbox-app.json` and no Cloud-Bongos app to point it at — so a cloudbongos builder had **no installable app**, only the browser terminal + manual SSH.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
Vendor the app into the dev-box module and make **every brand input a build-time value read from the instance branding**, so one source tree builds any instance's app.
|
|
19
|
+
|
|
20
|
+
1. **House it in the module:** `modules/dev-box/app/` (40 files, ~600K; `node_modules`/`dist` excluded). The desktop app is not a formal module `contributes` type (the manifest schema has no "app" — routes/pollers/uiSections/webSurfaces only), so it lives as **source inside the module**; `module.json` is unchanged. The generic `src/devbox-downloads.js` stays in core and reads the instance's `config/devbox-app.json` (Phase 2).
|
|
21
|
+
|
|
22
|
+
2. **Build-time brand generator** — `scripts/gen-brand.js` reads `config/branding.json` (→ `branding.neutral.json` fallback, the Cloud Bongos pack) and emits three generated, committed artifacts:
|
|
23
|
+
- `src/brand.generated.json` — `PRODUCT_NAME`, `APP_ID` (`com.<worldslug>.devbox`), `PRODUCT_SLUG` (artifact filenames), origins, `DESKTOP_ENV_NAME`, `COPYRIGHT`, `CONFIG_DIR`, `BG_COLOR`, `TAGLINE`. `src/brand.js` is now just `module.exports = require('./brand.generated.json')`.
|
|
24
|
+
- `renderer/theme.generated.css` — the `:root` design tokens (palette + fonts) from `theme.ui`; `styles.css` keeps only layout and consumes the vars, so the panel re-skins entirely from branding.
|
|
25
|
+
- `electron-builder.yml` — rendered from `electron-builder.tmpl.yml` (appId/productName/copyright/artifact slug substituted; electron-builder's own `${version}/${arch}` left literal).
|
|
26
|
+
It runs in `prep` (→ `prestart`/`pretest`/`predist:*`), so every build regenerates for the building instance. Same source → **"Cloud Bongos Dev Box" here, "Example Dev Box" there** — the ADR 0004 posture generalised to every instance, enforced by the `no hardcoded host identity` fitness gate (which this now passes).
|
|
27
|
+
|
|
28
|
+
3. **Example borrows it as a module** — it enables `dev-box` and its build runs `gen-brand` against its own `config/branding.json`, producing the OTB-branded app from the shared source. No forked copy.
|
|
29
|
+
|
|
30
|
+
4. **Functional cross-component constants stay** (not "design", so not rebranded): the ttyd terminal user `otb` and the SSH key filename `~/.ssh/otb_builder` are contracts with the box image (`box-terminal.service`, the authorized-keys fetch, `/builder-connect`); the `window.otb` renderer↔preload bridge is an internal namespace. The session file dir, however, **is** branding-driven now (`~/.config/<configDir>/gds-session.json`) so pairing the app still signs in the instance's own `/builder-*` CLI.
|
|
31
|
+
|
|
32
|
+
## Consequences
|
|
33
|
+
|
|
34
|
+
- The neutral core now carries a **Cloud-Bongos-branded** Dev Box app by default (warm palette, Baloo 2/Quicksand, plain modern voice, `com.cloudbongos.devbox`). Committed generated defaults come from `branding.neutral.json` (Cloud Bongos brand pack; `localhost` origins are the neutral dev default — a real instance build bakes its own origins + the runtime session/API base overrides them anyway).
|
|
35
|
+
- Verified Phase 1: `gen-brand` renders cleanly; the app's 56 unit tests pass (the one OTB-hardcoded assertion is now brand-agnostic); `node --check` clean; the client-vendor path fixed for the two-levels-deeper location; **all architecture fitness checks pass** (module→doorway-only, no hardcoded host identity, repo-map fresh).
|
|
36
|
+
- The **API/builders origins the distributed app pairs against must be baked from the instance branding at build time** — so the real cloudbongos installer must be built with the cloudbongos instance `config/branding.json` (`cloudbongos.com`), not the neutral core's `localhost`. This shapes Phase 3 (where the branded build runs).
|
|
37
|
+
|
|
38
|
+
## Follow-ups (open)
|
|
39
|
+
|
|
40
|
+
1. **Downloads (task 1002257) — DONE 2026-07-17.** `config/devbox-app.json` pushed to the instance repo → `cloudbongos.com/downloads/devbox/*` 302 to the v1.0.10 release assets (all targets verified through Caddy). ⚠ **Vendored-config quirk:** `serve-internal.js` reads the config via a naive `require('../../config/devbox-app.json')` that in a *vendored* instance resolves to `node_modules/@bongos/core/config/`, **not** the instance root where the file lives (unlike branding/modules). Workaround: copied the config there on the host + restarted `cloudbongos.service` — **lost on next core upgrade / `npm ci`**. Proper instance-root-resolve fix = **task 1002371** (same class as ADR 0144's `infra/`).
|
|
41
|
+
2. **Distribution (task 1002258) — DONE 2026-07-17.** CI `.github/workflows/build-devbox-app.yml` builds **signed + notarized** mac (arm64+x64) + win (x64+arm64); public releases repo `example-owner/cloudbongos-devbox-releases` hosts them; **v1.0.10 published**. Release origins baked via CI repo variables `DEVBOX_PUBLIC_ORIGIN`/`_BUILDERS_ORIGIN` (= cloudbongos.com). Gotcha found live: notarization 403'd until the owner accepted a lapsed **Apple Developer Program License Agreement** — then the signed+notarized build went green. Publishing = download CI artifacts → `gh release create/upload` (manual, no cross-repo CI token; ADR 0045).
|
|
42
|
+
3. **App icon still OTB art.** `scripts/gen-icons.js` draws the app/tray/DMG icons from **pixel grids in the script** (currently the OTB design); the committed PNGs are OTB. Regenerating them from the Cloud Bongos bongo motif (edit the grids + re-run `npm run icons`) is a distinct art follow-up — the app's *name/colors/voice* are Cloud Bongos, but the *icon* is not yet.
|
|
43
|
+
4. **Dev/CI env-var names** (`OTB_DEVBOX_API_BASE`/`_SCREENSHOT_DIR`/`_AUTOFLOW`) keep the `OTB_` prefix — harmless dev hooks, not user-visible; prefix-neutralising them is optional polish.
|
|
44
|
+
5. **ADR number collision:** `0144` is used twice on this branch (`devbox-rehome` + `federated-single-logout`, from a parallel merge). Cosmetic; a renumber is worth a follow-up.
|