@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,653 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// scripts/gds/sandbox-stage.js — stage the current working tree on the
|
|
3
|
+
// builder's own live game preview (the "sandbox", ADR 0044) so a change can be
|
|
4
|
+
// REVIEWED in a browser before /builder-ship pushes it toward the main game.
|
|
5
|
+
// (#927, ADR 0046 — the sandbox-first review step.)
|
|
6
|
+
//
|
|
7
|
+
// Two preview contexts (resolvePreviewContext picks one):
|
|
8
|
+
// - BOX (ADR 0031): box-game-preview.service serves the working tree at
|
|
9
|
+
// https://sandbox-<login>.amazonprimea.com; "staging" restarts the service.
|
|
10
|
+
// - LOCAL (task 1056): a builder on a full local clone (laptop) runs the same
|
|
11
|
+
// ADR 0052 game-only entry privately at http://localhost:<port> via
|
|
12
|
+
// scripts/gds/local-preview.js; "staging" (re)starts that local process.
|
|
13
|
+
// Either way staging = (re)start the preview to pick up the current working
|
|
14
|
+
// tree, health-check it, record a marker of exactly WHAT tree state was staged,
|
|
15
|
+
// and hand back the URL. ship.js consults the marker through runShipGate(): if
|
|
16
|
+
// the tree changed since the last staging, the builder is asked to stage +
|
|
17
|
+
// review again before the claim resolves. On approval (a TTY 'y' or an
|
|
18
|
+
// --approved re-run on a fresh stage) the gate returns a durable self-approval
|
|
19
|
+
// record that ship.js persists on the task (#1048) — box AND local alike.
|
|
20
|
+
//
|
|
21
|
+
// Usage (a partial clone with no game has no sandbox; the script says so):
|
|
22
|
+
// node scripts/gds/sandbox-stage.js # stage + print the review URL
|
|
23
|
+
// node scripts/gds/sandbox-stage.js status # preview state + is the marker current?
|
|
24
|
+
// node scripts/gds/sandbox-stage.js url # just print the sandbox URL
|
|
25
|
+
|
|
26
|
+
const { execFileSync } = require('node:child_process');
|
|
27
|
+
const crypto = require('node:crypto');
|
|
28
|
+
const fs = require('node:fs');
|
|
29
|
+
const os = require('node:os');
|
|
30
|
+
const path = require('node:path');
|
|
31
|
+
const readline = require('node:readline');
|
|
32
|
+
const localPreview = require('./local-preview-lib');
|
|
33
|
+
|
|
34
|
+
// /etc/otb/box.env exists ONLY on a provisioned dev box (written by box.js
|
|
35
|
+
// provision, #898) — the idiomatic "am I on a box?" marker in this codebase.
|
|
36
|
+
const BOX_ENV_PATH = '/etc/otb/box.env';
|
|
37
|
+
const PREVIEW_WRAPPER = '/usr/local/bin/box-preview';
|
|
38
|
+
const PREVIEW_UNIT = 'box-game-preview.service';
|
|
39
|
+
const HEALTH_URL = 'http://127.0.0.1:3000/';
|
|
40
|
+
const HEALTH_TIMEOUT_MS = 90_000; // first start may run npm ci (ExecStartPre)
|
|
41
|
+
const HEALTH_POLL_MS = 2_000;
|
|
42
|
+
|
|
43
|
+
// Game surfaces the sandbox can actually show. The sandbox host serves the
|
|
44
|
+
// GAME-ONLY entry (src/preview-server.js, ADR 0052), so only game-rendering paths
|
|
45
|
+
// are previewable — GDS/internal-tooling diffs have nothing to look at there.
|
|
46
|
+
// src/preview-server.js + server.js are the entrypoints that render the game.
|
|
47
|
+
const PREVIEWABLE_PREFIXES = ['public/', 'src/world/', 'src/rooms/'];
|
|
48
|
+
const PREVIEWABLE_FILES = new Set(['server.js', 'src/preview-server.js']);
|
|
49
|
+
// Same surfaces as git pathspecs (no trailing slash) for scoped plumbing calls.
|
|
50
|
+
const PREVIEWABLE_PATHSPECS = ['public', 'src/world', 'src/rooms', 'server.js', 'src/preview-server.js'];
|
|
51
|
+
|
|
52
|
+
// On a box, box-game-preview.service has WorkingDirectory=/workspace and serves
|
|
53
|
+
// /workspace/public — the MAIN checkout. A Claude session, though, runs in a git
|
|
54
|
+
// WORKTREE under /workspace/.claude/worktrees/<name>, so its edits never touch
|
|
55
|
+
// /workspace and the sandbox re-served stale code (the #1068 "I don't feel them"
|
|
56
|
+
// bug). We sync the previewable surfaces from the session's branch into this
|
|
57
|
+
// served root before restarting. Kept as a constant so tests can point it at a
|
|
58
|
+
// temp dir.
|
|
59
|
+
const BOX_SERVED_ROOT = '/workspace';
|
|
60
|
+
|
|
61
|
+
function isDevBox(deps = {}) {
|
|
62
|
+
const f = deps.fs || fs;
|
|
63
|
+
return f.existsSync(deps.boxEnvPath || BOX_ENV_PATH);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Parse BOX_PREVIEW_HOSTNAME out of box.env text. Returns the hostname string
|
|
67
|
+
// or null (a quick-tunnel box has no preview hostname — ADR 0044 §Consequences).
|
|
68
|
+
function readPreviewHostname(envText) {
|
|
69
|
+
const m = /^\s*(?:export\s+)?BOX_PREVIEW_HOSTNAME=(.*)$/m.exec(String(envText || ''));
|
|
70
|
+
if (!m) return null;
|
|
71
|
+
const v = m[1].trim().replace(/^["']|["']$/g, '').trim();
|
|
72
|
+
return v || null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function previewUrl(deps = {}) {
|
|
76
|
+
const f = deps.fs || fs;
|
|
77
|
+
const p = deps.boxEnvPath || BOX_ENV_PATH;
|
|
78
|
+
try {
|
|
79
|
+
const host = readPreviewHostname(f.readFileSync(p, 'utf8'));
|
|
80
|
+
return host ? `https://${host}` : null;
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isPreviewableFile(file) {
|
|
87
|
+
const fp = String(file || '').replace(/\\/g, '/');
|
|
88
|
+
if (PREVIEWABLE_FILES.has(fp)) return true;
|
|
89
|
+
return PREVIEWABLE_PREFIXES.some((p) => fp.startsWith(p));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function anyPreviewable(files) {
|
|
93
|
+
return (files || []).some(isPreviewableFile);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Identity of the staged state: a CONTENT hash of the previewable game
|
|
97
|
+
// surfaces as they sit in the working tree right now — exactly what the
|
|
98
|
+
// sandbox serves. Scoped + content-stable on purpose:
|
|
99
|
+
// - editing docs/GDS files does NOT invalidate a staged review (the sandbox
|
|
100
|
+
// shows none of that), and
|
|
101
|
+
// - `git add` / committing the SAME content does not either (blob hashes are
|
|
102
|
+
// content hashes), so the natural stage → review → commit → ship flow
|
|
103
|
+
// keeps the marker fresh.
|
|
104
|
+
// Any actual change to a game file (tracked, staged, or untracked) produces a
|
|
105
|
+
// different stamp and the ship gate asks for a fresh stage + review. Returns
|
|
106
|
+
// null if git fails (not a repo) — callers treat that as "cannot assert
|
|
107
|
+
// freshness".
|
|
108
|
+
function computeTreeStamp(deps = {}) {
|
|
109
|
+
const run = deps.execFileSync || execFileSync;
|
|
110
|
+
const cwd = deps.cwd || process.cwd();
|
|
111
|
+
try {
|
|
112
|
+
const tracked = run('git', ['ls-files', '--', ...PREVIEWABLE_PATHSPECS], { cwd, encoding: 'utf8' });
|
|
113
|
+
const untracked = run('git', ['ls-files', '-o', '--exclude-standard', '--', ...PREVIEWABLE_PATHSPECS], { cwd, encoding: 'utf8' });
|
|
114
|
+
const f = deps.fs || fs;
|
|
115
|
+
const files = [...new Set([...tracked.split('\n'), ...untracked.split('\n')])]
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
.filter((p) => f.existsSync(path.join(cwd, p))) // deleted-but-still-indexed files
|
|
118
|
+
.sort();
|
|
119
|
+
const hashes = files.length === 0 ? '' : run('git', ['hash-object', '--stdin-paths'], {
|
|
120
|
+
cwd, encoding: 'utf8', input: files.join('\n') + '\n', maxBuffer: 64 * 1024 * 1024,
|
|
121
|
+
});
|
|
122
|
+
// The sorted file list is part of the stamp so deletions/renames count too.
|
|
123
|
+
return crypto.createHash('sha256').update(files.join('\n') + '\n' + hashes).digest('hex');
|
|
124
|
+
} catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// True when the WORKING TREE has uncommitted (or untracked) changes on a
|
|
130
|
+
// previewable surface — the committed diff alone misses these, but the
|
|
131
|
+
// sandbox shows them, so the gate must too.
|
|
132
|
+
function workingTreePreviewable(deps = {}) {
|
|
133
|
+
const run = deps.execFileSync || execFileSync;
|
|
134
|
+
const cwd = deps.cwd || process.cwd();
|
|
135
|
+
try {
|
|
136
|
+
const out = run('git', ['status', '--porcelain', '--', ...PREVIEWABLE_PATHSPECS], { cwd, encoding: 'utf8' });
|
|
137
|
+
return out.trim().length > 0;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function markerPath(deps = {}) {
|
|
144
|
+
return deps.markerPath || path.join((deps.tmpdir || os.tmpdir)(), 'otb-sandbox-staged.json');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function readMarker(deps = {}) {
|
|
148
|
+
const f = deps.fs || fs;
|
|
149
|
+
try {
|
|
150
|
+
return JSON.parse(f.readFileSync(markerPath(deps), 'utf8'));
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function writeMarker(marker, deps = {}) {
|
|
157
|
+
const f = deps.fs || fs;
|
|
158
|
+
f.writeFileSync(markerPath(deps), JSON.stringify(marker, null, 2) + '\n');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Pure decision for the ship gate. Returns one of:
|
|
162
|
+
// skip — gate doesn't apply (no sandbox here / nothing previewable / no
|
|
163
|
+
// preview URL / --skip-stage); ship proceeds untouched.
|
|
164
|
+
// pass — current game-surface state is already staged on the sandbox;
|
|
165
|
+
// the builder had their review opportunity — proceed.
|
|
166
|
+
// review — interactive TTY: stage now, hand over the URL, ask before
|
|
167
|
+
// resolving.
|
|
168
|
+
// stage_abort — non-interactive (the dominant case: an agent-driven session
|
|
169
|
+
// runs ship.js through a non-TTY shell): stage so the sandbox
|
|
170
|
+
// shows the work, then ABORT with the claim intact and the
|
|
171
|
+
// review URL. The agent relays the URL, the human reviews, and
|
|
172
|
+
// the re-run passes on the now-fresh marker. Never hangs on
|
|
173
|
+
// stdin; never silently skips the review.
|
|
174
|
+
// gateActive = there IS a sandbox here to review on (a dev box OR a local game
|
|
175
|
+
// preview). The decision is identical for both; only HOW we stage + the URL differ.
|
|
176
|
+
function decideShipGate({ gateActive, previewUrl: url, previewable, stagedFresh, tty, skipStage }) {
|
|
177
|
+
if (skipStage) return { action: 'skip', reason: '--skip-stage' };
|
|
178
|
+
if (!gateActive) return { action: 'skip', reason: 'no sandbox here (not a dev box; no local game preview)' };
|
|
179
|
+
if (!previewable) return { action: 'skip', reason: 'no previewable game surfaces in the diff' };
|
|
180
|
+
if (!url) return { action: 'skip', reason: 'preview has no URL (quick-tunnel box / local preview unavailable)' };
|
|
181
|
+
if (stagedFresh) return { action: 'pass', reason: 'working tree already staged' };
|
|
182
|
+
return tty ? { action: 'review', reason: 'stage + review before ship' }
|
|
183
|
+
: { action: 'stage_abort', reason: 'non-interactive: stage, then pause for review' };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function restartPreview(deps = {}) {
|
|
187
|
+
const run = deps.execFileSync || execFileSync;
|
|
188
|
+
const f = deps.fs || fs;
|
|
189
|
+
// The baked wrapper is the expected path on every box (cloud-init +
|
|
190
|
+
// box-source-fetch self-heal bake it to /usr/local/bin, and it handles its
|
|
191
|
+
// own sudo). The raw systemctl branch is only a degraded fallback.
|
|
192
|
+
if (f.existsSync(deps.previewWrapper || PREVIEW_WRAPPER)) {
|
|
193
|
+
run(deps.previewWrapper || PREVIEW_WRAPPER, ['restart'], { stdio: 'inherit' });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const needSudo = typeof process.getuid === 'function' && process.getuid() !== 0;
|
|
197
|
+
const cmd = needSudo ? 'sudo' : 'systemctl';
|
|
198
|
+
const argv = needSudo ? ['-n', 'systemctl', 'restart', PREVIEW_UNIT] : ['restart', PREVIEW_UNIT];
|
|
199
|
+
run(cmd, argv, { stdio: 'inherit' });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function waitHealthy(deps = {}) {
|
|
203
|
+
const fetchImpl = deps.fetchImpl || fetch;
|
|
204
|
+
const healthUrl = deps.healthUrl || HEALTH_URL;
|
|
205
|
+
const deadline = Date.now() + (deps.timeoutMs || HEALTH_TIMEOUT_MS);
|
|
206
|
+
let lastErr = 'no response';
|
|
207
|
+
while (Date.now() < deadline) {
|
|
208
|
+
try {
|
|
209
|
+
const res = await fetchImpl(healthUrl, { signal: AbortSignal.timeout(5_000) });
|
|
210
|
+
if (res.status < 500) return { ok: true };
|
|
211
|
+
lastErr = `HTTP ${res.status}`;
|
|
212
|
+
} catch (e) {
|
|
213
|
+
lastErr = e.message;
|
|
214
|
+
}
|
|
215
|
+
await new Promise((r) => setTimeout(r, deps.pollMs || HEALTH_POLL_MS));
|
|
216
|
+
}
|
|
217
|
+
return { ok: false, reason: lastErr };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// The git checkout the session is editing. On a box this is a linked worktree
|
|
221
|
+
// under /workspace/.claude/worktrees/<name>; on a laptop it's the clone root.
|
|
222
|
+
// Returns the toplevel path or null (not a repo).
|
|
223
|
+
function sessionCheckoutRoot(deps = {}) {
|
|
224
|
+
const run = deps.execFileSync || execFileSync;
|
|
225
|
+
const cwd = deps.cwd || process.cwd();
|
|
226
|
+
try {
|
|
227
|
+
return run('git', ['rev-parse', '--show-toplevel'], { cwd, encoding: 'utf8' }).trim() || null;
|
|
228
|
+
} catch {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Box-only (#1068 gap 1): materialize the session worktree's previewable game
|
|
234
|
+
// surfaces into the served checkout (/workspace) so the box preview shows the
|
|
235
|
+
// SESSION's edits, not stale main. The served root and the worktree share one
|
|
236
|
+
// object store (linked worktree), so `git -C /workspace checkout <branch> -- <paths>`
|
|
237
|
+
// brings the branch's committed content for exactly the previewable pathspecs.
|
|
238
|
+
// ship.js preflight already proved the worktree is clean (committed == working
|
|
239
|
+
// tree), so committed content is what the builder means. No-op when the session
|
|
240
|
+
// checkout IS the served root (a box where the builder edits /workspace directly,
|
|
241
|
+
// or a laptop). Returns { ok, synced, reason?, branch? }.
|
|
242
|
+
// Canonicalize a path through symlinks for a same-directory comparison. Needed
|
|
243
|
+
// because `git rev-parse --show-toplevel` (sessionCheckoutRoot) returns the REAL
|
|
244
|
+
// path, while servedRoot may be a symlink — on macOS `/tmp` -> `/private/var`
|
|
245
|
+
// (idea #278), or any symlinked served root. path.resolve does NOT resolve
|
|
246
|
+
// symlinks, so the raw comparison false-negatives "same dir" and the code would
|
|
247
|
+
// wrongly try to git-sync a checkout onto itself. Falls back to path.resolve when
|
|
248
|
+
// the path doesn't exist yet (realpathSync throws ENOENT).
|
|
249
|
+
function realPathOr(p) {
|
|
250
|
+
try { return fs.realpathSync(p); } catch { return path.resolve(p); }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function syncWorktreeToServed(deps = {}) {
|
|
254
|
+
const run = deps.execFileSync || execFileSync;
|
|
255
|
+
const servedRoot = deps.servedRoot || BOX_SERVED_ROOT;
|
|
256
|
+
const sessionRoot = sessionCheckoutRoot(deps);
|
|
257
|
+
if (!sessionRoot || realPathOr(sessionRoot) === realPathOr(servedRoot)) {
|
|
258
|
+
return { ok: true, synced: false, reason: 'session checkout is the served checkout' };
|
|
259
|
+
}
|
|
260
|
+
let branch;
|
|
261
|
+
try {
|
|
262
|
+
branch = run('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: sessionRoot, encoding: 'utf8' }).trim();
|
|
263
|
+
} catch {
|
|
264
|
+
branch = null;
|
|
265
|
+
}
|
|
266
|
+
if (!branch || branch === 'HEAD') {
|
|
267
|
+
return { ok: false, synced: false, reason: 'could not resolve the session branch (detached HEAD?)' };
|
|
268
|
+
}
|
|
269
|
+
// Check out each previewable pathspec INDEPENDENTLY: `git checkout <ref> -- a b c`
|
|
270
|
+
// fails ENTIRELY if any single pathspec is absent from the ref, and a sparse
|
|
271
|
+
// box (STARTER_SPARSE_PATHS) may legitimately lack server.js / src/preview-server.js.
|
|
272
|
+
// Per-pathspec lets us sync what exists and skip what doesn't; verifyServedFresh
|
|
273
|
+
// is the safety net that catches a sync that didn't actually land. First restore
|
|
274
|
+
// each path from the served checkout's own HEAD (undo any prior ship's leftovers),
|
|
275
|
+
// then overlay the session branch's content.
|
|
276
|
+
let synced = false;
|
|
277
|
+
let lastErr = null;
|
|
278
|
+
for (const ps of PREVIEWABLE_PATHSPECS) {
|
|
279
|
+
try {
|
|
280
|
+
run('git', ['-C', servedRoot, 'checkout', '--', ps], { stdio: 'ignore' });
|
|
281
|
+
} catch {
|
|
282
|
+
/* pathspec absent in the served HEAD — nothing to restore, fine */
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
run('git', ['-C', servedRoot, 'checkout', branch, '--', ps], { stdio: 'ignore' });
|
|
286
|
+
synced = true;
|
|
287
|
+
} catch (e) {
|
|
288
|
+
lastErr = e; // pathspec absent in the branch (sparse/missing) — skip it
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (!synced) {
|
|
292
|
+
return { ok: false, synced: false, reason: `git checkout ${branch} -- <previewable> in ${servedRoot} synced nothing${lastErr ? ` (${lastErr.message})` : ''}` };
|
|
293
|
+
}
|
|
294
|
+
return { ok: true, synced: true, branch };
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Pick the smallest cheap-to-compare changed previewable static file to verify,
|
|
298
|
+
// and the URL path the preview serves it at (public/game/x.js -> /game/x.js).
|
|
299
|
+
// Returns { relPath, urlPath } or null when there's no served static change.
|
|
300
|
+
function pickVerifyTarget(deps = {}) {
|
|
301
|
+
const run = deps.execFileSync || execFileSync;
|
|
302
|
+
const cwd = deps.cwd || process.cwd();
|
|
303
|
+
const f = deps.fs || fs;
|
|
304
|
+
try {
|
|
305
|
+
const out = run('git', ['status', '--porcelain', '--', 'public'], { cwd, encoding: 'utf8' });
|
|
306
|
+
let chosen = out
|
|
307
|
+
.split('\n')
|
|
308
|
+
.map((line) => line.slice(3).replace(/^"|"$/g, '').trim())
|
|
309
|
+
.find((rel) => rel && rel.startsWith('public/') && f.existsSync(path.join(cwd, rel)));
|
|
310
|
+
if (!chosen) {
|
|
311
|
+
// committed-only change: fall back to the diff vs the frozen origin/main
|
|
312
|
+
const diff = run('git', ['diff', '--name-only', 'origin/main...HEAD', '--', 'public'], { cwd, encoding: 'utf8' });
|
|
313
|
+
chosen = diff
|
|
314
|
+
.split('\n')
|
|
315
|
+
.map((s) => s.trim())
|
|
316
|
+
.find((p) => p.startsWith('public/') && f.existsSync(path.join(cwd, p)));
|
|
317
|
+
}
|
|
318
|
+
if (!chosen) return null;
|
|
319
|
+
return { relPath: chosen, urlPath: '/' + chosen.replace(/^public\//, '') };
|
|
320
|
+
} catch {
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Box-only (#1068 gap 1b): after staging, fetch one changed static file from the
|
|
326
|
+
// RUNNING preview over loopback (bypasses Cloudflare + browser cache, so it
|
|
327
|
+
// proves the SERVER is fresh) and confirm it byte-matches the worktree. Returns
|
|
328
|
+
// { ok, verified?|skipped?, reason? }. A mismatch means the sandbox is serving
|
|
329
|
+
// stale code despite the restart — fail loudly.
|
|
330
|
+
async function verifyServedFresh(deps = {}) {
|
|
331
|
+
const fetchImpl = deps.fetchImpl || fetch;
|
|
332
|
+
const f = deps.fs || fs;
|
|
333
|
+
const cwd = deps.cwd || process.cwd();
|
|
334
|
+
const base = (deps.healthUrl || HEALTH_URL).replace(/\/$/, '');
|
|
335
|
+
const target = pickVerifyTarget(deps);
|
|
336
|
+
if (!target) return { ok: true, skipped: true, reason: 'no served static change to verify (e.g. only src/rooms changed)' };
|
|
337
|
+
let want;
|
|
338
|
+
try {
|
|
339
|
+
want = f.readFileSync(path.join(cwd, target.relPath), 'utf8');
|
|
340
|
+
} catch {
|
|
341
|
+
return { ok: true, skipped: true, reason: 'could not read the worktree file to compare' };
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const res = await fetchImpl(`${base}${target.urlPath}`, {
|
|
345
|
+
headers: { 'Cache-Control': 'no-cache' },
|
|
346
|
+
signal: AbortSignal.timeout(5_000),
|
|
347
|
+
});
|
|
348
|
+
if (res.status >= 400) return { ok: false, reason: `preview returned HTTP ${res.status} for ${target.urlPath}` };
|
|
349
|
+
const got = await res.text();
|
|
350
|
+
if (got === want) return { ok: true, verified: target.relPath };
|
|
351
|
+
return { ok: false, reason: `served ${target.urlPath} does NOT match your worktree ${target.relPath} — the sandbox is serving stale code` };
|
|
352
|
+
} catch (e) {
|
|
353
|
+
return { ok: false, reason: `could not fetch ${target.urlPath} from the running preview to verify freshness: ${e.message}` };
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Which sandbox does this machine have? A box (ADR 0044) is keyed by ANY box
|
|
358
|
+
// marker (localPreview.onBox: box.env, the box-preview wrapper, or the
|
|
359
|
+
// box-game-preview.service unit — broader than box.env alone so a box with a
|
|
360
|
+
// lost/unreadable box.env is STILL routed to the box branch, never to localhost
|
|
361
|
+
// — task 1443); a full LOCAL clone (task 1056) is keyed by the presence of the
|
|
362
|
+
// game-only entry (src/preview-server.js). Returns a uniform context
|
|
363
|
+
// { kind, url, healthUrl, restart(deps) } — or null when there is NO sandbox
|
|
364
|
+
// here (a partial clone with no game). On a box the url comes from box.env's
|
|
365
|
+
// BOX_PREVIEW_HOSTNAME; if that's missing the url is null and stage() returns a
|
|
366
|
+
// clear "no sandbox hostname" message — but it is NEVER a localhost URL the
|
|
367
|
+
// builder's browser can't reach. deps.previewContext short-circuits for
|
|
368
|
+
// hermetic tests. The box branch is checked FIRST: a box also has the game
|
|
369
|
+
// entry, so order is what keeps onBox from being shadowed by hasGameEntry.
|
|
370
|
+
function resolvePreviewContext(deps = {}) {
|
|
371
|
+
if (deps.previewContext !== undefined) return deps.previewContext;
|
|
372
|
+
if (localPreview.onBox(deps)) {
|
|
373
|
+
return {
|
|
374
|
+
kind: 'box',
|
|
375
|
+
url: previewUrl(deps),
|
|
376
|
+
healthUrl: HEALTH_URL,
|
|
377
|
+
restart: (d) => restartPreview(d),
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
if (localPreview.hasGameEntry(deps)) {
|
|
381
|
+
return {
|
|
382
|
+
kind: 'local',
|
|
383
|
+
url: localPreview.localUrl(deps),
|
|
384
|
+
healthUrl: localPreview.healthUrl(deps),
|
|
385
|
+
// localPreview.restart returns {ok,reason}; throw so stage()'s try/catch
|
|
386
|
+
// turns a failed local start into the standard "could not start" reason.
|
|
387
|
+
restart: (d) => { const r = localPreview.restart(d); if (!r.ok) throw new Error(r.reason); },
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// Stage the current working tree: (re)start the resolved preview, wait for it to
|
|
394
|
+
// answer, write the staged marker. Returns { ok, url, kind, reason? }.
|
|
395
|
+
async function stage({ taskId } = {}, deps = {}) {
|
|
396
|
+
const ctx = resolvePreviewContext(deps);
|
|
397
|
+
if (!ctx) return { ok: false, reason: 'no sandbox here (not a dev box, and this clone has no local game preview)' };
|
|
398
|
+
if (!ctx.url) {
|
|
399
|
+
return { ok: false, reason: ctx.kind === 'box'
|
|
400
|
+
? 'no sandbox hostname on this box — box.env has no BOX_PREVIEW_HOSTNAME (a quick-tunnel box, or box.env is missing/unreadable). Run `box-preview status` for your URL, or ask the operator to re-provision with BOX_NAMED_TUNNEL=1 (ADR 0044). NOT a localhost link — that is unreachable from your browser on a box.'
|
|
401
|
+
: 'local preview URL unavailable' };
|
|
402
|
+
}
|
|
403
|
+
console.log(ctx.kind === 'local'
|
|
404
|
+
? 'Staging your working tree on your local sandbox (starting the game preview)...'
|
|
405
|
+
: 'Staging your working tree on the sandbox (syncing your worktree, then restarting the game preview)...');
|
|
406
|
+
// #1068 gap 1: a box serves /workspace, not the session worktree. Sync the
|
|
407
|
+
// previewable surfaces from the branch into /workspace BEFORE the restart so
|
|
408
|
+
// the preview picks up the SESSION's edits. hard:true → the ship gate aborts
|
|
409
|
+
// (a stale sandbox review is worse than no review). Local already serves the
|
|
410
|
+
// worktree, so this is box-only.
|
|
411
|
+
if (ctx.kind === 'box') {
|
|
412
|
+
const sync = (deps.syncWorktreeToServed || syncWorktreeToServed)(deps);
|
|
413
|
+
if (!sync.ok) {
|
|
414
|
+
return { ok: false, hard: true, reason: `could not sync your worktree to the served checkout (${sync.reason}); the sandbox would show stale ${deps.servedRoot || BOX_SERVED_ROOT} code` };
|
|
415
|
+
}
|
|
416
|
+
if (sync.synced) console.log(` synced previewable surfaces from ${sync.branch} into ${deps.servedRoot || BOX_SERVED_ROOT}`);
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
ctx.restart(deps);
|
|
420
|
+
} catch (e) {
|
|
421
|
+
return { ok: false, reason: `could not start the ${ctx.kind} preview: ${e.message}` };
|
|
422
|
+
}
|
|
423
|
+
const health = await waitHealthy({ ...deps, healthUrl: ctx.healthUrl });
|
|
424
|
+
if (!health.ok) {
|
|
425
|
+
const where = ctx.kind === 'local' ? 'node scripts/gds/local-preview.js logs' : 'box-preview logs';
|
|
426
|
+
return { ok: false, reason: `preview did not come up healthy (${health.reason}) — check '${where}'` };
|
|
427
|
+
}
|
|
428
|
+
// #1068 gap 1b: confirm the restarted box preview is actually serving the
|
|
429
|
+
// synced bytes (loopback fetch, cache-bypassed). A mismatch is a hard fail —
|
|
430
|
+
// claiming "staged" when the sandbox shows stale code is the bug we're killing.
|
|
431
|
+
if (ctx.kind === 'box') {
|
|
432
|
+
const v = await (deps.verifyServedFresh || verifyServedFresh)({ ...deps, healthUrl: ctx.healthUrl });
|
|
433
|
+
if (!v.ok) {
|
|
434
|
+
return { ok: false, hard: true, reason: `staged but FAILED freshness verification: ${v.reason}` };
|
|
435
|
+
}
|
|
436
|
+
if (v.verified) console.log(` verified the sandbox is serving your edits (${v.verified} matches)`);
|
|
437
|
+
else if (v.skipped) console.log(` freshness verify skipped (${v.reason})`);
|
|
438
|
+
}
|
|
439
|
+
writeMarker({
|
|
440
|
+
stamp: computeTreeStamp(deps),
|
|
441
|
+
url: ctx.url,
|
|
442
|
+
kind: ctx.kind,
|
|
443
|
+
task_id: taskId ?? null,
|
|
444
|
+
staged_at: new Date().toISOString(),
|
|
445
|
+
}, deps);
|
|
446
|
+
return { ok: true, url: ctx.url, kind: ctx.kind };
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function promptYesNo(question) {
|
|
450
|
+
return new Promise((resolve) => {
|
|
451
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
452
|
+
rl.question(question, (answer) => {
|
|
453
|
+
rl.close();
|
|
454
|
+
resolve(/^y(es)?$/i.test(String(answer || '').trim()));
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// The prominent, easy-to-surface review block (#1048). ship.js almost always
|
|
460
|
+
// runs in a NON-TTY shell inside the builder's Claude session, so the AGENT is
|
|
461
|
+
// the one that relays this to the human — the /builder-ship skill instructs it
|
|
462
|
+
// to present the URL as its own callout in chat. Keep the URL ALONE on its own
|
|
463
|
+
// line, framed by a rule, so it stands out from the surrounding log noise and
|
|
464
|
+
// stays clickable. This is the moment the change is "ready to review", so the
|
|
465
|
+
// link has to be impossible to miss. Works for a box (sandbox-<login>) or a
|
|
466
|
+
// local clone (http://localhost:<port>) — the URL is passed in.
|
|
467
|
+
function printReviewBlock(url, taskId) {
|
|
468
|
+
const bar = '─'.repeat(64);
|
|
469
|
+
console.log('');
|
|
470
|
+
console.log(bar);
|
|
471
|
+
console.log(' 🔍 REVIEW REQUIRED — your change is live on YOUR sandbox (not prod)');
|
|
472
|
+
console.log('');
|
|
473
|
+
console.log(` ${url}`);
|
|
474
|
+
console.log('');
|
|
475
|
+
console.log(` Open that link and walk through the change in the browser${taskId ? ` (task #${taskId})` : ''}.`);
|
|
476
|
+
console.log(' When it looks right, approve to ship to the main game:');
|
|
477
|
+
console.log(' re-run /builder-ship --approved ← records your sign-off');
|
|
478
|
+
console.log(bar);
|
|
479
|
+
console.log('');
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Build the recorded-approval payload ship.js threads into the resolve call
|
|
483
|
+
// (#1048). The server stamps `by`/`at` authoritatively — we only supply the
|
|
484
|
+
// content stamp of what was reviewed, the sandbox URL (box OR local), and HOW
|
|
485
|
+
// it was approved.
|
|
486
|
+
function approvalRecord(method, url, deps) {
|
|
487
|
+
return { stamp: computeTreeStamp(deps), url, method };
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// The gate ship.js runs before resolving the claim (#927, ADR 0046).
|
|
491
|
+
// Returns { ok: true } to proceed or { ok: false, reason } to abort the ship
|
|
492
|
+
// with the claim still active so the builder can iterate. On a recorded
|
|
493
|
+
// approval it also returns { sandboxReview } so ship.js can persist the
|
|
494
|
+
// self-approval as a durable fact on the task (#1048) — for a box or a local
|
|
495
|
+
// clone (task 1056).
|
|
496
|
+
//
|
|
497
|
+
// `approved` (the --approved flag) records the builder's sign-off, but ONLY
|
|
498
|
+
// when the current game state is already staged-fresh (decideShipGate → 'pass')
|
|
499
|
+
// — i.e. a re-run after the work was staged and reviewed on a prior invocation.
|
|
500
|
+
// It can never short-circuit the first stage+review of a change: a stale/absent
|
|
501
|
+
// marker still stages and pauses, so there is nothing to "pre-approve".
|
|
502
|
+
async function runShipGate({ taskId, files, skipStage, tty, approved }, deps = {}) {
|
|
503
|
+
const ctx = resolvePreviewContext(deps);
|
|
504
|
+
const gateActive = Boolean(ctx);
|
|
505
|
+
const url = ctx ? ctx.url : null;
|
|
506
|
+
// Previewable = the committed diff OR uncommitted working-tree edits touch a
|
|
507
|
+
// game surface — the sandbox serves the working tree, so both views count.
|
|
508
|
+
const previewable = anyPreviewable(files) || (gateActive && workingTreePreviewable(deps));
|
|
509
|
+
const marker = gateActive ? readMarker(deps) : null;
|
|
510
|
+
const stamp = gateActive ? computeTreeStamp(deps) : null;
|
|
511
|
+
const stagedFresh = Boolean(stamp && marker && marker.stamp === stamp);
|
|
512
|
+
const d = decideShipGate({ gateActive, previewUrl: url, previewable, stagedFresh, tty, skipStage });
|
|
513
|
+
|
|
514
|
+
if (d.action === 'skip') {
|
|
515
|
+
if (gateActive && previewable) console.log(`Sandbox review gate: skipped (${d.reason}).`);
|
|
516
|
+
return { ok: true };
|
|
517
|
+
}
|
|
518
|
+
if (d.action === 'pass') {
|
|
519
|
+
// This exact game state is already staged + reviewable on the sandbox.
|
|
520
|
+
if (approved) {
|
|
521
|
+
// Explicit sign-off after an out-of-band review — record it (#1048).
|
|
522
|
+
console.log(`Sandbox review: recorded your approval of ${url} — shipping to the main game.`);
|
|
523
|
+
return { ok: true, sandboxReview: approvalRecord('flag', url, deps) };
|
|
524
|
+
}
|
|
525
|
+
// Back-compat / failure-open: a bare fresh-marker re-run still ships, but
|
|
526
|
+
// there is no human sign-off to record. Nudge toward --approved next time.
|
|
527
|
+
console.log(`Sandbox review: this exact game state is already staged at ${url} — proceeding.`);
|
|
528
|
+
console.log(' note: no sandbox approval recorded (re-ran on a fresh stage without --approved);');
|
|
529
|
+
console.log(' re-run /builder-ship --approved after reviewing to record your sign-off.');
|
|
530
|
+
return { ok: true };
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// 'review' and 'stage_abort' both stage first so the sandbox shows the work.
|
|
534
|
+
// Reuse the already-resolved context so we don't resolve it twice.
|
|
535
|
+
const staged = await stage({ taskId }, { ...deps, previewContext: ctx });
|
|
536
|
+
if (!staged.ok) {
|
|
537
|
+
// #1068: a HARD failure (couldn't sync the worktree to the served checkout,
|
|
538
|
+
// or the preview verifiably served stale code) means a review here would be
|
|
539
|
+
// a LIE — abort with the claim intact so the builder fixes it. A SOFT
|
|
540
|
+
// failure (the preview simply didn't come up) must not brick shipping — the
|
|
541
|
+
// gate is a review aid, not a wall: warn loudly and continue.
|
|
542
|
+
if (staged.hard) {
|
|
543
|
+
return {
|
|
544
|
+
ok: false,
|
|
545
|
+
review: true,
|
|
546
|
+
url: staged.url,
|
|
547
|
+
reason: `sandbox staging could not be trusted (${staged.reason}) — fix it, then re-run /builder-ship (or --skip-stage to bypass the review). Your claim is still active`,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
console.error(`warn: sandbox staging failed (${staged.reason}); continuing without the review step.`);
|
|
551
|
+
return { ok: true };
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (d.action === 'stage_abort') {
|
|
555
|
+
printReviewBlock(staged.url, taskId);
|
|
556
|
+
return {
|
|
557
|
+
ok: false,
|
|
558
|
+
review: true,
|
|
559
|
+
url: staged.url,
|
|
560
|
+
reason: `game changes must be reviewed on the sandbox before shipping — staged at ${staged.url}; open it, review the change (suggest fixes if needed), then re-run /builder-ship --approved to record your sign-off and ship (--skip-stage to bypass)`,
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Interactive (TTY): show the same prominent block, then ask in-line.
|
|
565
|
+
printReviewBlock(staged.url, taskId);
|
|
566
|
+
const yes = await (deps.promptYesNo || promptYesNo)(
|
|
567
|
+
'Reviewed on the sandbox — ship this to the main game? [y/N]: '
|
|
568
|
+
);
|
|
569
|
+
if (!yes) {
|
|
570
|
+
return {
|
|
571
|
+
ok: false,
|
|
572
|
+
review: true,
|
|
573
|
+
url: staged.url,
|
|
574
|
+
reason: `sandbox review declined — iterate on the change, restage (node scripts/gds/sandbox-stage.js), and re-run /builder-ship when it looks right at ${staged.url}`,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
// A TTY 'y' IS the explicit approval — record it (#1048).
|
|
578
|
+
return { ok: true, sandboxReview: approvalRecord('tty', staged.url, deps) };
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async function cliMain() {
|
|
582
|
+
const cmd = process.argv[2] || 'stage';
|
|
583
|
+
const ctx = resolvePreviewContext();
|
|
584
|
+
const NO_SANDBOX = 'No sandbox here — not a dev box, and this clone has no game preview entry (src/preview-server.js).';
|
|
585
|
+
|
|
586
|
+
if (cmd === 'url') {
|
|
587
|
+
console.log(ctx && ctx.url ? ctx.url : '(no sandbox here — not a dev box, and no local game preview in this clone)');
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
if (cmd === 'status') {
|
|
591
|
+
if (!ctx) { console.log(NO_SANDBOX); return; }
|
|
592
|
+
const marker = readMarker();
|
|
593
|
+
const stamp = computeTreeStamp();
|
|
594
|
+
const fresh = Boolean(stamp && marker && marker.stamp === stamp);
|
|
595
|
+
console.log(`sandbox kind: ${ctx.kind}`);
|
|
596
|
+
console.log(`sandbox URL: ${ctx.url || '(none — quick-tunnel box)'}`);
|
|
597
|
+
if (ctx.kind === 'local') {
|
|
598
|
+
console.log(`local preview: ${localPreview.isRunning() ? `running (pid ${localPreview.readPid()})` : 'stopped — staging will start it'}`);
|
|
599
|
+
}
|
|
600
|
+
console.log(`staged marker: ${marker ? `staged ${marker.staged_at}${marker.task_id ? ` (task #${marker.task_id})` : ''}` : '(never staged)'}`);
|
|
601
|
+
console.log(`current game state: ${fresh ? 'MATCHES the staged state — sandbox is current' : 'differs from the staged state — run sandbox-stage to refresh'}`);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (cmd !== 'stage') {
|
|
605
|
+
console.error(`sandbox-stage: unknown command '${cmd}' (try: stage | status | url)`);
|
|
606
|
+
process.exit(2);
|
|
607
|
+
}
|
|
608
|
+
if (!ctx) {
|
|
609
|
+
console.log(NO_SANDBOX);
|
|
610
|
+
console.log('A full local clone gets a private localhost preview; a partial clone does not.');
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
const res = await stage({});
|
|
614
|
+
if (!res.ok) {
|
|
615
|
+
console.error(`sandbox-stage failed: ${res.reason}`);
|
|
616
|
+
process.exit(1);
|
|
617
|
+
}
|
|
618
|
+
console.log('');
|
|
619
|
+
console.log(`Staged. Review your change in a browser at: ${res.url}`);
|
|
620
|
+
if (res.kind === 'local') console.log('(A private localhost copy — degraded DB, nothing shipped. Edit + re-run to refresh.)');
|
|
621
|
+
console.log('When it looks right, run /builder-ship to push it to the main game.');
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
module.exports = {
|
|
625
|
+
isDevBox,
|
|
626
|
+
readPreviewHostname,
|
|
627
|
+
previewUrl,
|
|
628
|
+
isPreviewableFile,
|
|
629
|
+
anyPreviewable,
|
|
630
|
+
computeTreeStamp,
|
|
631
|
+
workingTreePreviewable,
|
|
632
|
+
markerPath,
|
|
633
|
+
readMarker,
|
|
634
|
+
writeMarker,
|
|
635
|
+
decideShipGate,
|
|
636
|
+
resolvePreviewContext,
|
|
637
|
+
stage,
|
|
638
|
+
runShipGate,
|
|
639
|
+
BOX_ENV_PATH,
|
|
640
|
+
BOX_SERVED_ROOT,
|
|
641
|
+
PREVIEWABLE_PATHSPECS,
|
|
642
|
+
sessionCheckoutRoot,
|
|
643
|
+
syncWorktreeToServed,
|
|
644
|
+
pickVerifyTarget,
|
|
645
|
+
verifyServedFresh,
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
if (require.main === module) {
|
|
649
|
+
cliMain().catch((e) => {
|
|
650
|
+
console.error('sandbox-stage error:', e.message);
|
|
651
|
+
process.exit(1);
|
|
652
|
+
});
|
|
653
|
+
}
|