@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
package/src/bongos/db-kernel.js
CHANGED
|
@@ -183,6 +183,32 @@ async function hasInvitedAccessRequest(login) {
|
|
|
183
183
|
return rows.length > 0;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
// accessStateByLogin — the three admission-relevant facts about a github login,
|
|
187
|
+
// in ONE round trip: is there already a builder row (member), has an Archon
|
|
188
|
+
// approved them (invited), are they waiting on one (pending). Case-insensitive
|
|
189
|
+
// throughout, matching hasInvitedAccessRequest above.
|
|
190
|
+
//
|
|
191
|
+
// This exists for the "confirming access" waiting page (task 1002097): the page
|
|
192
|
+
// polls a probe that must distinguish "admission is imminent" from "genuine
|
|
193
|
+
// stranger", and doing that with three separate helpers would mean three
|
|
194
|
+
// queries per poll per visitor. It reports FACTS ONLY — the admission DECISION
|
|
195
|
+
// stays in auth.firstTimeAdmissionBlocked, which is the single gate both flows
|
|
196
|
+
// share (SR-19). Nothing here grants access.
|
|
197
|
+
async function accessStateByLogin(login) {
|
|
198
|
+
const { rows } = await pool.query(
|
|
199
|
+
`SELECT
|
|
200
|
+
EXISTS (SELECT 1 FROM builders
|
|
201
|
+
WHERE lower(github_login) = lower($1)) AS member,
|
|
202
|
+
EXISTS (SELECT 1 FROM access_requests
|
|
203
|
+
WHERE lower(github_login) = lower($1) AND status = 'invited') AS invited,
|
|
204
|
+
EXISTS (SELECT 1 FROM access_requests
|
|
205
|
+
WHERE lower(github_login) = lower($1) AND status = 'pending') AS pending`,
|
|
206
|
+
[login]
|
|
207
|
+
);
|
|
208
|
+
const r = rows[0] || {};
|
|
209
|
+
return { member: !!r.member, invited: !!r.invited, pending: !!r.pending };
|
|
210
|
+
}
|
|
211
|
+
|
|
186
212
|
// --- Auth sessions (kernel: the builder_sessions token store auth.js drives) ----
|
|
187
213
|
|
|
188
214
|
// SESSION_TTL_MS — session TTL on create/refresh. Centralized so the migration's
|
|
@@ -247,6 +273,7 @@ module.exports = {
|
|
|
247
273
|
seatFirstAdminIfUnclaimed,
|
|
248
274
|
getBuilderByGithubId,
|
|
249
275
|
hasInvitedAccessRequest,
|
|
276
|
+
accessStateByLogin,
|
|
250
277
|
createSession,
|
|
251
278
|
lookupSession,
|
|
252
279
|
};
|
package/src/bongos/db.js
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
// grade-count SQL runs on both sides of the kernel↔module line — keep in sync.
|
|
26
26
|
|
|
27
27
|
const { pool } = require('./pool');
|
|
28
|
+
const secretBox = require('./secret-box');
|
|
28
29
|
// Module seam (ADR 0083 / BV1.R43). The rank/status-change paths EMIT
|
|
29
30
|
// `builder.box-reconcile-needed` AFTER COMMIT (best-effort) so the dev-box module
|
|
30
31
|
// can reconcile a droplet a demotion/graduation implies — never a direct require
|
|
@@ -205,6 +206,68 @@ async function updateBuilderDisciplines(builderId, disciplines) {
|
|
|
205
206
|
// { enc: null, ... } when no key is set.
|
|
206
207
|
|
|
207
208
|
|
|
209
|
+
// ---- GitHub OAuth repo token, encrypted at rest (core_192 / task 1002099) ----
|
|
210
|
+
//
|
|
211
|
+
// The onboarding wizard (public-landing/create.html) opts into `public_repo` at
|
|
212
|
+
// sign-in so it can list + create the user's repos. That user-to-server GitHub
|
|
213
|
+
// token is held here BRIEFLY: encrypted with secret-box (master key in server env
|
|
214
|
+
// only — the plaintext never touches the DB) and given a short TTL (one wizard
|
|
215
|
+
// sitting), read back by the repo picker/creator, then deleted on use. It is the
|
|
216
|
+
// auth system's OWN handshake token (distinct from a feature's third-party key
|
|
217
|
+
// like the art module's Gemini key, ADR 0102), so it lives in core auth. secret-box
|
|
218
|
+
// is the gate: with no master key configured we NEVER store a plaintext token —
|
|
219
|
+
// capture no-ops and the wizard degrades to manual repo entry (ADR 0143).
|
|
220
|
+
const GITHUB_TOKEN_TTL_MS = 60 * 60 * 1000; // 1h — one wizard sitting.
|
|
221
|
+
|
|
222
|
+
// Store (or replace) the builder's GitHub repo token. `token` is the raw
|
|
223
|
+
// user-to-server access token; it is encrypted here so the plaintext never touches
|
|
224
|
+
// the DB. No-ops when secret-box is unconfigured (returns { stored:false }).
|
|
225
|
+
async function upsertGithubToken({ builderId, token, scope = null, ttlMs = GITHUB_TOKEN_TTL_MS, p = pool }) {
|
|
226
|
+
if (!secretBox.isConfigured()) return { stored: false };
|
|
227
|
+
const enc = secretBox.encrypt(token);
|
|
228
|
+
const expiresAt = new Date(Date.now() + ttlMs);
|
|
229
|
+
await p.query(
|
|
230
|
+
`INSERT INTO github_oauth_tokens (builder_id, token_enc, scope, created_at, expires_at)
|
|
231
|
+
VALUES ($1, $2, $3, now(), $4)
|
|
232
|
+
ON CONFLICT (builder_id) DO UPDATE
|
|
233
|
+
SET token_enc = EXCLUDED.token_enc, scope = EXCLUDED.scope,
|
|
234
|
+
created_at = now(), expires_at = EXCLUDED.expires_at`,
|
|
235
|
+
[builderId, enc, scope, expiresAt],
|
|
236
|
+
);
|
|
237
|
+
return { stored: true, expires_at: expiresAt };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Read + decrypt the builder's GitHub token, or null when there is none, it has
|
|
241
|
+
// expired, or secret-box is unconfigured. Lazily deletes an expired row so the
|
|
242
|
+
// table self-cleans without a cron (mirrors the deviceFlows reaping in auth.js).
|
|
243
|
+
// The 503-vs-403 distinction the endpoint needs is made by the endpoint checking
|
|
244
|
+
// secretBox.isConfigured() itself before calling this.
|
|
245
|
+
async function getGithubToken({ builderId, p = pool }) {
|
|
246
|
+
if (!secretBox.isConfigured()) return null;
|
|
247
|
+
const { rows } = await p.query(
|
|
248
|
+
`SELECT token_enc, scope, expires_at FROM github_oauth_tokens WHERE builder_id = $1`,
|
|
249
|
+
[builderId],
|
|
250
|
+
);
|
|
251
|
+
const row = rows[0];
|
|
252
|
+
if (!row) return null;
|
|
253
|
+
if (new Date(row.expires_at).getTime() <= Date.now()) {
|
|
254
|
+
await p.query(`DELETE FROM github_oauth_tokens WHERE builder_id = $1`, [builderId]).catch(() => {});
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
let token;
|
|
258
|
+
try { token = secretBox.decrypt(row.token_enc); }
|
|
259
|
+
catch { return null; } // a blob that won't decrypt (e.g. rotated master key) reads as "none".
|
|
260
|
+
return { token, scope: row.scope, expires_at: row.expires_at };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Delete the builder's token (called after the wizard's terminal enqueue, and on
|
|
264
|
+
// expiry). Best-effort; safe to call when nothing is stored.
|
|
265
|
+
async function deleteGithubToken({ builderId, p = pool }) {
|
|
266
|
+
await p.query(`DELETE FROM github_oauth_tokens WHERE builder_id = $1`, [builderId]);
|
|
267
|
+
return { deleted: true };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
208
271
|
// leaderboard() carved into modules/economy/credits.js (BV1.R77 / ADR 0093 §1-2).
|
|
209
272
|
// Core read routes resolve it via the `reward` kernel port.
|
|
210
273
|
|
|
@@ -235,6 +298,15 @@ async function updateBuilderDisciplines(builderId, disciplines) {
|
|
|
235
298
|
// shipped." Pure decision helper is exported so tests/rank_gate.mjs can exercise
|
|
236
299
|
// the threshold without a DB.
|
|
237
300
|
|
|
301
|
+
// REQUIRES_RANK_TIER — the canonical rank → tier (1-based) map: the rank "brain".
|
|
302
|
+
// MUST stay byte-identical to permission-path-check.js RANK_TIER and
|
|
303
|
+
// modules/lifecycle/db.js REQUIRES_RANK_TIER (tests/permission_path.mjs guards the
|
|
304
|
+
// drift; gate-review.js + diagram-facts.js parse this literal by regex, so keep it
|
|
305
|
+
// an inline object literal). Restores the binding the LIVE_RANK_LADDER carve
|
|
306
|
+
// (ADR 0102) left dangling — both singleRungPromotionError below and the
|
|
307
|
+
// db.REQUIRES_RANK_TIER export depend on it.
|
|
308
|
+
const REQUIRES_RANK_TIER = { xenos: 1, thetes: 2, metic: 3, archon: 4 };
|
|
309
|
+
|
|
238
310
|
function singleRungPromotionError(oldRank, newRank) {
|
|
239
311
|
const a = REQUIRES_RANK_TIER[oldRank];
|
|
240
312
|
const b = REQUIRES_RANK_TIER[newRank];
|
|
@@ -267,6 +339,24 @@ function singleRungPromotionError(oldRank, newRank) {
|
|
|
267
339
|
// has nothing to collide on, so it's returned unchanged. Pure + exported so
|
|
268
340
|
// tests can exercise it without a DB; claimTask calls it inside the txn.
|
|
269
341
|
|
|
342
|
+
// syncGovernanceRankRole — keep governance_builder_roles in step with builders.rank
|
|
343
|
+
// (BV1.R95b, ADR 0151). Resolved through the `governance.roleSync` kernel port and
|
|
344
|
+
// run on the CALLER's transaction client, so the role rotation is atomic with the
|
|
345
|
+
// rank write beside it. Core never requires modules/governance/ (ADR 0083).
|
|
346
|
+
//
|
|
347
|
+
// A missing port means the governance module is disabled, and skipping is the
|
|
348
|
+
// fail-closed answer: the builder then holds no role and resolves to ZERO
|
|
349
|
+
// permissions. Admitting anything here would make disabling a module a privilege
|
|
350
|
+
// escalation — the same call requirePermission() makes on a missing port.
|
|
351
|
+
//
|
|
352
|
+
// TWINNED with modules/lifecycle/db.js (the boundary-forced _applyRankChangeTx
|
|
353
|
+
// duplication, ADR 0091 §2) — keep the two in sync.
|
|
354
|
+
async function syncGovernanceRankRole(client, builderId, rank) {
|
|
355
|
+
const roleSync = seams.resolveOptional('governance.roleSync');
|
|
356
|
+
if (!roleSync || typeof roleSync.syncRankRole !== 'function') return null;
|
|
357
|
+
return roleSync.syncRankRole(client, { builderId, rank });
|
|
358
|
+
}
|
|
359
|
+
|
|
270
360
|
async function _applyRankChangeTx(client, { builderId, newRank, actorBuilderId, reasonNote = null, enforceSingleRungPromotion = false }) {
|
|
271
361
|
const { rows } = await client.query(
|
|
272
362
|
`SELECT id, rank, status FROM builders WHERE id = $1 FOR UPDATE`,
|
|
@@ -291,6 +381,17 @@ async function _applyRankChangeTx(client, { builderId, newRank, actorBuilderId,
|
|
|
291
381
|
[builderId, newRank]
|
|
292
382
|
);
|
|
293
383
|
|
|
384
|
+
// BV1.R95b — rotate the seeded rank-role IN THIS TRANSACTION. A DEMOTION removes
|
|
385
|
+
// the higher role rather than merely adding the lower one; without that, a demoted
|
|
386
|
+
// Archon keeps resolving Archon permissions (the ADR 0016 freshness promise broken
|
|
387
|
+
// one layer beneath the uncached resolver).
|
|
388
|
+
//
|
|
389
|
+
// Deliberately NOT wrapped in try/catch. If the rotation cannot be written the rank
|
|
390
|
+
// write must roll back with it: a committed rank change whose role rotation failed
|
|
391
|
+
// IS the privilege-retention bug, just with a smaller window. Refusing leaves the
|
|
392
|
+
// builder consistently at their OLD rank, which the actor can retry.
|
|
393
|
+
await syncGovernanceRankRole(client, builderId, newRank);
|
|
394
|
+
|
|
294
395
|
// V3.R28 / #249 — ceremony delta. Promotion (moving UP the ladder = lower
|
|
295
396
|
// index in RANKS) earns +5; demotion is audit-only (0).
|
|
296
397
|
const oldIdx = RANKS.indexOf(oldRank);
|
|
@@ -897,6 +998,7 @@ module.exports = {
|
|
|
897
998
|
SESSION_TTL_MS,
|
|
898
999
|
LIVE_RANK_LADDER,
|
|
899
1000
|
singleRungPromotionError,
|
|
1001
|
+
REQUIRES_RANK_TIER,
|
|
900
1002
|
recentKarmaForBuilder,
|
|
901
1003
|
karmaDelta30d,
|
|
902
1004
|
insertAuditLog,
|
|
@@ -908,4 +1010,7 @@ module.exports = {
|
|
|
908
1010
|
upsertSecurityDoc,
|
|
909
1011
|
getSecurityDoc,
|
|
910
1012
|
listSecurityDocs,
|
|
1013
|
+
upsertGithubToken,
|
|
1014
|
+
getGithubToken,
|
|
1015
|
+
deleteGithubToken,
|
|
911
1016
|
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// GitHub repo list/create on behalf of the signed-in user — the server half of the
|
|
2
|
+
// onboarding wizard's repo picker (adopt) + auto-create (fresh). Task 1002099 / ADR 0143.
|
|
3
|
+
//
|
|
4
|
+
// Raw `fetch` against GitHub's REST API (the house style — see auth.js
|
|
5
|
+
// fetchGithubUser; no octokit dependency). The user-to-server token these take is
|
|
6
|
+
// the `public_repo`-scoped token the web callback captured and stored (db.js
|
|
7
|
+
// github_oauth_tokens); callers pass the decrypted token in, this module never
|
|
8
|
+
// touches storage. `fetchImpl` is injectable so tests can drive it with a mock and
|
|
9
|
+
// never hit the network.
|
|
10
|
+
|
|
11
|
+
const { userAgent } = require('../branding');
|
|
12
|
+
|
|
13
|
+
const GH_API = 'https://api.github.com';
|
|
14
|
+
const PER_PAGE = 100;
|
|
15
|
+
// Up to 300 most-recently-updated OWNED repos — plenty to back a picker for the vast
|
|
16
|
+
// majority of accounts, and a hard bound so a power user can't make us page forever
|
|
17
|
+
// (v1 cap; the picker filters this set client-and-server-side by substring).
|
|
18
|
+
const MAX_PAGES = 3;
|
|
19
|
+
|
|
20
|
+
class GithubApiError extends Error {
|
|
21
|
+
constructor(message, { status, code } = {}) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = 'GithubApiError';
|
|
24
|
+
this.status = status;
|
|
25
|
+
this.code = code;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ghHeaders(token, extra = {}) {
|
|
30
|
+
return {
|
|
31
|
+
Authorization: `Bearer ${token}`,
|
|
32
|
+
'User-Agent': userAgent(),
|
|
33
|
+
Accept: 'application/vnd.github+json',
|
|
34
|
+
...extra,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// List the signed-in user's OWN repos (affiliation=owner so `full_name` is always
|
|
39
|
+
// `login/repo` and the org-OAuth-policy complexity is out of scope for v1),
|
|
40
|
+
// most-recently-updated first, optionally filtered by a case-insensitive substring
|
|
41
|
+
// `q` on the full name. Returns [{ full_name, name, owner, private }].
|
|
42
|
+
async function listUserRepos(token, { q = '', fetchImpl = fetch } = {}) {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
45
|
+
const url = `${GH_API}/user/repos?per_page=${PER_PAGE}&page=${page}&sort=updated&affiliation=owner`;
|
|
46
|
+
const res = await fetchImpl(url, { headers: ghHeaders(token) });
|
|
47
|
+
if (res.status === 401) {
|
|
48
|
+
throw new GithubApiError('GitHub rejected the stored token', { status: 401, code: 'github_unauthorized' });
|
|
49
|
+
}
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
throw new GithubApiError(`GitHub /user/repos failed (${res.status})`, { status: res.status, code: 'github_error' });
|
|
52
|
+
}
|
|
53
|
+
const rows = await res.json();
|
|
54
|
+
if (!Array.isArray(rows) || rows.length === 0) break;
|
|
55
|
+
for (const r of rows) {
|
|
56
|
+
out.push({
|
|
57
|
+
full_name: r.full_name,
|
|
58
|
+
name: r.name,
|
|
59
|
+
owner: r.owner && r.owner.login,
|
|
60
|
+
private: !!r.private,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
if (rows.length < PER_PAGE) break;
|
|
64
|
+
}
|
|
65
|
+
const needle = String(q || '').trim().toLowerCase();
|
|
66
|
+
return needle ? out.filter((r) => String(r.full_name).toLowerCase().includes(needle)) : out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Create an EMPTY repo in the signed-in user's personal account. auto_init:false =
|
|
70
|
+
// no README/first commit (exactly the "leave it completely empty" the manual step
|
|
71
|
+
// demanded); private:false because we hold only `public_repo`. Returns
|
|
72
|
+
// { full_name, html_url }. A 422 (name already exists / invalid) becomes a typed
|
|
73
|
+
// `name_taken` error the route maps to a friendly 409 rather than an opaque 500.
|
|
74
|
+
async function createUserRepo(token, { name, fetchImpl = fetch } = {}) {
|
|
75
|
+
const res = await fetchImpl(`${GH_API}/user/repos`, {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
headers: ghHeaders(token, { 'Content-Type': 'application/json' }),
|
|
78
|
+
body: JSON.stringify({ name, private: false, auto_init: false }),
|
|
79
|
+
});
|
|
80
|
+
if (res.status === 201) {
|
|
81
|
+
const r = await res.json();
|
|
82
|
+
return { full_name: r.full_name, html_url: r.html_url };
|
|
83
|
+
}
|
|
84
|
+
if (res.status === 401) {
|
|
85
|
+
throw new GithubApiError('GitHub rejected the stored token', { status: 401, code: 'github_unauthorized' });
|
|
86
|
+
}
|
|
87
|
+
if (res.status === 422) {
|
|
88
|
+
throw new GithubApiError('A repository with that name already exists on your account', { status: 422, code: 'name_taken' });
|
|
89
|
+
}
|
|
90
|
+
throw new GithubApiError(`GitHub create-repo failed (${res.status})`, { status: res.status, code: 'github_error' });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { listUserRepos, createUserRepo, GithubApiError, MAX_PAGES };
|
|
@@ -166,6 +166,18 @@ const MODULE_GLOBS = {
|
|
|
166
166
|
// to the kernel key (02-module-map §5).
|
|
167
167
|
'modules/security/',
|
|
168
168
|
],
|
|
169
|
+
// --- configurable roles & permissions: the permission resolver, catalog, and
|
|
170
|
+
// requirePermission gate (BV1 goal 1000030, ADR 0151). A core default:true
|
|
171
|
+
// module. `protected` DERIVES true — its 'modules/governance/' glob is in
|
|
172
|
+
// PROTECTED_GLOBS (the authz core) — so creating a goal scoped to governance is
|
|
173
|
+
// Archon-only (BV1.R57 / POST /goals). The config globs are the per-instance
|
|
174
|
+
// role templates (R96), listed here as goal territory; the module code lands in
|
|
175
|
+
// R93+ (the carve precedes the feature — ADR 0086 §4). Written as exact paths,
|
|
176
|
+
// not 'config/governance*.json' — the touches convention has no wildcards. ---
|
|
177
|
+
governance: [
|
|
178
|
+
'modules/governance/',
|
|
179
|
+
'config/governance.json', 'config/governance.neutral.json',
|
|
180
|
+
],
|
|
169
181
|
// --- the two web surfaces ---
|
|
170
182
|
// BV1.R85: hall-UI graduated to modules/hall-ui/ — public-builders/ moved to
|
|
171
183
|
// modules/hall-ui/public/ and is now a loader-discovered web-surface module
|
|
@@ -194,7 +206,21 @@ const MODULE_GLOBS = {
|
|
|
194
206
|
// core/CLI-side under scripts/discord/.
|
|
195
207
|
'scripts/discord/', 'modules/discord/',
|
|
196
208
|
],
|
|
197
|
-
|
|
209
|
+
// --- per-builder cloud dev boxes (DO droplets + Cloudflare tunnels), the sandbox
|
|
210
|
+
// preview, server-mediated branch publish. First module carved to modules/dev-box/
|
|
211
|
+
// (BV1.R43 — ADR 0083). Like the lifecycle/onboarding CLIs, the dev-box OPERATOR +
|
|
212
|
+
// connect commands travel with the domain but stay under scripts/gds/: box.js (the
|
|
213
|
+
// DO/CF provisioning control plane), box-auth-check, box-connect-lib, and the box
|
|
214
|
+
// smoke test. Listing them here so a `dev-box`-scoped goal's wall covers the box
|
|
215
|
+
// provisioning / bring-up work (BV1.R91, goal 1000051 C2), not just modules/dev-box/.
|
|
216
|
+
// The box BRING-UP scripts (infra/box-*.sh — box-source-fetch, heartbeat, terminal
|
|
217
|
+
// units) are INSTANCE-VENDORED (ADR 0144; not tracked in core), so they are not
|
|
218
|
+
// listed here yet — they come under this key when de-vendored (task 1002243).
|
|
219
|
+
'dev-box': [
|
|
220
|
+
'modules/dev-box/', 'devbox-app/',
|
|
221
|
+
'scripts/gds/box.js', 'scripts/gds/box-auth-check.js', 'scripts/gds/box-connect-lib.js',
|
|
222
|
+
'scripts/gds/smoke-box.sh',
|
|
223
|
+
],
|
|
198
224
|
};
|
|
199
225
|
|
|
200
226
|
// A glob set is protected iff it overlaps the imported PROTECTED_GLOBS — the one
|