@bongos/core 1.18.3 → 1.18.19
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 +1576 -286
- package/.claude/skills/builder-box/SKILL.md +6 -0
- package/.claude/skills/builder-sequence/SKILL.md +97 -0
- package/.claude/skills/builder-ship/SKILL.md +8 -2
- package/.claude/skills/builder-start/SKILL.md +11 -0
- package/.claude/skills/builder-sync/SKILL.md +41 -0
- package/.claude/skills/fix-task/SKILL.md +64 -0
- package/.claude/skills/goal-create/SKILL.md +158 -0
- package/.claude/skills/goal-review/SKILL.md +3 -1
- package/.claude/skills/idea-triage/SKILL.md +14 -8
- package/.claude/skills/merge-mode/SKILL.md +2 -2
- package/.claude/skills/new-project/SKILL.md +1 -0
- package/.claude/skills/planning-session/SKILL.md +45 -18
- package/.env.local.example +4 -3
- package/README.md +4 -2
- package/bin/bongos.js +1 -0
- package/clients/bongos-client/README.md +2 -2
- package/clients/bongos-client/bongos-client.global.js +82 -18
- package/clients/bongos-client/index.cjs +82 -18
- package/clients/bongos-client/index.d.ts +131 -29
- package/clients/bongos-client/index.mjs +82 -18
- package/config/branding.neutral.json +6 -1
- package/config/governance.neutral.json +21 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +24 -0
- package/docs/adr/0090-metic-task-authoring.md +1 -1
- package/docs/adr/0144-devbox-rehome-onto-cloudbongos-plane.md +41 -0
- package/docs/adr/0144-federated-single-logout-backchannel.md +42 -0
- package/docs/adr/0145-devbox-app-branding-driven-module.md +44 -0
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +62 -0
- package/docs/adr/0146-configurable-reward-mode-cost-plus-only.md +53 -0
- package/docs/adr/0147-standalone-live-docs-regen.md +39 -0
- package/docs/adr/0148-task-scoped-box-source-access.md +48 -0
- package/docs/adr/0149-bongos-dev-local-launcher.md +57 -0
- package/docs/adr/0150-box-first-boot-bringup-vendored-instances.md +68 -0
- package/docs/adr/0151-governance-permissions-as-atom-ranks-as-roles.md +229 -0
- package/docs/adr/0152-landing-gate-served-by-the-core-app.md +92 -0
- package/docs/adr/0152-metic-task-abandonment.md +67 -0
- package/docs/adr/0153-sequential-chain-runner.md +51 -0
- package/docs/adr/0154-goal-owner-criterion-authoring.md +86 -0
- package/docs/adr/README.md +10 -0
- package/docs/api/openapi.json +843 -17
- package/docs/api-reference.md +23 -10
- package/docs/architecture.md +4 -2
- package/docs/branding-contract.md +3 -1
- package/docs/canonical-permissions.md +21 -8
- package/docs/file-map.md +8 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +2 -2
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +3 -1
- package/docs/onboarding/diagrams/05-versioning.mmd +1 -3
- package/docs/onboarding/diagrams/assertions.json +4 -7
- package/docs/onboarding/drachmae-and-karma.md +3 -3
- package/docs/onboarding/primer.md +17 -16
- package/docs/onboarding/slash-commands.md +124 -0
- package/docs/recipes/builder-box-lifecycle.md +23 -0
- package/docs/recipes/devbox-app-release.md +14 -4
- package/docs/recipes/instance-first-run.md +16 -0
- package/docs/recipes/local-dev.md +81 -0
- package/docs/recipes/ops-gotchas.md +19 -1
- package/docs/recipes/overnight-builder.md +1 -1
- package/docs/recipes/parallel-goal-waves.md +174 -0
- package/docs/recipes/ship-and-regrade.md +2 -2
- package/docs/recipes/standalone-live-docs.md +48 -0
- package/docs/recipes/work-on-a-task-from-your-dev-box.md +108 -0
- package/migrations/003_pms.sql +6 -7
- package/migrations/006_pms_v2.sql +3 -31
- package/migrations/core_193_task_needs_rebase.sql +28 -0
- package/migrations/core_194_confirmed_backlog_clawback.sql +63 -0
- package/migrations/core_195_idea_triage_provenance.sql +57 -0
- package/migrations/core_196_session_reward_topup.sql +69 -0
- package/modules/autonomy/pollers/routine-timers.js +9 -8
- package/modules/builder-settings/wandering-prefs.js +61 -18
- package/modules/dev-box/app/README.md +73 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-alertTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-busyTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-offTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate.png +0 -0
- package/modules/dev-box/app/assets/tray/mac-onTemplate@2x.png +0 -0
- package/modules/dev-box/app/assets/tray/win-alert.png +0 -0
- package/modules/dev-box/app/assets/tray/win-busy.png +0 -0
- package/modules/dev-box/app/assets/tray/win-off.png +0 -0
- package/modules/dev-box/app/assets/tray/win-on.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background.png +0 -0
- package/modules/dev-box/app/build-resources/dmg-background@2x.png +0 -0
- package/modules/dev-box/app/build-resources/icon.png +0 -0
- package/modules/dev-box/app/electron-builder.tmpl.yml +95 -0
- package/modules/dev-box/app/electron-builder.yml +95 -0
- package/modules/dev-box/app/package-lock.json +5291 -0
- package/modules/dev-box/app/package.json +30 -0
- package/modules/dev-box/app/renderer/app.js +319 -0
- package/modules/dev-box/app/renderer/index.html +45 -0
- package/modules/dev-box/app/renderer/styles.css +246 -0
- package/modules/dev-box/app/renderer/theme.generated.css +16 -0
- package/modules/dev-box/app/scripts/apply-dmg-backdrop.sh +82 -0
- package/modules/dev-box/app/scripts/dmgbuild-settings.py +39 -0
- package/modules/dev-box/app/scripts/gen-brand.js +138 -0
- package/modules/dev-box/app/scripts/gen-dmg-backdrop.py +323 -0
- package/modules/dev-box/app/scripts/gen-icons.js +286 -0
- package/modules/dev-box/app/scripts/vendor-client.js +23 -0
- package/modules/dev-box/app/src/box-controller.js +287 -0
- package/modules/dev-box/app/src/brand.generated.json +13 -0
- package/modules/dev-box/app/src/brand.js +16 -0
- package/modules/dev-box/app/src/config.js +19 -0
- package/modules/dev-box/app/src/gds-client.js +90 -0
- package/modules/dev-box/app/src/main.js +610 -0
- package/modules/dev-box/app/src/pairing.js +57 -0
- package/modules/dev-box/app/src/preload.js +29 -0
- package/modules/dev-box/app/src/session-store.js +58 -0
- package/modules/dev-box/app/src/ssh-setup.js +569 -0
- package/modules/dev-box/app/src/task-picker.js +70 -0
- package/modules/dev-box/app/src/tray.js +99 -0
- package/modules/dev-box/app/src/updater.js +55 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +698 -0
- package/modules/dev-box/app/test/unit.mjs +526 -0
- package/modules/dev-box/box-access.js +121 -4
- package/modules/dev-box/boxes.js +20 -0
- package/modules/dev-box/module.json +1 -1
- package/modules/dev-box/routes/box.js +87 -3
- package/modules/economy/credits.js +116 -25
- package/modules/economy/reward.js +8 -0
- package/modules/economy/streak.js +2 -1
- package/modules/governance/CLAUDE.md +15 -0
- package/modules/governance/catalog.js +419 -0
- package/modules/governance/config.js +174 -0
- package/modules/governance/db.js +125 -0
- package/modules/governance/migrations/governance_001_tables.sql +81 -0
- package/modules/governance/migrations/governance_002_seed_and_backfill.sql +103 -0
- package/modules/governance/migrations/governance_003_task_abandon_metic.sql +28 -0
- package/modules/governance/migrations/governance_004_criterion_create.sql +39 -0
- package/modules/governance/migrations/governance_005_resync_builder_rank_roles.sql +56 -0
- package/modules/governance/module.json +10 -0
- package/modules/governance/protected-surfaces.js +88 -0
- package/modules/governance/protected-surfaces.json +80 -0
- package/modules/governance/rank-roles.js +83 -0
- package/modules/governance/resolver.js +221 -0
- package/modules/governance/routes/governance.js +89 -0
- package/modules/governance/routes/role-sync.js +49 -0
- package/modules/governance/session-scopes.js +127 -0
- package/modules/governance/session-scopes.json +38 -0
- package/modules/hall-ui/public/atlas.css +117 -0
- package/modules/hall-ui/public/atlas.html +3 -114
- package/modules/hall-ui/public/brand-apply.js +34 -6
- package/modules/hall-ui/public/builders.js +187 -219
- package/modules/hall-ui/public/diagrams.html +2 -0
- package/modules/hall-ui/public/dom-utils.js +27 -0
- package/modules/hall-ui/public/drachmae.html +2 -0
- package/modules/hall-ui/public/drachmae.js +54 -1
- package/modules/hall-ui/public/gate.css +98 -0
- package/modules/hall-ui/public/gate.html +3 -95
- package/modules/hall-ui/public/goal-inbox.js +4 -1
- package/modules/hall-ui/public/goals-page.js +626 -114
- package/modules/hall-ui/public/goals.css +79 -1
- package/modules/hall-ui/public/goals.html +38 -11
- package/modules/hall-ui/public/hall-widgets.js +62 -52
- package/modules/hall-ui/public/harbor.css +123 -0
- package/modules/hall-ui/public/harbor.html +3 -120
- package/modules/hall-ui/public/index.html +11 -4
- package/modules/hall-ui/public/instances-panel.js +4 -1
- package/modules/hall-ui/public/modules.css +63 -0
- package/modules/hall-ui/public/modules.html +3 -60
- package/modules/hall-ui/public/new-project-wizard.js +7 -3
- package/modules/hall-ui/public/not-ready.html +2 -0
- package/modules/hall-ui/public/pair.css +73 -0
- package/modules/hall-ui/public/pair.html +3 -70
- package/modules/hall-ui/public/palette.js +302 -0
- package/modules/hall-ui/public/primer.css +13 -0
- package/modules/hall-ui/public/primer.html +2 -0
- package/modules/hall-ui/public/profile.html +2 -0
- package/modules/hall-ui/public/ranks.html +2 -0
- package/modules/hall-ui/public/roadmap.css +179 -0
- package/modules/hall-ui/public/roadmap.html +9 -172
- package/modules/hall-ui/public/roadmap.js +329 -316
- package/modules/hall-ui/public/sessions.css +16 -0
- package/modules/hall-ui/public/sessions.html +3 -13
- package/modules/hall-ui/public/settings.html +2 -0
- package/modules/hall-ui/public/settings.js +4 -4
- package/modules/hall-ui/public/shell.js +143 -18
- package/modules/hall-ui/public/style.css +231 -39
- package/modules/hall-ui/public/task-detail.js +347 -26
- package/modules/hall-ui/public/task.html +6 -1
- package/modules/hall-ui/public/watch.html +2 -0
- package/modules/hall-ui/public/work.html +8 -6
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/ideas/inbox.js +61 -11
- package/modules/ideas/routes/inbox.js +23 -0
- package/modules/lifecycle/claim-eligibility.js +72 -0
- package/modules/lifecycle/db.js +519 -139
- package/modules/lifecycle/done-when.js +18 -3
- package/modules/lifecycle/github-push.js +19 -2
- package/modules/lifecycle/goal-advisory.js +114 -0
- package/modules/lifecycle/goal-authz.js +62 -0
- package/modules/lifecycle/lifecycle.js +9 -0
- package/modules/lifecycle/publish-reconciler.js +109 -6
- package/modules/lifecycle/routes/claims.js +68 -23
- package/modules/lifecycle/routes/done-when.js +110 -15
- package/modules/lifecycle/routes/goals.js +8 -38
- package/modules/lifecycle/routes/tasks.js +38 -6
- package/modules/lifecycle/ship-card.js +6 -0
- package/modules/onboarding/onboarding-state.js +1 -1
- package/modules/platform-identity/CLAUDE.md +15 -0
- package/modules/platform-identity/hub-device.js +147 -0
- package/modules/platform-identity/hub-keys.js +151 -0
- package/modules/platform-identity/migrations/platform_identity_001_tables.sql +114 -0
- package/modules/platform-identity/migrations/platform_identity_002_client_origin_index.sql +18 -0
- package/modules/platform-identity/migrations/platform_identity_003_project_memberships.sql +42 -0
- package/modules/platform-identity/migrations/platform_identity_004_projects.sql +44 -0
- package/modules/platform-identity/migrations/platform_identity_005_builder_activity.sql +42 -0
- package/modules/platform-identity/module.json +18 -0
- package/modules/platform-identity/platform-identity.js +531 -0
- package/modules/platform-identity/pollers/code-sweep.js +43 -0
- package/modules/platform-identity/routes/my-projects.js +140 -0
- package/modules/platform-identity/routes/projects.js +107 -0
- package/modules/platform-identity/routes/scouting.js +35 -0
- package/modules/platform-identity/routes/sso.js +402 -0
- package/modules/platform-identity/tests/platform-identity.mjs +388 -0
- package/modules/platform-identity/ui/.gitkeep +0 -0
- package/modules/security/routes/reports.js +10 -0
- package/modules/sessions/db.js +166 -21
- package/modules/sessions/module.json +1 -1
- package/modules/sessions/pollers/session-reward-reconcile.js +78 -0
- package/modules/sessions/routes/sessions.js +33 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/anim/idle/frame_00.webp +0 -0
- package/public-landing/assets/anim/idle/frame_01.webp +0 -0
- package/public-landing/assets/anim/idle/frame_02.webp +0 -0
- package/public-landing/assets/anim/idle/frame_03.webp +0 -0
- package/public-landing/assets/anim/idle/frame_04.webp +0 -0
- package/public-landing/assets/anim/idle/frame_05.webp +0 -0
- package/public-landing/assets/anim/idle/frame_06.webp +0 -0
- package/public-landing/assets/anim/idle/frame_07.webp +0 -0
- package/public-landing/assets/anim/idle/frame_08.webp +0 -0
- package/public-landing/assets/anim/idle/frame_09.webp +0 -0
- package/public-landing/assets/anim/idle/frame_10.webp +0 -0
- package/public-landing/assets/anim/idle/frame_11.webp +0 -0
- package/public-landing/assets/anim/idle/frame_12.webp +0 -0
- package/public-landing/assets/anim/idle/frame_13.webp +0 -0
- package/public-landing/assets/anim/idle/frame_14.webp +0 -0
- package/public-landing/assets/anim/idle/frame_15.webp +0 -0
- package/public-landing/assets/anim/idle/frame_16.webp +0 -0
- package/public-landing/assets/anim/idle/frame_17.webp +0 -0
- package/public-landing/assets/anim/idle/frame_18.webp +0 -0
- package/public-landing/assets/anim/idle/frame_19.webp +0 -0
- package/public-landing/assets/anim/idle/frame_20.webp +0 -0
- package/public-landing/assets/anim/idle/frame_21.webp +0 -0
- package/public-landing/assets/anim/idle/frame_22.webp +0 -0
- package/public-landing/assets/anim/idle/frame_23.webp +0 -0
- package/public-landing/assets/anim/idle/frame_24.webp +0 -0
- package/public-landing/assets/anim/idle/frame_25.webp +0 -0
- package/public-landing/assets/anim/idle/frame_26.webp +0 -0
- package/public-landing/assets/anim/idle/frame_27.webp +0 -0
- package/public-landing/assets/anim/idle/frame_28.webp +0 -0
- package/public-landing/assets/anim/idle/frame_29.webp +0 -0
- package/public-landing/assets/anim/idle/frame_30.webp +0 -0
- package/public-landing/assets/anim/idle/frame_31.webp +0 -0
- package/public-landing/assets/anim/idle/frame_32.webp +0 -0
- package/public-landing/assets/anim/idle/frame_33.webp +0 -0
- package/public-landing/assets/anim/idle/frame_34.webp +0 -0
- package/public-landing/assets/anim/idle/frame_35.webp +0 -0
- package/public-landing/assets/anim/idle/frame_36.webp +0 -0
- package/public-landing/assets/anim/idle/frame_37.webp +0 -0
- package/public-landing/assets/anim/idle/frame_38.webp +0 -0
- package/public-landing/assets/anim/idle/frame_39.webp +0 -0
- package/public-landing/assets/anim/idle/frame_40.webp +0 -0
- package/public-landing/assets/anim/idle/frame_41.webp +0 -0
- package/public-landing/assets/anim/idle/frame_42.webp +0 -0
- package/public-landing/assets/anim/idle/frame_43.webp +0 -0
- package/public-landing/create.html +51 -58
- package/public-landing/gate/README.md +137 -0
- package/public-landing/gate/dispmaps/bar.png +0 -0
- package/public-landing/gate/dispmaps/flat.png +0 -0
- package/public-landing/gate/dispmaps/key.png +0 -0
- package/public-landing/gate/index.html +587 -0
- package/public-landing/gate/previews/cloud-bongos.jpg +0 -0
- package/public-landing/gate/previews/off-the-boats.jpg +0 -0
- package/public-landing/gate/space.css +799 -0
- package/public-landing/gate/space.js +1826 -0
- package/public-landing/gate/sprites/enter.png +0 -0
- package/public-landing/gate/sprites/search.png +0 -0
- package/public-landing/gate/sprites/terminal-blank.png +0 -0
- package/public-landing/gate/sprites/tile.png +0 -0
- package/public-landing/world/assets/clouds/cloud-island-large.png +0 -0
- package/public-landing/world/assets/clouds/cloud-puff.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-cargo.png +0 -0
- package/public-landing/world/assets/creatures/creature-whale-glide.png +0 -0
- package/public-landing/world/assets/plates/plate-clouds-near.png +0 -0
- package/public-landing/world/assets/plates/scene-establishing.png +0 -0
- package/scripts/gds/abandon.js +6 -4
- package/scripts/gds/api.js +10 -5
- package/scripts/gds/api.ps1 +26 -0
- package/scripts/gds/api.sh +6 -0
- package/scripts/gds/audit-ships.js +7 -1
- package/scripts/gds/backfill-sessions.js +78 -18
- package/scripts/gds/backup.js +23 -1
- package/scripts/gds/box-connect-lib.js +124 -31
- package/scripts/gds/box-sync.js +66 -0
- package/scripts/gds/box.js +225 -53
- package/scripts/gds/cf-tunnel.js +145 -6
- package/scripts/gds/claim.js +34 -3
- package/scripts/gds/cli-lib.js +161 -27
- package/scripts/gds/code.js +6 -2
- package/scripts/gds/deploy-divergence.js +209 -0
- package/scripts/gds/dev-lib.js +309 -0
- package/scripts/gds/dev.js +322 -0
- package/scripts/gds/doctor.js +90 -61
- package/scripts/gds/fetch-art-key.js +1 -1
- package/scripts/gds/fetch-sound-prefs.js +2 -2
- package/scripts/gds/fitness.js +228 -12
- package/scripts/gds/gds-db-backup.service +16 -1
- package/scripts/gds/gds-db-offsite.service +9 -1
- package/scripts/gds/gen-api-client.js +1 -1
- package/scripts/gds/gen-api-docs.js +36 -14
- package/scripts/gds/gen-diagrams.js +45 -28
- package/scripts/gds/gen-file-map.js +2 -1
- package/scripts/gds/gen-freshness.js +32 -0
- package/scripts/gds/gen-repo-map.js +3 -2
- package/scripts/gds/gen-session-index.js +14 -5
- package/scripts/gds/hooks/pre-push.js +2 -2
- package/scripts/gds/init.js +60 -3
- package/scripts/gds/install-git-hooks.js +1 -1
- package/scripts/gds/key-card.js +15 -6
- package/scripts/gds/key-status.js +1 -1
- package/scripts/gds/linkify-refs.js +35 -9
- package/scripts/gds/login.js +16 -1
- package/scripts/gds/paste-token.js +7 -1
- package/scripts/gds/preflight.js +126 -0
- package/scripts/gds/provision.js +123 -12
- package/scripts/gds/publish-manifest.js +7 -1
- package/scripts/gds/reauth.js +7 -3
- package/scripts/gds/regen-instance-docs.js +47 -0
- package/scripts/gds/run-unit-tests.js +4 -2
- package/scripts/gds/seed-bongos-v1-seo-tasks.js +104 -0
- package/scripts/gds/seed-bv1-profiles-tasks.js +126 -0
- package/scripts/gds/sequence.js +425 -0
- package/scripts/gds/session-cost.js +10 -1
- package/scripts/gds/setup.js +31 -5
- package/scripts/gds/shell.js +5 -3
- package/scripts/gds/ship.js +319 -29
- package/scripts/gds/smoke-gds.js +139 -8
- package/scripts/gds/start.js +171 -22
- package/scripts/gds/status.js +1 -1
- package/scripts/gds/triage.js +10 -9
- package/scripts/gds/upgrade.js +124 -2
- package/scripts/migrate.sh +99 -14
- package/scripts/status-mirror-sync.js +114 -84
- package/src/bongos/api-errors.js +1 -0
- package/src/bongos/auth.js +447 -102
- package/src/bongos/db-kernel.js +27 -0
- package/src/bongos/db.js +39 -0
- package/src/bongos/module-scope-map.js +27 -1
- package/src/bongos/permission-path-check.js +136 -102
- package/src/bongos/repo-info.js +47 -11
- package/src/bongos/route-rank-check.js +429 -46
- package/src/bongos/routes/_helpers.js +12 -1
- package/src/bongos/routes/auth.js +219 -2
- package/src/bongos/routes/backup.js +58 -2
- package/src/bongos/routes/me.js +35 -1
- package/src/bongos/serve-internal.js +84 -15
- package/src/branding.js +32 -0
- package/src/instance-config.js +30 -0
- package/src/module-api.js +124 -1
- package/src/platform-server.js +86 -9
- package/tests/abandon_task.mjs +59 -3
- package/tests/api_cli_flags.mjs +53 -0
- package/tests/auth_page_gate.mjs +13 -0
- package/tests/backfill_sessions.mjs +127 -1
- package/tests/backup_cli.mjs +54 -0
- package/tests/bongos_box_connect.mjs +77 -0
- package/tests/box_access.mjs +130 -1
- package/tests/box_credential.mjs +125 -0
- package/tests/box_host_keys.mjs +24 -0
- package/tests/box_infra_resolve.mjs +149 -0
- package/tests/box_scope_session.mjs +6 -2
- package/tests/box_sync.mjs +55 -0
- package/tests/box_task_scope.mjs +99 -0
- package/tests/branding.mjs +12 -0
- package/tests/cf_ruleset_preflight.mjs +142 -0
- package/tests/cf_tunnel.mjs +37 -0
- package/tests/claim_gate_rebase.mjs +98 -0
- package/tests/clawback_confirmed_backlog.mjs +103 -0
- package/tests/cli_lib_formatters.mjs +20 -0
- package/tests/confirm_attribution.mjs +30 -46
- package/tests/credit_grant.mjs +198 -10
- package/tests/criterion_authoring_gate.mjs +272 -0
- package/tests/criterion_progress.mjs +33 -1
- package/tests/dev_lib.mjs +253 -0
- package/tests/devbox_artifact_gate.mjs +75 -0
- package/tests/devbox_dmg_backdrop.mjs +137 -0
- package/tests/devbox_icons.mjs +304 -0
- package/tests/devbox_installer_brand.mjs +232 -0
- package/tests/devbox_key_register.mjs +234 -0
- package/tests/docs_openapi_route.mjs +110 -0
- package/tests/doctor_hooks.mjs +141 -0
- package/tests/extract_json.mjs +140 -0
- package/tests/fitness.mjs +89 -0
- package/tests/gen_freshness.mjs +96 -0
- package/tests/goal_advisory.mjs +251 -0
- package/tests/goal_criterion_confirm_ui.mjs +269 -0
- package/tests/goal_routes.mjs +59 -4
- package/tests/goal_tier.mjs +12 -3
- package/tests/governance_catalog.mjs +129 -0
- package/tests/governance_claim_eligibility.mjs +262 -0
- package/tests/governance_config.mjs +187 -0
- package/tests/governance_ownership_scope.mjs +410 -0
- package/tests/governance_page_gates.mjs +324 -0
- package/tests/governance_parity.mjs +336 -0
- package/tests/governance_principals.mjs +232 -0
- package/tests/governance_protected_surfaces.mjs +208 -0
- package/tests/governance_require_permission.mjs +223 -0
- package/tests/governance_resolver.mjs +84 -0
- package/tests/governance_role_sync.mjs +231 -0
- package/tests/governance_seed.mjs +127 -0
- package/tests/governance_session_scope.mjs +434 -0
- package/tests/governance_vanilla_boot.mjs +203 -0
- package/tests/grade_attribution.mjs +7 -7
- package/tests/hall_audit.mjs +223 -0
- package/tests/hall_nav.mjs +191 -0
- package/tests/hall_palette.mjs +206 -0
- package/tests/hall_signout.mjs +124 -0
- package/tests/hook_user_agents.mjs +10 -0
- package/tests/idea_triage.mjs +162 -0
- package/tests/idp_device_exchange.mjs +93 -0
- package/tests/init.mjs +51 -0
- package/tests/instance_config.mjs +65 -0
- package/tests/instance_mismatch_guard.mjs +23 -6
- package/tests/instance_release_config.mjs +104 -0
- package/tests/linkify_refs.mjs +15 -2
- package/tests/migrate_root_resolution.mjs +124 -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/parse_cookie_decode.mjs +42 -0
- package/tests/pay_on_land.mjs +129 -0
- package/tests/platform_boot.mjs +100 -1
- package/tests/post_login_landing.mjs +42 -0
- package/tests/preflight_checks.mjs +72 -0
- package/tests/provision.mjs +132 -7
- package/tests/publish_branch_route.mjs +53 -0
- package/tests/publish_reconciler.mjs +187 -2
- package/tests/repo_info_binding.mjs +248 -0
- package/tests/reward_gate.mjs +11 -2
- package/tests/reward_mode_cost_plus_only.mjs +116 -0
- package/tests/reward_mode_surfacing.mjs +168 -0
- package/tests/route_permission_check.mjs +301 -0
- package/tests/route_rank_check.mjs +254 -12
- package/tests/route_validation.mjs +30 -0
- package/tests/sequence.mjs +267 -0
- package/tests/session_digest.mjs +44 -0
- package/tests/session_index.mjs +18 -6
- package/tests/session_records.mjs +39 -1
- package/tests/session_reward_on_land.mjs +381 -0
- package/tests/session_reward_reconcile.mjs +229 -0
- package/tests/ship_api_client_pathspec.mjs +100 -0
- package/tests/ship_base_flag.mjs +93 -0
- package/tests/ship_ci_deploy.mjs +80 -3
- package/tests/ship_upstream_deletion.mjs +57 -0
- package/tests/smoke_target.mjs +233 -0
- package/tests/start_env_guard.mjs +87 -0
- package/tests/start_rebase_warning.mjs +103 -0
- package/tests/status_mirror_sync.mjs +122 -0
- package/tests/stop_refcheck.mjs +19 -1
- package/tests/task_goal_link.mjs +15 -6
- package/tests/upgrade.mjs +139 -0
- package/tests/web_admission_status.mjs +162 -0
- package/tests/write_validation_gaps.mjs +110 -0
package/scripts/gds/smoke-gds.js
CHANGED
|
@@ -3,17 +3,127 @@
|
|
|
3
3
|
// Works on Windows (Git Bash / PowerShell / cmd), macOS, and Linux.
|
|
4
4
|
//
|
|
5
5
|
// Usage:
|
|
6
|
-
// node scripts/gds/smoke-gds.js # against
|
|
6
|
+
// node scripts/gds/smoke-gds.js # against THIS instance
|
|
7
7
|
// GDS_API_BASE=http://localhost:3000 node scripts/gds/smoke-gds.js
|
|
8
8
|
//
|
|
9
|
-
// Exit 0 = all checks passed. Exit 1 = one or more
|
|
9
|
+
// Exit 0 = all checks passed (or the local-target skip). Exit 1 = one or more
|
|
10
|
+
// failures, or no resolvable target (see resolveSmokeTarget).
|
|
10
11
|
|
|
11
12
|
const https = require('https');
|
|
12
13
|
const http = require('http');
|
|
13
14
|
const net = require('net');
|
|
14
15
|
const { URL } = require('url');
|
|
16
|
+
const ic = require('../../src/instance-config');
|
|
17
|
+
const { loadSessionSync } = require('./cli-lib');
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
function safeBranding() {
|
|
20
|
+
try { return require('../../src/branding').branding(); } catch (_) { return {}; }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// readSessionApiBase — the signed-in session's persisted api_base (the instance
|
|
24
|
+
// this CLI is actually pointed at), or null when not signed in / unreadable. The
|
|
25
|
+
// session's OWN value only — deliberately NOT cli-lib's readSessionToken().apiBase,
|
|
26
|
+
// which already folds in the env override + branding default; resolveSmokeTarget
|
|
27
|
+
// orders that precedence itself so it stays pure over its injected inputs. Twin of
|
|
28
|
+
// ship.js's readSessionApiBase.
|
|
29
|
+
function readSessionApiBase() {
|
|
30
|
+
try {
|
|
31
|
+
const s = loadSessionSync();
|
|
32
|
+
return (s && typeof s.api_base === 'string' && s.api_base.trim()) ? s.api_base.trim() : null;
|
|
33
|
+
} catch (_) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const normalizeBase = (s) => (typeof s === 'string' && s.trim() ? s.trim().replace(/\/+$/, '') : null);
|
|
39
|
+
|
|
40
|
+
// Which <PREFIX>_API_BASE supplied the override — the same prefix list, in the
|
|
41
|
+
// same order, that ic.resolveEnv() itself walks. A lookup of the winning NAME,
|
|
42
|
+
// not a second copy of the precedence.
|
|
43
|
+
function matchedApiBaseVar(env) {
|
|
44
|
+
for (const p of [ic.envPrefix(), ...ic.LEGACY_ENV_PREFIXES]) {
|
|
45
|
+
const k = `${p}_API_BASE`;
|
|
46
|
+
if (env[k] !== undefined && env[k] !== '') return k;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// resolveSmokeTarget — WHICH instance these checks are run against. Precedence
|
|
52
|
+
// mirrors ship.js's resolveInstanceBase(): <PREFIX>_API_BASE env (incl. legacy
|
|
53
|
+
// GDS_/OTB_/PMS_) → the signed-in session's api_base → branding publicOrigin →
|
|
54
|
+
// null.
|
|
55
|
+
//
|
|
56
|
+
// There is deliberately NO hardcoded host. This file baked in
|
|
57
|
+
// `https://amazonprimea.com` as its fallback, so a builder signed into any OTHER
|
|
58
|
+
// instance who shipped without an env override ran the ship's verification smoke
|
|
59
|
+
// against the founder's box — which PASSED, because that box is healthy. The ship
|
|
60
|
+
// then reported "smoke=clean" on the strength of testing a system it never
|
|
61
|
+
// touched (task 1002418; the smoke sibling of resolveInstanceBase's task 1002232).
|
|
62
|
+
//
|
|
63
|
+
// FAILS CLOSED: a null base is an error, not a fallback. Verifying nothing and
|
|
64
|
+
// saying so beats verifying the wrong instance and calling it a pass.
|
|
65
|
+
//
|
|
66
|
+
// Pure over its injected inputs (env / sessionApiBase / branding) so the
|
|
67
|
+
// precedence is unit-tested without fs/env/network; the defaults read the real
|
|
68
|
+
// session file + brand pack.
|
|
69
|
+
function resolveSmokeTarget({
|
|
70
|
+
env = process.env,
|
|
71
|
+
sessionApiBase = readSessionApiBase(),
|
|
72
|
+
branding = safeBranding(),
|
|
73
|
+
} = {}) {
|
|
74
|
+
const envBase = normalizeBase(ic.resolveEnv('API_BASE', { env }));
|
|
75
|
+
const session = normalizeBase(sessionApiBase);
|
|
76
|
+
const brandOrigin = normalizeBase(branding && branding.domains && branding.domains.publicOrigin);
|
|
77
|
+
|
|
78
|
+
const base = envBase || session || brandOrigin || null;
|
|
79
|
+
let source = null;
|
|
80
|
+
if (envBase) source = 'env';
|
|
81
|
+
else if (session) source = 'session';
|
|
82
|
+
else if (brandOrigin) source = 'branding';
|
|
83
|
+
|
|
84
|
+
const same = (a, b) => String(a).toLowerCase() === String(b).toLowerCase();
|
|
85
|
+
return {
|
|
86
|
+
base,
|
|
87
|
+
source,
|
|
88
|
+
envVar: envBase ? matchedApiBaseVar(env) : null,
|
|
89
|
+
sessionApiBase: session,
|
|
90
|
+
mismatch: Boolean(base && session && !same(base, session)),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const SOURCE_LABELS = {
|
|
95
|
+
session: 'signed-in session api_base',
|
|
96
|
+
branding: 'branding domains.publicOrigin',
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// The env leg names the variable that actually matched, so "clear the override"
|
|
100
|
+
// is actionable — a builder with a stale OTB_API_BASE shouldn't have to guess
|
|
101
|
+
// which of four names to unset (and shouldn't be shown a literal "<PREFIX>").
|
|
102
|
+
const sourceLabel = ({ source, envVar }) =>
|
|
103
|
+
(source === 'env' ? `${envVar || 'API_BASE'} env override` : SOURCE_LABELS[source] || source);
|
|
104
|
+
|
|
105
|
+
// formatTargetReport — the lines main() prints BEFORE any check runs, so every run
|
|
106
|
+
// states what it is about to verify. A target that disagrees with the signed-in
|
|
107
|
+
// session gets a loud banner: silence about the mismatch is what made the old
|
|
108
|
+
// hardcoded fallback dangerous. Returns lines so the warning is unit-testable.
|
|
109
|
+
function formatTargetReport({ base, source, envVar, sessionApiBase, mismatch }) {
|
|
110
|
+
const label = sourceLabel({ source, envVar });
|
|
111
|
+
const lines = [`=== GDS smoke target: ${base} (source: ${label}) ===`];
|
|
112
|
+
if (!mismatch) return lines;
|
|
113
|
+
const bar = '!'.repeat(72);
|
|
114
|
+
lines.push(
|
|
115
|
+
bar,
|
|
116
|
+
'!! WARNING: the smoke target is NOT the instance you are signed into.',
|
|
117
|
+
`!! smoke target : ${base} (${label})`,
|
|
118
|
+
`!! your session : ${sessionApiBase}`,
|
|
119
|
+
'!! These checks verify the smoke target ONLY. A ship that reports',
|
|
120
|
+
'!! "smoke=clean" off this run is making a claim about the target above,',
|
|
121
|
+
`!! not about your own instance. Unset ${envVar || 'the API_BASE env override'} to verify`,
|
|
122
|
+
'!! the instance you are signed into.',
|
|
123
|
+
bar,
|
|
124
|
+
);
|
|
125
|
+
return lines;
|
|
126
|
+
}
|
|
17
127
|
|
|
18
128
|
// Laptop-ergonomics preflight (#958 / V4.R20). The smoke checks need a running
|
|
19
129
|
// GDS server. When BASE points at a LOCAL listener that isn't up, every check
|
|
@@ -40,7 +150,10 @@ function probeListener(host, port, timeoutMs = 1500) {
|
|
|
40
150
|
});
|
|
41
151
|
}
|
|
42
152
|
|
|
43
|
-
const
|
|
153
|
+
// Built per-run from the resolved base (was a module-level const off a hardcoded
|
|
154
|
+
// BASE): resolution now happens inside main(), so requiring this module for its
|
|
155
|
+
// helpers stays side-effect-free.
|
|
156
|
+
const buildChecks = (BASE) => [
|
|
44
157
|
// Public read-only surface
|
|
45
158
|
['GET /api/gds/healthz', `${BASE}/api/gds/healthz`, 200],
|
|
46
159
|
['GET /api/gds/versions', `${BASE}/api/gds/versions`, 200],
|
|
@@ -100,7 +213,26 @@ function checkUrl(label, url, expectStatus, method = 'GET') {
|
|
|
100
213
|
}
|
|
101
214
|
|
|
102
215
|
async function main() {
|
|
103
|
-
const
|
|
216
|
+
const target = resolveSmokeTarget();
|
|
217
|
+
if (!target.base) {
|
|
218
|
+
console.log('=== GDS smoke FAILED: no target ===');
|
|
219
|
+
console.log('Could not resolve which instance to verify: no <PREFIX>_API_BASE env var,');
|
|
220
|
+
console.log('no signed-in session (node scripts/gds/setup.js), and no readable branding');
|
|
221
|
+
console.log('domains.publicOrigin. Refusing to guess a host — a smoke run against the');
|
|
222
|
+
console.log('wrong instance passes and certifies nothing (task 1002418).');
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
const BASE = target.base;
|
|
226
|
+
for (const line of formatTargetReport(target)) console.log(line);
|
|
227
|
+
|
|
228
|
+
let parsed;
|
|
229
|
+
try {
|
|
230
|
+
parsed = new URL(BASE);
|
|
231
|
+
} catch (_) {
|
|
232
|
+
console.log(`=== GDS smoke FAILED: unusable target ===`);
|
|
233
|
+
console.log(`"${BASE}" is not an absolute URL — it needs a scheme (https://host).`);
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
104
236
|
const host = parsed.hostname;
|
|
105
237
|
const port = Number(parsed.port) || (parsed.protocol === 'https:' ? 443 : 80);
|
|
106
238
|
|
|
@@ -112,8 +244,7 @@ async function main() {
|
|
|
112
244
|
process.exit(0);
|
|
113
245
|
}
|
|
114
246
|
|
|
115
|
-
|
|
116
|
-
const results = await Promise.all(CHECKS.map(([label, url, status, method]) => checkUrl(label, url, status, method)));
|
|
247
|
+
const results = await Promise.all(buildChecks(BASE).map(([label, url, status, method]) => checkUrl(label, url, status, method)));
|
|
117
248
|
const passed = results.filter(Boolean).length;
|
|
118
249
|
const failed = results.length - passed;
|
|
119
250
|
console.log(`=== ${passed} passed, ${failed} failed ===`);
|
|
@@ -122,4 +253,4 @@ async function main() {
|
|
|
122
253
|
|
|
123
254
|
if (require.main === module) main();
|
|
124
255
|
|
|
125
|
-
module.exports = { isLocalTarget, probeListener };
|
|
256
|
+
module.exports = { isLocalTarget, probeListener, resolveSmokeTarget, formatTargetReport, buildChecks };
|
package/scripts/gds/start.js
CHANGED
|
@@ -52,8 +52,9 @@
|
|
|
52
52
|
//
|
|
53
53
|
// Returns JSON if --json is passed (for the slash command to parse cleanly).
|
|
54
54
|
|
|
55
|
-
const { cliClient, requireSession, fmtUsd, printOnboardingNudge, printCostWarning, printNeedsNudge } = require('./cli-lib');
|
|
55
|
+
const { cliClient, requireSession, fmtUsd, printOnboardingNudge, printCostWarning, printNeedsNudge, hallBase, API_BASE, rewardPolicy, costPlusOnlyNote } = require('./cli-lib');
|
|
56
56
|
const { contextPack, formatContextPackCompact } = require('./context-pack');
|
|
57
|
+
const { depsFinding } = require('./preflight');
|
|
57
58
|
|
|
58
59
|
// task 1284: the card shows only the top N claimable rows. The table is the bulk
|
|
59
60
|
// of the widget HTML the model relays verbatim, so fewer rows = fewer tokens +
|
|
@@ -200,15 +201,22 @@ function whatItIs(t) {
|
|
|
200
201
|
// The claimable table — # / Version / Type / Reward / Est. / What it is.
|
|
201
202
|
// Ids are emitted as hall links (renders as a clean #N) — a bare "#NNN" in a
|
|
202
203
|
// relayed chat message autolinks to GitHub and 404s (CLAUDE.md ref rule).
|
|
203
|
-
const HALL_TASK =
|
|
204
|
-
function claimableTable(rows) {
|
|
204
|
+
const HALL_TASK = `${hallBase()}#/task/`;
|
|
205
|
+
function claimableTable(rows, rewardFromServer) {
|
|
206
|
+
// On a cost-plus-only instance the Reward column is an advertised estimate that
|
|
207
|
+
// is never paid — say so in the header so the column can't read as a promise,
|
|
208
|
+
// and footnote what IS paid below the table (task 1002469).
|
|
209
|
+
const perTask = rewardPolicy(rewardFromServer).perTaskCredit;
|
|
210
|
+
const rewardHead = perTask ? 'Reward' : 'Reward (est.)';
|
|
205
211
|
const out = [
|
|
206
|
-
|
|
212
|
+
`| # | Version | Type | ${rewardHead} | Est. | What it is |`,
|
|
207
213
|
'|---|---|---|---|---|---|',
|
|
208
214
|
];
|
|
209
215
|
for (const t of rows) {
|
|
210
216
|
out.push(`| [#${t.id}](${HALL_TASK}${t.id}) | ${cell(t.version_id || '?')} | ${cell(disciplineLabel(t) || '—')} | ${t.credits_reward ?? 0}c | ${estimateShort(t)} | ${cell(whatItIs(t))} |`);
|
|
211
217
|
}
|
|
218
|
+
const cpNote = costPlusOnlyNote(rewardFromServer);
|
|
219
|
+
if (cpNote) out.push('', `_${cpNote}_`);
|
|
212
220
|
return out.join('\n');
|
|
213
221
|
}
|
|
214
222
|
|
|
@@ -228,6 +236,49 @@ function miniBar(pct) {
|
|
|
228
236
|
return `<span class="bs-bar"><span class="bs-barfill" style="width:${pct}%;"></span></span>`;
|
|
229
237
|
}
|
|
230
238
|
|
|
239
|
+
// ---------- owed-rebase warning (ADR 0120 part 5) ----------
|
|
240
|
+
// The builder's un-landed confirmed tasks the publish-reconciler flagged
|
|
241
|
+
// needs_rebase (part 2). They GATE new claims (part 3: claimTask refuses with
|
|
242
|
+
// REBASE_REQUIRED) and their per-task reward now lands only on ship (part 1),
|
|
243
|
+
// so this is the single most urgent thing to show at session start — rendered
|
|
244
|
+
// prominently, before the claimable table, in both the markdown card and the
|
|
245
|
+
// widget. /me carries them as `needs_rebase_tasks` (each { id, title, … }).
|
|
246
|
+
// Refs use the `task N` form, NEVER a bare "#N" (a bare #N in relayed chat
|
|
247
|
+
// autolinks to GitHub issues and 404s — the CLAUDE.md linkify rule).
|
|
248
|
+
|
|
249
|
+
// Normalize the /me list into a small render model, or null when nothing is
|
|
250
|
+
// owed. Shared by the markdown + widget renderers and unit-tested directly
|
|
251
|
+
// (no live server needed).
|
|
252
|
+
function rebaseWarningModel(needsRebaseTasks) {
|
|
253
|
+
const owed = Array.isArray(needsRebaseTasks)
|
|
254
|
+
? needsRebaseTasks.filter((t) => t && t.id != null)
|
|
255
|
+
: [];
|
|
256
|
+
if (owed.length === 0) return null;
|
|
257
|
+
const n = owed.length;
|
|
258
|
+
return {
|
|
259
|
+
count: n,
|
|
260
|
+
refs: owed.map((t) => `task ${t.id}`).join(', '),
|
|
261
|
+
noun: n === 1 ? 'task' : 'tasks',
|
|
262
|
+
pronoun: n === 1 ? 'it' : 'them',
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// The markdown warning line (prominent, before the claimable table), or null
|
|
267
|
+
// when nothing is owed.
|
|
268
|
+
function rebaseWarningMarkdown(needsRebaseTasks) {
|
|
269
|
+
const w = rebaseWarningModel(needsRebaseTasks);
|
|
270
|
+
if (!w) return null;
|
|
271
|
+
return `⚠️ **Rebase owed — your queue is GATED.** ${w.count} ${w.noun} can't land and block new claims until you rebase + re-ship (or \`/builder-release\`) ${w.pronoun}: ${w.refs}.`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// The widget warning block (Tabler alert icon, danger-tinted), or '' when none.
|
|
275
|
+
function rebaseWarningWidget(needsRebaseTasks) {
|
|
276
|
+
const w = rebaseWarningModel(needsRebaseTasks);
|
|
277
|
+
if (!w) return '';
|
|
278
|
+
return `<div class="bs-warn"><i class="ti ti-alert-triangle" aria-hidden="true"></i>`
|
|
279
|
+
+ `<span><strong>Rebase owed — your queue is GATED.</strong> ${w.count} ${w.noun} can't land and block new claims until you rebase + re-ship (or /builder-release) ${w.pronoun}: ${hesc(w.refs)}.</span></div>`;
|
|
280
|
+
}
|
|
281
|
+
|
|
231
282
|
// Run console.log-based helpers (printCostWarning/printOnboardingNudge) without
|
|
232
283
|
// polluting stdout (which must be pure HTML in --widget mode); return the lines.
|
|
233
284
|
function captureLog(fn) {
|
|
@@ -272,6 +323,8 @@ const WIDGET_STYLE = `<style>
|
|
|
272
323
|
.bs-dot{color:var(--color-text-tertiary);}
|
|
273
324
|
.bs-bar{display:inline-block;width:34px;height:5px;border-radius:3px;background:var(--color-border-tertiary);overflow:hidden;vertical-align:middle;}
|
|
274
325
|
.bs-barfill{display:block;height:100%;background:#1D9E75;}
|
|
326
|
+
.bs-warn{display:flex;gap:8px;align-items:flex-start;font-size:13px;margin-top:8px;padding:8px 10px;border-radius:var(--border-radius-md);background:var(--color-background-danger);color:var(--color-text-danger);}
|
|
327
|
+
.bs-warn i{font-size:15px;flex:none;margin-top:1px;}
|
|
275
328
|
.bs-line{font-size:13px;color:var(--color-text-secondary);margin-top:8px;}
|
|
276
329
|
.bs-line i{font-size:14px;vertical-align:-2px;margin-right:4px;}
|
|
277
330
|
.bs-holditem{margin-top:4px;padding-left:18px;}
|
|
@@ -291,8 +344,11 @@ const WIDGET_STYLE = `<style>
|
|
|
291
344
|
.bs-foot{font-size:13px;color:var(--color-text-tertiary);margin-top:12px;}
|
|
292
345
|
</style>`;
|
|
293
346
|
|
|
294
|
-
function renderWidget({ builder, claims, claimable, total, streak, recommendations, header, routingByPreference, preferred, filters, readyToClose }) {
|
|
347
|
+
function renderWidget({ builder, claims, claimable, total, streak, recommendations, header, routingByPreference, preferred, filters, readyToClose, needsRebaseTasks }) {
|
|
295
348
|
const b = builder || {};
|
|
349
|
+
// ADR 0120 part 5: the owed-rebase gate warning, rendered at the top of the
|
|
350
|
+
// card (before status/holdings) since it blocks new claims. '' when none owed.
|
|
351
|
+
const rebaseRow = rebaseWarningWidget(needsRebaseTasks);
|
|
296
352
|
// Streak badge — warm amber, the one bold pop of colour + the motivational
|
|
297
353
|
// stat. Shown only on an active (>0) streak; tooltip carries the record.
|
|
298
354
|
// (Singular element — left inline; the savings live in the repeated grid.)
|
|
@@ -318,7 +374,7 @@ function renderWidget({ builder, claims, claimable, total, streak, recommendatio
|
|
|
318
374
|
|
|
319
375
|
// holdings — each held task gets quick actions off it (ship / release /
|
|
320
376
|
// open). Parallel sessions under one builder are normal, so this informs.
|
|
321
|
-
const hallUrl = (id) =>
|
|
377
|
+
const hallUrl = (id) => `${hallBase()}#/task/${encodeURIComponent(id)}`;
|
|
322
378
|
const dot = '<span class="bs-dot"> · </span>';
|
|
323
379
|
const act = (label, msg) => `<a href="#" onclick="event.preventDefault();sendPrompt('${jsq(msg)}')" class="bs-link">${label} ↗</a>`;
|
|
324
380
|
const actionsFor = (c) => `${act('Ship', 'Ship task ' + c.task_id)}${dot}${act('Release', 'Release task ' + c.task_id)}${dot}<a href="${hesc(hallUrl(c.task_id))}" class="bs-link">Open ↗</a>`;
|
|
@@ -395,6 +451,7 @@ function renderWidget({ builder, claims, claimable, total, streak, recommendatio
|
|
|
395
451
|
<span class="bs-brand"><span class="bs-title"><i class="ti ti-player-play" aria-hidden="true"></i>builder-start</span>${streakBadge}</span>
|
|
396
452
|
<span class="bs-meta">${hesc(b.github_login)} · ${hesc(rank)} · ${hesc(credits)} credits · ${hesc(disc)}</span>
|
|
397
453
|
</div>
|
|
454
|
+
${rebaseRow}
|
|
398
455
|
${statusRow}
|
|
399
456
|
${holdings}
|
|
400
457
|
${closeBanner}
|
|
@@ -439,7 +496,49 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
439
496
|
return outside.slice(0, Math.max(0, limit));
|
|
440
497
|
}
|
|
441
498
|
|
|
442
|
-
(
|
|
499
|
+
// ---------- environment guard (task 1002403 / goal 1000052) ----------
|
|
500
|
+
// /builder-start is often the FIRST command run in a freshly-cloned instance —
|
|
501
|
+
// before the local server has ever been brought up. When the API can't be
|
|
502
|
+
// reached, guide the builder to the one-command bring-up instead of dying with a
|
|
503
|
+
// raw fetch stack trace (the old failure). The generated client REJECTS on a
|
|
504
|
+
// network error even under throwOnError:false (see clients/bongos-client), so the
|
|
505
|
+
// Promise.all in main() throws into the guard below. Wrong-instance (exit 3) and
|
|
506
|
+
// no-session (exit 2) are handled upstream in cliClient()/apiCall, and the
|
|
507
|
+
// builder-start skill routes those + the pre-install "bongos not found" case.
|
|
508
|
+
function isConnectionError(err) {
|
|
509
|
+
if (!err) return false;
|
|
510
|
+
const codes = ['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN', 'ETIMEDOUT', 'UND_ERR_CONNECT_TIMEOUT', 'UND_ERR_SOCKET'];
|
|
511
|
+
const code = err.code || (err.cause && err.cause.code) || '';
|
|
512
|
+
if (codes.includes(code)) return true;
|
|
513
|
+
const msg = `${err.message || ''} ${(err.cause && err.cause.message) || ''}`;
|
|
514
|
+
return /fetch failed|ECONNREFUSED|ENOTFOUND|EAI_AGAIN|network|socket hang up/i.test(msg);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// The guided "instance isn't running" card. Markdown (never leads with `<`), so
|
|
518
|
+
// the builder-start skill relays it verbatim even in --widget mode. Tailors the
|
|
519
|
+
// first step to whether deps are installed — a fresh clone needs `npm install`
|
|
520
|
+
// before the `bongos` CLI (which ships inside @bongos/core) even exists.
|
|
521
|
+
function instanceNotRunningCard({ origin, depsMissing } = {}) {
|
|
522
|
+
const out = [];
|
|
523
|
+
out.push(`**builder-start — this instance isn't reachable yet**`);
|
|
524
|
+
out.push('');
|
|
525
|
+
out.push(`I couldn't reach the Cloud Bongos instance${origin ? ` at \`${origin}\`` : ''}. On a freshly-cloned project that almost always just means it hasn't been brought up yet. To start it locally:`);
|
|
526
|
+
out.push('');
|
|
527
|
+
let n = 1;
|
|
528
|
+
if (depsMissing) {
|
|
529
|
+
out.push(`${n++}. \`npm install\` — installs the toolchain first (the \`bongos\` CLI ships inside \`@bongos/core\`, so nothing else runs until this does).`);
|
|
530
|
+
}
|
|
531
|
+
out.push(`${n++}. \`bongos dev\` — one command: starts Postgres, builds the tables, runs the server, and signs you in.`);
|
|
532
|
+
out.push(`${n++}. Re-run \`/builder-start\`.`);
|
|
533
|
+
out.push('');
|
|
534
|
+
out.push(`Meant to work on a *different* instance that's already running? Sign in to it with \`bongos login <url>\` first.`);
|
|
535
|
+
return out.join('\n');
|
|
536
|
+
}
|
|
537
|
+
function emitInstanceNotRunningCard(opts) {
|
|
538
|
+
console.log(instanceNotRunningCard(opts));
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
async function main() {
|
|
443
542
|
await requireSession();
|
|
444
543
|
const args = process.argv.slice(2);
|
|
445
544
|
const json = args.includes('--json');
|
|
@@ -479,16 +578,32 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
479
578
|
// endpoint fails, that widget degrades to "N/A" rather than killing
|
|
480
579
|
// /builder-start.
|
|
481
580
|
const api = await cliClient();
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
581
|
+
let me, r, closeRes, progressRes, costRes, recentRes, inboxRes, blockersRes;
|
|
582
|
+
try {
|
|
583
|
+
[me, r, closeRes, progressRes, costRes, recentRes, inboxRes, blockersRes] = await Promise.all([
|
|
584
|
+
api.me.getMe(),
|
|
585
|
+
api.tasks.getTasksClaimable({ query: claimableQuery }),
|
|
586
|
+
api.versions.getVersionsCloseSuggestions(),
|
|
587
|
+
api.public.getPublicProgress(),
|
|
588
|
+
api.public.getPublicCostSummary(),
|
|
589
|
+
api.public.getPublicRecentShipped(),
|
|
590
|
+
api.inbox.getInbox({ query: { status: 'open' } }),
|
|
591
|
+
api.blockers.getBlockers(),
|
|
592
|
+
]);
|
|
593
|
+
} catch (err) {
|
|
594
|
+
// A fresh-clone instance that was never brought up refuses the connection.
|
|
595
|
+
// Human modes get a guided bring-up card + clean exit; machine modes (--json,
|
|
596
|
+
// --hook) keep the throw so the autonomous runner still sees the failure.
|
|
597
|
+
if (isConnectionError(err) && !json && !hookMode) {
|
|
598
|
+
let depsMissing = false;
|
|
599
|
+
try { depsMissing = depsFinding({ repoRoot: process.cwd() }).level !== 'ok'; } catch (_) { /* best-effort */ }
|
|
600
|
+
let origin = '';
|
|
601
|
+
try { origin = new URL(API_BASE).origin; } catch (_) { origin = API_BASE || ''; }
|
|
602
|
+
emitInstanceNotRunningCard({ origin, depsMissing });
|
|
603
|
+
process.exit(0);
|
|
604
|
+
}
|
|
605
|
+
throw err;
|
|
606
|
+
}
|
|
492
607
|
// #766: the primer-read gate on the claimable endpoint was removed, so a
|
|
493
608
|
// newcomer no longer gets a 403 stage_required here. A generic stage_required
|
|
494
609
|
// (any future onboarding gate) still renders cleanly rather than crashing.
|
|
@@ -548,6 +663,13 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
548
663
|
? blockersRes.data.blockers.filter((b) => b.status === 'open' || !b.status).length
|
|
549
664
|
: null;
|
|
550
665
|
|
|
666
|
+
// ADR 0120 part 5: the confirmed tasks this builder owes a rebase on (they
|
|
667
|
+
// GATE new claims; the reward lands only on ship). Shared by every card form;
|
|
668
|
+
// already present verbatim in --json via me.data.needs_rebase_tasks below.
|
|
669
|
+
const needsRebaseTasks = me.ok && Array.isArray(me.data?.needs_rebase_tasks)
|
|
670
|
+
? me.data.needs_rebase_tasks
|
|
671
|
+
: [];
|
|
672
|
+
|
|
551
673
|
if (json) {
|
|
552
674
|
console.log(JSON.stringify(
|
|
553
675
|
{
|
|
@@ -602,6 +724,7 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
602
724
|
preferred,
|
|
603
725
|
filters: { version, discipline, fit },
|
|
604
726
|
readyToClose,
|
|
727
|
+
needsRebaseTasks,
|
|
605
728
|
}) + '\n');
|
|
606
729
|
return;
|
|
607
730
|
}
|
|
@@ -638,6 +761,15 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
638
761
|
}
|
|
639
762
|
}
|
|
640
763
|
|
|
764
|
+
// ADR 0120 part 5: the owed-rebase gate warning — rendered directly under the
|
|
765
|
+
// identity line and before the claimable table, since it BLOCKS new claims
|
|
766
|
+
// until the builder lands (rebase + re-ship) or releases the flagged tasks.
|
|
767
|
+
const rebaseLine = rebaseWarningMarkdown(needsRebaseTasks);
|
|
768
|
+
if (rebaseLine) {
|
|
769
|
+
console.log('');
|
|
770
|
+
console.log(rebaseLine);
|
|
771
|
+
}
|
|
772
|
+
|
|
641
773
|
// ambient status: one quiet line by default; the full widgets + context pack
|
|
642
774
|
// under --full.
|
|
643
775
|
if (full) {
|
|
@@ -708,7 +840,7 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
708
840
|
console.log('');
|
|
709
841
|
if (claimable.length) {
|
|
710
842
|
const cardRows = claimable.slice(0, CARD_ROWS);
|
|
711
|
-
console.log(claimableTable(cardRows));
|
|
843
|
+
console.log(claimableTable(cardRows, me.ok ? me.data?.reward : null));
|
|
712
844
|
const moreN = filtered.length - cardRows.length;
|
|
713
845
|
if (moreN > 0) {
|
|
714
846
|
console.log('');
|
|
@@ -761,6 +893,7 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
761
893
|
preferred,
|
|
762
894
|
filters: { version, discipline, fit },
|
|
763
895
|
readyToClose,
|
|
896
|
+
needsRebaseTasks,
|
|
764
897
|
})
|
|
765
898
|
: null;
|
|
766
899
|
const markdown = captureLog(emitMarkdownCard).join('\n');
|
|
@@ -776,7 +909,23 @@ function rankCrossDisciplineRecommendations(claimable, preferredDisciplines, lim
|
|
|
776
909
|
// body to stdout.
|
|
777
910
|
emitCardDirective('markdown');
|
|
778
911
|
emitMarkdownCard();
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Only auto-run when invoked directly (`node start.js …`); a `require()` (the
|
|
915
|
+
// unit test) imports the pure render helpers without executing the fetch flow —
|
|
916
|
+
// the claim.js precedent. The owed-rebase warning helpers (ADR 0120 part 5) are
|
|
917
|
+
// exported so they can be unit-tested without a live server.
|
|
918
|
+
if (require.main === module) {
|
|
919
|
+
main().catch((err) => {
|
|
920
|
+
console.error('fatal:', err);
|
|
921
|
+
process.exit(1);
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
module.exports = {
|
|
926
|
+
rebaseWarningModel,
|
|
927
|
+
rebaseWarningMarkdown,
|
|
928
|
+
rebaseWarningWidget,
|
|
929
|
+
isConnectionError,
|
|
930
|
+
instanceNotRunningCard,
|
|
931
|
+
};
|
package/scripts/gds/status.js
CHANGED
|
@@ -59,7 +59,7 @@ async function fetchProgress(version) {
|
|
|
59
59
|
let res;
|
|
60
60
|
try {
|
|
61
61
|
res = await fetch(`${API_BASE}/api/gds/versions/${encodeURIComponent(version)}/progress`, {
|
|
62
|
-
headers: { 'User-Agent': '
|
|
62
|
+
headers: { 'User-Agent': require('../../src/branding').userAgent() },
|
|
63
63
|
});
|
|
64
64
|
} catch (err) {
|
|
65
65
|
console.error(`status: could not reach ${API_BASE} (${err.message})`);
|
package/scripts/gds/triage.js
CHANGED
|
@@ -22,13 +22,10 @@
|
|
|
22
22
|
// Prompts per idea:
|
|
23
23
|
// [p]romote → create a backlog task, mark idea 'promoted',
|
|
24
24
|
// reviewed_at=now, promoted_to_task_id=<new>
|
|
25
|
-
// [m]erge with #N → mark idea 'merged' with
|
|
26
|
-
// (N is the canonical
|
|
27
|
-
// the
|
|
28
|
-
//
|
|
29
|
-
// target task's description via API — we just link
|
|
30
|
-
// via promoted_to_task_id. The body remains in the
|
|
31
|
-
// merged idea row for history.
|
|
25
|
+
// [m]erge with #N → mark idea 'merged' with merged_into_idea_id=N
|
|
26
|
+
// (N is the canonical IDEA to keep). The body remains
|
|
27
|
+
// on the merged idea row for history — there is no
|
|
28
|
+
// description-append vector, so nothing is copied to N.
|
|
32
29
|
// [d]iscard → mark idea 'discarded', reviewed_at=now
|
|
33
30
|
// [s]kip → no patch; idea surfaces again next triage
|
|
34
31
|
// [q]uit → exit early, print partial summary
|
|
@@ -269,7 +266,7 @@ async function main() {
|
|
|
269
266
|
const inline = ans.replace(/^m(\s|#)*/, '').trim();
|
|
270
267
|
if (inline) target = Number(inline.replace(/^#/, ''));
|
|
271
268
|
if (!Number.isFinite(target) || target <= 0) {
|
|
272
|
-
const a = (await prompt(rl, ' merge into
|
|
269
|
+
const a = (await prompt(rl, ' merge into idea #: ')).trim().replace(/^#/, '');
|
|
273
270
|
target = Number(a);
|
|
274
271
|
}
|
|
275
272
|
if (!Number.isFinite(target) || target <= 0) {
|
|
@@ -278,9 +275,13 @@ async function main() {
|
|
|
278
275
|
continue;
|
|
279
276
|
}
|
|
280
277
|
try {
|
|
278
|
+
// task 1002447 / migration core_195: the merge target belongs in
|
|
279
|
+
// merged_into_idea_id. This used to write promoted_to_task_id — a
|
|
280
|
+
// column that is REFERENCES tasks(id), so an idea id there either
|
|
281
|
+
// tripped the FK or silently named an unrelated task.
|
|
281
282
|
await patchIdea(idea.id, {
|
|
282
283
|
status: 'merged',
|
|
283
|
-
|
|
284
|
+
merged_into_idea_id: target,
|
|
284
285
|
reviewed_at: new Date().toISOString(),
|
|
285
286
|
});
|
|
286
287
|
summary.merged++;
|