@bongos/core 1.17.0
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 +5727 -0
- package/.claude/skills/blocker-review/SKILL.md +91 -0
- package/.claude/skills/blocker-solve/SKILL.md +96 -0
- package/.claude/skills/builder-backup/SKILL.md +54 -0
- package/.claude/skills/builder-box/SKILL.md +45 -0
- package/.claude/skills/builder-claim/SKILL.md +76 -0
- package/.claude/skills/builder-connect/SKILL.md +59 -0
- package/.claude/skills/builder-cost/SKILL.md +47 -0
- package/.claude/skills/builder-end/SKILL.md +81 -0
- package/.claude/skills/builder-exit/SKILL.md +88 -0
- package/.claude/skills/builder-key/SKILL.md +40 -0
- package/.claude/skills/builder-reauth/SKILL.md +50 -0
- package/.claude/skills/builder-redteam/SKILL.md +109 -0
- package/.claude/skills/builder-release/SKILL.md +41 -0
- package/.claude/skills/builder-setup/SKILL.md +62 -0
- package/.claude/skills/builder-ship/SKILL.md +79 -0
- package/.claude/skills/builder-stage/SKILL.md +51 -0
- package/.claude/skills/builder-start/SKILL.md +46 -0
- package/.claude/skills/close-box/SKILL.md +43 -0
- package/.claude/skills/design-sync/SKILL.md +69 -0
- package/.claude/skills/dev/SKILL.md +49 -0
- package/.claude/skills/feedback/SKILL.md +32 -0
- package/.claude/skills/figma-design-sync/SKILL.md +74 -0
- package/.claude/skills/goal-review/SKILL.md +89 -0
- package/.claude/skills/idea-triage/SKILL.md +144 -0
- package/.claude/skills/ideate/SKILL.md +82 -0
- package/.claude/skills/merge-mode/SKILL.md +169 -0
- package/.claude/skills/new-project/SKILL.md +108 -0
- package/.claude/skills/otb-character-review/SKILL.md +71 -0
- package/.claude/skills/otb-design-review/SKILL.md +47 -0
- package/.claude/skills/otb-feedback-capture/SKILL.md +45 -0
- package/.claude/skills/otb-figma-sync/SKILL.md +54 -0
- package/.claude/skills/otb-tile-generate/SKILL.md +45 -0
- package/.claude/skills/paint/SKILL.md +70 -0
- package/.claude/skills/planning-session/SKILL.md +299 -0
- package/.claude/skills/priority-session/SKILL.md +134 -0
- package/.claude/skills/read-session-export/SKILL.md +58 -0
- package/.claude/skills/recall/SKILL.md +52 -0
- package/.claude/skills/session-handoff/SKILL.md +46 -0
- package/.claude/skills/status/SKILL.md +33 -0
- package/.devcontainer/Dockerfile +69 -0
- package/.devcontainer/README.md +73 -0
- package/.devcontainer/devcontainer-lock.json +19 -0
- package/.devcontainer/devcontainer.json +93 -0
- package/.devcontainer/healthcheck.sh +84 -0
- package/.devcontainer/init-firewall.sh +198 -0
- package/.devcontainer/post-create.sh +153 -0
- package/.dockerignore +36 -0
- package/.env.local.example +32 -0
- package/.gitattributes +83 -0
- package/.gitignore +91 -0
- package/CLAUDE.md +242 -0
- package/CODE_OF_CONDUCT.md +46 -0
- package/CONTRIBUTING.md +51 -0
- package/Dockerfile +46 -0
- package/GOVERNANCE.md +44 -0
- package/LICENSE +661 -0
- package/README.md +88 -0
- package/bin/bongos.js +222 -0
- package/clients/bongos-client/README.md +48 -0
- package/clients/bongos-client/bongos-client.global.js +617 -0
- package/clients/bongos-client/examples/hello-world.mjs +62 -0
- package/clients/bongos-client/index.cjs +619 -0
- package/clients/bongos-client/index.d.ts +793 -0
- package/clients/bongos-client/index.mjs +614 -0
- package/clients/bongos-client/package.json +32 -0
- package/config/branding.neutral.json +60 -0
- package/config/design-tokens.neutral.json +51 -0
- package/config/design-tokens.schema.json +96 -0
- package/config/modules.neutral.json +9 -0
- package/docker-compose.yml +52 -0
- package/docker-entrypoint.sh +30 -0
- package/docs/adr/0001-stack-choice-single-vps.md +45 -0
- package/docs/adr/0002-digitalocean-over-hetzner.md +27 -0
- package/docs/adr/0003-cloudflare-origin-cert-over-letsencrypt.md +35 -0
- package/docs/adr/0004-amazonprimea-name-and-trademark-acceptance.md +45 -0
- package/docs/adr/0005-invisible-other-players-in-v1.md +37 -0
- package/docs/adr/0006-singleton-worldroom-plus-queueroom.md +30 -0
- package/docs/adr/0007-persistent-identity-via-localstorage-uuid.md +31 -0
- package/docs/adr/0008-family-based-tile-generation.md +86 -0
- package/docs/adr/0008-google-chat-oauth-user-auth.md +37 -0
- package/docs/adr/0009-autotile-architecture.md +181 -0
- package/docs/adr/0010-pms-architecture.md +70 -0
- package/docs/adr/0011-terrain-id-rendering-model.md +174 -0
- package/docs/adr/0012-ground-object-cell-split.md +208 -0
- package/docs/adr/0013-paths-as-object-overlays-with-autotile-dispatch.md +158 -0
- package/docs/adr/0014-families-canonical-over-vocabulary.md +103 -0
- package/docs/adr/0015-task-dependencies-and-auto-promotion.md +125 -0
- package/docs/adr/0016-trust-boundary-server-enforced-permissions.md +132 -0
- package/docs/adr/0017-code-simplification-and-repo-cleanliness.md +74 -0
- package/docs/adr/0018-three-rank-model-goes-live.md +97 -0
- package/docs/adr/0019-red-team-bounty-payout-table.md +52 -0
- package/docs/adr/0020-security-model-public-stub.md +70 -0
- package/docs/adr/0021-per-builder-skill-model-preferences.md +99 -0
- package/docs/adr/0022-secrets-policy.md +124 -0
- package/docs/adr/0023-kind-multipliers-and-idea-bonus.md +118 -0
- package/docs/adr/0024-cloneable-repo-local-first-memory.md +277 -0
- package/docs/adr/0024-multi-agent-system-architecture.md +125 -0
- package/docs/adr/0025-offsite-backup-vendor-digitalocean-spaces.md +59 -0
- package/docs/adr/0025-structured-criterion-task-link.md +44 -0
- package/docs/adr/0026-bfg-memory-hygiene-and-cross-builder-learning.md +117 -0
- package/docs/adr/0027-bfg-session-inefficiency-evaluator.md +170 -0
- package/docs/adr/0028-honest-llm-spend-accounting.md +109 -0
- package/docs/adr/0029-status-page-outage-resilience.md +59 -0
- package/docs/adr/0030-builders-hall-live-updates.md +59 -0
- package/docs/adr/0031-cloud-dev-environments-for-builders.md +222 -0
- package/docs/adr/0032-discord-mirror-of-gds.md +50 -0
- package/docs/adr/0033-discord-bot-service-principal.md +82 -0
- package/docs/adr/0034-thetes-graduated-newcomer-rank.md +53 -0
- package/docs/adr/0035-builder-onboarding-three-paths.md +128 -0
- package/docs/adr/0036-builders-subdomain-and-ui-reorg.md +40 -0
- package/docs/adr/0037-discord-channel-management.md +51 -0
- package/docs/adr/0038-chromebook-ttyd-cloudflare-tunnel.md +111 -0
- package/docs/adr/0039-setup-first-onboarding-ux.md +49 -0
- package/docs/adr/0040-remote-control-default-browser-onramp.md +47 -0
- package/docs/adr/0041-temporary-grader-bypass-killswitch.md +40 -0
- package/docs/adr/0042-builder-self-deploy-ci-auto-merge.md +82 -0
- package/docs/adr/0043-git-ssh-trust-boundary-and-rank-floor-on-permission-paths.md +74 -0
- package/docs/adr/0044-mediterranean-palette-replacement.md +73 -0
- package/docs/adr/0044-per-box-live-game-preview.md +57 -0
- package/docs/adr/0045-devbox-desktop-app.md +133 -0
- package/docs/adr/0046-sandbox-first-review-gate.md +72 -0
- package/docs/adr/0047-discord-bugs-intake-anti-abuse.md +36 -0
- package/docs/adr/0048-works-in-progress-ia-split.md +32 -0
- package/docs/adr/0049-split-parallel-safety-contract.md +46 -0
- package/docs/adr/0050-device-flow-admission-invite-gated-by-default.md +43 -0
- package/docs/adr/0051-full-session-transcript-corpus.md +57 -0
- package/docs/adr/0052-sandbox-for-everyone-game-only-preview.md +70 -0
- package/docs/adr/0053-scoped-dev-box-session.md +55 -0
- package/docs/adr/0054-session-token-reward-cost-plus.md +63 -0
- package/docs/adr/0055-server-mediated-branch-publish.md +47 -0
- package/docs/adr/0056-prod-deploy-script-mirror-and-healthcheck-retry.md +62 -0
- package/docs/adr/0057-container-cost-ledger.md +28 -0
- package/docs/adr/0057-discord-archon-approval-channels.md +64 -0
- package/docs/adr/0058-automatic-gate-surface-gatekeeper.md +64 -0
- package/docs/adr/0059-single-approval-remove-devbox-approval-gate.md +37 -0
- package/docs/adr/0060-gds-retrieval-layer.md +97 -0
- package/docs/adr/0061-context-layer-decomposition.md +61 -0
- package/docs/adr/0062-medusa-instance-model-decoupling.md +107 -0
- package/docs/adr/0063-generated-repo-map-symbol-skeleton.md +44 -0
- package/docs/adr/0064-rename-medusa-to-cloud-bongos.md +49 -0
- package/docs/adr/0065-agpl-nonprofit-ai-first-governance.md +69 -0
- package/docs/adr/0066-generated-file-map-sections.md +51 -0
- package/docs/adr/0067-session-start-fast-forward-pull.md +43 -0
- package/docs/adr/0068-shared-art-key-for-newcomers.md +38 -0
- package/docs/adr/0069-hall-live-channel-sse-decouple.md +35 -0
- package/docs/adr/0070-deterministic-session-card-delivery.md +44 -0
- package/docs/adr/0071-box-confirm-before-destroyed-and-drift-reconcile.md +59 -0
- package/docs/adr/0072-bongos-app-mac-signed-first-windows-deferred.md +35 -0
- package/docs/adr/0072-dev-box-code-staleness-visibility.md +39 -0
- package/docs/adr/0073-builder-needs-signal-and-byok-gemini-key.md +64 -0
- package/docs/adr/0073-secrets-scan-exclude-uri-detector.md +37 -0
- package/docs/adr/0074-memory-map-stays-light.md +32 -0
- package/docs/adr/0075-per-system-cost-attribution.md +37 -0
- package/docs/adr/0076-in-session-deterministic-compaction.md +58 -0
- package/docs/adr/0077-content-addressed-llm-cache.md +32 -0
- package/docs/adr/0078-deterministic-first-cron.md +48 -0
- package/docs/adr/0079-value-gated-autonomous-engagement.md +39 -0
- package/docs/adr/0080-llm-cache-api-transport-and-trust-model.md +46 -0
- package/docs/adr/0081-tool-agnostic-design-layer.md +62 -0
- package/docs/adr/0082-productized-key-storage-provisioning.md +32 -0
- package/docs/adr/0082-server-side-merge-conflict-auto-resolution.md +55 -0
- package/docs/adr/0083-modular-architecture-strangler-build-plan.md +143 -0
- package/docs/adr/0084-auto-derived-per-task-rank-floor.md +86 -0
- package/docs/adr/0085-remove-default-per-builder-spend-cap.md +39 -0
- package/docs/adr/0086-goal-scoped-work-hierarchy.md +123 -0
- package/docs/adr/0087-bongos-app-architecture-and-handoff-contract.md +49 -0
- package/docs/adr/0087-compete-on-governance-not-tooling-cursor.md +65 -0
- package/docs/adr/0088-consistent-character-generative-animation.md +169 -0
- package/docs/adr/0089-modular-multi-model-adversarial-grader.md +179 -0
- package/docs/adr/0090-metic-task-authoring.md +73 -0
- package/docs/adr/0091-bounding-the-kernel-and-db-carve.md +106 -0
- package/docs/adr/0092-hosting-module-and-on-prem-target.md +117 -0
- package/docs/adr/0093-tranche-2-core-carve-sequence.md +72 -0
- package/docs/adr/0094-repo-atlas-self-drawing-codebase-map.md +49 -0
- package/docs/adr/0095-borrowed-memory-and-retrieval-concepts.md +65 -0
- package/docs/adr/0095-cross-agent-context-management.md +58 -0
- package/docs/adr/0096-require-reward-before-workable.md +209 -0
- package/docs/adr/0097-one-active-claim-per-session-and-worktree-binding.md +46 -0
- package/docs/adr/0097-retroactive-reward-backfill.md +124 -0
- package/docs/adr/0098-public-mirror-publish-manifest.md +92 -0
- package/docs/adr/0099-delayed-redacted-mirror-export.md +55 -0
- package/docs/adr/0100-two-repo-instance-model.md +60 -0
- package/docs/adr/0101-goal-hierarchy-phase-5-judge-membership-reward.md +90 -0
- package/docs/adr/0102-finish-bounding-the-kernel.md +36 -0
- package/docs/adr/0103-core-first-extraction-cloud-bongos-trunk.md +70 -0
- package/docs/adr/0103-gdsv4-bongos-consolidation.md +28 -0
- package/docs/adr/0104-trust-gds-api-channel-in-auto-mode.md +42 -0
- package/docs/adr/0105-instance-seed-migrations-out-of-core.md +47 -0
- package/docs/adr/0106-goal-owner-manager-authority.md +84 -0
- package/docs/adr/0107-module-upstreaming-contribution-to-core-catalog.md +83 -0
- package/docs/adr/0108-instance-composition-configurable-root.md +87 -0
- package/docs/adr/0109-self-describing-openapi-and-hosted-docs.md +44 -0
- package/docs/adr/0110-untrack-whole-file-generated-nav-docs.md +49 -0
- package/docs/adr/0111-instance-hosting-provisioning-module.md +135 -0
- package/docs/adr/0112-private-goals-invitations-join-requests.md +72 -0
- package/docs/adr/0113-sandbox-studio-descope-superseded-by-0044-0052.md +41 -0
- package/docs/adr/0114-instance-docs-discovery-contract.md +32 -0
- package/docs/adr/0115-scheduled-routines-portability.md +31 -0
- package/docs/adr/0116-api-error-envelope-and-code-taxonomy.md +62 -0
- package/docs/adr/0117-api-versioning-and-deprecation-policy.md +50 -0
- package/docs/adr/0118-api-contract-source-of-truth-code-first.md +47 -0
- package/docs/adr/0119-api-pagination-contract.md +34 -0
- package/docs/adr/0120-pay-on-land-and-builder-owned-rebase-gate.md +108 -0
- package/docs/adr/0121-greenfield-vs-brownfield-onboarding-adopt-existing-repo.md +97 -0
- package/docs/adr/0122-onboarding-diagram-renders-deploy-rendered-off-git.md +43 -0
- package/docs/adr/0123-box-idle-sweep-autosave-before-destroy.md +36 -0
- package/docs/adr/0124-typed-api-response-bodies.md +37 -0
- package/docs/adr/0125-control-plane-scaffolds-standalone-instance-repo.md +36 -0
- package/docs/adr/0126-dedicated-cloudbongos-control-plane-droplet.md +30 -0
- package/docs/adr/0127-cross-box-fleet-observability.md +64 -0
- package/docs/adr/0128-provisioning-runner-privilege-and-db-auth-model.md +46 -0
- package/docs/adr/0129-cloudbongos-control-plane-pull-deploy.md +34 -0
- package/docs/adr/0130-provision-remote-exec-over-ssh.md +61 -0
- package/docs/adr/0131-rank-scoped-skill-visibility.md +47 -0
- package/docs/adr/0132-cohost-fleet-control-plane-migration.md +54 -0
- package/docs/adr/0133-github-app-manifest-onboarding-signin.md +42 -0
- package/docs/adr/0134-private-first-npm-distribution.md +38 -0
- package/docs/adr/README.md +208 -0
- package/docs/api/openapi.json +13720 -0
- package/docs/api-reference.md +437 -0
- package/docs/architecture.md +244 -0
- package/docs/branding-contract.md +66 -0
- package/docs/branding-fill-prompt.md +25 -0
- package/docs/canonical-permissions.md +241 -0
- package/docs/design/container-exterior-tiles.md +49 -0
- package/docs/design/container-exterior.md +81 -0
- package/docs/design/container-interior.md +77 -0
- package/docs/design/modular-architecture/00-research-report.md +107 -0
- package/docs/design/modular-architecture/01-architecture.md +125 -0
- package/docs/design/modular-architecture/02-module-map.md +116 -0
- package/docs/design/modular-architecture/03-builder-flows.md +104 -0
- package/docs/design/modular-architecture/04-module-lifecycle.md +62 -0
- package/docs/design/modular-architecture/README.md +27 -0
- package/docs/design/vanilla-hall-ui-redesign-scope.md +284 -0
- package/docs/design/world-map-scroll.md +41 -0
- package/docs/design-contract.md +320 -0
- package/docs/file-map.md +418 -0
- package/docs/handoff-template.md +92 -0
- package/docs/modules-contract.md +293 -0
- package/docs/onboarding/browser-terminal-guide.md +73 -0
- package/docs/onboarding/diagrams/01-task-lifecycle.mmd +28 -0
- package/docs/onboarding/diagrams/02-rank-ladder.mmd +54 -0
- package/docs/onboarding/diagrams/03-drachmae-karma.mmd +37 -0
- package/docs/onboarding/diagrams/04-architecture.mmd +51 -0
- package/docs/onboarding/diagrams/05-versioning.mmd +29 -0
- package/docs/onboarding/diagrams/README.md +94 -0
- package/docs/onboarding/diagrams/assertions.json +170 -0
- package/docs/onboarding/diagrams/puppeteer-config.json +1 -0
- package/docs/onboarding/diagrams/render-config.json +9 -0
- package/docs/onboarding/drachmae-and-karma.md +178 -0
- package/docs/onboarding/primer.md +202 -0
- package/docs/project-context.template.md +67 -0
- package/docs/recipes/README.md +35 -0
- package/docs/recipes/audit-replay.md +100 -0
- package/docs/recipes/bongos-cli-release.md +66 -0
- package/docs/recipes/builder-box-lifecycle.md +152 -0
- package/docs/recipes/claude-design-loop.md +143 -0
- package/docs/recipes/claude-gemini-bongos-doors.md +155 -0
- package/docs/recipes/cloudbongos-staging-gate.md +139 -0
- package/docs/recipes/cloudbongos-standup.md +111 -0
- package/docs/recipes/devbox-app-release.md +93 -0
- package/docs/recipes/devbox-app-windows-test.md +128 -0
- package/docs/recipes/failed-ship-recovery-proof.md +102 -0
- package/docs/recipes/figma-design-loop.md +129 -0
- package/docs/recipes/gds-db-backup.md +255 -0
- package/docs/recipes/instance-deploy.md +37 -0
- package/docs/recipes/managed-settings-remote-control.md +416 -0
- package/docs/recipes/memory-backup.md +71 -0
- package/docs/recipes/memory-sync-conflicts.md +98 -0
- package/docs/recipes/multi-builder-merge.md +78 -0
- package/docs/recipes/ops-gotchas.md +212 -0
- package/docs/recipes/overnight-builder.md +53 -0
- package/docs/recipes/packaging-the-core.md +49 -0
- package/docs/recipes/parallel-load-results-2026-05-30.md +63 -0
- package/docs/recipes/parallel-load-test.md +32 -0
- package/docs/recipes/pixel-art-pipeline.md +411 -0
- package/docs/recipes/private-npm-distribution.md +79 -0
- package/docs/recipes/search-index-ingestion.md +67 -0
- package/docs/recipes/self-host.md +60 -0
- package/docs/recipes/ship-and-regrade.md +72 -0
- package/docs/recipes/staging-data.md +50 -0
- package/docs/recipes/staging-environment.md +215 -0
- package/docs/recipes/upgrading-the-core.md +58 -0
- package/docs/research/cursor-competitive-analysis.md +255 -0
- package/docs/research/llm-model-agnostic-and-cheaper-grader.md +227 -0
- package/migrations/003_pms.sql +284 -0
- package/migrations/004_pms_cost_idempotency.sql +13 -0
- package/migrations/005_pms_smoke_filter.sql +44 -0
- package/migrations/006_pms_v2.sql +378 -0
- package/migrations/007_pms_v2_hierarchy_trigger.sql +59 -0
- package/migrations/008_pms_v2_migration_allocator.sql +27 -0
- package/migrations/009_pms_v2_blockers_table.sql +68 -0
- package/migrations/010_uptime.sql +29 -0
- package/migrations/011_backfill_v2_v3_done_when.sql +20 -0
- package/migrations/012_pms_v2_task_lifecycle_states.sql +82 -0
- package/migrations/013_claim_locking.sql +22 -0
- package/migrations/014_pms_task_discipline.sql +86 -0
- package/migrations/015_pms_estimation_calibration.sql +140 -0
- package/migrations/016_pms_task_grades.sql +60 -0
- package/migrations/017_version_progress_exclude_abandoned.sql +49 -0
- package/migrations/019_rename_pms_v3_to_gds_v3.sql +65 -0
- package/migrations/020_task_dependencies.sql +99 -0
- package/migrations/021_v3_renumber_and_deps.sql +224 -0
- package/migrations/022_v3_reconcile_dep_gated_status.sql +41 -0
- package/migrations/023_pms_rank.sql +30 -0
- package/migrations/025_builder_exit_status.sql +15 -0
- package/migrations/027_builders_preferred_disciplines.sql +46 -0
- package/migrations/028_tasks_parallel_safe.sql +71 -0
- package/migrations/029_rank_three_live.sql +32 -0
- package/migrations/030_vulnerability_reports.sql +61 -0
- package/migrations/031_reward_simplification.sql +57 -0
- package/migrations/032_repo_health_snapshots.sql +56 -0
- package/migrations/033_audit_log.sql +64 -0
- package/migrations/034_lifecycle_breakdown_leaf_only.sql +62 -0
- package/migrations/035_auth_token_hygiene.sql +66 -0
- package/migrations/037_builder_skill_model_prefs.sql +44 -0
- package/migrations/038_task_override_requests.sql +51 -0
- package/migrations/039_newcomer_friendly_column.sql +124 -0
- package/migrations/040_builder_karma.sql +58 -0
- package/migrations/041_kind_multipliers_and_idea_bonus.sql +42 -0
- package/migrations/042_criterion_proposal_workflow.sql +78 -0
- package/migrations/043_builder_onboarding_observability.sql +66 -0
- package/migrations/044_tasks_requires_rank.sql +97 -0
- package/migrations/045_builder_onboarding_state.sql +147 -0
- package/migrations/046_cost_log_builder_attribution.sql +42 -0
- package/migrations/054_builder_memory.sql +108 -0
- package/migrations/055_task_criteria.sql +90 -0
- package/migrations/058_peer_votes.sql +41 -0
- package/migrations/059_onboarding_pick_disciplines.sql +59 -0
- package/migrations/060_access_requests.sql +46 -0
- package/migrations/061_backfill_override_ship_attribution.sql +29 -0
- package/migrations/062_session_records.sql +34 -0
- package/migrations/063_session_records_tool_errors_idx.sql +11 -0
- package/migrations/064_grade_attempts.sql +18 -0
- package/migrations/065_bfg_principal.sql +58 -0
- package/migrations/066_live_notify_triggers.sql +69 -0
- package/migrations/067_builder_boxes.sql +117 -0
- package/migrations/067_discord_bot_foundation.sql +69 -0
- package/migrations/068_thetes_requires_rank.sql +27 -0
- package/migrations/069_builder_ssh_keys.sql +66 -0
- package/migrations/070_box_intents.sql +101 -0
- package/migrations/071_box_first_provision_approval.sql +46 -0
- package/migrations/072_onboarding_ship_three_remove_primer.sql +80 -0
- package/migrations/073_box_terminal_access.sql +46 -0
- package/migrations/075_builder_sound_prefs.sql +28 -0
- package/migrations/078_box_claude_active.sql +22 -0
- package/migrations/079_box_first_connected_at.sql +20 -0
- package/migrations/081_tasks_needs_migration.sql +34 -0
- package/migrations/084_tasks_security_sensitive.sql +24 -0
- package/migrations/085_security_engagement_docs.sql +34 -0
- package/migrations/086_rename_disciplines.sql +125 -0
- package/migrations/088_builders_anthropic_link.sql +28 -0
- package/migrations/089_builders_monthly_budget.sql +19 -0
- package/migrations/090_box_scoped_sessions.sql +38 -0
- package/migrations/091_session_token_reward.sql +44 -0
- package/migrations/093_tasks_sandbox_review.sql +22 -0
- package/migrations/102_remove_box_first_provision_approval.sql +58 -0
- package/migrations/103_search_chunks.sql +90 -0
- package/migrations/104_builder_box_blocked.sql +34 -0
- package/migrations/105_box_host_keys.sql +35 -0
- package/migrations/111_medusa_customer0_framing.sql +35 -0
- package/migrations/112_drop_track_check.sql +25 -0
- package/migrations/113_merge_lease.sql +16 -0
- package/migrations/114_cloudbongos_rename_live_strings.sql +32 -0
- package/migrations/118_currency_label_decoupling.sql +23 -0
- package/migrations/119_builder_behavior_prefs.sql +31 -0
- package/migrations/121_box_code_version.sql +37 -0
- package/migrations/122_builder_gemini_key.sql +30 -0
- package/migrations/123_cost_log_tiers.sql +33 -0
- package/migrations/124_cost_baseline.sql +45 -0
- package/migrations/125_llm_cache.sql +54 -0
- package/migrations/126_autonomy_runs.sql +33 -0
- package/migrations/143_cost_calibration.sql +63 -0
- package/migrations/145_backfill_task_requires_rank.sql +84 -0
- package/migrations/160_goal_tier.sql +88 -0
- package/migrations/163_polymorphic_dependencies.sql +187 -0
- package/migrations/164_event_sound_prefs.sql +20 -0
- package/migrations/165_task_module_key.sql +15 -0
- package/migrations/171_claims_published_head_sha.sql +24 -0
- package/migrations/174_close_orphaned_claims_on_terminal_tasks.sql +30 -0
- package/migrations/175_task_grades_diff_hash.sql +9 -0
- package/migrations/176_promotion_respects_open_blockers.sql +58 -0
- package/migrations/176_ui_discipline.sql +40 -0
- package/migrations/177_require_reward_before_workable.sql +76 -0
- package/migrations/178_reward_gate_auto_assign_revert_autopromote.sql +61 -0
- package/migrations/179_search_chunk_usefulness.sql +33 -0
- package/migrations/180_one_active_claim_per_session.sql +54 -0
- package/migrations/181_cost_log_skill_name.sql +33 -0
- package/migrations/184_claim_release_requested.sql +25 -0
- package/migrations/185_module_upstreaming_goal_wiring.sql +59 -0
- package/migrations/187_goal_sort_order.sql +30 -0
- package/migrations/187_tasks_kind_check_add_verify.sql +21 -0
- package/migrations/README.md +88 -0
- package/migrations/core_188_goal_visibility_and_membership_requests.sql +71 -0
- package/migrations/core_189_core_upgrades_ledger.sql +37 -0
- package/migrations/core_189_credit_log_task_id_index.sql +19 -0
- package/migrations/core_190_rebuild_claimable_task_views.sql +71 -0
- package/migrations/instance/018_pms_v3_planning_seed.sql +131 -0
- package/migrations/instance/080_gds_v4_planning_seed.sql +75 -0
- package/migrations/instance/110_medusa_planning_seed.sql +70 -0
- package/migrations/instance/120_bongos_v1_planning_seed.sql +69 -0
- package/migrations/instance/144_bongos_v1_module_system_criterion.sql +26 -0
- package/migrations/instance/159_bongos_v1_goal_hierarchy_criterion.sql +29 -0
- package/migrations/instance/172_v2_world_planning_seed.sql +163 -0
- package/migrations/instance/173_bongos_v1_c7_core_modularized.sql +33 -0
- package/migrations/instance/182_gdsv4_bongos_consolidation.sql +132 -0
- package/migrations/instance/183_gdsv4_carryover_themed_goals.sql +116 -0
- package/migrations/instance/186_bongos_v1_governance_planning_seed.sql +69 -0
- package/modules/autonomy/CLAUDE.md +49 -0
- package/modules/autonomy/db.js +50 -0
- package/modules/autonomy/module.json +13 -0
- package/modules/autonomy/pollers/routine-timers.js +146 -0
- package/modules/autonomy/routes/autonomy.js +37 -0
- package/modules/builder-settings/CLAUDE.md +58 -0
- package/modules/builder-settings/builder-needs.js +115 -0
- package/modules/builder-settings/db.js +168 -0
- package/modules/builder-settings/display-name.js +84 -0
- package/modules/builder-settings/event-sound-prefs.js +169 -0
- package/modules/builder-settings/interaction-prefs.js +201 -0
- package/modules/builder-settings/model-alloc-prefs.js +147 -0
- package/modules/builder-settings/module.json +10 -0
- package/modules/builder-settings/render-prefs.js +103 -0
- package/modules/builder-settings/routes/settings.js +417 -0
- package/modules/builder-settings/settings.js +52 -0
- package/modules/builder-settings/skill-prefs.js +196 -0
- package/modules/builder-settings/sound-prefs.js +178 -0
- package/modules/builder-settings/wandering-prefs.js +282 -0
- package/modules/dev-box/CLAUDE.md +38 -0
- package/modules/dev-box/box-access.js +275 -0
- package/modules/dev-box/box-credential.js +94 -0
- package/modules/dev-box/box-onboard.js +486 -0
- package/modules/dev-box/boxes.js +842 -0
- package/modules/dev-box/db.js +39 -0
- package/modules/dev-box/module.json +14 -0
- package/modules/dev-box/routes/box.js +977 -0
- package/modules/discord/CLAUDE.md +50 -0
- package/modules/discord/auth.js +54 -0
- package/modules/discord/bug-attachments.js +210 -0
- package/modules/discord/db.js +96 -0
- package/modules/discord/discord-approvals.js +145 -0
- package/modules/discord/discord-audit.js +29 -0
- package/modules/discord/discord-bot.js +545 -0
- package/modules/discord/discord-bugs.js +257 -0
- package/modules/discord/discord-channels.js +412 -0
- package/modules/discord/discord-inbound.js +147 -0
- package/modules/discord/discord-message-buffer.js +54 -0
- package/modules/discord/discord-reaction.js +186 -0
- package/modules/discord/discord-role-sync.js +318 -0
- package/modules/discord/module.json +14 -0
- package/modules/discord/pollers/discord-bot.js +19 -0
- package/modules/discord/routes/bug-attachments.js +44 -0
- package/modules/discord/routes/discord.js +102 -0
- package/modules/discord/ship-broadcast.js +78 -0
- package/modules/discord/webhook.js +74 -0
- package/modules/economy/CLAUDE.md +48 -0
- package/modules/economy/achievements.js +594 -0
- package/modules/economy/cost-classify.js +331 -0
- package/modules/economy/cost-summary-shape.js +90 -0
- package/modules/economy/cost.js +438 -0
- package/modules/economy/credits.js +430 -0
- package/modules/economy/migrations/economy_001_fix_gds_shipper_description.sql +91 -0
- package/modules/economy/module.json +10 -0
- package/modules/economy/reward.js +61 -0
- package/modules/economy/routes/cost.js +97 -0
- package/modules/economy/routes/leaderboard.js +26 -0
- package/modules/economy/routes/reward.js +42 -0
- package/modules/economy/streak.js +285 -0
- package/modules/grading/CLAUDE.md +42 -0
- package/modules/grading/db.js +39 -0
- package/modules/grading/grader-rubric.json +151 -0
- package/modules/grading/grader-workers/efficiency.js +213 -0
- package/modules/grading/grader-workers/extract-json.js +80 -0
- package/modules/grading/grader-workers/fence.js +100 -0
- package/modules/grading/grader-workers/hacker.js +239 -0
- package/modules/grading/grader-workers/index.js +183 -0
- package/modules/grading/grader-workers/narc.js +207 -0
- package/modules/grading/grader-workers/quality.js +198 -0
- package/modules/grading/grader-workers/rubric.js +20 -0
- package/modules/grading/grader-workers/worker-prompt.js +89 -0
- package/modules/grading/grader-workers/worker-verdict.js +50 -0
- package/modules/grading/grader.js +1790 -0
- package/modules/grading/module.json +12 -0
- package/modules/grading/routes/grade.js +51 -0
- package/modules/hall-ui/CLAUDE.md +61 -0
- package/modules/hall-ui/module.json +14 -0
- package/modules/hall-ui/public/atlas.html +180 -0
- package/modules/hall-ui/public/atlas.js +336 -0
- package/modules/hall-ui/public/box-panel.js +423 -0
- package/modules/hall-ui/public/brand-apply.js +117 -0
- package/modules/hall-ui/public/builders.js +3028 -0
- package/modules/hall-ui/public/chime.wav +0 -0
- package/modules/hall-ui/public/copy-on-click.js +174 -0
- package/modules/hall-ui/public/cursors/arrow.png +0 -0
- package/modules/hall-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier-out.png +0 -0
- package/modules/hall-ui/public/cursors/magnifier.png +0 -0
- package/modules/hall-ui/public/diagram-viewer.css +125 -0
- package/modules/hall-ui/public/diagram-viewer.js +330 -0
- package/modules/hall-ui/public/diagrams.html +113 -0
- package/modules/hall-ui/public/dom-utils.js +212 -0
- package/modules/hall-ui/public/drachmae.html +68 -0
- package/modules/hall-ui/public/drachmae.js +136 -0
- package/modules/hall-ui/public/gate.html +143 -0
- package/modules/hall-ui/public/gate.js +228 -0
- package/modules/hall-ui/public/goals-page.js +1297 -0
- package/modules/hall-ui/public/goals.html +376 -0
- package/modules/hall-ui/public/goals.js +119 -0
- package/modules/hall-ui/public/hall-widgets.js +189 -0
- package/modules/hall-ui/public/harbor.html +167 -0
- package/modules/hall-ui/public/harbor.js +335 -0
- package/modules/hall-ui/public/index.html +116 -0
- package/modules/hall-ui/public/instances-panel.js +172 -0
- package/modules/hall-ui/public/md-reader.js +234 -0
- package/modules/hall-ui/public/modules.html +119 -0
- package/modules/hall-ui/public/modules.js +154 -0
- package/modules/hall-ui/public/new-project-wizard.js +186 -0
- package/modules/hall-ui/public/not-ready.html +48 -0
- package/modules/hall-ui/public/pair.html +119 -0
- package/modules/hall-ui/public/pair.js +132 -0
- package/modules/hall-ui/public/primer.css +404 -0
- package/modules/hall-ui/public/primer.html +85 -0
- package/modules/hall-ui/public/primer.js +641 -0
- package/modules/hall-ui/public/profile.html +85 -0
- package/modules/hall-ui/public/profile.js +236 -0
- package/modules/hall-ui/public/ranks.html +69 -0
- package/modules/hall-ui/public/ranks.js +206 -0
- package/modules/hall-ui/public/roadmap.html +209 -0
- package/modules/hall-ui/public/roadmap.js +375 -0
- package/modules/hall-ui/public/sessions.html +92 -0
- package/modules/hall-ui/public/sessions.js +222 -0
- package/modules/hall-ui/public/settings.html +640 -0
- package/modules/hall-ui/public/settings.js +1219 -0
- package/modules/hall-ui/public/shell.js +495 -0
- package/modules/hall-ui/public/style.css +1748 -0
- package/modules/hall-ui/public/task-detail.js +253 -0
- package/modules/hall-ui/public/task.html +83 -0
- package/modules/hall-ui/public/task.js +326 -0
- package/modules/hall-ui/public/watch.html +333 -0
- package/modules/hall-ui/public/watch.js +859 -0
- package/modules/hall-ui/public/work.html +469 -0
- package/modules/hall-ui/public/work.js +1292 -0
- package/modules/ideas/CLAUDE.md +37 -0
- package/modules/ideas/blockers.js +100 -0
- package/modules/ideas/inbox.js +459 -0
- package/modules/ideas/module.json +10 -0
- package/modules/ideas/routes/blockers.js +120 -0
- package/modules/ideas/routes/inbox.js +230 -0
- package/modules/lifecycle/CLAUDE.md +63 -0
- package/modules/lifecycle/conflict-resolve.js +436 -0
- package/modules/lifecycle/db.js +4970 -0
- package/modules/lifecycle/done-when.js +355 -0
- package/modules/lifecycle/github-push.js +969 -0
- package/modules/lifecycle/goal-conflicts.js +133 -0
- package/modules/lifecycle/hierarchy.js +104 -0
- package/modules/lifecycle/lifecycle.js +58 -0
- package/modules/lifecycle/merge-lock.js +261 -0
- package/modules/lifecycle/migrations/lifecycle_001_goal_first_leads.sql +28 -0
- package/modules/lifecycle/migrations/lifecycle_002_backfill_orphan_task_goals.sql +36 -0
- package/modules/lifecycle/module.json +13 -0
- package/modules/lifecycle/pollers/publish-reconciler.js +20 -0
- package/modules/lifecycle/publish-reconciler.js +418 -0
- package/modules/lifecycle/routes/analytics.js +63 -0
- package/modules/lifecycle/routes/claims.js +506 -0
- package/modules/lifecycle/routes/dependencies.js +82 -0
- package/modules/lifecycle/routes/done-when.js +136 -0
- package/modules/lifecycle/routes/gate-approvals.js +197 -0
- package/modules/lifecycle/routes/goals.js +1419 -0
- package/modules/lifecycle/routes/lifecycle.js +43 -0
- package/modules/lifecycle/routes/tasks.js +1703 -0
- package/modules/lifecycle/routes/versions.js +128 -0
- package/modules/lifecycle/ship-card.js +505 -0
- package/modules/lifecycle/ship-preflight.js +225 -0
- package/modules/lifecycle/task-classifier.js +512 -0
- package/modules/lifecycle/version-close.js +106 -0
- package/modules/memory/CLAUDE.md +40 -0
- package/modules/memory/learnings.js +275 -0
- package/modules/memory/memory.js +572 -0
- package/modules/memory/module.json +12 -0
- package/modules/memory/routes/learnings.js +90 -0
- package/modules/memory/routes/memory.js +916 -0
- package/modules/memory/routes/search.js +188 -0
- package/modules/memory/search-chunker.js +252 -0
- package/modules/memory/search.js +320 -0
- package/modules/onboarding/CLAUDE.md +55 -0
- package/modules/onboarding/approval-broadcast.js +59 -0
- package/modules/onboarding/db.js +54 -0
- package/modules/onboarding/module.json +10 -0
- package/modules/onboarding/newcomer-restock.js +212 -0
- package/modules/onboarding/onboarding-state.js +532 -0
- package/modules/onboarding/onboarding.js +508 -0
- package/modules/onboarding/port.js +63 -0
- package/modules/onboarding/routes/access-requests.js +208 -0
- package/modules/onboarding/routes/onboarding.js +54 -0
- package/modules/security/CLAUDE.md +44 -0
- package/modules/security/module.json +10 -0
- package/modules/security/routes/reports.js +251 -0
- package/modules/security/secret-scrub.js +201 -0
- package/modules/security/security.js +294 -0
- package/modules/sessions/CLAUDE.md +39 -0
- package/modules/sessions/bfg.js +357 -0
- package/modules/sessions/db.js +326 -0
- package/modules/sessions/module.json +10 -0
- package/modules/sessions/pulse.js +149 -0
- package/modules/sessions/routes/sessions.js +331 -0
- package/modules/status-ui/CLAUDE.md +47 -0
- package/modules/status-ui/module.json +14 -0
- package/modules/status-ui/public/README.md +29 -0
- package/modules/status-ui/public/cursors/arrow.png +0 -0
- package/modules/status-ui/public/cursors/hand-pointer.png +0 -0
- package/modules/status-ui/public/index.html +363 -0
- package/modules/status-ui/public/snapshots/.gitkeep +0 -0
- package/modules/status-ui/public/status.js +1375 -0
- package/modules/status-ui/public/style.css +1342 -0
- package/package-lock.json +975 -0
- package/package.json +28 -0
- package/public-docs/index.html +35 -0
- package/public-docs/redoc.standalone.js +1838 -0
- package/public-docs/redoc.standalone.js.LICENSE.txt +102 -0
- package/public-landing/buddha.png +0 -0
- package/public-landing/create.html +868 -0
- package/public-landing/index.html +168 -0
- package/scripts/bongos-mcp.js +28 -0
- package/scripts/cron/style_guide_audit.sh +134 -0
- package/scripts/discord/README.md +52 -0
- package/scripts/discord/lib.js +80 -0
- package/scripts/discord/post.js +51 -0
- package/scripts/gds/CLAUDE.md +144 -0
- package/scripts/gds/abandon.js +58 -0
- package/scripts/gds/adopt-detect.js +123 -0
- package/scripts/gds/adopt-import.js +111 -0
- package/scripts/gds/adopt-preflight.js +121 -0
- package/scripts/gds/api.js +78 -0
- package/scripts/gds/architect-audit.js +288 -0
- package/scripts/gds/art-stage.js +152 -0
- package/scripts/gds/audit-authorship.sh +243 -0
- package/scripts/gds/audit-deps.js +121 -0
- package/scripts/gds/audit-exports.js +128 -0
- package/scripts/gds/audit-replay.sh +161 -0
- package/scripts/gds/audit-ships.js +251 -0
- package/scripts/gds/autonomy-gate.js +135 -0
- package/scripts/gds/backfill-cost.js +165 -0
- package/scripts/gds/backfill-sessions.js +351 -0
- package/scripts/gds/backfill-task-rewards.js +408 -0
- package/scripts/gds/backup.js +94 -0
- package/scripts/gds/bfg-principal-token.js +65 -0
- package/scripts/gds/box-auth-check.js +160 -0
- package/scripts/gds/box-connect-lib.js +453 -0
- package/scripts/gds/box.js +1258 -0
- package/scripts/gds/build-bongos.js +94 -0
- package/scripts/gds/capture.js +123 -0
- package/scripts/gds/cf-tunnel.js +419 -0
- package/scripts/gds/ci-grade.js +82 -0
- package/scripts/gds/claim-recall.js +112 -0
- package/scripts/gds/claim.js +333 -0
- package/scripts/gds/classify-discipline.js +153 -0
- package/scripts/gds/claude-materialize.js +176 -0
- package/scripts/gds/cleanup-orphans.js +74 -0
- package/scripts/gds/cli-lib.js +518 -0
- package/scripts/gds/code.js +101 -0
- package/scripts/gds/codemod-rename-src-gds.js +145 -0
- package/scripts/gds/conductor-dispatch.js +426 -0
- package/scripts/gds/context-pack.js +228 -0
- package/scripts/gds/coreB-carve-proof.sh +716 -0
- package/scripts/gds/cost.js +47 -0
- package/scripts/gds/db-backup-nightly.sh +160 -0
- package/scripts/gds/db-backup-offsite.sh +152 -0
- package/scripts/gds/demote.js +40 -0
- package/scripts/gds/design-sync.js +62 -0
- package/scripts/gds/diagnose-achievements.js +118 -0
- package/scripts/gds/diagram-facts.js +319 -0
- package/scripts/gds/discipline-modes.json +25 -0
- package/scripts/gds/discord-channels.js +66 -0
- package/scripts/gds/do-api.js +176 -0
- package/scripts/gds/docs-entropy.js +403 -0
- package/scripts/gds/doctor.js +389 -0
- package/scripts/gds/feedback-latest.js +94 -0
- package/scripts/gds/fetch-art-key.js +106 -0
- package/scripts/gds/fetch-sound-prefs.js +88 -0
- package/scripts/gds/figma-design-sync.js +61 -0
- package/scripts/gds/fitness.js +1446 -0
- package/scripts/gds/gate-review.js +322 -0
- package/scripts/gds/gating.js +325 -0
- package/scripts/gds/gds-db-backup.service +24 -0
- package/scripts/gds/gds-db-backup.timer +20 -0
- package/scripts/gds/gds-db-offsite.service +29 -0
- package/scripts/gds/gds-db-offsite.timer +18 -0
- package/scripts/gds/gen-api-client.js +508 -0
- package/scripts/gds/gen-api-docs.js +1037 -0
- package/scripts/gds/gen-atlas.js +366 -0
- package/scripts/gds/gen-diagrams.js +608 -0
- package/scripts/gds/gen-file-map.js +196 -0
- package/scripts/gds/gen-repo-map.js +519 -0
- package/scripts/gds/gen-session-index.js +210 -0
- package/scripts/gds/git-merge-regen.js +147 -0
- package/scripts/gds/grade-smoke.js +205 -0
- package/scripts/gds/hooks/pre-push.js +169 -0
- package/scripts/gds/http-api-client.js +88 -0
- package/scripts/gds/init.js +903 -0
- package/scripts/gds/install-git-hooks.js +114 -0
- package/scripts/gds/key-card.js +213 -0
- package/scripts/gds/key-status.js +126 -0
- package/scripts/gds/land-watch.js +168 -0
- package/scripts/gds/learning-capture.js +145 -0
- package/scripts/gds/lib.sh +44 -0
- package/scripts/gds/linkify-refs.js +473 -0
- package/scripts/gds/local-preview-lib.js +159 -0
- package/scripts/gds/local-preview.js +95 -0
- package/scripts/gds/login.js +225 -0
- package/scripts/gds/main-audit.js +279 -0
- package/scripts/gds/me.js +88 -0
- package/scripts/gds/memory-map.js +174 -0
- package/scripts/gds/merge-lock.js +71 -0
- package/scripts/gds/migration-namespace.js +200 -0
- package/scripts/gds/mirror-lineage-check.js +319 -0
- package/scripts/gds/mirror-redact.js +305 -0
- package/scripts/gds/module.js +482 -0
- package/scripts/gds/newcomer-floor.config.json +13 -0
- package/scripts/gds/newcomer-floor.js +415 -0
- package/scripts/gds/newcomer-floor.templates.json +86 -0
- package/scripts/gds/newcomer-floor.test.js +235 -0
- package/scripts/gds/next-number.js +163 -0
- package/scripts/gds/oauth-secret.js +197 -0
- package/scripts/gds/onboard.js +217 -0
- package/scripts/gds/onboarding-analyze.js +226 -0
- package/scripts/gds/onboarding-config.js +178 -0
- package/scripts/gds/onboarding-ship.js +92 -0
- package/scripts/gds/package-core.js +684 -0
- package/scripts/gds/paste-token.js +131 -0
- package/scripts/gds/portability-smoke-art.sh +85 -0
- package/scripts/gds/portability-smoke-memory.sh +147 -0
- package/scripts/gds/provision.js +1324 -0
- package/scripts/gds/publish-manifest.js +307 -0
- package/scripts/gds/pulse.js +309 -0
- package/scripts/gds/push-main.js +45 -0
- package/scripts/gds/read-session-export.js +359 -0
- package/scripts/gds/reauth.js +149 -0
- package/scripts/gds/recall.js +135 -0
- package/scripts/gds/release.js +71 -0
- package/scripts/gds/render-ideas.js +173 -0
- package/scripts/gds/repo-metrics.js +363 -0
- package/scripts/gds/resolve-skill-model.js +57 -0
- package/scripts/gds/run-routine.js +197 -0
- package/scripts/gds/run-unit-tests.js +178 -0
- package/scripts/gds/sandbox-stage.js +653 -0
- package/scripts/gds/search-ingest-db.js +209 -0
- package/scripts/gds/search-ingest-md.js +225 -0
- package/scripts/gds/security-baseline-check.sh +180 -0
- package/scripts/gds/seed-adopt-tasks.js +75 -0
- package/scripts/gds/seed-api-contract-goal-tasks.js +141 -0
- package/scripts/gds/seed-bongos-app-tasks.js +294 -0
- package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +81 -0
- package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +100 -0
- package/scripts/gds/seed-bongos-goal-hierarchy-tasks.js +307 -0
- package/scripts/gds/seed-bongos-module-system-tasks.js +346 -0
- package/scripts/gds/seed-bongos-tasks.js +214 -0
- package/scripts/gds/seed-gds-v4-tasks.js +624 -0
- package/scripts/gds/seed-governance-tasks.js +340 -0
- package/scripts/gds/seed-medusa-tasks.js +440 -0
- package/scripts/gds/seed-module-upstreaming.js +219 -0
- package/scripts/gds/seed-productization-tasks.js +235 -0
- package/scripts/gds/seed-provisioning-tasks.js +83 -0
- package/scripts/gds/seed-staging.sh +104 -0
- package/scripts/gds/seed-v2-world-tasks.js +283 -0
- package/scripts/gds/seed-v3-tasks.js +1981 -0
- package/scripts/gds/session-cost.js +393 -0
- package/scripts/gds/session-digest.js +179 -0
- package/scripts/gds/session-eval.js +576 -0
- package/scripts/gds/session.js +404 -0
- package/scripts/gds/setup.js +504 -0
- package/scripts/gds/shell.js +100 -0
- package/scripts/gds/ship.js +3618 -0
- package/scripts/gds/smoke-batch-claim.sh +213 -0
- package/scripts/gds/smoke-batch-release.sh +296 -0
- package/scripts/gds/smoke-box.sh +150 -0
- package/scripts/gds/smoke-claim-consistency.sh +212 -0
- package/scripts/gds/smoke-dependencies.sh +84 -0
- package/scripts/gds/smoke-gds.js +125 -0
- package/scripts/gds/smoke-write.sh +168 -0
- package/scripts/gds/start.js +782 -0
- package/scripts/gds/status.js +365 -0
- package/scripts/gds/triage.js +366 -0
- package/scripts/gds/upgrade.js +421 -0
- package/scripts/gds/validate-design.js +254 -0
- package/scripts/gds/version-close.js +549 -0
- package/scripts/migrate.sh +183 -0
- package/scripts/migrate_cost_ledger.sh +178 -0
- package/scripts/public-mirror-export.js +291 -0
- package/scripts/render-diagrams.sh +88 -0
- package/scripts/security/dep-audit.js +276 -0
- package/scripts/setup-builder.js +274 -0
- package/scripts/setup-builder.sh +28 -0
- package/scripts/snapshots/backfill-history.mjs +292 -0
- package/scripts/snapshots/maybe-render-on-deploy.sh +66 -0
- package/scripts/snapshots/render-pre-art-eras.mjs +329 -0
- package/scripts/snapshots/render-world.mjs +322 -0
- package/scripts/status-mirror-sync.js +192 -0
- package/scripts/status-probe.mjs +185 -0
- package/server.js +212 -0
- package/src/asset-version.js +71 -0
- package/src/bongos/CLAUDE.md +64 -0
- package/src/bongos/api-errors.js +281 -0
- package/src/bongos/api-path-404.js +67 -0
- package/src/bongos/api-prefix.js +38 -0
- package/src/bongos/app-pair.js +172 -0
- package/src/bongos/auth.js +979 -0
- package/src/bongos/cascade-dispatch.js +123 -0
- package/src/bongos/db-kernel.js +252 -0
- package/src/bongos/db.js +911 -0
- package/src/bongos/goal-scope-check.js +120 -0
- package/src/bongos/hierarchy-config.js +189 -0
- package/src/bongos/live-channel.js +145 -0
- package/src/bongos/llm-cache.js +260 -0
- package/src/bongos/llm-pricing.js +220 -0
- package/src/bongos/metrics.js +286 -0
- package/src/bongos/middleware/audit.js +274 -0
- package/src/bongos/middleware/error-envelope.js +93 -0
- package/src/bongos/middleware/rate-limit.js +195 -0
- package/src/bongos/module-scope-map.js +271 -0
- package/src/bongos/optimizer.js +166 -0
- package/src/bongos/path-match.js +47 -0
- package/src/bongos/permission-path-check.js +248 -0
- package/src/bongos/pool.js +55 -0
- package/src/bongos/repo-info.js +91 -0
- package/src/bongos/route-rank-check.js +420 -0
- package/src/bongos/routes/CLAUDE.md +43 -0
- package/src/bongos/routes/_helpers.js +369 -0
- package/src/bongos/routes/audit-log.js +59 -0
- package/src/bongos/routes/auth.js +755 -0
- package/src/bongos/routes/backup.js +104 -0
- package/src/bongos/routes/builders.js +526 -0
- package/src/bongos/routes/healthz.js +16 -0
- package/src/bongos/routes/instance.js +129 -0
- package/src/bongos/routes/live.js +125 -0
- package/src/bongos/routes/llm-cache.js +119 -0
- package/src/bongos/routes/me.js +380 -0
- package/src/bongos/routes/modules.js +131 -0
- package/src/bongos/routes/optimizer.js +54 -0
- package/src/bongos/routes/public.js +476 -0
- package/src/bongos/routes/security.js +207 -0
- package/src/bongos/routes.js +166 -0
- package/src/bongos/secret-box.js +177 -0
- package/src/bongos/sensitive-surfaces.js +30 -0
- package/src/bongos/serve-internal.js +889 -0
- package/src/bongos/uptime-poller.js +90 -0
- package/src/bongos-downloads.js +70 -0
- package/src/branding.js +182 -0
- package/src/build-info.js +77 -0
- package/src/devbox-downloads.js +67 -0
- package/src/instance-config.js +200 -0
- package/src/module-api.js +366 -0
- package/src/module-loader/loader.js +268 -0
- package/src/module-loader/manifest-schema.js +140 -0
- package/src/module-loader/provenance.js +28 -0
- package/src/module-loader/semver.js +100 -0
- package/src/module-seams.js +291 -0
- package/src/modules.js +254 -0
- package/src/platform-server.js +135 -0
- package/src/ui/adapters/claude-design/index.js +333 -0
- package/src/ui/adapters/figma/index.js +328 -0
- package/tests/abandon_task.mjs +138 -0
- package/tests/achievements_reconcile.mjs +167 -0
- package/tests/adopt_detect.mjs +141 -0
- package/tests/adopt_import.mjs +132 -0
- package/tests/adopt_preflight.mjs +105 -0
- package/tests/anti_grid.mjs +89 -0
- package/tests/api_client.mjs +231 -0
- package/tests/api_docs.mjs +283 -0
- package/tests/api_error_envelope_buildcheck.mjs +56 -0
- package/tests/api_error_envelope_middleware.mjs +99 -0
- package/tests/api_error_registry.mjs +108 -0
- package/tests/api_pagination_contract.mjs +51 -0
- package/tests/api_path_404.mjs +96 -0
- package/tests/app_pair.mjs +168 -0
- package/tests/architect.mjs +140 -0
- package/tests/art_key.mjs +121 -0
- package/tests/art_stage.mjs +121 -0
- package/tests/asset_version.mjs +94 -0
- package/tests/atlas.mjs +69 -0
- package/tests/audit_deps.mjs +74 -0
- package/tests/audit_middleware.mjs +385 -0
- package/tests/auth_admission_gate.mjs +164 -0
- package/tests/auth_anthropic_identity.mjs +95 -0
- package/tests/auth_duplicate_cookie.mjs +56 -0
- package/tests/auth_error_brand.mjs +77 -0
- package/tests/auth_flow_slice1.mjs +223 -0
- package/tests/auth_inactive_builder.mjs +94 -0
- package/tests/auth_page_gate.mjs +92 -0
- package/tests/auth_session_ttl.mjs +155 -0
- package/tests/autonomous_fit_protected_paths.mjs +115 -0
- package/tests/autonomy_gate.mjs +85 -0
- package/tests/autotile_variants.mjs +256 -0
- package/tests/autotile_xverify.mjs +133 -0
- package/tests/backfill_sessions.mjs +101 -0
- package/tests/backfill_task_rewards.mjs +152 -0
- package/tests/backup_cli.mjs +104 -0
- package/tests/bfg.mjs +327 -0
- package/tests/bfg_write.mjs +423 -0
- package/tests/bongos_box_connect.mjs +89 -0
- package/tests/bongos_dispatch.mjs +74 -0
- package/tests/bongos_downloads.mjs +118 -0
- package/tests/bongos_login.mjs +34 -0
- package/tests/box_access.mjs +186 -0
- package/tests/box_auth_check.mjs +114 -0
- package/tests/box_code_staleness.mjs +116 -0
- package/tests/box_connect_e2e.mjs +196 -0
- package/tests/box_cost.mjs +70 -0
- package/tests/box_dns_repoint.mjs +151 -0
- package/tests/box_host_keys.mjs +102 -0
- package/tests/box_onboard.mjs +317 -0
- package/tests/box_scope_session.mjs +115 -0
- package/tests/box_ship_permissions.mjs +71 -0
- package/tests/box_terminal_ssrf.mjs +90 -0
- package/tests/boxes.mjs +1255 -0
- package/tests/branding.mjs +88 -0
- package/tests/bug_attachments.mjs +189 -0
- package/tests/build_info.mjs +88 -0
- package/tests/builder_needs.mjs +99 -0
- package/tests/cap_newcomer_tasks.mjs +114 -0
- package/tests/cascade-dispatch.mjs +95 -0
- package/tests/cf_tunnel.mjs +459 -0
- package/tests/claim_recall.mjs +150 -0
- package/tests/claims_bind_session.mjs +47 -0
- package/tests/claude_materialize.mjs +148 -0
- package/tests/cli_box_scope.mjs +52 -0
- package/tests/cli_lib_formatters.mjs +87 -0
- package/tests/cli_token_reissue.mjs +147 -0
- package/tests/client_bundle_route.mjs +47 -0
- package/tests/cloud_bongos_pack.mjs +85 -0
- package/tests/conductor.mjs +496 -0
- package/tests/confirm_attribution.mjs +156 -0
- package/tests/conflict_resolve.mjs +462 -0
- package/tests/context_pack.mjs +240 -0
- package/tests/cost.mjs +94 -0
- package/tests/cost_audit.mjs +122 -0
- package/tests/cost_budget_status.mjs +78 -0
- package/tests/cost_reconcile.mjs +102 -0
- package/tests/cost_summary_shape.mjs +94 -0
- package/tests/credit_grant.mjs +376 -0
- package/tests/criterion_progress.mjs +220 -0
- package/tests/criterion_proposal.mjs +109 -0
- package/tests/criterion_ref_parse.mjs +53 -0
- package/tests/currency_label.mjs +119 -0
- package/tests/day_cycle.mjs +197 -0
- package/tests/dependencies_migration.mjs +77 -0
- package/tests/dependencies_polymorphic.mjs +212 -0
- package/tests/deploy_instance.mjs +78 -0
- package/tests/devbox_downloads.mjs +122 -0
- package/tests/diff_derived_signals.mjs +115 -0
- package/tests/discord_approvals.mjs +174 -0
- package/tests/discord_autojoin.mjs +158 -0
- package/tests/discord_bot.mjs +94 -0
- package/tests/discord_bugs.mjs +297 -0
- package/tests/discord_channels.mjs +337 -0
- package/tests/discord_foundation.mjs +76 -0
- package/tests/discord_inbound.mjs +190 -0
- package/tests/discord_message_buffer.mjs +87 -0
- package/tests/discord_oauth.mjs +55 -0
- package/tests/discord_reaction.mjs +170 -0
- package/tests/discord_role_sync.mjs +151 -0
- package/tests/display_name.mjs +123 -0
- package/tests/dns_preflight.mjs +74 -0
- package/tests/event_sound_prefs.mjs +194 -0
- package/tests/eviction_policy.mjs +279 -0
- package/tests/figma_adapter.mjs +199 -0
- package/tests/file_map.mjs +91 -0
- package/tests/first_admin_bootstrap.mjs +40 -0
- package/tests/fitness.mjs +435 -0
- package/tests/fitness_two_root.mjs +104 -0
- package/tests/fixtures/session-506-digest.json +34 -0
- package/tests/gate_approvals.mjs +451 -0
- package/tests/gate_review.mjs +152 -0
- package/tests/git_merge_regen.mjs +151 -0
- package/tests/github_push_ancestry.mjs +119 -0
- package/tests/github_push_land_proof.mjs +127 -0
- package/tests/github_push_merge_driver.mjs +175 -0
- package/tests/goal_abuse_matrix.mjs +187 -0
- package/tests/goal_achievement.mjs +146 -0
- package/tests/goal_conflicts.mjs +305 -0
- package/tests/goal_dependencies_read.mjs +73 -0
- package/tests/goal_member_roles.mjs +420 -0
- package/tests/goal_membership_requests.mjs +332 -0
- package/tests/goal_routes.mjs +203 -0
- package/tests/goal_scope_check.mjs +167 -0
- package/tests/goal_tier.mjs +312 -0
- package/tests/goal_wall_proof.mjs +112 -0
- package/tests/grade_attempts.mjs +73 -0
- package/tests/grade_attribution.mjs +117 -0
- package/tests/grade_diff_hash.mjs +191 -0
- package/tests/grade_server_authoritative.mjs +305 -0
- package/tests/grade_unavailable_display.mjs +66 -0
- package/tests/grader.mjs +1960 -0
- package/tests/grader_bypass.mjs +57 -0
- package/tests/grader_panel.mjs +252 -0
- package/tests/grader_prompt_fencing.mjs +192 -0
- package/tests/helpers.mjs +52 -0
- package/tests/hierarchy-config.mjs +81 -0
- package/tests/init.mjs +463 -0
- package/tests/instance_config.mjs +76 -0
- package/tests/instance_manifest.mjs +110 -0
- package/tests/interaction_prefs.mjs +72 -0
- package/tests/key-card.mjs +110 -0
- package/tests/key-status.mjs +45 -0
- package/tests/land_watch.mjs +115 -0
- package/tests/lifecycle-card.mjs +145 -0
- package/tests/lifecycle_breakdown_view.mjs +236 -0
- package/tests/linkify_refs.mjs +264 -0
- package/tests/live_channel.mjs +128 -0
- package/tests/live_sse.mjs +122 -0
- package/tests/llm-cache-route.mjs +110 -0
- package/tests/llm-cache.mjs +140 -0
- package/tests/llm-pricing.mjs +152 -0
- package/tests/local_preview.mjs +136 -0
- package/tests/main_audit.mjs +137 -0
- package/tests/memory_isolation.mjs +431 -0
- package/tests/memory_map.mjs +107 -0
- package/tests/memory_pull.mjs +429 -0
- package/tests/merge_lease.mjs +100 -0
- package/tests/merge_lock.mjs +312 -0
- package/tests/metrics.mjs +147 -0
- package/tests/migration_allocation.mjs +146 -0
- package/tests/migration_namespace.mjs +185 -0
- package/tests/migrations_fresh_replay_guard.mjs +38 -0
- package/tests/mirror_lineage_fulltree.mjs +45 -0
- package/tests/mirror_lineage_proof.mjs +72 -0
- package/tests/mirror_redact.mjs +193 -0
- package/tests/model_alloc_prefs.mjs +63 -0
- package/tests/module-scope-map.mjs +88 -0
- package/tests/module_api.mjs +110 -0
- package/tests/module_cli.mjs +292 -0
- package/tests/module_contributions.mjs +148 -0
- package/tests/module_loader.mjs +286 -0
- package/tests/module_manifest.mjs +194 -0
- package/tests/module_owned_tests.mjs +105 -0
- package/tests/module_provenance.mjs +34 -0
- package/tests/module_route_rank.mjs +147 -0
- package/tests/module_seams.mjs +68 -0
- package/tests/modules.mjs +156 -0
- package/tests/modules_route.mjs +38 -0
- package/tests/newcomer_floor.mjs +17 -0
- package/tests/newcomer_restock.mjs +80 -0
- package/tests/next_number.mjs +154 -0
- package/tests/oauth_secret.mjs +60 -0
- package/tests/onboard.mjs +70 -0
- package/tests/onboarding_gate.mjs +267 -0
- package/tests/onboarding_observability.mjs +344 -0
- package/tests/onboarding_route_signals.mjs +175 -0
- package/tests/onboarding_state.mjs +346 -0
- package/tests/one_active_claim_per_session.mjs +111 -0
- package/tests/orphaned_claim_ship.mjs +135 -0
- package/tests/override_attribution.mjs +142 -0
- package/tests/override_request_ownership.mjs +235 -0
- package/tests/package_core.mjs +435 -0
- package/tests/parallel-load.mjs +402 -0
- package/tests/path_match.mjs +62 -0
- package/tests/permission_path.mjs +151 -0
- package/tests/platform_boot.mjs +167 -0
- package/tests/pre_compact.mjs +60 -0
- package/tests/preview_server.mjs +127 -0
- package/tests/profile_route.mjs +197 -0
- package/tests/provision.mjs +805 -0
- package/tests/provisioning_github_app_routes.mjs +98 -0
- package/tests/public_mirror_export.mjs +124 -0
- package/tests/public_task_resolver.mjs +112 -0
- package/tests/publish_branch_route.mjs +422 -0
- package/tests/publish_manifest.mjs +184 -0
- package/tests/publish_reconciler.mjs +728 -0
- package/tests/rank_gate.mjs +463 -0
- package/tests/rate_limit_public.mjs +217 -0
- package/tests/read_session_export.mjs +89 -0
- package/tests/recall_cli.mjs +82 -0
- package/tests/recall_hints.mjs +119 -0
- package/tests/recent_shipped_window.mjs +80 -0
- package/tests/regrade_eligibility.mjs +202 -0
- package/tests/render_prefs.mjs +122 -0
- package/tests/repo_map.mjs +92 -0
- package/tests/reward_gate.mjs +284 -0
- package/tests/route_rank_check.mjs +243 -0
- package/tests/route_validation.mjs +490 -0
- package/tests/routine_timers.mjs +72 -0
- package/tests/rubric_fixtures.mjs +140 -0
- package/tests/run_routine.mjs +69 -0
- package/tests/sandbox_stage.mjs +582 -0
- package/tests/scrubber_corpus.mjs +257 -0
- package/tests/search_chunker.mjs +209 -0
- package/tests/search_ingest.mjs +96 -0
- package/tests/search_ingest_db.mjs +88 -0
- package/tests/search_isolation.mjs +204 -0
- package/tests/search_route.mjs +95 -0
- package/tests/secret_box.mjs +189 -0
- package/tests/security_docs.mjs +186 -0
- package/tests/security_route.mjs +108 -0
- package/tests/served_paths_shipped.mjs +118 -0
- package/tests/session-cards.mjs +142 -0
- package/tests/session_506_regression.mjs +69 -0
- package/tests/session_caps.mjs +238 -0
- package/tests/session_cost.mjs +133 -0
- package/tests/session_digest.mjs +73 -0
- package/tests/session_eval.mjs +386 -0
- package/tests/session_index.mjs +105 -0
- package/tests/session_records.mjs +369 -0
- package/tests/session_search.mjs +78 -0
- package/tests/session_start_freshness.mjs +123 -0
- package/tests/setup_smoke.mjs +154 -0
- package/tests/ship_autolinkify.mjs +60 -0
- package/tests/ship_automerge_injection.mjs +174 -0
- package/tests/ship_broadcast_routing.mjs +125 -0
- package/tests/ship_broadcast_server.mjs +175 -0
- package/tests/ship_card.mjs +280 -0
- package/tests/ship_ci_deploy.mjs +374 -0
- package/tests/ship_preflight.mjs +368 -0
- package/tests/ship_premerge.mjs +75 -0
- package/tests/ship_resume.mjs +129 -0
- package/tests/ship_upload_skip.mjs +89 -0
- package/tests/ship_zero_commit.mjs +60 -0
- package/tests/single_host_hall.mjs +98 -0
- package/tests/skill_prefs.mjs +150 -0
- package/tests/smoke_preflight.mjs +66 -0
- package/tests/snapshot_picker.mjs +233 -0
- package/tests/sound_prefs.mjs +198 -0
- package/tests/sprite_facing.mjs +35 -0
- package/tests/status-probe.mjs +89 -0
- package/tests/status_backfill.mjs +94 -0
- package/tests/stop_refcheck.mjs +127 -0
- package/tests/streak.mjs +175 -0
- package/tests/subdomain_auth.mjs +58 -0
- package/tests/task_classifier_vocab.mjs +41 -0
- package/tests/task_create_idempotency.mjs +96 -0
- package/tests/task_goal_link.mjs +93 -0
- package/tests/task_ownership_gate.mjs +125 -0
- package/tests/terrain_picker.mjs +298 -0
- package/tests/touches_overlap.mjs +75 -0
- package/tests/triage_development.mjs +140 -0
- package/tests/turn_in_place.mjs +280 -0
- package/tests/upgrade.mjs +357 -0
- package/tests/verify_task_guard.mjs +64 -0
- package/tests/version_close.mjs +76 -0
- package/tests/versions_route.mjs +93 -0
- package/tests/walkability.mjs +188 -0
- package/tests/wandering_prefs.mjs +176 -0
- package/tests/worktree_disambiguation.mjs +105 -0
- package/tests/worktree_guard.mjs +90 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/gds/box-auth-check.js — dev-box session-start auth gate (task 1712).
|
|
3
|
+
//
|
|
4
|
+
// THE FIRST THING a dev-box session should confirm: that its GDS CLI session is
|
|
5
|
+
// a REAL, full-authority session — not the box-scoped bootstrap token, and not
|
|
6
|
+
// an expired one. A box's baked session is `source:'box'` (ADR 0053 / #919): it
|
|
7
|
+
// may call the on-box bootstrap endpoints but is 403'd (`box_scope`) on
|
|
8
|
+
// claim / ship / publish. Nothing used to surface that until a ship hit the
|
|
9
|
+
// publish-branch wall (the 2026-07-02 incident: a doc couldn't be pushed and the
|
|
10
|
+
// session burned time on raw `git push`). This check makes the session say, up
|
|
11
|
+
// front, "re-auth first" so no work starts on a token that can't finish it.
|
|
12
|
+
//
|
|
13
|
+
// Self-gating + fail-open, by design:
|
|
14
|
+
// * NOT a dev box (no /etc/otb/box.env) → silent no-op. Laptops handle auth at
|
|
15
|
+
// point-of-use and can't be box-scoped, so this stays out of their way.
|
|
16
|
+
// * a subagent (OTB_SUBAGENT) → silent (grader/worker context stays clean).
|
|
17
|
+
// * box-scoped or missing session → the directive comes from the LOCAL file
|
|
18
|
+
// alone (no network) — instant, and exactly the incident case.
|
|
19
|
+
// * a real token present → ONE bounded, fail-open GET /me to also catch an
|
|
20
|
+
// EXPIRED/revoked token; a quiet '✓ authed' on success; silent when the
|
|
21
|
+
// network is flaky (point-of-use still catches a genuine problem — never
|
|
22
|
+
// cry wolf and never delay session start).
|
|
23
|
+
//
|
|
24
|
+
// Printed to stdout so the SessionStart hook forwards it into session context.
|
|
25
|
+
// Wired FIRST (right after the identity card) in .claude/hooks/session-start.js.
|
|
26
|
+
|
|
27
|
+
const fs = require('node:fs');
|
|
28
|
+
|
|
29
|
+
const BOX_ENV_PATH = '/etc/otb/box.env';
|
|
30
|
+
const ME_TIMEOUT_MS = 3000;
|
|
31
|
+
|
|
32
|
+
// Pure decision — given the auth facts, what should the card do? Exported +
|
|
33
|
+
// unit-tested (tests/box_auth_check.mjs). Never does I/O.
|
|
34
|
+
// onBox: provisioned dev box (/etc/otb/box.env present)
|
|
35
|
+
// hasToken: a local session file with a token exists
|
|
36
|
+
// isBoxScoped: that session is the baked box token (source === 'box')
|
|
37
|
+
// meStatus: HTTP status of a bounded GET /me, or null (not attempted / network failed)
|
|
38
|
+
// → { action: 'skip' | 'setup' | 'reauth' | 'ok', reason }
|
|
39
|
+
//
|
|
40
|
+
// Ordering matters: isBoxScoped is decided from the local file BEFORE any
|
|
41
|
+
// meStatus, so the incident case never needs (or waits on) the network.
|
|
42
|
+
function decideBoxAuth({ onBox, hasToken, isBoxScoped, meStatus }) {
|
|
43
|
+
if (!onBox) return { action: 'skip', reason: 'not-a-box' };
|
|
44
|
+
if (!hasToken) return { action: 'setup', reason: 'no-session' };
|
|
45
|
+
if (isBoxScoped) return { action: 'reauth', reason: 'box-scoped' };
|
|
46
|
+
if (meStatus === 200) return { action: 'ok', reason: 'validated' };
|
|
47
|
+
if (meStatus === 401 || meStatus === 403) return { action: 'reauth', reason: 'expired-or-revoked' };
|
|
48
|
+
// Couldn't definitively verify (no network / fetch unavailable / timeout /
|
|
49
|
+
// 5xx). A locally valid-looking real token is trusted; stay silent rather
|
|
50
|
+
// than warn falsely — the point-of-use guard (cli-lib) still catches a real
|
|
51
|
+
// 401/403 the moment a command runs.
|
|
52
|
+
return { action: 'skip', reason: 'unverified' };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function onBox() {
|
|
56
|
+
try {
|
|
57
|
+
return fs.existsSync(BOX_ENV_PATH);
|
|
58
|
+
} catch (_) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Bounded, fail-open GET /me. Returns { status, login }; status is null and
|
|
64
|
+
// login is null on ANY failure (no global fetch, network error, abort/timeout).
|
|
65
|
+
// Never throws.
|
|
66
|
+
async function probeMe(tokenInfo) {
|
|
67
|
+
if (!tokenInfo || !tokenInfo.token || typeof fetch !== 'function') {
|
|
68
|
+
return { status: null, login: null };
|
|
69
|
+
}
|
|
70
|
+
const ctl = new AbortController();
|
|
71
|
+
const timer = setTimeout(() => ctl.abort(), ME_TIMEOUT_MS);
|
|
72
|
+
try {
|
|
73
|
+
const res = await fetch(`${tokenInfo.apiBase}/api/gds/me`, {
|
|
74
|
+
method: 'GET',
|
|
75
|
+
headers: { Authorization: `Bearer ${tokenInfo.token}`, 'User-Agent': 'box-auth-check/1.0' },
|
|
76
|
+
signal: ctl.signal,
|
|
77
|
+
});
|
|
78
|
+
let login = null;
|
|
79
|
+
if (res.ok) {
|
|
80
|
+
try {
|
|
81
|
+
const j = await res.json();
|
|
82
|
+
login = (j && j.builder && j.builder.github_login) || null;
|
|
83
|
+
} catch (_) { /* body parse is cosmetic only */ }
|
|
84
|
+
}
|
|
85
|
+
return { status: res.status, login };
|
|
86
|
+
} catch (_) {
|
|
87
|
+
return { status: null, login: null };
|
|
88
|
+
} finally {
|
|
89
|
+
clearTimeout(timer);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function printReauth({ boxScoped }) {
|
|
94
|
+
const why = boxScoped
|
|
95
|
+
? 'This box holds the BOX-SCOPED bootstrap token (source=box, ADR 0053) — it can bootstrap the box but is refused (403) on claim / ship / publish.'
|
|
96
|
+
: 'This session token is EXPIRED or revoked (CLI tokens carry a 24h idle TTL).';
|
|
97
|
+
console.log('[otb] ── dev box: RE-AUTH BEFORE YOU WORK ──');
|
|
98
|
+
console.log(`[otb] ${why}`);
|
|
99
|
+
console.log('[otb] ⚠ FIRST STEP this session: get the builder onto a real CLI session BEFORE claiming or shipping —');
|
|
100
|
+
console.log('[otb] run /builder-reauth (UI-first: opens Settings → "Re-issue CLI token" → paste the one-liner back).');
|
|
101
|
+
console.log('[otb] Work claimed on this token cannot be shipped/published — it will strand at the publish 403 wall.');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function printSetup() {
|
|
105
|
+
console.log('[otb] ── dev box: NO GDS SESSION — SIGN IN BEFORE YOU WORK ──');
|
|
106
|
+
console.log('[otb] ⚠ No CLI session was found on this box. FIRST STEP this session: sign in before claiming or');
|
|
107
|
+
console.log('[otb] shipping any work — run /builder-reauth (UI-first), or /builder-setup for a brand-new machine.');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function main() {
|
|
111
|
+
if (process.env.OTB_SUBAGENT) return;
|
|
112
|
+
if (!onBox()) return;
|
|
113
|
+
|
|
114
|
+
let lib;
|
|
115
|
+
let session = null;
|
|
116
|
+
let tokenInfo = null;
|
|
117
|
+
try {
|
|
118
|
+
lib = require('./cli-lib');
|
|
119
|
+
session = lib.loadSessionSync();
|
|
120
|
+
tokenInfo = lib.readSessionToken();
|
|
121
|
+
} catch (_) {
|
|
122
|
+
// cli-lib unreadable → treat as no-session (the setup path), which is the
|
|
123
|
+
// safe, actionable default rather than silence.
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const hasToken = !!(session && session.token);
|
|
127
|
+
const isBoxScoped = !!(session && session.source === 'box');
|
|
128
|
+
|
|
129
|
+
// Only pay a network round-trip when a real (non-box) token is present — the
|
|
130
|
+
// box-scoped and no-session cases are already decided from the file alone.
|
|
131
|
+
let meStatus = null;
|
|
132
|
+
let login = null;
|
|
133
|
+
if (hasToken && !isBoxScoped) {
|
|
134
|
+
({ status: meStatus, login } = await probeMe(tokenInfo));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const { action } = decideBoxAuth({ onBox: true, hasToken, isBoxScoped, meStatus });
|
|
138
|
+
if (action === 'reauth') {
|
|
139
|
+
printReauth({ boxScoped: isBoxScoped });
|
|
140
|
+
} else if (action === 'setup') {
|
|
141
|
+
printSetup();
|
|
142
|
+
} else if (action === 'ok') {
|
|
143
|
+
console.log(`[otb] ✓ dev box: GDS session is a real CLI session${login ? ` (signed in as ${login})` : ''} — clear to claim + ship.`);
|
|
144
|
+
}
|
|
145
|
+
// action === 'skip' → say nothing (off-box handled above; 'unverified' is silent).
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Direct run (the SessionStart hook spawns `node .../box-auth-check.js`) — run
|
|
149
|
+
// the check and exit fast. A require() of this file (the unit test importing
|
|
150
|
+
// decideBoxAuth) must NOT run main, so guard on require.main. The watchdog is
|
|
151
|
+
// belt-and-suspenders: the SessionStart hook spawns this synchronously with no
|
|
152
|
+
// timeout of its own, so guarantee a bounded exit even if something wedges (the
|
|
153
|
+
// fetch already self-aborts at ME_TIMEOUT_MS).
|
|
154
|
+
if (require.main === module) {
|
|
155
|
+
const watchdog = setTimeout(() => process.exit(0), ME_TIMEOUT_MS + 1500);
|
|
156
|
+
watchdog.unref();
|
|
157
|
+
main().then(() => process.exit(0)).catch(() => process.exit(0));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = { decideBoxAuth, onBox, printReauth, printSetup };
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
// scripts/gds/box-connect-lib.js — shared machinery for `bongos shell` / `bongos code`
|
|
2
|
+
// (GDS-V4 · V4.R80 · task 1247; Phase 2 of the bongos toolkit, epic 1245).
|
|
3
|
+
//
|
|
4
|
+
// `bongos shell` opens a terminal on the builder's cloud dev box; `bongos code`
|
|
5
|
+
// attaches VS Code over Remote-SSH at /workspace. Both reduce to the same four
|
|
6
|
+
// steps, which live here so the two verbs stay thin and the string-building is
|
|
7
|
+
// unit-testable without a network or a box:
|
|
8
|
+
//
|
|
9
|
+
// 1. Ensure the local ed25519 key exists (~/.ssh/otb_builder) and is registered
|
|
10
|
+
// with the GDS — so a FRESH laptop with no prior setup still connects.
|
|
11
|
+
// 2. Wake/provision the box (POST /box/ensure) and poll (GET /box/me) until it
|
|
12
|
+
// is active and has a hostname (DNS is repointed on every wake/provision, so
|
|
13
|
+
// we always connect by hostname, never a cached IP).
|
|
14
|
+
// 3. Pin the box's reported host keys into ~/.ssh/known_hosts (authoritative,
|
|
15
|
+
// survives a re-provision) and write a marker-delimited Host alias into
|
|
16
|
+
// ~/.ssh/config (User root + the box key) so the system OpenSSH client — the
|
|
17
|
+
// one VS Code Remote-SSH drives — resolves the box the same way every time.
|
|
18
|
+
// 4. Hand off to `ssh` / `code`.
|
|
19
|
+
//
|
|
20
|
+
// No bash-isms: node is the one guaranteed runtime (#686). The pure helpers below
|
|
21
|
+
// (buildSshAliasBlock, upsertSshConfigText, buildKnownHostsUpsert, rankAtLeast,
|
|
22
|
+
// buildRemoteShellCommand, parseEnsure, remoteAuthority) take no I/O and are
|
|
23
|
+
// covered by tests/bongos_box_connect.mjs.
|
|
24
|
+
|
|
25
|
+
'use strict';
|
|
26
|
+
|
|
27
|
+
const fs = require('node:fs');
|
|
28
|
+
const os = require('node:os');
|
|
29
|
+
const path = require('node:path');
|
|
30
|
+
const { spawnSync } = require('node:child_process');
|
|
31
|
+
const ic = require('../../src/instance-config');
|
|
32
|
+
const { cliClient } = require('./cli-lib');
|
|
33
|
+
|
|
34
|
+
// The box always runs as root and the repo is cloned to /workspace (the devcontainer
|
|
35
|
+
// standardizes the same path). NOT ~/workspace — root's ~ is /root, which has no clone.
|
|
36
|
+
const BOX_USER = 'root';
|
|
37
|
+
const WORKSPACE = '/workspace';
|
|
38
|
+
// VS Code extension id for Claude Code (mirrors .devcontainer/devcontainer.json).
|
|
39
|
+
const CLAUDE_VSCODE_EXTENSION = 'anthropic.claude-code';
|
|
40
|
+
|
|
41
|
+
// The rank ladder, entry→top. `--local` is a Metic+ convenience gate (a nudge to
|
|
42
|
+
// keep newcomers on the standard cloud box, NOT a security boundary — real
|
|
43
|
+
// authority is server-side and unaffected). thetes sits between xenos and metic
|
|
44
|
+
// even though requires_rank only enumerates xenos/metic/archon.
|
|
45
|
+
const RANK_ORDER = { xenos: 0, thetes: 1, metic: 2, archon: 3 };
|
|
46
|
+
|
|
47
|
+
function rankAtLeast(rank, min) {
|
|
48
|
+
const r = RANK_ORDER[rank];
|
|
49
|
+
const m = RANK_ORDER[min];
|
|
50
|
+
if (r == null || m == null) return false;
|
|
51
|
+
return r >= m;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function escapeRegExp(s) {
|
|
55
|
+
return String(s).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// -------------------------------------------------------------------------
|
|
59
|
+
// Pure string builders (no I/O — unit tested)
|
|
60
|
+
// -------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
// A marker-delimited, idempotent Host block for ONE box. Markers carry the
|
|
63
|
+
// hostname so re-running upserts THIS box's block without touching any other
|
|
64
|
+
// (a builder may connect to more than one instance's box over time).
|
|
65
|
+
function buildSshAliasBlock({ hostname, identityFile }) {
|
|
66
|
+
return [
|
|
67
|
+
`# >>> bongos-managed dev-box: ${hostname} >>>`,
|
|
68
|
+
`Host ${hostname}`,
|
|
69
|
+
` HostName ${hostname}`,
|
|
70
|
+
` User ${BOX_USER}`,
|
|
71
|
+
` IdentityFile ${identityFile}`,
|
|
72
|
+
` IdentitiesOnly yes`,
|
|
73
|
+
` StrictHostKeyChecking accept-new`,
|
|
74
|
+
`# <<< bongos-managed dev-box: ${hostname} <<<`,
|
|
75
|
+
].join('\n');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Upsert the alias block into an existing ~/.ssh/config body. Replaces this
|
|
79
|
+
// host's block in place if present, else appends it with a blank-line gap.
|
|
80
|
+
function upsertSshConfigText(existing, { hostname, identityFile }) {
|
|
81
|
+
const block = buildSshAliasBlock({ hostname, identityFile });
|
|
82
|
+
const h = escapeRegExp(hostname);
|
|
83
|
+
const re = new RegExp(
|
|
84
|
+
`# >>> bongos-managed dev-box: ${h} >>>[\\s\\S]*?# <<< bongos-managed dev-box: ${h} <<<`,
|
|
85
|
+
'm'
|
|
86
|
+
);
|
|
87
|
+
const base = existing || '';
|
|
88
|
+
if (re.test(base)) return base.replace(re, block);
|
|
89
|
+
const gap = base ? (base.endsWith('\n') ? '\n' : '\n\n') : '';
|
|
90
|
+
return `${base}${gap}${block}\n`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Authoritative known_hosts upsert: drop any stale line for THIS host (exact
|
|
94
|
+
// field-1 match), keep every other host, then append the box's reported keys.
|
|
95
|
+
// hostKeysRaw is the newline-joined `<keytype> <base64>` string from /box/me.
|
|
96
|
+
function buildKnownHostsUpsert(existing, hostname, hostKeysRaw) {
|
|
97
|
+
const keep = (existing || '')
|
|
98
|
+
.split('\n')
|
|
99
|
+
.filter((line) => line.trim() && line.split(/\s+/)[0] !== hostname);
|
|
100
|
+
const added = (hostKeysRaw || '')
|
|
101
|
+
.split('\n')
|
|
102
|
+
.map((k) => k.trim())
|
|
103
|
+
.filter(Boolean)
|
|
104
|
+
.map((k) => `${hostname} ${k}`);
|
|
105
|
+
const all = [...keep, ...added];
|
|
106
|
+
return all.length ? all.join('\n') + '\n' : '';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// The remote command `ssh -t root@host …` runs. Lands the builder in /workspace;
|
|
110
|
+
// on the first connection to this box it runs an interactive `claude` first so the
|
|
111
|
+
// Trusted-Devices /login enrollment (interactive-only by design — ADR 0038) is
|
|
112
|
+
// completed once, then drops to a login shell. Silent on every later connect.
|
|
113
|
+
function buildRemoteShellCommand({ firstRun = false, workdir = WORKSPACE } = {}) {
|
|
114
|
+
const cd = `cd ${workdir} 2>/dev/null || true`;
|
|
115
|
+
const login = firstRun
|
|
116
|
+
? `echo '↪ First time on this box — complete /login in claude once (browser device flow), then exit to a shell.'; claude || true; `
|
|
117
|
+
: '';
|
|
118
|
+
return `${cd}; ${login}exec bash -l`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// VS Code Remote-SSH authority for a host (VS Code resolves it via the ~/.ssh
|
|
122
|
+
// Host alias we wrote, so User/IdentityFile/host-key policy all apply).
|
|
123
|
+
function remoteAuthority(hostname) {
|
|
124
|
+
return `ssh-remote+${hostname}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Normalize the POST /box/ensure body into { action, state, message }.
|
|
128
|
+
function parseEnsure(data) {
|
|
129
|
+
const d = data || {};
|
|
130
|
+
return { action: d.action || null, state: d.state || null, message: d.message || null };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// -------------------------------------------------------------------------
|
|
134
|
+
// Local toolchain + paths (thin I/O)
|
|
135
|
+
// -------------------------------------------------------------------------
|
|
136
|
+
|
|
137
|
+
function sshKeyPath() {
|
|
138
|
+
// OTB_SSH_KEY (via the instance env prefix) is the advanced/test override; the
|
|
139
|
+
// Dev Box app + connect.sh both pin the fixed ~/.ssh/otb_builder default.
|
|
140
|
+
return ic.resolveEnv('SSH_KEY') || path.join(os.homedir(), '.ssh', 'otb_builder');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function sshDir() {
|
|
144
|
+
return path.join(os.homedir(), '.ssh');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Is a CLI launchable? (shell:true on win32 so a .cmd/.exe shim resolves — same
|
|
148
|
+
// posture as doctor.js's claude/gh checks.)
|
|
149
|
+
function binPresent(bin, versionArgs = ['--version']) {
|
|
150
|
+
try {
|
|
151
|
+
const r = spawnSync(bin, versionArgs, {
|
|
152
|
+
encoding: 'utf8',
|
|
153
|
+
shell: process.platform === 'win32',
|
|
154
|
+
windowsHide: true,
|
|
155
|
+
timeout: 15000,
|
|
156
|
+
});
|
|
157
|
+
return !!r && !r.error && (r.status === 0 || r.status === null);
|
|
158
|
+
} catch (_) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Local SHA256 fingerprint of a public key, or null if ssh-keygen can't read it.
|
|
164
|
+
function localKeyFingerprint(pubPath) {
|
|
165
|
+
try {
|
|
166
|
+
const r = spawnSync('ssh-keygen', ['-lf', pubPath], {
|
|
167
|
+
encoding: 'utf8',
|
|
168
|
+
shell: process.platform === 'win32',
|
|
169
|
+
windowsHide: true,
|
|
170
|
+
timeout: 15000,
|
|
171
|
+
});
|
|
172
|
+
if (!r || r.error || r.status !== 0) return null;
|
|
173
|
+
const m = (r.stdout || '').match(/SHA256:[A-Za-z0-9+/=]+/);
|
|
174
|
+
return m ? m[0] : null;
|
|
175
|
+
} catch (_) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// -------------------------------------------------------------------------
|
|
181
|
+
// SSH key: ensure it exists locally + is registered with the GDS
|
|
182
|
+
// -------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
// Ensure ~/.ssh/otb_builder exists (generate an ed25519 pair if not) and return
|
|
185
|
+
// { keyPath, pubKey, created }. Throws with actionable guidance if ssh-keygen is
|
|
186
|
+
// missing or the key can't be read.
|
|
187
|
+
function ensureSshKey({ log = console.log } = {}) {
|
|
188
|
+
const keyPath = sshKeyPath();
|
|
189
|
+
const pubPath = `${keyPath}.pub`;
|
|
190
|
+
let created = false;
|
|
191
|
+
if (!fs.existsSync(keyPath)) {
|
|
192
|
+
fs.mkdirSync(sshDir(), { recursive: true });
|
|
193
|
+
try {
|
|
194
|
+
fs.chmodSync(sshDir(), 0o700);
|
|
195
|
+
} catch (_) {
|
|
196
|
+
/* best-effort on non-POSIX */
|
|
197
|
+
}
|
|
198
|
+
log(` Creating an SSH key at ${keyPath.replace(os.homedir(), '~')} (private half stays on this machine)…`);
|
|
199
|
+
const comment = `bongos ${os.hostname() || 'device'}`.slice(0, 80);
|
|
200
|
+
// No separate presence probe — ssh-keygen has no side-effect-free version
|
|
201
|
+
// flag, and a missing binary surfaces here as ENOENT with a clear message.
|
|
202
|
+
const r = spawnSync('ssh-keygen', ['-t', 'ed25519', '-N', '', '-C', comment, '-f', keyPath, '-q'], {
|
|
203
|
+
stdio: 'inherit',
|
|
204
|
+
shell: process.platform === 'win32',
|
|
205
|
+
windowsHide: true,
|
|
206
|
+
});
|
|
207
|
+
if (r && r.error && r.error.code === 'ENOENT') {
|
|
208
|
+
throw new Error(
|
|
209
|
+
'ssh-keygen was not found. Install OpenSSH (macOS/Linux ship it; on Windows enable the "OpenSSH Client" optional feature) and re-run.'
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
if (!r || r.error || r.status !== 0) {
|
|
213
|
+
throw new Error(`ssh-keygen failed to create ${keyPath}${r && r.error ? `: ${r.error.message}` : ''}`);
|
|
214
|
+
}
|
|
215
|
+
created = true;
|
|
216
|
+
}
|
|
217
|
+
let pubKey = null;
|
|
218
|
+
try {
|
|
219
|
+
// Trim to "<type> <base64>" — matches what connect.sh/the server keep.
|
|
220
|
+
const parts = fs.readFileSync(pubPath, 'utf8').trim().split(/\s+/);
|
|
221
|
+
if (parts.length >= 2) pubKey = `${parts[0]} ${parts[1]}`;
|
|
222
|
+
} catch (_) {
|
|
223
|
+
/* handled below */
|
|
224
|
+
}
|
|
225
|
+
if (!pubKey) throw new Error(`could not read a valid public key from ${pubPath}`);
|
|
226
|
+
return { keyPath, pubKey, created };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Register the public key with the GDS if it isn't already. Registers
|
|
230
|
+
// unconditionally when we just generated it (fresh laptop); otherwise only when
|
|
231
|
+
// the server's key list doesn't already carry this fingerprint — so re-runs don't
|
|
232
|
+
// spam the 10-key-per-builder cap. Best-effort: a failure here is surfaced as a
|
|
233
|
+
// warning, not fatal (SSH will report a genuine auth problem clearly).
|
|
234
|
+
async function ensureKeyRegistered({ created, keyPath, pubKey, log = console.log } = {}) {
|
|
235
|
+
const api = await cliClient();
|
|
236
|
+
let needed = created;
|
|
237
|
+
if (!needed) {
|
|
238
|
+
const fp = localKeyFingerprint(`${keyPath}.pub`);
|
|
239
|
+
let listed = null;
|
|
240
|
+
try {
|
|
241
|
+
const res = await api.box.getBoxSshKey();
|
|
242
|
+
if (res.ok && res.data && Array.isArray(res.data.keys)) listed = res.data.keys;
|
|
243
|
+
} catch (_) {
|
|
244
|
+
/* tolerate — fall through to the heuristics below */
|
|
245
|
+
}
|
|
246
|
+
if (fp && Array.isArray(listed)) {
|
|
247
|
+
needed = !listed.some((k) => k && k.fingerprint === fp);
|
|
248
|
+
} else if (fp == null && Array.isArray(listed) && listed.length > 0) {
|
|
249
|
+
needed = false; // can't compare, but keys exist → assume registered
|
|
250
|
+
} else {
|
|
251
|
+
needed = false; // no info → don't spam; SSH will surface a real auth failure
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (!needed) return { registered: false };
|
|
255
|
+
try {
|
|
256
|
+
const label = `bongos ${process.platform}`.slice(0, 80);
|
|
257
|
+
const res = await api.box.postBoxSshKey({ body: { public_key: pubKey, label } });
|
|
258
|
+
if (res.ok) {
|
|
259
|
+
log(' ✓ Registered your public key with the dev system.');
|
|
260
|
+
return { registered: true };
|
|
261
|
+
}
|
|
262
|
+
log(` ! Could not register your key (${res.data?.error || res.status}); if SSH is refused, add it via /builder-box.`);
|
|
263
|
+
} catch (err) {
|
|
264
|
+
log(` ! Could not register your key (${err.message}); if SSH is refused, add it via /builder-box.`);
|
|
265
|
+
}
|
|
266
|
+
return { registered: false };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// -------------------------------------------------------------------------
|
|
270
|
+
// Box lifecycle: ensure active + read connection details
|
|
271
|
+
// -------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
function sleep(ms) {
|
|
274
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Wake/provision the box and poll until it is active with a hostname. Returns the
|
|
278
|
+
// public box object from /box/me ({ state, hostname, ip, host_keys, … }).
|
|
279
|
+
// Throws on a provision denial (rank/blocked) or a timeout.
|
|
280
|
+
async function ensureBoxActive({ log = console.log, timeoutMs = 6 * 60 * 1000, intervalMs = 5000, sleepFn = sleep } = {}) {
|
|
281
|
+
const api = await cliClient();
|
|
282
|
+
const ensureRes = await api.box.postBoxEnsure();
|
|
283
|
+
if (ensureRes.status === 403) {
|
|
284
|
+
const msg = ensureRes.data?.message || ensureRes.data?.reason || 'dev-box access denied';
|
|
285
|
+
throw new Error(`Box could not be started: ${msg}`);
|
|
286
|
+
}
|
|
287
|
+
if (!ensureRes.ok) {
|
|
288
|
+
throw new Error(`POST /box/ensure failed (HTTP ${ensureRes.status}${ensureRes.data?.error ? `: ${ensureRes.data.error}` : ''})`);
|
|
289
|
+
}
|
|
290
|
+
const { action, message } = parseEnsure(ensureRes.data);
|
|
291
|
+
if (action === 'ready') {
|
|
292
|
+
log(' ✓ Box is already active.');
|
|
293
|
+
} else {
|
|
294
|
+
log(` Box is being ${action === 'wake' ? 'woken' : action === 'provision' ? 'created' : 'prepared'} — ${message || 'this can take a minute or two'}.`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const deadline = Date.now() + timeoutMs;
|
|
298
|
+
let lastState = null;
|
|
299
|
+
let announced = 0;
|
|
300
|
+
for (;;) {
|
|
301
|
+
const me = await api.box.getBoxMe();
|
|
302
|
+
const box = me.ok && me.data ? me.data.box : null;
|
|
303
|
+
if (box && box.state === 'active' && box.hostname) {
|
|
304
|
+
log(` ✓ Box active: ${box.hostname}`);
|
|
305
|
+
return box;
|
|
306
|
+
}
|
|
307
|
+
if (box && box.state !== lastState) {
|
|
308
|
+
lastState = box.state;
|
|
309
|
+
}
|
|
310
|
+
if (Date.now() >= deadline) {
|
|
311
|
+
throw new Error(
|
|
312
|
+
`Timed out after ${Math.round(timeoutMs / 1000)}s waiting for the box to become active (last state: ${box ? box.state : 'unknown'}). ` +
|
|
313
|
+
'It may still be provisioning — re-run in a minute, or check `bongos box` / the hall.'
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
// A quiet progress line every ~15s so the wait doesn't look hung.
|
|
317
|
+
if (Date.now() - announced >= 15000) {
|
|
318
|
+
log(` …still ${box && box.state ? box.state : 'starting'} (waiting for the box to come up)`);
|
|
319
|
+
announced = Date.now();
|
|
320
|
+
}
|
|
321
|
+
await sleepFn(intervalMs);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Fetch the caller's rank (GET /me). Returns the rank string, or null if it
|
|
326
|
+
// can't be determined.
|
|
327
|
+
async function fetchRank() {
|
|
328
|
+
try {
|
|
329
|
+
const api = await cliClient({ allowUnauthenticated: true });
|
|
330
|
+
const res = await api.me.getMe();
|
|
331
|
+
if (res.ok && res.data && res.data.builder) return res.data.builder.rank || null;
|
|
332
|
+
} catch (_) {
|
|
333
|
+
/* fall through */
|
|
334
|
+
}
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// -------------------------------------------------------------------------
|
|
339
|
+
// Write ~/.ssh/config alias + pin known_hosts (idempotent, best-effort)
|
|
340
|
+
// -------------------------------------------------------------------------
|
|
341
|
+
|
|
342
|
+
function writeSshAlias({ hostname, keyPath, log = console.log }) {
|
|
343
|
+
const cfgPath = path.join(sshDir(), 'config');
|
|
344
|
+
// IdentityFile keeps the ~ literal so it reads cleanly and works cross-machine.
|
|
345
|
+
const identityFile = keyPath.startsWith(os.homedir())
|
|
346
|
+
? keyPath.replace(os.homedir(), '~')
|
|
347
|
+
: keyPath;
|
|
348
|
+
let existing = '';
|
|
349
|
+
try {
|
|
350
|
+
existing = fs.readFileSync(cfgPath, 'utf8');
|
|
351
|
+
} catch (_) {
|
|
352
|
+
/* no config yet */
|
|
353
|
+
}
|
|
354
|
+
const next = upsertSshConfigText(existing, { hostname, identityFile });
|
|
355
|
+
if (next !== existing) {
|
|
356
|
+
fs.mkdirSync(sshDir(), { recursive: true });
|
|
357
|
+
fs.writeFileSync(cfgPath, next, { mode: 0o600 });
|
|
358
|
+
try {
|
|
359
|
+
fs.chmodSync(cfgPath, 0o600);
|
|
360
|
+
} catch (_) {
|
|
361
|
+
/* best-effort */
|
|
362
|
+
}
|
|
363
|
+
log(` ✓ Wrote SSH host alias for ${hostname} into ~/.ssh/config`);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function pinKnownHosts({ hostname, hostKeys, log = console.log }) {
|
|
368
|
+
if (!hostKeys) return; // box hasn't reported keys yet; accept-new covers first connect
|
|
369
|
+
const khPath = path.join(sshDir(), 'known_hosts');
|
|
370
|
+
let existing = '';
|
|
371
|
+
try {
|
|
372
|
+
existing = fs.readFileSync(khPath, 'utf8');
|
|
373
|
+
} catch (_) {
|
|
374
|
+
/* none yet */
|
|
375
|
+
}
|
|
376
|
+
const next = buildKnownHostsUpsert(existing, hostname, hostKeys);
|
|
377
|
+
if (next !== existing) {
|
|
378
|
+
fs.mkdirSync(sshDir(), { recursive: true });
|
|
379
|
+
fs.writeFileSync(khPath, next, { mode: 0o600 });
|
|
380
|
+
try {
|
|
381
|
+
fs.chmodSync(khPath, 0o600);
|
|
382
|
+
} catch (_) {
|
|
383
|
+
/* best-effort */
|
|
384
|
+
}
|
|
385
|
+
log(` ✓ Pinned ${hostname}'s verified host key(s) into ~/.ssh/known_hosts`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// The one-shot "get the box ready + local SSH set up" used by both verbs.
|
|
390
|
+
// Returns { box, keyPath }.
|
|
391
|
+
async function prepareConnection({ log = console.log } = {}) {
|
|
392
|
+
const { keyPath, pubKey, created } = ensureSshKey({ log });
|
|
393
|
+
await ensureKeyRegistered({ created, keyPath, pubKey, log });
|
|
394
|
+
const box = await ensureBoxActive({ log });
|
|
395
|
+
pinKnownHosts({ hostname: box.hostname, hostKeys: box.host_keys, log });
|
|
396
|
+
writeSshAlias({ hostname: box.hostname, keyPath, log });
|
|
397
|
+
return { box, keyPath };
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// First-run marker (per box hostname). /login enrollment persists on the box, so
|
|
401
|
+
// we only force the interactive claude handoff the first time we connect to a
|
|
402
|
+
// given box from this laptop.
|
|
403
|
+
function loginMarkerPath(hostname) {
|
|
404
|
+
const safe = String(hostname).replace(/[^A-Za-z0-9._-]/g, '_');
|
|
405
|
+
return ic.configPath(`box-login-${safe}.done`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function isFirstLogin(hostname) {
|
|
409
|
+
return !fs.existsSync(loginMarkerPath(hostname));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function markLoginDone(hostname) {
|
|
413
|
+
const p = loginMarkerPath(hostname);
|
|
414
|
+
try {
|
|
415
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
416
|
+
fs.writeFileSync(p, `${new Date().toISOString()}\n`);
|
|
417
|
+
} catch (_) {
|
|
418
|
+
/* best-effort — a missed marker just re-runs the harmless handoff */
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
module.exports = {
|
|
423
|
+
// constants
|
|
424
|
+
BOX_USER,
|
|
425
|
+
WORKSPACE,
|
|
426
|
+
CLAUDE_VSCODE_EXTENSION,
|
|
427
|
+
RANK_ORDER,
|
|
428
|
+
// pure helpers (tested)
|
|
429
|
+
rankAtLeast,
|
|
430
|
+
buildSshAliasBlock,
|
|
431
|
+
upsertSshConfigText,
|
|
432
|
+
buildKnownHostsUpsert,
|
|
433
|
+
buildRemoteShellCommand,
|
|
434
|
+
remoteAuthority,
|
|
435
|
+
parseEnsure,
|
|
436
|
+
// toolchain / paths
|
|
437
|
+
sshKeyPath,
|
|
438
|
+
binPresent,
|
|
439
|
+
localKeyFingerprint,
|
|
440
|
+
// key + box
|
|
441
|
+
ensureSshKey,
|
|
442
|
+
ensureKeyRegistered,
|
|
443
|
+
ensureBoxActive,
|
|
444
|
+
fetchRank,
|
|
445
|
+
// local ssh wiring
|
|
446
|
+
writeSshAlias,
|
|
447
|
+
pinKnownHosts,
|
|
448
|
+
prepareConnection,
|
|
449
|
+
// first-run login handoff
|
|
450
|
+
loginMarkerPath,
|
|
451
|
+
isFirstLogin,
|
|
452
|
+
markLoginDone,
|
|
453
|
+
};
|