@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,641 @@
|
|
|
1
|
+
// primer.js — the primer reader page (V3.R13-followup #406).
|
|
2
|
+
//
|
|
3
|
+
// Fetches /builders/primer.md (canonical markdown from docs/onboarding/),
|
|
4
|
+
// parses it with a small hand-rolled parser covering the subset the primer
|
|
5
|
+
// uses (headings, paragraphs, lists, tables, fenced code, hr, inline
|
|
6
|
+
// **bold** / *italic* / `code` / [link](url)), inlines the five onboarding
|
|
7
|
+
// diagrams at matching sections, builds a TOC from h2s with a scrollspy,
|
|
8
|
+
// drives a top reading-progress bar, and soft-gates the footer ack button
|
|
9
|
+
// until the reader has scrolled past ~90% of the article. Acking POSTs to
|
|
10
|
+
// /api/gds/builders/me/onboarding/primer-read (same endpoint /builder-
|
|
11
|
+
// primer-read uses).
|
|
12
|
+
//
|
|
13
|
+
// No build step. No external markdown dep. The parser is purpose-built for
|
|
14
|
+
// the primer's syntax, not a general-purpose markdown engine — extending it
|
|
15
|
+
// for new constructs is straightforward but should match what the primer
|
|
16
|
+
// actually contains.
|
|
17
|
+
|
|
18
|
+
(() => {
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const API = '/api/gds';
|
|
22
|
+
const ACK_SCROLL_THRESHOLD = 0.90; // 90% of article scrolled → button enables
|
|
23
|
+
// V3.R13-followup-2 (#411): the canonical repo on GitHub. Relative file
|
|
24
|
+
// paths in the primer markdown (../../CLAUDE.md, ../recipes/, etc.) are
|
|
25
|
+
// rewritten to URLs under these bases so the rendered links go somewhere
|
|
26
|
+
// useful instead of 404-ing under /builders/*. The bases are NOT hardcoded
|
|
27
|
+
// here — that would violate the V3.R12 (#236) authorship-attribution audit.
|
|
28
|
+
// Instead, primer.js fetches /api/gds/public/repo-info at boot; the server
|
|
29
|
+
// derives the owner/repo at process start from `git remote get-url origin`
|
|
30
|
+
// (src/bongos/repo-info.js). When the bases are unavailable (network glitch
|
|
31
|
+
// pre-render, or the server can't reach git), the link rewriter degrades
|
|
32
|
+
// gracefully — repo-relative hrefs are passed through unchanged so they
|
|
33
|
+
// 404 instead of crashing the page.
|
|
34
|
+
let repoBlobBase = null;
|
|
35
|
+
let repoTreeBase = null;
|
|
36
|
+
|
|
37
|
+
// Diagrams to inline at matching h2 sections. The keys are LOWERCASED h2
|
|
38
|
+
// text (matched as substrings) — keep them tight so the wrong heading
|
|
39
|
+
// doesn't pick up the wrong picture. The image paths resolve at
|
|
40
|
+
// /builders/diagrams/* (mounted in server.js).
|
|
41
|
+
const DIAGRAM_AT_HEADING = [
|
|
42
|
+
{ match: 'two tracks', src: '/builders/diagrams/05-two-track-versioning.png', alt: 'The two tracks: product (the game) and internal (the dev system)' },
|
|
43
|
+
{ match: 'claim → ship lifecycle', src: '/builders/diagrams/01-task-lifecycle.png', alt: 'The full task lifecycle from backlog through shipped' },
|
|
44
|
+
{ match: 'rank ladder', src: '/builders/diagrams/02-rank-ladder.png', alt: 'The rank ladder — the ranks a builder can hold and how to rise' },
|
|
45
|
+
{ match: 'drachmae and karma', src: '/builders/diagrams/03-drachmae-karma.png', alt: 'How the reward currency and karma differ — pay for shipped work vs. reputation signals' },
|
|
46
|
+
{ match: 'get set up', src: '/builders/diagrams/04-architecture.png', alt: 'The complete architecture: your device is just the screen, the dev box holds the worker, the code, and your local memory, the droplet is the authority and production, GitHub holds the repo — and how code travels from the box to prod' },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
// -----------------------------------------------------------------------
|
|
50
|
+
// Tiny utilities
|
|
51
|
+
// -----------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
function $(sel) { return document.querySelector(sel); }
|
|
54
|
+
|
|
55
|
+
function escapeHtml(s) {
|
|
56
|
+
return String(s)
|
|
57
|
+
.replace(/&/g, '&')
|
|
58
|
+
.replace(/</g, '<')
|
|
59
|
+
.replace(/>/g, '>')
|
|
60
|
+
.replace(/"/g, '"')
|
|
61
|
+
.replace(/'/g, ''');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Stable slug for heading anchors. Lowercases, strips non-alphanum, joins
|
|
65
|
+
// with dashes. Matches what most static-site generators do, so anchor
|
|
66
|
+
// links in the primer's prose ([§foo](#foo)) work the same way.
|
|
67
|
+
function slugify(text) {
|
|
68
|
+
return String(text)
|
|
69
|
+
.toLowerCase()
|
|
70
|
+
.replace(/[—–]/g, '-') // em/en dashes
|
|
71
|
+
.replace(/[^a-z0-9\s-]/g, '') // strip punctuation
|
|
72
|
+
.trim()
|
|
73
|
+
.replace(/\s+/g, '-')
|
|
74
|
+
.replace(/-+/g, '-');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function toast(msg, type) {
|
|
78
|
+
// Shared toast mechanism (style.css .toast[data-visible="1"]) — same
|
|
79
|
+
// data-visible contract OTB.toast uses on pages that load dom-utils.js.
|
|
80
|
+
const el = $('#toast');
|
|
81
|
+
if (!el) return;
|
|
82
|
+
el.textContent = msg;
|
|
83
|
+
el.dataset.type = type || 'info';
|
|
84
|
+
el.dataset.visible = '1';
|
|
85
|
+
clearTimeout(toast._t);
|
|
86
|
+
toast._t = setTimeout(() => { el.dataset.visible = '0'; }, 3000);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// V3.R13-followup-2 (#411): rewrite relative repo paths in primer-markdown
|
|
90
|
+
// links so they land somewhere usable in the browser rather than 404-ing
|
|
91
|
+
// under /builders/*. The primer markdown was written for the repo view
|
|
92
|
+
// (relative paths to other repo files), but it's rendered at
|
|
93
|
+
// /builders/primer where those paths don't resolve.
|
|
94
|
+
//
|
|
95
|
+
// Rules (most-specific first):
|
|
96
|
+
// - http(s)://… absolute URL → keep as-is
|
|
97
|
+
// - #anchor in-page → keep as-is
|
|
98
|
+
// - 'diagrams/' or 'diagrams' → /builders/diagrams
|
|
99
|
+
// (the diagrams page lives in the hall; trailing slash falls through
|
|
100
|
+
// to the game, so we always rewrite to the no-slash form)
|
|
101
|
+
// - paths starting with ./ or ../ or any / → resolve against the
|
|
102
|
+
// primer's repo location (docs/onboarding/) and link to GitHub.
|
|
103
|
+
// We use the 'blob/main' base for files and 'tree/main' for dirs
|
|
104
|
+
// (heuristic: trailing slash or no '.' in basename = dir).
|
|
105
|
+
// - anything else → keep as-is
|
|
106
|
+
function resolveLinkHref(href) {
|
|
107
|
+
if (!href) return href;
|
|
108
|
+
if (/^https?:\/\//i.test(href)) return href;
|
|
109
|
+
if (href.startsWith('#')) return href;
|
|
110
|
+
if (href.startsWith('mailto:') || href.startsWith('tel:')) return href;
|
|
111
|
+
if (href === 'diagrams/' || href === 'diagrams') return '/builders/diagrams';
|
|
112
|
+
// task 1472: the drachmae-and-karma doc now has an in-hall reader page, so
|
|
113
|
+
// keep the reader in the hall instead of bouncing to GitHub. (The repo /
|
|
114
|
+
// GitHub view still resolves the plain relative link.)
|
|
115
|
+
if (href === 'drachmae-and-karma.md') return '/builders/drachmae';
|
|
116
|
+
// The primer.md lives at docs/onboarding/primer.md, so relative paths
|
|
117
|
+
// resolve against docs/onboarding/.
|
|
118
|
+
const PRIMER_DIR = 'docs/onboarding/';
|
|
119
|
+
let resolved;
|
|
120
|
+
if (href.startsWith('/')) {
|
|
121
|
+
// Absolute repo path. Strip the leading slash.
|
|
122
|
+
resolved = href.replace(/^\/+/, '');
|
|
123
|
+
} else {
|
|
124
|
+
// Relative. Join with PRIMER_DIR and normalize.
|
|
125
|
+
resolved = normalizePath(PRIMER_DIR + href);
|
|
126
|
+
}
|
|
127
|
+
// Decide blob (file) vs tree (directory). Heuristic: trailing slash =
|
|
128
|
+
// dir; no '.' in last segment = dir; else file.
|
|
129
|
+
const trailingSlash = resolved.endsWith('/');
|
|
130
|
+
const lastSeg = resolved.replace(/\/+$/, '').split('/').pop() || '';
|
|
131
|
+
const isDir = trailingSlash || !lastSeg.includes('.');
|
|
132
|
+
const cleanResolved = resolved.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
133
|
+
const base = isDir ? repoTreeBase : repoBlobBase;
|
|
134
|
+
// Graceful degradation: if the server-side repo-info fetch failed or
|
|
135
|
+
// hasn't completed before this render, leave the href as the original
|
|
136
|
+
// (which 404s harmlessly) rather than producing a broken /undefined/ URL.
|
|
137
|
+
if (!base) return href;
|
|
138
|
+
return `${base}/${cleanResolved}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Resolve '../' and './' segments in a path. Defensive against edge cases
|
|
142
|
+
// (no leading slash, repeated slashes); the input is already trusted
|
|
143
|
+
// because it came from the primer markdown we ship.
|
|
144
|
+
function normalizePath(p) {
|
|
145
|
+
const parts = p.split('/');
|
|
146
|
+
const out = [];
|
|
147
|
+
for (const part of parts) {
|
|
148
|
+
if (part === '' || part === '.') continue;
|
|
149
|
+
if (part === '..') { out.pop(); continue; }
|
|
150
|
+
out.push(part);
|
|
151
|
+
}
|
|
152
|
+
// Preserve a trailing slash if the original had one (matters for the
|
|
153
|
+
// file/dir heuristic in resolveLinkHref).
|
|
154
|
+
return out.join('/') + (p.endsWith('/') ? '/' : '');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// -----------------------------------------------------------------------
|
|
158
|
+
// Markdown parser (purpose-built for the primer's subset)
|
|
159
|
+
//
|
|
160
|
+
// Block grammar (line-by-line):
|
|
161
|
+
// ^# title → h1
|
|
162
|
+
// ^## section → h2
|
|
163
|
+
// ^### subsection → h3
|
|
164
|
+
// ^---$ → hr
|
|
165
|
+
// ^``` → fenced code (closes on next ```)
|
|
166
|
+
// ^- item or ^[0-9]+\. item → list (single level)
|
|
167
|
+
// ^| col | col | → table (separator row '|---|---|' follows)
|
|
168
|
+
// blank line → paragraph break
|
|
169
|
+
// anything else → paragraph (run inline)
|
|
170
|
+
//
|
|
171
|
+
// Inline grammar (in order; substitution avoids re-matching):
|
|
172
|
+
// `code` → <code>…</code>
|
|
173
|
+
// **bold** → <strong>…</strong>
|
|
174
|
+
// *italic* → <em>…</em>
|
|
175
|
+
// [text](url) → <a href="url">text</a>
|
|
176
|
+
// -----------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
// Inline substitutions. We process them on already-escaped text so we
|
|
179
|
+
// don't have to defend against html-injection inside literal text — code
|
|
180
|
+
// spans are escape-safe because the content is the matched group (which
|
|
181
|
+
// we re-escape). Bold + italic + link use the captured group as-is
|
|
182
|
+
// (already escaped by the block-level pass).
|
|
183
|
+
function renderInline(escapedText) {
|
|
184
|
+
// Code spans first so their contents aren't touched by other rules.
|
|
185
|
+
// Use a placeholder pass to avoid re-matching.
|
|
186
|
+
const codeSpans = [];
|
|
187
|
+
let out = escapedText.replace(/`([^`]+)`/g, (_m, g1) => {
|
|
188
|
+
codeSpans.push(g1);
|
|
189
|
+
return `CODE${codeSpans.length - 1}`;
|
|
190
|
+
});
|
|
191
|
+
// Links — [text](url). url must be the next paren-group, no nested parens.
|
|
192
|
+
out = out.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, text, url) => {
|
|
193
|
+
// url is already html-escaped by the block-level escape; that's fine
|
|
194
|
+
// for href because we use the raw string and let the browser handle
|
|
195
|
+
// %-encoding. We strip the quotes that the escape replaced with ".
|
|
196
|
+
const safeUrl = url.replace(/&/g, '&').replace(/'/g, "'");
|
|
197
|
+
const resolved = resolveLinkHref(safeUrl);
|
|
198
|
+
// External (off-instance) links open in a new tab so the reader
|
|
199
|
+
// doesn't lose their place in the primer.
|
|
200
|
+
const instApex = location.hostname.split('.').slice(-2).join('.');
|
|
201
|
+
let linkHost = '';
|
|
202
|
+
try { linkHost = new URL(resolved, location.href).hostname; } catch (_) { /* relative/opaque href */ }
|
|
203
|
+
const sameInstance = !!linkHost && (linkHost === location.hostname || linkHost === instApex || linkHost.endsWith('.' + instApex));
|
|
204
|
+
const external = /^https?:\/\//.test(resolved) && !sameInstance;
|
|
205
|
+
const attrs = external ? ' target="_blank" rel="noopener"' : '';
|
|
206
|
+
return `<a href="${escapeHtml(resolved)}"${attrs}>${text}</a>`;
|
|
207
|
+
});
|
|
208
|
+
// Bold (run before italic so **x** doesn't match as *(*x*)*).
|
|
209
|
+
out = out.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
210
|
+
// Italic.
|
|
211
|
+
out = out.replace(/(^|[^*])\*([^*]+)\*(?!\*)/g, '$1<em>$2</em>');
|
|
212
|
+
// Restore code spans.
|
|
213
|
+
out = out.replace(/CODE(\d+)/g, (_m, idx) => {
|
|
214
|
+
return `<code>${escapeHtml(codeSpans[Number(idx)])}</code>`;
|
|
215
|
+
});
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function parseMarkdown(md) {
|
|
220
|
+
// Normalize line endings.
|
|
221
|
+
const lines = String(md).replace(/\r\n?/g, '\n').split('\n');
|
|
222
|
+
const out = [];
|
|
223
|
+
const headings = []; // { level, text, id } — used to build TOC + scrollspy
|
|
224
|
+
let i = 0;
|
|
225
|
+
|
|
226
|
+
while (i < lines.length) {
|
|
227
|
+
const line = lines[i];
|
|
228
|
+
const raw = line;
|
|
229
|
+
|
|
230
|
+
// Fenced code block.
|
|
231
|
+
if (raw.startsWith('```')) {
|
|
232
|
+
i += 1;
|
|
233
|
+
const codeLines = [];
|
|
234
|
+
while (i < lines.length && !lines[i].startsWith('```')) {
|
|
235
|
+
codeLines.push(lines[i]);
|
|
236
|
+
i += 1;
|
|
237
|
+
}
|
|
238
|
+
i += 1; // consume closing ```
|
|
239
|
+
out.push(`<pre><code>${escapeHtml(codeLines.join('\n'))}</code></pre>`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Headings.
|
|
244
|
+
let hm;
|
|
245
|
+
if ((hm = raw.match(/^(#{1,3})\s+(.+?)\s*$/))) {
|
|
246
|
+
const level = hm[1].length;
|
|
247
|
+
const text = hm[2];
|
|
248
|
+
const id = slugify(text);
|
|
249
|
+
headings.push({ level, text, id });
|
|
250
|
+
out.push(`<h${level} id="${escapeHtml(id)}">${renderInline(escapeHtml(text))}</h${level}>`);
|
|
251
|
+
i += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Horizontal rule.
|
|
256
|
+
if (/^---+\s*$/.test(raw)) {
|
|
257
|
+
out.push('<hr>');
|
|
258
|
+
i += 1;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Blank line — paragraph separator.
|
|
263
|
+
if (/^\s*$/.test(raw)) {
|
|
264
|
+
i += 1;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Table: header row '| ... |' followed by separator row '| --- | --- |'.
|
|
269
|
+
if (/^\|/.test(raw) && i + 1 < lines.length && /^\|[\s\-:|]+\|\s*$/.test(lines[i + 1])) {
|
|
270
|
+
const headerCells = splitTableRow(raw);
|
|
271
|
+
i += 2;
|
|
272
|
+
const bodyRows = [];
|
|
273
|
+
while (i < lines.length && /^\|/.test(lines[i])) {
|
|
274
|
+
bodyRows.push(splitTableRow(lines[i]));
|
|
275
|
+
i += 1;
|
|
276
|
+
}
|
|
277
|
+
let html = '<table><thead><tr>';
|
|
278
|
+
for (const c of headerCells) html += `<th>${renderInline(escapeHtml(c))}</th>`;
|
|
279
|
+
html += '</tr></thead><tbody>';
|
|
280
|
+
for (const row of bodyRows) {
|
|
281
|
+
html += '<tr>';
|
|
282
|
+
for (const c of row) html += `<td>${renderInline(escapeHtml(c))}</td>`;
|
|
283
|
+
html += '</tr>';
|
|
284
|
+
}
|
|
285
|
+
html += '</tbody></table>';
|
|
286
|
+
out.push(html);
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Lists (unordered '- ' or ordered '1. '). Single-level; consecutive
|
|
291
|
+
// list items collapse into one <ul>/<ol>.
|
|
292
|
+
if (/^(-|\d+\.)\s+/.test(raw)) {
|
|
293
|
+
const ordered = /^\d+\.\s+/.test(raw);
|
|
294
|
+
const items = [];
|
|
295
|
+
while (i < lines.length && /^(-|\d+\.)\s+/.test(lines[i])) {
|
|
296
|
+
const content = lines[i].replace(/^(-|\d+\.)\s+/, '');
|
|
297
|
+
items.push(`<li>${renderInline(escapeHtml(content))}</li>`);
|
|
298
|
+
i += 1;
|
|
299
|
+
}
|
|
300
|
+
out.push(`<${ordered ? 'ol' : 'ul'}>${items.join('')}</${ordered ? 'ol' : 'ul'}>`);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Paragraph — collect consecutive non-blank, non-special lines.
|
|
305
|
+
const paraLines = [raw];
|
|
306
|
+
i += 1;
|
|
307
|
+
while (i < lines.length &&
|
|
308
|
+
!/^\s*$/.test(lines[i]) &&
|
|
309
|
+
!/^(#{1,3})\s/.test(lines[i]) &&
|
|
310
|
+
!/^---+\s*$/.test(lines[i]) &&
|
|
311
|
+
!/^```/.test(lines[i]) &&
|
|
312
|
+
!/^\|/.test(lines[i]) &&
|
|
313
|
+
!/^(-|\d+\.)\s+/.test(lines[i])) {
|
|
314
|
+
paraLines.push(lines[i]);
|
|
315
|
+
i += 1;
|
|
316
|
+
}
|
|
317
|
+
const text = paraLines.join(' ');
|
|
318
|
+
out.push(`<p>${renderInline(escapeHtml(text))}</p>`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return { html: out.join('\n'), headings };
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function splitTableRow(line) {
|
|
325
|
+
// '| a | b | c |' → ['a', 'b', 'c']. Trims, drops the leading/trailing empty cells.
|
|
326
|
+
const cells = line.split('|').map((c) => c.trim());
|
|
327
|
+
// Drop the empty strings introduced by the leading/trailing pipes.
|
|
328
|
+
if (cells.length && cells[0] === '') cells.shift();
|
|
329
|
+
if (cells.length && cells[cells.length - 1] === '') cells.pop();
|
|
330
|
+
return cells;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// -----------------------------------------------------------------------
|
|
334
|
+
// Diagram inlining — after the HTML is in the DOM, walk every <h2> and
|
|
335
|
+
// append a <figure> right after it if the heading matches a known diagram.
|
|
336
|
+
// -----------------------------------------------------------------------
|
|
337
|
+
|
|
338
|
+
function inlineDiagrams(articleEl) {
|
|
339
|
+
const h2s = articleEl.querySelectorAll('h2');
|
|
340
|
+
for (const h of h2s) {
|
|
341
|
+
const txt = h.textContent.toLowerCase();
|
|
342
|
+
const match = DIAGRAM_AT_HEADING.find((d) => txt.includes(d.match));
|
|
343
|
+
if (!match) continue;
|
|
344
|
+
const fig = document.createElement('figure');
|
|
345
|
+
fig.className = 'primer-figure';
|
|
346
|
+
const img = document.createElement('img');
|
|
347
|
+
img.src = match.src;
|
|
348
|
+
img.alt = match.alt;
|
|
349
|
+
img.loading = 'lazy';
|
|
350
|
+
const cap = document.createElement('figcaption');
|
|
351
|
+
cap.textContent = match.alt;
|
|
352
|
+
fig.appendChild(img);
|
|
353
|
+
fig.appendChild(cap);
|
|
354
|
+
// Place the figure AFTER the h2's first paragraph so it sits inside
|
|
355
|
+
// the section's flow rather than directly under the heading rule.
|
|
356
|
+
// Falls back to "right after the h2" if there's no paragraph next.
|
|
357
|
+
const next = h.nextElementSibling;
|
|
358
|
+
if (next && next.tagName === 'P') {
|
|
359
|
+
next.insertAdjacentElement('afterend', fig);
|
|
360
|
+
} else {
|
|
361
|
+
h.insertAdjacentElement('afterend', fig);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// -----------------------------------------------------------------------
|
|
367
|
+
// TOC — built from h2 headings.
|
|
368
|
+
// -----------------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
function renderToc(headings) {
|
|
371
|
+
const list = $('#primer-toc-list');
|
|
372
|
+
if (!list) return [];
|
|
373
|
+
const h2s = headings.filter((h) => h.level === 2);
|
|
374
|
+
if (h2s.length === 0) {
|
|
375
|
+
list.innerHTML = '<li class="primer-toc__placeholder">(no sections)</li>';
|
|
376
|
+
return [];
|
|
377
|
+
}
|
|
378
|
+
list.innerHTML = h2s.map((h) =>
|
|
379
|
+
`<li><a href="#${escapeHtml(h.id)}" data-section="${escapeHtml(h.id)}">${escapeHtml(h.text)}</a></li>`
|
|
380
|
+
).join('');
|
|
381
|
+
return h2s;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// -----------------------------------------------------------------------
|
|
385
|
+
// Scrollspy — highlight the TOC entry for the section the reader is in.
|
|
386
|
+
//
|
|
387
|
+
// Behaviour: the "active" section is the LAST h2 whose top has scrolled
|
|
388
|
+
// past a fixed reading line near the top of the viewport. That way the
|
|
389
|
+
// active state stays sticky while the reader is in the middle of a
|
|
390
|
+
// section's paragraphs (not just the brief moment the h2 itself is in
|
|
391
|
+
// a thin band, which is what an IntersectionObserver with a narrow root-
|
|
392
|
+
// margin would give us).
|
|
393
|
+
// -----------------------------------------------------------------------
|
|
394
|
+
|
|
395
|
+
function setupScrollspy(tocSections) {
|
|
396
|
+
if (tocSections.length === 0) return;
|
|
397
|
+
const links = new Map();
|
|
398
|
+
for (const a of document.querySelectorAll('.primer-toc__list a')) {
|
|
399
|
+
links.set(a.dataset.section, a);
|
|
400
|
+
}
|
|
401
|
+
if (links.size === 0) return;
|
|
402
|
+
// Reading line — the y-coordinate (in viewport space) we treat as
|
|
403
|
+
// "where the reader is looking right now". 100px is well below the
|
|
404
|
+
// progress bar and any fixed header, and matches where the eye
|
|
405
|
+
// naturally lands when reading down a page.
|
|
406
|
+
const READING_LINE_Y = 100;
|
|
407
|
+
let last = null;
|
|
408
|
+
function update() {
|
|
409
|
+
let active = null;
|
|
410
|
+
for (const s of tocSections) {
|
|
411
|
+
const el = document.getElementById(s.id);
|
|
412
|
+
if (!el) continue;
|
|
413
|
+
if (el.getBoundingClientRect().top <= READING_LINE_Y) {
|
|
414
|
+
active = s.id;
|
|
415
|
+
} else {
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (active === last) return;
|
|
420
|
+
last = active;
|
|
421
|
+
for (const [id, a] of links) {
|
|
422
|
+
a.classList.toggle('is-active', id === active);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
window.addEventListener('scroll', update, { passive: true });
|
|
426
|
+
window.addEventListener('resize', update, { passive: true });
|
|
427
|
+
update();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// -----------------------------------------------------------------------
|
|
431
|
+
// Reading-progress bar — fraction of the article scrolled past.
|
|
432
|
+
// -----------------------------------------------------------------------
|
|
433
|
+
|
|
434
|
+
function setupProgressBar(articleEl, onProgress) {
|
|
435
|
+
const bar = $('#primer-progress-bar');
|
|
436
|
+
if (!bar) return;
|
|
437
|
+
function update() {
|
|
438
|
+
const rect = articleEl.getBoundingClientRect();
|
|
439
|
+
const viewport = window.innerHeight || document.documentElement.clientHeight;
|
|
440
|
+
// 0 when the top of the article is at/below the viewport top;
|
|
441
|
+
// 1 when the bottom of the article is at/above the viewport top.
|
|
442
|
+
// We use article.bottom — viewportTop as "how much has scrolled past
|
|
443
|
+
// me" then normalize by article.height.
|
|
444
|
+
const total = rect.height + viewport * 0; // article only
|
|
445
|
+
const scrolled = Math.max(0, -rect.top);
|
|
446
|
+
const frac = total > 0 ? Math.min(1, scrolled / Math.max(1, rect.height - viewport)) : 0;
|
|
447
|
+
bar.style.width = `${Math.round(frac * 100)}%`;
|
|
448
|
+
if (typeof onProgress === 'function') onProgress(frac);
|
|
449
|
+
}
|
|
450
|
+
window.addEventListener('scroll', update, { passive: true });
|
|
451
|
+
window.addEventListener('resize', update, { passive: true });
|
|
452
|
+
update();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// -----------------------------------------------------------------------
|
|
456
|
+
// Footer ack module — soft gate on the 'I have read it' button.
|
|
457
|
+
// -----------------------------------------------------------------------
|
|
458
|
+
|
|
459
|
+
let ackEnabled = false;
|
|
460
|
+
function setupAck() {
|
|
461
|
+
const ackSection = $('#primer-ack');
|
|
462
|
+
const btn = $('#primer-ack-btn');
|
|
463
|
+
const lede = $('#primer-ack-lede');
|
|
464
|
+
if (!ackSection || !btn) return;
|
|
465
|
+
ackSection.hidden = false;
|
|
466
|
+
btn.addEventListener('click', async () => {
|
|
467
|
+
if (!ackEnabled || btn.disabled) return;
|
|
468
|
+
btn.disabled = true;
|
|
469
|
+
btn.textContent = 'Marking…';
|
|
470
|
+
try {
|
|
471
|
+
const resp = await fetch(`${API}/builders/me/onboarding/primer-read`, {
|
|
472
|
+
method: 'POST',
|
|
473
|
+
credentials: 'same-origin',
|
|
474
|
+
headers: { 'Content-Type': 'application/json' },
|
|
475
|
+
body: '{}',
|
|
476
|
+
});
|
|
477
|
+
if (resp.status === 401) {
|
|
478
|
+
// Not signed in — bounce through the web auth flow and come back.
|
|
479
|
+
const here = encodeURIComponent(window.location.pathname);
|
|
480
|
+
window.location.assign(`${API}/auth/web/start?return=${here}`);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (!resp.ok) throw new Error(`primer-read → ${resp.status}`);
|
|
484
|
+
const data = await resp.json().catch(() => ({}));
|
|
485
|
+
if (data.already_cleared) {
|
|
486
|
+
showAckedState('Already acknowledged — you\'re all set.');
|
|
487
|
+
} else if (data.just_graduated) {
|
|
488
|
+
showAckedState('Primer acknowledged. You have completed onboarding — welcome.');
|
|
489
|
+
} else {
|
|
490
|
+
showAckedState('Primer acknowledged. The work queue is open to you.');
|
|
491
|
+
}
|
|
492
|
+
toast('Primer acknowledged.', 'success');
|
|
493
|
+
} catch (err) {
|
|
494
|
+
console.error('[primer] ack failed', err);
|
|
495
|
+
btn.disabled = false;
|
|
496
|
+
btn.textContent = 'I have read it';
|
|
497
|
+
toast('Could not mark the primer just now. Try again.', 'error');
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// V3.R13-followup-2 (#411): once acked, hide the button entirely. The
|
|
503
|
+
// previous design left a washed-out "✓ ACKNOWLEDGED" disabled button in
|
|
504
|
+
// place which read as clunky. Now: the ack panel collapses to a single
|
|
505
|
+
// confirmation line + return link, with a subtle check mark.
|
|
506
|
+
function showAckedState(message) {
|
|
507
|
+
const btn = $('#primer-ack-btn');
|
|
508
|
+
const lede = $('#primer-ack-lede');
|
|
509
|
+
const note = $('#primer-ack-note');
|
|
510
|
+
const inner = document.querySelector('.primer-ack__inner');
|
|
511
|
+
if (btn) btn.hidden = true;
|
|
512
|
+
if (lede) lede.hidden = true;
|
|
513
|
+
if (inner) inner.classList.add('primer-ack__inner--acked');
|
|
514
|
+
if (note) {
|
|
515
|
+
note.hidden = false;
|
|
516
|
+
note.innerHTML = `<span class="primer-ack__check" aria-hidden="true">✓</span> ${escapeHtml(message)} <a href="/builders">Back to home</a>.`;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function onArticleProgress(frac) {
|
|
521
|
+
if (frac >= ACK_SCROLL_THRESHOLD && !ackEnabled) {
|
|
522
|
+
const btn = $('#primer-ack-btn');
|
|
523
|
+
const lede = $('#primer-ack-lede');
|
|
524
|
+
if (btn && !btn.dataset.alreadyAcked) {
|
|
525
|
+
btn.disabled = false;
|
|
526
|
+
ackEnabled = true;
|
|
527
|
+
}
|
|
528
|
+
if (lede) {
|
|
529
|
+
lede.textContent = 'You have reached the end. The button below is now active.';
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// -----------------------------------------------------------------------
|
|
535
|
+
// Pre-check: if the builder already has primer_read cleared, render the
|
|
536
|
+
// ack panel in the already-acknowledged state so the page doesn't
|
|
537
|
+
// pretend they still need to ack.
|
|
538
|
+
// -----------------------------------------------------------------------
|
|
539
|
+
|
|
540
|
+
async function checkAlreadyAcked() {
|
|
541
|
+
try {
|
|
542
|
+
const r = await fetch(`${API}/me`, { credentials: 'same-origin' });
|
|
543
|
+
if (r.status === 401) return; // anonymous reader; let them read + ack
|
|
544
|
+
if (!r.ok) return;
|
|
545
|
+
const data = await r.json();
|
|
546
|
+
const ob = data.onboarding;
|
|
547
|
+
if (!ob) return;
|
|
548
|
+
const cleared = Array.isArray(ob.completed_stages) && ob.completed_stages.includes('primer_read');
|
|
549
|
+
const past = ob.graduated || (ob.current_stage && ['first_start', 'first_claim', 'first_ship', 'first_vote_received', 'graduated'].includes(ob.current_stage));
|
|
550
|
+
if (cleared || past) {
|
|
551
|
+
const btn = $('#primer-ack-btn');
|
|
552
|
+
if (btn) btn.dataset.alreadyAcked = '1';
|
|
553
|
+
showAckedState('Already acknowledged — you can re-read the primer any time.');
|
|
554
|
+
}
|
|
555
|
+
} catch (_) {
|
|
556
|
+
// network glitch — let them ack the normal way
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// -----------------------------------------------------------------------
|
|
561
|
+
// TOC mobile toggle
|
|
562
|
+
// -----------------------------------------------------------------------
|
|
563
|
+
|
|
564
|
+
function setupTocToggle() {
|
|
565
|
+
const toc = $('#primer-toc');
|
|
566
|
+
const btn = $('#primer-toc-toggle');
|
|
567
|
+
if (!toc || !btn) return;
|
|
568
|
+
btn.addEventListener('click', () => {
|
|
569
|
+
const open = toc.classList.toggle('is-open');
|
|
570
|
+
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
571
|
+
});
|
|
572
|
+
// Close the TOC after a section is picked on mobile.
|
|
573
|
+
toc.addEventListener('click', (e) => {
|
|
574
|
+
const a = e.target.closest('a[data-section]');
|
|
575
|
+
if (!a) return;
|
|
576
|
+
if (window.matchMedia('(max-width: 760px)').matches) {
|
|
577
|
+
toc.classList.remove('is-open');
|
|
578
|
+
btn.setAttribute('aria-expanded', 'false');
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// -----------------------------------------------------------------------
|
|
584
|
+
// Boot
|
|
585
|
+
// -----------------------------------------------------------------------
|
|
586
|
+
|
|
587
|
+
// V3.R13-followup-2 (#411): fetch the GitHub URL bases from the server so
|
|
588
|
+
// they don't have to be hardcoded in this client file (V3.R12 #236 rule).
|
|
589
|
+
// Fire in parallel with the markdown fetch — both are independent, both
|
|
590
|
+
// must settle before render. Failure here is non-fatal: resolveLinkHref
|
|
591
|
+
// gracefully degrades when the bases are null.
|
|
592
|
+
async function loadRepoInfoBases() {
|
|
593
|
+
try {
|
|
594
|
+
const r = await fetch('/api/gds/public/repo-info', { credentials: 'same-origin' });
|
|
595
|
+
if (!r.ok) return;
|
|
596
|
+
const data = await r.json();
|
|
597
|
+
if (data && typeof data.blob_base === 'string') repoBlobBase = data.blob_base;
|
|
598
|
+
if (data && typeof data.tree_base === 'string') repoTreeBase = data.tree_base;
|
|
599
|
+
} catch (_) {
|
|
600
|
+
/* swallow — links degrade to the original relative href */
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
async function boot() {
|
|
605
|
+
const article = $('#primer-article');
|
|
606
|
+
if (!article) return;
|
|
607
|
+
let md;
|
|
608
|
+
try {
|
|
609
|
+
// Fetch markdown + repo bases in parallel. The bases must be populated
|
|
610
|
+
// BEFORE parseMarkdown runs so resolveLinkHref returns GitHub URLs
|
|
611
|
+
// (not the relative-href fallback).
|
|
612
|
+
const [mdRes] = await Promise.all([
|
|
613
|
+
fetch('/builders/primer.md', { credentials: 'same-origin' }),
|
|
614
|
+
loadRepoInfoBases(),
|
|
615
|
+
]);
|
|
616
|
+
if (!mdRes.ok) throw new Error(`primer.md → ${mdRes.status}`);
|
|
617
|
+
md = await mdRes.text();
|
|
618
|
+
} catch (err) {
|
|
619
|
+
console.error('[primer] failed to load markdown', err);
|
|
620
|
+
article.innerHTML = `<p class="primer-loading">Could not load the primer. <a href="/builders">Go back</a> and try again.</p>`;
|
|
621
|
+
article.removeAttribute('aria-busy');
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
const { html, headings } = parseMarkdown(md);
|
|
625
|
+
article.innerHTML = html;
|
|
626
|
+
article.removeAttribute('aria-busy');
|
|
627
|
+
inlineDiagrams(article);
|
|
628
|
+
const tocSections = renderToc(headings);
|
|
629
|
+
setupTocToggle();
|
|
630
|
+
setupScrollspy(tocSections);
|
|
631
|
+
setupProgressBar(article, onArticleProgress);
|
|
632
|
+
setupAck();
|
|
633
|
+
checkAlreadyAcked();
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (document.readyState === 'loading') {
|
|
637
|
+
document.addEventListener('DOMContentLoaded', boot);
|
|
638
|
+
} else {
|
|
639
|
+
boot();
|
|
640
|
+
}
|
|
641
|
+
})();
|