voidforge-build 23.9.1
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/dist/.claude/agents/adolin-brand.md +40 -0
- package/dist/.claude/agents/ahsoka-access-control.md +56 -0
- package/dist/.claude/agents/alfred-dependencies.md +43 -0
- package/dist/.claude/agents/alia-threat-detect.md +40 -0
- package/dist/.claude/agents/anakin-dark-side.md +41 -0
- package/dist/.claude/agents/aquaman-deep-dive.md +43 -0
- package/dist/.claude/agents/aragorn-orchestration.md +39 -0
- package/dist/.claude/agents/archer-greenfield.md +48 -0
- package/dist/.claude/agents/armin-clever.md +39 -0
- package/dist/.claude/agents/arwen-ui-polish.md +42 -0
- package/dist/.claude/agents/ashitaka-tech-debt.md +39 -0
- package/dist/.claude/agents/asuka-performance.md +39 -0
- package/dist/.claude/agents/bail-organa-governance.md +37 -0
- package/dist/.claude/agents/banner-database.md +44 -0
- package/dist/.claude/agents/barton-smoke-test.md +59 -0
- package/dist/.claude/agents/bashir-field-medic.md +63 -0
- package/dist/.claude/agents/batgirl-detail.md +43 -0
- package/dist/.claude/agents/batman-qa.md +73 -0
- package/dist/.claude/agents/bayta-evals.md +41 -0
- package/dist/.claude/agents/beast-boy-cross-env.md +43 -0
- package/dist/.claude/agents/beerus-destroyer.md +39 -0
- package/dist/.claude/agents/bel-riose-orchestration.md +40 -0
- package/dist/.claude/agents/beru-subprocess.md +37 -0
- package/dist/.claude/agents/bilbo-microcopy.md +43 -0
- package/dist/.claude/agents/black-canary-monitoring.md +43 -0
- package/dist/.claude/agents/bliss-ai-safety.md +40 -0
- package/dist/.claude/agents/bo-katan-perimeter.md +40 -0
- package/dist/.claude/agents/bombadil-forge-sync.md +62 -0
- package/dist/.claude/agents/boromir-hubris.md +40 -0
- package/dist/.claude/agents/breeze-platform-relations.md +40 -0
- package/dist/.claude/agents/bucky-legacy.md +43 -0
- package/dist/.claude/agents/bulma-engineering.md +40 -0
- package/dist/.claude/agents/calcifer-daemon.md +39 -0
- package/dist/.claude/agents/cara-dune-enforcement.md +37 -0
- package/dist/.claude/agents/cassian-recon.md +37 -0
- package/dist/.claude/agents/cc-persistent-process.md +39 -0
- package/dist/.claude/agents/celeborn-design-system.md +40 -0
- package/dist/.claude/agents/celebrimbor-forge-artist.md +62 -0
- package/dist/.claude/agents/chakotay-bridge.md +47 -0
- package/dist/.claude/agents/chani-worm-rider.md +61 -0
- package/dist/.claude/agents/chewie-dependency-audit.md +41 -0
- package/dist/.claude/agents/chrome-discovery.md +37 -0
- package/dist/.claude/agents/constantine-cursed-code.md +59 -0
- package/dist/.claude/agents/coulson-release.md +64 -0
- package/dist/.claude/agents/crusher-diagnostics.md +48 -0
- package/dist/.claude/agents/cyborg-system-integration.md +43 -0
- package/dist/.claude/agents/dalinar-positioning.md +40 -0
- package/dist/.claude/agents/daneel-model-migration.md +40 -0
- package/dist/.claude/agents/data-tech-debt.md +48 -0
- package/dist/.claude/agents/dax-legacy-wisdom.md +48 -0
- package/dist/.claude/agents/deathstroke-adversarial.md +59 -0
- package/dist/.claude/agents/denji-determination.md +39 -0
- package/dist/.claude/agents/din-djarin-bounty.md +42 -0
- package/dist/.claude/agents/dockson-treasury.md +67 -0
- package/dist/.claude/agents/dori-integration-check.md +37 -0
- package/dist/.claude/agents/dors-observability.md +40 -0
- package/dist/.claude/agents/drax-exact-match.md +42 -0
- package/dist/.claude/agents/ducem-token-economics.md +41 -0
- package/dist/.claude/agents/duncan-relay.md +40 -0
- package/dist/.claude/agents/duo-teardown.md +38 -0
- package/dist/.claude/agents/ed-network-scan.md +38 -0
- package/dist/.claude/agents/elrond-ux-strategy.md +39 -0
- package/dist/.claude/agents/eowyn-delight.md +56 -0
- package/dist/.claude/agents/erwin-strategy.md +39 -0
- package/dist/.claude/agents/ezra-catches-missed.md +40 -0
- package/dist/.claude/agents/ezri-session-analyst.md +45 -0
- package/dist/.claude/agents/falcon-migration.md +43 -0
- package/dist/.claude/agents/faramir-judgment.md +40 -0
- package/dist/.claude/agents/faye-resourceful.md +39 -0
- package/dist/.claude/agents/fenring-passive-monitor.md +37 -0
- package/dist/.claude/agents/fern-protocol.md +37 -0
- package/dist/.claude/agents/feyd-adversarial.md +41 -0
- package/dist/.claude/agents/flash-rapid-test.md +43 -0
- package/dist/.claude/agents/friday-automation.md +42 -0
- package/dist/.claude/agents/frieren-long-term.md +39 -0
- package/dist/.claude/agents/frodo-critical-path.md +40 -0
- package/dist/.claude/agents/fury-initiative.md +65 -0
- package/dist/.claude/agents/gaal-prompt-arch.md +41 -0
- package/dist/.claude/agents/galadriel-frontend.md +69 -0
- package/dist/.claude/agents/gamora-perf-assassin.md +43 -0
- package/dist/.claude/agents/gandalf-setup-wizard.md +63 -0
- package/dist/.claude/agents/gen-docs.md +37 -0
- package/dist/.claude/agents/ghanima-paired-monitor.md +37 -0
- package/dist/.claude/agents/gimli-performance.md +41 -0
- package/dist/.claude/agents/giyu-silent-guard.md +39 -0
- package/dist/.claude/agents/glorfindel-rendering.md +40 -0
- package/dist/.claude/agents/gohan-hidden-power.md +39 -0
- package/dist/.claude/agents/gojo-infinite-scale.md +39 -0
- package/dist/.claude/agents/goku-scaling.md +39 -0
- package/dist/.claude/agents/goldberry-change-detect.md +37 -0
- package/dist/.claude/agents/gordon-escalation.md +42 -0
- package/dist/.claude/agents/green-arrow-precision.md +43 -0
- package/dist/.claude/agents/green-lantern-scenarios.md +43 -0
- package/dist/.claude/agents/grogu-tiny-vulns.md +38 -0
- package/dist/.claude/agents/groot-caching.md +43 -0
- package/dist/.claude/agents/gurney-delivery.md +40 -0
- package/dist/.claude/agents/haku-deploy-wizard.md +65 -0
- package/dist/.claude/agents/haldir-boundaries.md +40 -0
- package/dist/.claude/agents/han-vuln-hunter.md +40 -0
- package/dist/.claude/agents/hange-experimentation.md +39 -0
- package/dist/.claude/agents/harah-protocol.md +38 -0
- package/dist/.claude/agents/hawkgirl-regression-sweep.md +43 -0
- package/dist/.claude/agents/heero-mission-deploy.md +39 -0
- package/dist/.claude/agents/hera-navigation.md +41 -0
- package/dist/.claude/agents/hill-mission-control.md +43 -0
- package/dist/.claude/agents/himmel-legacy.md +37 -0
- package/dist/.claude/agents/hober-tool-schema.md +40 -0
- package/dist/.claude/agents/hoid-copywriting.md +40 -0
- package/dist/.claude/agents/howl-migration.md +39 -0
- package/dist/.claude/agents/hughes-observability.md +37 -0
- package/dist/.claude/agents/huntress-flaky-bugs.md +42 -0
- package/dist/.claude/agents/irulan-historian.md +37 -0
- package/dist/.claude/agents/jake-reporter.md +45 -0
- package/dist/.claude/agents/janeway-novel-arch.md +48 -0
- package/dist/.claude/agents/janov-context-eng.md +40 -0
- package/dist/.claude/agents/jarvis-status.md +42 -0
- package/dist/.claude/agents/jean-pragmatic.md +39 -0
- package/dist/.claude/agents/jessica-voice.md +40 -0
- package/dist/.claude/agents/jet-maintenance.md +39 -0
- package/dist/.claude/agents/jin-disciplined-adv.md +39 -0
- package/dist/.claude/agents/kaji-intelligence.md +39 -0
- package/dist/.claude/agents/kaladin-organic-growth.md +40 -0
- package/dist/.claude/agents/kallen-hard-deploy.md +39 -0
- package/dist/.claude/agents/kanan-intuitive.md +41 -0
- package/dist/.claude/agents/kaoru-harmony.md +37 -0
- package/dist/.claude/agents/kaworu-solver.md +39 -0
- package/dist/.claude/agents/kelsier-growth.md +64 -0
- package/dist/.claude/agents/kenobi-security.md +70 -0
- package/dist/.claude/agents/kim-api-design.md +49 -0
- package/dist/.claude/agents/kira-pragmatic.md +48 -0
- package/dist/.claude/agents/kishibe-hardening.md +39 -0
- package/dist/.claude/agents/kohaku-rapid-response.md +36 -0
- package/dist/.claude/agents/krillin-support.md +36 -0
- package/dist/.claude/agents/kusanagi-devops.md +70 -0
- package/dist/.claude/agents/la-forge-reliability.md +63 -0
- package/dist/.claude/agents/lang-micro-changes.md +43 -0
- package/dist/.claude/agents/legolas-precision.md +42 -0
- package/dist/.claude/agents/leia-secrets.md +41 -0
- package/dist/.claude/agents/lelouch-orchestration.md +39 -0
- package/dist/.claude/agents/leto-ii-persistence.md +40 -0
- package/dist/.claude/agents/leto-protection.md +40 -0
- package/dist/.claude/agents/levi-deploy.md +40 -0
- package/dist/.claude/agents/liet-kynes-deep-system.md +40 -0
- package/dist/.claude/agents/lift-social-media.md +40 -0
- package/dist/.claude/agents/loki-chaos.md +58 -0
- package/dist/.claude/agents/lucius-config.md +43 -0
- package/dist/.claude/agents/luke-audit-journey.md +41 -0
- package/dist/.claude/agents/manhunter-shapeshifting.md +43 -0
- package/dist/.claude/agents/marsh-competitive-intel.md +41 -0
- package/dist/.claude/agents/maul-red-team.md +57 -0
- package/dist/.claude/agents/merry-pair-review.md +40 -0
- package/dist/.claude/agents/mikasa-protection.md +39 -0
- package/dist/.claude/agents/miles-teg-perf.md +40 -0
- package/dist/.claude/agents/milim-load-test.md +39 -0
- package/dist/.claude/agents/misato-operations.md +39 -0
- package/dist/.claude/agents/mob-capacity.md +39 -0
- package/dist/.claude/agents/mohiam-authentication.md +40 -0
- package/dist/.claude/agents/mon-mothma-security-mgmt.md +41 -0
- package/dist/.claude/agents/mugen-chaos.md +39 -0
- package/dist/.claude/agents/mule-adversarial-ai.md +41 -0
- package/dist/.claude/agents/mustang-cleanup.md +39 -0
- package/dist/.claude/agents/nanami-structured-ops.md +39 -0
- package/dist/.claude/agents/nausicaa-resources.md +39 -0
- package/dist/.claude/agents/navani-technical-seo.md +40 -0
- package/dist/.claude/agents/nebula-optimization.md +43 -0
- package/dist/.claude/agents/nightwing-regression.md +59 -0
- package/dist/.claude/agents/nobara-direct-fix.md +39 -0
- package/dist/.claude/agents/nog-solutions.md +48 -0
- package/dist/.claude/agents/nori-asset-scanner.md +37 -0
- package/dist/.claude/agents/obrien-root-cause.md +48 -0
- package/dist/.claude/agents/odo-structural-anomaly.md +48 -0
- package/dist/.claude/agents/okoye-data-integrity.md +43 -0
- package/dist/.claude/agents/olivier-hardening.md +39 -0
- package/dist/.claude/agents/oracle-static-analysis.md +59 -0
- package/dist/.claude/agents/ori-prompt-crafter.md +37 -0
- package/dist/.claude/agents/padme-data-protection.md +42 -0
- package/dist/.claude/agents/paris-route-planner.md +47 -0
- package/dist/.claude/agents/parker-connections.md +43 -0
- package/dist/.claude/agents/paul-orchestration.md +40 -0
- package/dist/.claude/agents/picard-architecture.md +64 -0
- package/dist/.claude/agents/piccolo-tactics.md +39 -0
- package/dist/.claude/agents/pike-bold-decisions.md +48 -0
- package/dist/.claude/agents/pippin-discovery.md +40 -0
- package/dist/.claude/agents/plo-koon-edge-cases.md +37 -0
- package/dist/.claude/agents/power-chaotic.md +39 -0
- package/dist/.claude/agents/qui-gon-subtle-vulns.md +40 -0
- package/dist/.claude/agents/radagast-edge-cases.md +41 -0
- package/dist/.claude/agents/raoden-conversion.md +41 -0
- package/dist/.claude/agents/raven-deep-analysis.md +43 -0
- package/dist/.claude/agents/red-hood-aggressive.md +47 -0
- package/dist/.claude/agents/rei-dangerous-tasks.md +39 -0
- package/dist/.claude/agents/reigen-debugger.md +39 -0
- package/dist/.claude/agents/rengoku-intense-monitor.md +39 -0
- package/dist/.claude/agents/rex-infrastructure.md +41 -0
- package/dist/.claude/agents/rhodes-production.md +43 -0
- package/dist/.claude/agents/riker-review.md +62 -0
- package/dist/.claude/agents/rimuru-adapter.md +39 -0
- package/dist/.claude/agents/riza-backup.md +39 -0
- package/dist/.claude/agents/robin-apprentice.md +42 -0
- package/dist/.claude/agents/rocket-scrappy.md +43 -0
- package/dist/.claude/agents/rogers-api-design.md +43 -0
- package/dist/.claude/agents/romanoff-integrations.md +44 -0
- package/dist/.claude/agents/sabine-unconventional.md +40 -0
- package/dist/.claude/agents/salvor-model-selection.md +42 -0
- package/dist/.claude/agents/samwise-accessibility.md +43 -0
- package/dist/.claude/agents/sarene-outreach.md +40 -0
- package/dist/.claude/agents/sasha-resources.md +37 -0
- package/dist/.claude/agents/scotty-infrastructure.md +48 -0
- package/dist/.claude/agents/seldon-ai.md +67 -0
- package/dist/.claude/agents/senku-provisioning.md +40 -0
- package/dist/.claude/agents/sentaro-scheduling.md +37 -0
- package/dist/.claude/agents/seven-optimization.md +48 -0
- package/dist/.claude/agents/shallan-creative.md +40 -0
- package/dist/.claude/agents/sheeana-transport.md +40 -0
- package/dist/.claude/agents/shuri-innovation.md +43 -0
- package/dist/.claude/agents/silver-surfer-herald.md +90 -0
- package/dist/.claude/agents/siona-evasion.md +41 -0
- package/dist/.claude/agents/sisko-campaign.md +68 -0
- package/dist/.claude/agents/spike-routing.md +40 -0
- package/dist/.claude/agents/spock-schema.md +62 -0
- package/dist/.claude/agents/starfire-brute-force.md +43 -0
- package/dist/.claude/agents/stark-backend.md +71 -0
- package/dist/.claude/agents/steris-budget.md +41 -0
- package/dist/.claude/agents/stilgar-channel-security.md +40 -0
- package/dist/.claude/agents/strange-service-arch.md +44 -0
- package/dist/.claude/agents/sung-workers.md +39 -0
- package/dist/.claude/agents/superman-strength-test.md +43 -0
- package/dist/.claude/agents/suzaku-execution.md +39 -0
- package/dist/.claude/agents/szeth-compliance.md +40 -0
- package/dist/.claude/agents/tanjiro-persistent.md +39 -0
- package/dist/.claude/agents/tchalla-quality.md +43 -0
- package/dist/.claude/agents/thanos-gauntlet.md +68 -0
- package/dist/.claude/agents/theoden-rally.md +40 -0
- package/dist/.claude/agents/thor-queues.md +44 -0
- package/dist/.claude/agents/thufir-protocol-parsing.md +40 -0
- package/dist/.claude/agents/todo-brute-force.md +39 -0
- package/dist/.claude/agents/torres-site-scanner.md +47 -0
- package/dist/.claude/agents/totoro-guardian.md +39 -0
- package/dist/.claude/agents/tpol-disciplined.md +48 -0
- package/dist/.claude/agents/treebeard-deliberation.md +41 -0
- package/dist/.claude/agents/troi-prd-compliance.md +64 -0
- package/dist/.claude/agents/trunks-rollback.md +39 -0
- package/dist/.claude/agents/tuvok-deep-current.md +63 -0
- package/dist/.claude/agents/uhura-integration.md +47 -0
- package/dist/.claude/agents/valkyrie-recovery.md +43 -0
- package/dist/.claude/agents/vegeta-monitoring.md +39 -0
- package/dist/.claude/agents/veldora-dormant.md +37 -0
- package/dist/.claude/agents/vin-analytics.md +41 -0
- package/dist/.claude/agents/vision-data-analysis.md +43 -0
- package/dist/.claude/agents/wanda-seldon-validation.md +38 -0
- package/dist/.claude/agents/wanda-state.md +43 -0
- package/dist/.claude/agents/wax-paid-ads.md +40 -0
- package/dist/.claude/agents/wayne-ab-testing.md +40 -0
- package/dist/.claude/agents/whis-precision.md +39 -0
- package/dist/.claude/agents/windu-input-validation.md +41 -0
- package/dist/.claude/agents/winry-maintenance.md +39 -0
- package/dist/.claude/agents/wonder-woman-truth.md +43 -0
- package/dist/.claude/agents/wong-documentation.md +58 -0
- package/dist/.claude/agents/worf-security-arch.md +49 -0
- package/dist/.claude/agents/yoda-auth.md +57 -0
- package/dist/.claude/agents/yueh-trust-verify.md +40 -0
- package/dist/.claude/agents/zatanna-impossible.md +43 -0
- package/dist/.claude/agents/zechs-rival.md +39 -0
- package/dist/.claude/agents/zenitsu-alerts.md +37 -0
- package/dist/.claude/commands/ai.md +84 -0
- package/dist/.claude/commands/architect.md +107 -0
- package/dist/.claude/commands/assemble.md +223 -0
- package/dist/.claude/commands/assess.md +86 -0
- package/dist/.claude/commands/blueprint.md +135 -0
- package/dist/.claude/commands/build.md +138 -0
- package/dist/.claude/commands/campaign.md +224 -0
- package/dist/.claude/commands/cultivation.md +184 -0
- package/dist/.claude/commands/current.md +128 -0
- package/dist/.claude/commands/dangerroom.md +74 -0
- package/dist/.claude/commands/debrief.md +180 -0
- package/dist/.claude/commands/deploy.md +108 -0
- package/dist/.claude/commands/devops.md +160 -0
- package/dist/.claude/commands/engage.md +135 -0
- package/dist/.claude/commands/gauntlet.md +179 -0
- package/dist/.claude/commands/git.md +104 -0
- package/dist/.claude/commands/grow.md +160 -0
- package/dist/.claude/commands/imagine.md +126 -0
- package/dist/.claude/commands/portfolio.md +51 -0
- package/dist/.claude/commands/prd.md +113 -0
- package/dist/.claude/commands/qa.md +130 -0
- package/dist/.claude/commands/review.md +9 -0
- package/dist/.claude/commands/security.md +9 -0
- package/dist/.claude/commands/sentinel.md +90 -0
- package/dist/.claude/commands/test.md +114 -0
- package/dist/.claude/commands/thumper.md +116 -0
- package/dist/.claude/commands/treasury.md +117 -0
- package/dist/.claude/commands/ux.md +132 -0
- package/dist/.claude/commands/vault.md +198 -0
- package/dist/.claude/commands/void.md +148 -0
- package/dist/CHANGELOG.md +2621 -0
- package/dist/CLAUDE.md +292 -0
- package/dist/HOLOCRON.md +859 -0
- package/dist/VERSION.md +149 -0
- package/dist/docs/NAMING_REGISTRY.md +479 -0
- package/dist/docs/methods/AI_INTELLIGENCE.md +276 -0
- package/dist/docs/methods/ASSEMBLER.md +142 -0
- package/dist/docs/methods/BACKEND_ENGINEER.md +165 -0
- package/dist/docs/methods/BUILD_JOURNAL.md +214 -0
- package/dist/docs/methods/BUILD_PROTOCOL.md +436 -0
- package/dist/docs/methods/CAMPAIGN.md +569 -0
- package/dist/docs/methods/CONTEXT_MANAGEMENT.md +189 -0
- package/dist/docs/methods/DEEP_CURRENT.md +184 -0
- package/dist/docs/methods/DEVOPS_ENGINEER.md +297 -0
- package/dist/docs/methods/FIELD_MEDIC.md +265 -0
- package/dist/docs/methods/FORGE_ARTIST.md +108 -0
- package/dist/docs/methods/FORGE_KEEPER.md +270 -0
- package/dist/docs/methods/GAUNTLET.md +364 -0
- package/dist/docs/methods/GROWTH_STRATEGIST.md +466 -0
- package/dist/docs/methods/HEARTBEAT.md +168 -0
- package/dist/docs/methods/MCP_INTEGRATION.md +139 -0
- package/dist/docs/methods/MUSTER.md +152 -0
- package/dist/docs/methods/PRD_GENERATOR.md +186 -0
- package/dist/docs/methods/PRODUCT_DESIGN_FRONTEND.md +252 -0
- package/dist/docs/methods/QA_ENGINEER.md +360 -0
- package/dist/docs/methods/RELEASE_MANAGER.md +145 -0
- package/dist/docs/methods/SECURITY_AUDITOR.md +328 -0
- package/dist/docs/methods/SUB_AGENTS.md +375 -0
- package/dist/docs/methods/SYSTEMS_ARCHITECT.md +180 -0
- package/dist/docs/methods/TESTING.md +359 -0
- package/dist/docs/methods/THUMPER.md +175 -0
- package/dist/docs/methods/TIME_VAULT.md +120 -0
- package/dist/docs/methods/TREASURY.md +184 -0
- package/dist/docs/methods/TROUBLESHOOTING.md +265 -0
- package/dist/docs/patterns/README.md +52 -0
- package/dist/docs/patterns/ad-billing-adapter.ts +537 -0
- package/dist/docs/patterns/ad-platform-adapter.ts +421 -0
- package/dist/docs/patterns/ai-classifier.ts +195 -0
- package/dist/docs/patterns/ai-eval.ts +272 -0
- package/dist/docs/patterns/ai-orchestrator.ts +341 -0
- package/dist/docs/patterns/ai-router.ts +194 -0
- package/dist/docs/patterns/ai-tool-schema.ts +237 -0
- package/dist/docs/patterns/api-route.ts +241 -0
- package/dist/docs/patterns/backtest-engine.ts +499 -0
- package/dist/docs/patterns/browser-review.ts +292 -0
- package/dist/docs/patterns/combobox.tsx +300 -0
- package/dist/docs/patterns/component.tsx +262 -0
- package/dist/docs/patterns/daemon-process.ts +338 -0
- package/dist/docs/patterns/data-pipeline.ts +297 -0
- package/dist/docs/patterns/database-migration.ts +466 -0
- package/dist/docs/patterns/e2e-test.ts +629 -0
- package/dist/docs/patterns/error-handling.ts +312 -0
- package/dist/docs/patterns/execution-safety.ts +601 -0
- package/dist/docs/patterns/financial-transaction.ts +366 -0
- package/dist/docs/patterns/funding-plan.ts +462 -0
- package/dist/docs/patterns/game-entity.ts +137 -0
- package/dist/docs/patterns/game-loop.ts +113 -0
- package/dist/docs/patterns/game-state.ts +143 -0
- package/dist/docs/patterns/job-queue.ts +225 -0
- package/dist/docs/patterns/kongo-integration.ts +164 -0
- package/dist/docs/patterns/middleware.ts +363 -0
- package/dist/docs/patterns/mobile-screen.tsx +139 -0
- package/dist/docs/patterns/mobile-service.ts +167 -0
- package/dist/docs/patterns/multi-tenant.ts +382 -0
- package/dist/docs/patterns/oauth-token-lifecycle.ts +223 -0
- package/dist/docs/patterns/outbound-rate-limiter.ts +260 -0
- package/dist/docs/patterns/prompt-template.ts +195 -0
- package/dist/docs/patterns/revenue-source-adapter.ts +311 -0
- package/dist/docs/patterns/service.ts +224 -0
- package/dist/docs/patterns/sse-endpoint.ts +118 -0
- package/dist/docs/patterns/stablecoin-adapter.ts +511 -0
- package/dist/docs/patterns/third-party-script.ts +68 -0
- package/dist/scripts/thumper/gom-jabbar.sh +241 -0
- package/dist/scripts/thumper/relay.sh +610 -0
- package/dist/scripts/thumper/scan.sh +359 -0
- package/dist/scripts/thumper/thumper.sh +190 -0
- package/dist/scripts/thumper/water-rings.sh +76 -0
- package/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +21 -0
- package/dist/scripts/voidforge.js +614 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +139 -0
- package/dist/wizard/api/blueprint.d.ts +34 -0
- package/dist/wizard/api/blueprint.js +161 -0
- package/dist/wizard/api/cloud-providers.d.ts +16 -0
- package/dist/wizard/api/cloud-providers.js +363 -0
- package/dist/wizard/api/credentials.d.ts +1 -0
- package/dist/wizard/api/credentials.js +265 -0
- package/dist/wizard/api/danger-room.d.ts +24 -0
- package/dist/wizard/api/danger-room.js +274 -0
- package/dist/wizard/api/deploy.d.ts +4 -0
- package/dist/wizard/api/deploy.js +164 -0
- package/dist/wizard/api/prd.d.ts +1 -0
- package/dist/wizard/api/prd.js +363 -0
- package/dist/wizard/api/project.d.ts +1 -0
- package/dist/wizard/api/project.js +241 -0
- package/dist/wizard/api/projects-data.d.ts +5 -0
- package/dist/wizard/api/projects-data.js +234 -0
- package/dist/wizard/api/projects-list.d.ts +5 -0
- package/dist/wizard/api/projects-list.js +227 -0
- package/dist/wizard/api/projects.d.ts +7 -0
- package/dist/wizard/api/projects.js +273 -0
- package/dist/wizard/api/provision-status.d.ts +5 -0
- package/dist/wizard/api/provision-status.js +47 -0
- package/dist/wizard/api/provision-steps.d.ts +21 -0
- package/dist/wizard/api/provision-steps.js +44 -0
- package/dist/wizard/api/provision-validate.d.ts +22 -0
- package/dist/wizard/api/provision-validate.js +164 -0
- package/dist/wizard/api/provision.d.ts +2 -0
- package/dist/wizard/api/provision.js +239 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +246 -0
- package/dist/wizard/api/users.d.ts +6 -0
- package/dist/wizard/api/users.js +244 -0
- package/dist/wizard/api/war-room.d.ts +16 -0
- package/dist/wizard/api/war-room.js +70 -0
- package/dist/wizard/danger-room.config.json +5 -0
- package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
- package/dist/wizard/lib/ad-platform-core.js +1 -0
- package/dist/wizard/lib/adapters/index.d.ts +52 -0
- package/dist/wizard/lib/adapters/index.js +38 -0
- package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
- package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
- package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
- package/dist/wizard/lib/adapters/sandbox.js +174 -0
- package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
- package/dist/wizard/lib/adapters/stripe.js +143 -0
- package/dist/wizard/lib/adapters/types.d.ts +9 -0
- package/dist/wizard/lib/adapters/types.js +10 -0
- package/dist/wizard/lib/agent-memory.d.ts +36 -0
- package/dist/wizard/lib/agent-memory.js +114 -0
- package/dist/wizard/lib/agent-registry.d.ts +21 -0
- package/dist/wizard/lib/agent-registry.js +105 -0
- package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
- package/dist/wizard/lib/anomaly-detection.js +122 -0
- package/dist/wizard/lib/anthropic.d.ts +21 -0
- package/dist/wizard/lib/anthropic.js +105 -0
- package/dist/wizard/lib/asset-scanner.d.ts +23 -0
- package/dist/wizard/lib/asset-scanner.js +107 -0
- package/dist/wizard/lib/audit-log.d.ts +23 -0
- package/dist/wizard/lib/audit-log.js +70 -0
- package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
- package/dist/wizard/lib/autonomy-controller.js +184 -0
- package/dist/wizard/lib/body-parser.d.ts +2 -0
- package/dist/wizard/lib/body-parser.js +36 -0
- package/dist/wizard/lib/build-analytics.d.ts +39 -0
- package/dist/wizard/lib/build-analytics.js +91 -0
- package/dist/wizard/lib/build-step.d.ts +21 -0
- package/dist/wizard/lib/build-step.js +104 -0
- package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
- package/dist/wizard/lib/campaign-proposer.js +181 -0
- package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
- package/dist/wizard/lib/campaign-state-machine.js +114 -0
- package/dist/wizard/lib/ci-generator.d.ts +14 -0
- package/dist/wizard/lib/ci-generator.js +187 -0
- package/dist/wizard/lib/claude-merge.d.ts +38 -0
- package/dist/wizard/lib/claude-merge.js +115 -0
- package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/erd-gen.js +98 -0
- package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
- package/dist/wizard/lib/codegen/integrations.js +189 -0
- package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
- package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
- package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
- package/dist/wizard/lib/codegen/prisma-types.js +44 -0
- package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
- package/dist/wizard/lib/codegen/seed-gen.js +128 -0
- package/dist/wizard/lib/compliance.d.ts +51 -0
- package/dist/wizard/lib/compliance.js +112 -0
- package/dist/wizard/lib/correlation-engine.d.ts +59 -0
- package/dist/wizard/lib/correlation-engine.js +152 -0
- package/dist/wizard/lib/cost-estimator.d.ts +22 -0
- package/dist/wizard/lib/cost-estimator.js +72 -0
- package/dist/wizard/lib/cost-tracker.d.ts +27 -0
- package/dist/wizard/lib/cost-tracker.js +37 -0
- package/dist/wizard/lib/daemon-aggregator.d.ts +76 -0
- package/dist/wizard/lib/daemon-aggregator.js +241 -0
- package/dist/wizard/lib/daemon-core.d.ts +16 -0
- package/dist/wizard/lib/daemon-core.js +39 -0
- package/dist/wizard/lib/dashboard-data.d.ts +123 -0
- package/dist/wizard/lib/dashboard-data.js +314 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +28 -0
- package/dist/wizard/lib/dashboard-ws.js +117 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +247 -0
- package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
- package/dist/wizard/lib/deploy-coordinator.js +86 -0
- package/dist/wizard/lib/deploy-log.d.ts +28 -0
- package/dist/wizard/lib/deploy-log.js +52 -0
- package/dist/wizard/lib/desktop-notify.d.ts +27 -0
- package/dist/wizard/lib/desktop-notify.js +98 -0
- package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
- package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
- package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
- package/dist/wizard/lib/dns/types.d.ts +22 -0
- package/dist/wizard/lib/dns/types.js +4 -0
- package/dist/wizard/lib/document-discovery.d.ts +33 -0
- package/dist/wizard/lib/document-discovery.js +145 -0
- package/dist/wizard/lib/env-validator.d.ts +14 -0
- package/dist/wizard/lib/env-validator.js +205 -0
- package/dist/wizard/lib/env-writer.d.ts +13 -0
- package/dist/wizard/lib/env-writer.js +26 -0
- package/dist/wizard/lib/exec.d.ts +30 -0
- package/dist/wizard/lib/exec.js +52 -0
- package/dist/wizard/lib/experiment.d.ts +70 -0
- package/dist/wizard/lib/experiment.js +169 -0
- package/dist/wizard/lib/extensions.d.ts +20 -0
- package/dist/wizard/lib/extensions.js +183 -0
- package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
- package/dist/wizard/lib/financial/adapter-factory.js +225 -0
- package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
- package/dist/wizard/lib/financial/billing/base.js +1 -0
- package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
- package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
- package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
- package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
- package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
- package/dist/wizard/lib/financial/campaign/base.js +1 -0
- package/dist/wizard/lib/financial/campaign/campaign-common.d.ts +21 -0
- package/dist/wizard/lib/financial/campaign/campaign-common.js +58 -0
- package/dist/wizard/lib/financial/campaign/google-api.d.ts +35 -0
- package/dist/wizard/lib/financial/campaign/google-api.js +118 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +38 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +186 -0
- package/dist/wizard/lib/financial/campaign/meta-api.d.ts +28 -0
- package/dist/wizard/lib/financial/campaign/meta-api.js +93 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +32 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +189 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
- package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
- package/dist/wizard/lib/financial/campaign/tiktok-api.d.ts +25 -0
- package/dist/wizard/lib/financial/campaign/tiktok-api.js +81 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +37 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +155 -0
- package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
- package/dist/wizard/lib/financial/funding-auto.js +52 -0
- package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
- package/dist/wizard/lib/financial/funding-policy.js +179 -0
- package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
- package/dist/wizard/lib/financial/platform-planner.js +134 -0
- package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
- package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
- package/dist/wizard/lib/financial/registry.d.ts +22 -0
- package/dist/wizard/lib/financial/registry.js +26 -0
- package/dist/wizard/lib/financial/reporting.d.ts +96 -0
- package/dist/wizard/lib/financial/reporting.js +198 -0
- package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
- package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
- package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
- package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
- package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
- package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
- package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
- package/dist/wizard/lib/financial/treasury-planner.js +128 -0
- package/dist/wizard/lib/financial-core.d.ts +6 -0
- package/dist/wizard/lib/financial-core.js +5 -0
- package/dist/wizard/lib/financial-vault.d.ts +34 -0
- package/dist/wizard/lib/financial-vault.js +200 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +99 -0
- package/dist/wizard/lib/gap-analysis.d.ts +37 -0
- package/dist/wizard/lib/gap-analysis.js +218 -0
- package/dist/wizard/lib/github.d.ts +22 -0
- package/dist/wizard/lib/github.js +261 -0
- package/dist/wizard/lib/headless-deploy.d.ts +14 -0
- package/dist/wizard/lib/headless-deploy.js +452 -0
- package/dist/wizard/lib/health-monitor.d.ts +15 -0
- package/dist/wizard/lib/health-monitor.js +91 -0
- package/dist/wizard/lib/health-poller.d.ts +9 -0
- package/dist/wizard/lib/health-poller.js +123 -0
- package/dist/wizard/lib/heartbeat-lifecycle.d.ts +71 -0
- package/dist/wizard/lib/heartbeat-lifecycle.js +107 -0
- package/dist/wizard/lib/heartbeat-scheduler.d.ts +26 -0
- package/dist/wizard/lib/heartbeat-scheduler.js +155 -0
- package/dist/wizard/lib/heartbeat.d.ts +22 -0
- package/dist/wizard/lib/heartbeat.js +538 -0
- package/dist/wizard/lib/herald.d.ts +28 -0
- package/dist/wizard/lib/herald.js +167 -0
- package/dist/wizard/lib/http-helpers.d.ts +9 -0
- package/dist/wizard/lib/http-helpers.js +24 -0
- package/dist/wizard/lib/image-gen.d.ts +56 -0
- package/dist/wizard/lib/image-gen.js +159 -0
- package/dist/wizard/lib/instance-sizing.d.ts +26 -0
- package/dist/wizard/lib/instance-sizing.js +51 -0
- package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
- package/dist/wizard/lib/kongo/analytics.js +179 -0
- package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
- package/dist/wizard/lib/kongo/campaigns.js +91 -0
- package/dist/wizard/lib/kongo/client.d.ts +58 -0
- package/dist/wizard/lib/kongo/client.js +221 -0
- package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
- package/dist/wizard/lib/kongo/jobs.js +122 -0
- package/dist/wizard/lib/kongo/pages.d.ts +60 -0
- package/dist/wizard/lib/kongo/pages.js +150 -0
- package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
- package/dist/wizard/lib/kongo/provisioner.js +116 -0
- package/dist/wizard/lib/kongo/seed.d.ts +49 -0
- package/dist/wizard/lib/kongo/seed.js +237 -0
- package/dist/wizard/lib/kongo/types.d.ts +323 -0
- package/dist/wizard/lib/kongo/types.js +11 -0
- package/dist/wizard/lib/kongo/variants.d.ts +57 -0
- package/dist/wizard/lib/kongo/variants.js +88 -0
- package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
- package/dist/wizard/lib/kongo/webhooks.js +112 -0
- package/dist/wizard/lib/marker.d.ts +28 -0
- package/dist/wizard/lib/marker.js +79 -0
- package/dist/wizard/lib/migrator.d.ts +35 -0
- package/dist/wizard/lib/migrator.js +190 -0
- package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
- package/dist/wizard/lib/natural-language-deploy.js +186 -0
- package/dist/wizard/lib/network.d.ts +22 -0
- package/dist/wizard/lib/network.js +72 -0
- package/dist/wizard/lib/oauth-core.d.ts +6 -0
- package/dist/wizard/lib/oauth-core.js +5 -0
- package/dist/wizard/lib/open-browser.d.ts +1 -0
- package/dist/wizard/lib/open-browser.js +26 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
- package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
- package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
- package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
- package/dist/wizard/lib/patterns/daemon-process.js +271 -0
- package/dist/wizard/lib/patterns/financial-transaction.d.ts +171 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +154 -0
- package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
- package/dist/wizard/lib/patterns/funding-plan.js +200 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
- package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
- package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
- package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
- package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
- package/dist/wizard/lib/prd-validator.d.ts +39 -0
- package/dist/wizard/lib/prd-validator.js +137 -0
- package/dist/wizard/lib/project-init.d.ts +24 -0
- package/dist/wizard/lib/project-init.js +228 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -0
- package/dist/wizard/lib/project-scope.d.ts +64 -0
- package/dist/wizard/lib/project-scope.js +96 -0
- package/dist/wizard/lib/project-vault.d.ts +47 -0
- package/dist/wizard/lib/project-vault.js +221 -0
- package/dist/wizard/lib/provision-manifest.d.ts +44 -0
- package/dist/wizard/lib/provision-manifest.js +164 -0
- package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
- package/dist/wizard/lib/provisioner-registry.js +34 -0
- package/dist/wizard/lib/provisioners/aws-config.d.ts +36 -0
- package/dist/wizard/lib/provisioners/aws-config.js +56 -0
- package/dist/wizard/lib/provisioners/aws-ec2.d.ts +19 -0
- package/dist/wizard/lib/provisioners/aws-ec2.js +241 -0
- package/dist/wizard/lib/provisioners/aws-rds.d.ts +10 -0
- package/dist/wizard/lib/provisioners/aws-rds.js +199 -0
- package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +231 -0
- package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
- package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
- package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
- package/dist/wizard/lib/provisioners/docker.js +75 -0
- package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
- package/dist/wizard/lib/provisioners/http-client.js +79 -0
- package/dist/wizard/lib/provisioners/railway-config.d.ts +24 -0
- package/dist/wizard/lib/provisioners/railway-config.js +220 -0
- package/dist/wizard/lib/provisioners/railway-deploy.d.ts +19 -0
- package/dist/wizard/lib/provisioners/railway-deploy.js +205 -0
- package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +45 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
- package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
- package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
- package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
- package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
- package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
- package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
- package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
- package/dist/wizard/lib/provisioners/static-s3.js +235 -0
- package/dist/wizard/lib/provisioners/types.d.ts +40 -0
- package/dist/wizard/lib/provisioners/types.js +4 -0
- package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
- package/dist/wizard/lib/provisioners/vercel.js +287 -0
- package/dist/wizard/lib/pty-manager.d.ts +42 -0
- package/dist/wizard/lib/pty-manager.js +244 -0
- package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
- package/dist/wizard/lib/rate-limiter-core.js +5 -0
- package/dist/wizard/lib/reconciliation.d.ts +43 -0
- package/dist/wizard/lib/reconciliation.js +173 -0
- package/dist/wizard/lib/revenue-types.d.ts +5 -0
- package/dist/wizard/lib/revenue-types.js +1 -0
- package/dist/wizard/lib/route-optimizer.d.ts +28 -0
- package/dist/wizard/lib/route-optimizer.js +93 -0
- package/dist/wizard/lib/s3-deploy.d.ts +19 -0
- package/dist/wizard/lib/s3-deploy.js +156 -0
- package/dist/wizard/lib/safety-tiers.d.ts +76 -0
- package/dist/wizard/lib/safety-tiers.js +134 -0
- package/dist/wizard/lib/sentry-generator.d.ts +15 -0
- package/dist/wizard/lib/sentry-generator.js +116 -0
- package/dist/wizard/lib/server-config.d.ts +13 -0
- package/dist/wizard/lib/server-config.js +23 -0
- package/dist/wizard/lib/service-install.d.ts +18 -0
- package/dist/wizard/lib/service-install.js +182 -0
- package/dist/wizard/lib/site-scanner.d.ts +80 -0
- package/dist/wizard/lib/site-scanner.js +262 -0
- package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
- package/dist/wizard/lib/ssh-deploy.js +225 -0
- package/dist/wizard/lib/templates.d.ts +24 -0
- package/dist/wizard/lib/templates.js +219 -0
- package/dist/wizard/lib/totp.d.ts +35 -0
- package/dist/wizard/lib/totp.js +277 -0
- package/dist/wizard/lib/tower-auth.d.ts +43 -0
- package/dist/wizard/lib/tower-auth.js +352 -0
- package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
- package/dist/wizard/lib/tower-rate-limit.js +61 -0
- package/dist/wizard/lib/tower-session.d.ts +28 -0
- package/dist/wizard/lib/tower-session.js +119 -0
- package/dist/wizard/lib/treasury-backup.d.ts +23 -0
- package/dist/wizard/lib/treasury-backup.js +127 -0
- package/dist/wizard/lib/treasury-circuit-breakers.d.ts +28 -0
- package/dist/wizard/lib/treasury-circuit-breakers.js +74 -0
- package/dist/wizard/lib/treasury-handlers.d.ts +21 -0
- package/dist/wizard/lib/treasury-handlers.js +281 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +18 -0
- package/dist/wizard/lib/treasury-heartbeat.js +20 -0
- package/dist/wizard/lib/treasury-io.d.ts +107 -0
- package/dist/wizard/lib/treasury-io.js +254 -0
- package/dist/wizard/lib/treasury-jobs.d.ts +14 -0
- package/dist/wizard/lib/treasury-jobs.js +589 -0
- package/dist/wizard/lib/treasury-migrator.d.ts +59 -0
- package/dist/wizard/lib/treasury-migrator.js +227 -0
- package/dist/wizard/lib/treasury-reader.d.ts +52 -0
- package/dist/wizard/lib/treasury-reader.js +235 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +203 -0
- package/dist/wizard/lib/user-manager.d.ts +39 -0
- package/dist/wizard/lib/user-manager.js +182 -0
- package/dist/wizard/lib/vault.d.ts +26 -0
- package/dist/wizard/lib/vault.js +161 -0
- package/dist/wizard/router.d.ts +12 -0
- package/dist/wizard/router.js +58 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +427 -0
- package/dist/wizard/ui/app.js +1357 -0
- package/dist/wizard/ui/danger-room-prophecy.js +217 -0
- package/dist/wizard/ui/danger-room.html +27 -0
- package/dist/wizard/ui/danger-room.js +29 -0
- package/dist/wizard/ui/deploy.html +181 -0
- package/dist/wizard/ui/deploy.js +616 -0
- package/dist/wizard/ui/favicon.svg +11 -0
- package/dist/wizard/ui/index.html +407 -0
- package/dist/wizard/ui/lobby.html +235 -0
- package/dist/wizard/ui/lobby.js +843 -0
- package/dist/wizard/ui/login.html +111 -0
- package/dist/wizard/ui/login.js +199 -0
- package/dist/wizard/ui/project.html +285 -0
- package/dist/wizard/ui/project.js +324 -0
- package/dist/wizard/ui/rollback.js +107 -0
- package/dist/wizard/ui/styles.css +1040 -0
- package/dist/wizard/ui/tower.html +177 -0
- package/dist/wizard/ui/tower.js +445 -0
- package/dist/wizard/ui/war-room-prophecy.js +217 -0
- package/dist/wizard/ui/war-room.html +27 -0
- package/dist/wizard/ui/war-room.js +29 -0
- package/package.json +60 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project creation — headless and browser init flows.
|
|
3
|
+
*
|
|
4
|
+
* Creates a new VoidForge project by copying methodology files,
|
|
5
|
+
* injecting project identity, writing the marker, and registering.
|
|
6
|
+
*/
|
|
7
|
+
import { mkdir, readFile, writeFile, readdir, cp } from 'node:fs/promises';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { join, resolve } from 'node:path';
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
import { createMarker, writeMarker, } from './marker.js';
|
|
12
|
+
import { addProject } from './project-registry.js';
|
|
13
|
+
// ── Methodology Source ───────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* Resolves the methodology source directory.
|
|
16
|
+
* In development: monorepo root (where CLAUDE.md lives).
|
|
17
|
+
* In production: the installed voidforge-build-methodology package.
|
|
18
|
+
*/
|
|
19
|
+
async function resolveMethodologyRoot() {
|
|
20
|
+
// Development: walk up from this file to find CLAUDE.md at monorepo root
|
|
21
|
+
const dir = import.meta.dirname ?? new URL('.', import.meta.url).pathname;
|
|
22
|
+
let current = dir;
|
|
23
|
+
for (let i = 0; i < 10; i++) {
|
|
24
|
+
if (existsSync(join(current, 'CLAUDE.md')) && existsSync(join(current, '.claude', 'commands'))) {
|
|
25
|
+
return current;
|
|
26
|
+
}
|
|
27
|
+
current = resolve(current, '..');
|
|
28
|
+
}
|
|
29
|
+
// Production: try to resolve from voidforge-build-methodology
|
|
30
|
+
try {
|
|
31
|
+
const { createRequire } = await import('node:module');
|
|
32
|
+
const require_ = createRequire(import.meta.url);
|
|
33
|
+
const methodologyPkg = require_.resolve('voidforge-build-methodology/package.json');
|
|
34
|
+
return resolve(methodologyPkg, '..');
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Package not installed — expected in development
|
|
38
|
+
}
|
|
39
|
+
throw new Error('Cannot find methodology source. Checked: CLAUDE.md walkup (development), ' +
|
|
40
|
+
'voidforge-build-methodology package (production). Ensure VoidForge is installed correctly.');
|
|
41
|
+
}
|
|
42
|
+
// ── Copy Methodology ─────────────────────────────────────
|
|
43
|
+
async function copyDir(src, dest) {
|
|
44
|
+
if (!existsSync(src))
|
|
45
|
+
return 0;
|
|
46
|
+
await mkdir(dest, { recursive: true });
|
|
47
|
+
let count = 0;
|
|
48
|
+
const entries = await readdir(src, { withFileTypes: true });
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const srcPath = join(src, entry.name);
|
|
51
|
+
const destPath = join(dest, entry.name);
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
count += await copyDir(srcPath, destPath);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
await cp(srcPath, destPath);
|
|
57
|
+
count++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return count;
|
|
61
|
+
}
|
|
62
|
+
async function copyMethodology(methodologyRoot, projectDir, core) {
|
|
63
|
+
let count = 0;
|
|
64
|
+
// Always copy: CLAUDE.md, VERSION.md
|
|
65
|
+
for (const file of ['CLAUDE.md', 'VERSION.md']) {
|
|
66
|
+
const src = join(methodologyRoot, file);
|
|
67
|
+
if (existsSync(src)) {
|
|
68
|
+
await cp(src, join(projectDir, file));
|
|
69
|
+
count++;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Full tier: also copy HOLOCRON.md, CHANGELOG.md
|
|
73
|
+
if (!core) {
|
|
74
|
+
for (const file of ['HOLOCRON.md', 'CHANGELOG.md']) {
|
|
75
|
+
const src = join(methodologyRoot, file);
|
|
76
|
+
if (existsSync(src)) {
|
|
77
|
+
await cp(src, join(projectDir, file));
|
|
78
|
+
count++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Commands
|
|
83
|
+
const commandsSrc = join(methodologyRoot, '.claude', 'commands');
|
|
84
|
+
if (existsSync(commandsSrc)) {
|
|
85
|
+
count += await copyDir(commandsSrc, join(projectDir, '.claude', 'commands'));
|
|
86
|
+
}
|
|
87
|
+
// Agent definitions (ADR-044)
|
|
88
|
+
const agentsSrc = join(methodologyRoot, '.claude', 'agents');
|
|
89
|
+
if (existsSync(agentsSrc)) {
|
|
90
|
+
count += await copyDir(agentsSrc, join(projectDir, '.claude', 'agents'));
|
|
91
|
+
}
|
|
92
|
+
// Methods
|
|
93
|
+
const methodsSrc = join(methodologyRoot, 'docs', 'methods');
|
|
94
|
+
if (existsSync(methodsSrc)) {
|
|
95
|
+
count += await copyDir(methodsSrc, join(projectDir, 'docs', 'methods'));
|
|
96
|
+
}
|
|
97
|
+
// Patterns (full tier only)
|
|
98
|
+
if (!core) {
|
|
99
|
+
const patternsSrc = join(methodologyRoot, 'docs', 'patterns');
|
|
100
|
+
if (existsSync(patternsSrc)) {
|
|
101
|
+
count += await copyDir(patternsSrc, join(projectDir, 'docs', 'patterns'));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Naming registry
|
|
105
|
+
const registrySrc = join(methodologyRoot, 'docs', 'NAMING_REGISTRY.md');
|
|
106
|
+
if (existsSync(registrySrc)) {
|
|
107
|
+
await mkdir(join(projectDir, 'docs'), { recursive: true });
|
|
108
|
+
await cp(registrySrc, join(projectDir, 'docs', 'NAMING_REGISTRY.md'));
|
|
109
|
+
count++;
|
|
110
|
+
}
|
|
111
|
+
// Thumper scripts
|
|
112
|
+
const thumperSrc = join(methodologyRoot, 'scripts', 'thumper');
|
|
113
|
+
if (existsSync(thumperSrc)) {
|
|
114
|
+
count += await copyDir(thumperSrc, join(projectDir, 'scripts', 'thumper'));
|
|
115
|
+
}
|
|
116
|
+
return count;
|
|
117
|
+
}
|
|
118
|
+
// ── Identity Injection ───────────────────────────────────
|
|
119
|
+
async function injectIdentity(projectDir, config) {
|
|
120
|
+
const claudePath = join(projectDir, 'CLAUDE.md');
|
|
121
|
+
if (!existsSync(claudePath))
|
|
122
|
+
return;
|
|
123
|
+
let content = await readFile(claudePath, 'utf-8');
|
|
124
|
+
// Two paths per ADR-058:
|
|
125
|
+
// (a) Legacy monorepo template: contains `[PROJECT_NAME]` placeholder → replace.
|
|
126
|
+
// (b) Published methodology package: `<!-- REMOVE-FOR-NPM-PUBLISH -->` strips
|
|
127
|
+
// the Project section in prepack.sh, so the downstream CLAUDE.md has no
|
|
128
|
+
// Project section at all. Insert one after the first `# CLAUDE.md` heading.
|
|
129
|
+
if (content.includes('[PROJECT_NAME]')) {
|
|
130
|
+
content = content.replace('[PROJECT_NAME]', config.name);
|
|
131
|
+
content = content.replace('[ONE_LINE_DESCRIPTION]', config.oneliner ?? '');
|
|
132
|
+
content = content.replace('[DOMAIN]', config.domain ?? '');
|
|
133
|
+
content = content.replace('[REPO_URL]', config.repoUrl ?? '');
|
|
134
|
+
}
|
|
135
|
+
else if (!content.includes('## Project')) {
|
|
136
|
+
// Published-package case: Project section was stripped. Insert a fresh one.
|
|
137
|
+
const projectBlock = [
|
|
138
|
+
'',
|
|
139
|
+
'## Project',
|
|
140
|
+
'',
|
|
141
|
+
`- **Name:** ${config.name}`,
|
|
142
|
+
`- **One-liner:** ${config.oneliner ?? ''}`,
|
|
143
|
+
`- **Domain:** ${config.domain ?? ''}`,
|
|
144
|
+
`- **Repo:** ${config.repoUrl ?? ''}`,
|
|
145
|
+
'',
|
|
146
|
+
].join('\n');
|
|
147
|
+
// Insert after the first "# CLAUDE.md" heading, or prepend if no heading.
|
|
148
|
+
const headingMatch = content.match(/^# CLAUDE\.md\s*\n/m);
|
|
149
|
+
if (headingMatch && headingMatch.index !== undefined) {
|
|
150
|
+
const insertAt = headingMatch.index + headingMatch[0].length;
|
|
151
|
+
content = content.slice(0, insertAt) + projectBlock + content.slice(insertAt);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
content = `# CLAUDE.md\n${projectBlock}${content}`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// If the Project section already exists and has no placeholders, leave it alone.
|
|
158
|
+
await writeFile(claudePath, content, 'utf-8');
|
|
159
|
+
}
|
|
160
|
+
// ── Git Init ─────────────────────────────────────────────
|
|
161
|
+
function gitInit(projectDir) {
|
|
162
|
+
try {
|
|
163
|
+
execSync('git init', { cwd: projectDir, stdio: 'pipe' });
|
|
164
|
+
execSync('git add -A', { cwd: projectDir, stdio: 'pipe' });
|
|
165
|
+
execSync('git commit -m "Initial commit — created with VoidForge"', {
|
|
166
|
+
cwd: projectDir,
|
|
167
|
+
stdio: 'pipe',
|
|
168
|
+
env: { ...process.env },
|
|
169
|
+
});
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// ── Main Entry ───────────────────────────────────────────
|
|
177
|
+
export async function createProject(config) {
|
|
178
|
+
const projectDir = resolve(config.directory);
|
|
179
|
+
// 1. Create directory
|
|
180
|
+
await mkdir(projectDir, { recursive: true });
|
|
181
|
+
// 2. Copy methodology
|
|
182
|
+
const methodologyRoot = await resolveMethodologyRoot();
|
|
183
|
+
const filesCreated = await copyMethodology(methodologyRoot, projectDir, config.core ?? false);
|
|
184
|
+
// 3. Inject project identity
|
|
185
|
+
await injectIdentity(projectDir, config);
|
|
186
|
+
// 4. Write .voidforge marker
|
|
187
|
+
const marker = createMarker('21.0.0', config.core ? 'methodology' : 'full', config.extensions ?? []);
|
|
188
|
+
await writeMarker(projectDir, marker);
|
|
189
|
+
// 5. Register in project registry
|
|
190
|
+
try {
|
|
191
|
+
await addProject({
|
|
192
|
+
name: config.name,
|
|
193
|
+
directory: projectDir,
|
|
194
|
+
deployTarget: '',
|
|
195
|
+
deployUrl: '',
|
|
196
|
+
sshHost: '',
|
|
197
|
+
framework: 'unknown',
|
|
198
|
+
database: 'none',
|
|
199
|
+
createdAt: marker.created,
|
|
200
|
+
lastBuildPhase: 0,
|
|
201
|
+
lastDeployAt: '',
|
|
202
|
+
healthCheckUrl: '',
|
|
203
|
+
monthlyCost: 0,
|
|
204
|
+
owner: '',
|
|
205
|
+
access: [],
|
|
206
|
+
linkedProjects: [],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Registry write is best-effort — don't fail project creation
|
|
211
|
+
}
|
|
212
|
+
// 6. Validate critical files were copied
|
|
213
|
+
if (!existsSync(join(projectDir, 'CLAUDE.md'))) {
|
|
214
|
+
throw new Error('Failed to copy CLAUDE.md — methodology source may be corrupted.');
|
|
215
|
+
}
|
|
216
|
+
// 7. Git init + initial commit
|
|
217
|
+
if (!config.skipGit) {
|
|
218
|
+
const gitOk = gitInit(projectDir);
|
|
219
|
+
if (!gitOk) {
|
|
220
|
+
console.warn('Warning: git init failed. Project created but not version-controlled.');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
projectDir,
|
|
225
|
+
markerId: marker.id,
|
|
226
|
+
filesCreated: filesCreated + 1, // +1 for .voidforge marker
|
|
227
|
+
};
|
|
228
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Registry — CRUD for ~/.voidforge/projects.json.
|
|
3
|
+
* Zero-dep JSON file storage for multi-project Avengers Tower.
|
|
4
|
+
* File permissions: 0600 (owner read/write only).
|
|
5
|
+
*
|
|
6
|
+
* Follows vault.ts patterns: serialized writes, atomic file ops, homedir().
|
|
7
|
+
*/
|
|
8
|
+
export type HealthStatus = 'healthy' | 'degraded' | 'down' | 'unchecked';
|
|
9
|
+
export interface ProjectAccessEntry {
|
|
10
|
+
username: string;
|
|
11
|
+
role: 'deployer' | 'viewer';
|
|
12
|
+
}
|
|
13
|
+
export interface Project {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
directory: string;
|
|
17
|
+
deployTarget: string;
|
|
18
|
+
deployUrl: string;
|
|
19
|
+
sshHost: string;
|
|
20
|
+
framework: string;
|
|
21
|
+
database: string;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
lastBuildPhase: number;
|
|
24
|
+
lastDeployAt: string;
|
|
25
|
+
healthCheckUrl: string;
|
|
26
|
+
monthlyCost: number;
|
|
27
|
+
healthStatus: HealthStatus;
|
|
28
|
+
healthCheckedAt: string;
|
|
29
|
+
owner: string;
|
|
30
|
+
access: ProjectAccessEntry[];
|
|
31
|
+
linkedProjects: string[];
|
|
32
|
+
}
|
|
33
|
+
export type ProjectInput = Omit<Project, 'id' | 'healthStatus' | 'healthCheckedAt'> & {
|
|
34
|
+
owner?: string;
|
|
35
|
+
access?: ProjectAccessEntry[];
|
|
36
|
+
linkedProjects?: string[];
|
|
37
|
+
};
|
|
38
|
+
/** Read the full registry. Returns empty array if file doesn't exist. */
|
|
39
|
+
export declare function readRegistry(): Promise<Project[]>;
|
|
40
|
+
/**
|
|
41
|
+
* Add a new project to the registry.
|
|
42
|
+
* @throws Error if a project with the same directory is already registered.
|
|
43
|
+
*/
|
|
44
|
+
export declare function addProject(input: ProjectInput): Promise<Project>;
|
|
45
|
+
/** Get a project by ID. Returns null if not found. */
|
|
46
|
+
export declare function getProject(id: string): Promise<Project | null>;
|
|
47
|
+
/** Find a project by directory path. Returns null if not found. */
|
|
48
|
+
export declare function findByDirectory(directory: string): Promise<Project | null>;
|
|
49
|
+
/** Update a project by ID. Merges only known mutable fields. Returns null if not found. */
|
|
50
|
+
export declare function updateProject(id: string, updates: Partial<Omit<Project, 'id' | 'createdAt' | 'directory'>>): Promise<Project | null>;
|
|
51
|
+
/** Remove a project by ID. Cleans up linked references in other projects. */
|
|
52
|
+
export declare function removeProject(id: string): Promise<boolean>;
|
|
53
|
+
/** Update health status for a project. */
|
|
54
|
+
export declare function updateHealthStatus(id: string, status: HealthStatus): Promise<void>;
|
|
55
|
+
/** LOKI-004: Batch update health status — single read-write cycle for N projects. */
|
|
56
|
+
export declare function batchUpdateHealthStatus(updates: Array<{
|
|
57
|
+
id: string;
|
|
58
|
+
status: HealthStatus;
|
|
59
|
+
}>): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Get projects visible to a user.
|
|
62
|
+
* Admins see all. Others see owned + explicitly shared.
|
|
63
|
+
*/
|
|
64
|
+
export declare function getProjectsForUser(username: string, globalRole: string): Promise<Project[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Check if a user can access a project at the given role level.
|
|
67
|
+
* Returns the effective role or null if no access.
|
|
68
|
+
*/
|
|
69
|
+
export declare function checkProjectAccess(projectId: string, username: string, globalRole: string): Promise<'admin' | 'deployer' | 'viewer' | null>;
|
|
70
|
+
/** Grant access to a project for a user. Overwrites existing entry for that user. */
|
|
71
|
+
export declare function grantAccess(projectId: string, username: string, role: 'deployer' | 'viewer'): Promise<void>;
|
|
72
|
+
/** Revoke access from a project for a user. */
|
|
73
|
+
export declare function revokeAccess(projectId: string, username: string): Promise<void>;
|
|
74
|
+
/** Remove a user from all project access lists and clear ownership (cleanup on user deletion). */
|
|
75
|
+
export declare function removeUserFromAllProjects(username: string): Promise<number>;
|
|
76
|
+
/** Get access list for a project. */
|
|
77
|
+
export declare function getProjectAccess(projectId: string): Promise<{
|
|
78
|
+
owner: string;
|
|
79
|
+
access: ProjectAccessEntry[];
|
|
80
|
+
} | null>;
|
|
81
|
+
/** Link two projects bidirectionally. */
|
|
82
|
+
export declare function linkProjects(projectIdA: string, projectIdB: string): Promise<void>;
|
|
83
|
+
/** Unlink two projects bidirectionally. */
|
|
84
|
+
export declare function unlinkProjects(projectIdA: string, projectIdB: string): Promise<void>;
|
|
85
|
+
/** Get all projects in the linked group (BFS traversal with cycle detection). */
|
|
86
|
+
export declare function getLinkedGroup(projectId: string): Promise<Project[]>;
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Registry — CRUD for ~/.voidforge/projects.json.
|
|
3
|
+
* Zero-dep JSON file storage for multi-project Avengers Tower.
|
|
4
|
+
* File permissions: 0600 (owner read/write only).
|
|
5
|
+
*
|
|
6
|
+
* Follows vault.ts patterns: serialized writes, atomic file ops, homedir().
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, rename, mkdir, open, copyFile, chmod } from 'node:fs/promises';
|
|
9
|
+
import { join, resolve } from 'node:path';
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { homedir } from 'node:os';
|
|
12
|
+
const VOIDFORGE_DIR = join(homedir(), '.voidforge');
|
|
13
|
+
const REGISTRY_PATH = join(VOIDFORGE_DIR, 'projects.json');
|
|
14
|
+
// ── Write serialization (from vault.ts) ────────────
|
|
15
|
+
let writeQueue = Promise.resolve();
|
|
16
|
+
function serialized(fn) {
|
|
17
|
+
const result = writeQueue.then(fn, () => fn());
|
|
18
|
+
writeQueue = result.then(() => { }, () => { });
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
// ── Validation ─────────────────────────────────────
|
|
22
|
+
const VALID_HEALTH_STATUSES = new Set(['healthy', 'degraded', 'down', 'unchecked']);
|
|
23
|
+
function isValidProject(obj) {
|
|
24
|
+
if (typeof obj !== 'object' || obj === null)
|
|
25
|
+
return false;
|
|
26
|
+
const p = obj;
|
|
27
|
+
const valid = (typeof p.id === 'string' &&
|
|
28
|
+
typeof p.name === 'string' &&
|
|
29
|
+
typeof p.directory === 'string' &&
|
|
30
|
+
typeof p.deployTarget === 'string' &&
|
|
31
|
+
typeof p.deployUrl === 'string' &&
|
|
32
|
+
typeof p.sshHost === 'string' &&
|
|
33
|
+
typeof p.framework === 'string' &&
|
|
34
|
+
typeof p.database === 'string' &&
|
|
35
|
+
typeof p.createdAt === 'string' &&
|
|
36
|
+
typeof p.lastBuildPhase === 'number' &&
|
|
37
|
+
typeof p.lastDeployAt === 'string' &&
|
|
38
|
+
typeof p.healthCheckUrl === 'string' &&
|
|
39
|
+
typeof p.monthlyCost === 'number' &&
|
|
40
|
+
typeof p.healthStatus === 'string' &&
|
|
41
|
+
VALID_HEALTH_STATUSES.has(p.healthStatus) &&
|
|
42
|
+
typeof p.healthCheckedAt === 'string');
|
|
43
|
+
if (!valid)
|
|
44
|
+
return false;
|
|
45
|
+
// Migrate legacy projects without owner/access/linkedProjects fields
|
|
46
|
+
if (typeof p.owner !== 'string')
|
|
47
|
+
p.owner = '';
|
|
48
|
+
if (!Array.isArray(p.access))
|
|
49
|
+
p.access = [];
|
|
50
|
+
if (!Array.isArray(p.linkedProjects))
|
|
51
|
+
p.linkedProjects = [];
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
// ── Path normalization ─────────────────────────────
|
|
55
|
+
function normalizePath(dir) {
|
|
56
|
+
return resolve(dir);
|
|
57
|
+
}
|
|
58
|
+
// ── File I/O (atomic writes, following vault.ts) ───
|
|
59
|
+
/** Read the full registry. Returns empty array if file doesn't exist. */
|
|
60
|
+
export async function readRegistry() {
|
|
61
|
+
try {
|
|
62
|
+
const raw = await readFile(REGISTRY_PATH, 'utf-8');
|
|
63
|
+
const parsed = JSON.parse(raw);
|
|
64
|
+
if (!Array.isArray(parsed))
|
|
65
|
+
return [];
|
|
66
|
+
// Validate each entry, filter out invalid ones
|
|
67
|
+
return parsed.filter(isValidProject);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
// File not found is expected — return empty registry
|
|
71
|
+
if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
// JSON parse error or permission denied — throw so callers don't overwrite data
|
|
75
|
+
throw new Error(`Registry corrupted or unreadable: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** Atomic write: backup → temp file → fsync → rename (from vault.ts). */
|
|
79
|
+
async function writeRegistry(projects) {
|
|
80
|
+
await mkdir(VOIDFORGE_DIR, { recursive: true });
|
|
81
|
+
// Backup current file before overwriting (data loss prevention)
|
|
82
|
+
try {
|
|
83
|
+
await copyFile(REGISTRY_PATH, REGISTRY_PATH + '.bak');
|
|
84
|
+
await chmod(REGISTRY_PATH + '.bak', 0o600);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
// ENOENT = no file to back up (expected on first write)
|
|
88
|
+
// Other errors (disk full, permissions) = log but don't block the write
|
|
89
|
+
if (!(err instanceof Error && 'code' in err && err.code === 'ENOENT')) {
|
|
90
|
+
console.error('Registry backup failed:', err instanceof Error ? err.message : 'Unknown error');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const data = JSON.stringify(projects, null, 2);
|
|
94
|
+
const tmpPath = REGISTRY_PATH + '.tmp';
|
|
95
|
+
const fh = await open(tmpPath, 'w', 0o600);
|
|
96
|
+
try {
|
|
97
|
+
await fh.writeFile(data);
|
|
98
|
+
await fh.sync();
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
await fh.close();
|
|
102
|
+
}
|
|
103
|
+
await rename(tmpPath, REGISTRY_PATH);
|
|
104
|
+
}
|
|
105
|
+
// ── Public API (all mutating ops are serialized) ───
|
|
106
|
+
/**
|
|
107
|
+
* Add a new project to the registry.
|
|
108
|
+
* @throws Error if a project with the same directory is already registered.
|
|
109
|
+
*/
|
|
110
|
+
export function addProject(input) {
|
|
111
|
+
return serialized(async () => {
|
|
112
|
+
const projects = await readRegistry();
|
|
113
|
+
const normalized = normalizePath(input.directory);
|
|
114
|
+
const exists = projects.some((p) => normalizePath(p.directory) === normalized);
|
|
115
|
+
if (exists) {
|
|
116
|
+
throw new Error(`Project already registered at ${input.directory}`);
|
|
117
|
+
}
|
|
118
|
+
const project = {
|
|
119
|
+
...input,
|
|
120
|
+
directory: normalized,
|
|
121
|
+
id: randomUUID(),
|
|
122
|
+
healthStatus: 'unchecked',
|
|
123
|
+
healthCheckedAt: '',
|
|
124
|
+
owner: input.owner ?? '',
|
|
125
|
+
access: input.access ?? [],
|
|
126
|
+
linkedProjects: input.linkedProjects ?? [],
|
|
127
|
+
};
|
|
128
|
+
projects.push(project);
|
|
129
|
+
await writeRegistry(projects);
|
|
130
|
+
return project;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Get a project by ID. Returns null if not found. */
|
|
134
|
+
export async function getProject(id) {
|
|
135
|
+
const projects = await readRegistry();
|
|
136
|
+
return projects.find((p) => p.id === id) ?? null;
|
|
137
|
+
}
|
|
138
|
+
/** Find a project by directory path. Returns null if not found. */
|
|
139
|
+
export async function findByDirectory(directory) {
|
|
140
|
+
const projects = await readRegistry();
|
|
141
|
+
const normalized = normalizePath(directory);
|
|
142
|
+
return projects.find((p) => normalizePath(p.directory) === normalized) ?? null;
|
|
143
|
+
}
|
|
144
|
+
/** Mutable fields — prevents callers from injecting arbitrary keys via spread. */
|
|
145
|
+
const MUTABLE_FIELDS = new Set([
|
|
146
|
+
'name', 'deployTarget', 'deployUrl', 'sshHost', 'framework', 'database',
|
|
147
|
+
'lastBuildPhase', 'lastDeployAt', 'healthCheckUrl', 'monthlyCost',
|
|
148
|
+
'healthStatus', 'healthCheckedAt',
|
|
149
|
+
]);
|
|
150
|
+
/** Update a project by ID. Merges only known mutable fields. Returns null if not found. */
|
|
151
|
+
export function updateProject(id, updates) {
|
|
152
|
+
return serialized(async () => {
|
|
153
|
+
const projects = await readRegistry();
|
|
154
|
+
const idx = projects.findIndex((p) => p.id === id);
|
|
155
|
+
if (idx === -1)
|
|
156
|
+
return null;
|
|
157
|
+
// Pick only known mutable fields from updates, validate enum fields
|
|
158
|
+
const safe = {};
|
|
159
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
160
|
+
if (!MUTABLE_FIELDS.has(key))
|
|
161
|
+
continue;
|
|
162
|
+
// Validate healthStatus against allowed values
|
|
163
|
+
if (key === 'healthStatus' && !VALID_HEALTH_STATUSES.has(value))
|
|
164
|
+
continue;
|
|
165
|
+
safe[key] = value;
|
|
166
|
+
}
|
|
167
|
+
projects[idx] = { ...projects[idx], ...safe };
|
|
168
|
+
await writeRegistry(projects);
|
|
169
|
+
return projects[idx];
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/** Remove a project by ID. Cleans up linked references in other projects. */
|
|
173
|
+
export function removeProject(id) {
|
|
174
|
+
return serialized(async () => {
|
|
175
|
+
const projects = await readRegistry();
|
|
176
|
+
const idx = projects.findIndex((p) => p.id === id);
|
|
177
|
+
if (idx === -1)
|
|
178
|
+
return false;
|
|
179
|
+
projects.splice(idx, 1);
|
|
180
|
+
// Clean up linked references in remaining projects
|
|
181
|
+
for (const project of projects) {
|
|
182
|
+
project.linkedProjects = project.linkedProjects.filter((lid) => lid !== id);
|
|
183
|
+
}
|
|
184
|
+
await writeRegistry(projects);
|
|
185
|
+
return true;
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/** Update health status for a project. */
|
|
189
|
+
export function updateHealthStatus(id, status) {
|
|
190
|
+
return serialized(async () => {
|
|
191
|
+
const projects = await readRegistry();
|
|
192
|
+
const idx = projects.findIndex((p) => p.id === id);
|
|
193
|
+
if (idx === -1)
|
|
194
|
+
return;
|
|
195
|
+
projects[idx] = {
|
|
196
|
+
...projects[idx],
|
|
197
|
+
healthStatus: status,
|
|
198
|
+
healthCheckedAt: new Date().toISOString(),
|
|
199
|
+
};
|
|
200
|
+
await writeRegistry(projects);
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/** LOKI-004: Batch update health status — single read-write cycle for N projects. */
|
|
204
|
+
export function batchUpdateHealthStatus(updates) {
|
|
205
|
+
return serialized(async () => {
|
|
206
|
+
const projects = await readRegistry();
|
|
207
|
+
const now = new Date().toISOString();
|
|
208
|
+
for (const { id, status } of updates) {
|
|
209
|
+
const idx = projects.findIndex((p) => p.id === id);
|
|
210
|
+
if (idx === -1)
|
|
211
|
+
continue;
|
|
212
|
+
projects[idx] = { ...projects[idx], healthStatus: status, healthCheckedAt: now };
|
|
213
|
+
}
|
|
214
|
+
await writeRegistry(projects);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
// ── Per-project access control ──────────────────────
|
|
218
|
+
/**
|
|
219
|
+
* Get projects visible to a user.
|
|
220
|
+
* Admins see all. Others see owned + explicitly shared.
|
|
221
|
+
*/
|
|
222
|
+
export async function getProjectsForUser(username, globalRole) {
|
|
223
|
+
const projects = await readRegistry();
|
|
224
|
+
if (globalRole === 'admin')
|
|
225
|
+
return projects;
|
|
226
|
+
return projects.filter((p) => p.owner === username || p.access.some((a) => a.username === username));
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Check if a user can access a project at the given role level.
|
|
230
|
+
* Returns the effective role or null if no access.
|
|
231
|
+
*/
|
|
232
|
+
export async function checkProjectAccess(projectId, username, globalRole) {
|
|
233
|
+
const project = await getProject(projectId);
|
|
234
|
+
if (!project)
|
|
235
|
+
return null;
|
|
236
|
+
// Global admins have full access
|
|
237
|
+
if (globalRole === 'admin')
|
|
238
|
+
return 'admin';
|
|
239
|
+
// Project owner has full access
|
|
240
|
+
if (project.owner === username)
|
|
241
|
+
return 'admin';
|
|
242
|
+
// Check access list
|
|
243
|
+
const entry = project.access.find((a) => a.username === username);
|
|
244
|
+
return entry?.role ?? null;
|
|
245
|
+
}
|
|
246
|
+
/** Grant access to a project for a user. Overwrites existing entry for that user. */
|
|
247
|
+
export function grantAccess(projectId, username, role) {
|
|
248
|
+
return serialized(async () => {
|
|
249
|
+
const projects = await readRegistry();
|
|
250
|
+
const idx = projects.findIndex((p) => p.id === projectId);
|
|
251
|
+
if (idx === -1)
|
|
252
|
+
throw new Error('Project not found');
|
|
253
|
+
const project = projects[idx];
|
|
254
|
+
// Remove existing entry for this user (if any)
|
|
255
|
+
project.access = project.access.filter((a) => a.username !== username);
|
|
256
|
+
project.access.push({ username, role });
|
|
257
|
+
await writeRegistry(projects);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
/** Revoke access from a project for a user. */
|
|
261
|
+
export function revokeAccess(projectId, username) {
|
|
262
|
+
return serialized(async () => {
|
|
263
|
+
const projects = await readRegistry();
|
|
264
|
+
const idx = projects.findIndex((p) => p.id === projectId);
|
|
265
|
+
if (idx === -1)
|
|
266
|
+
throw new Error('Project not found');
|
|
267
|
+
const project = projects[idx];
|
|
268
|
+
const before = project.access.length;
|
|
269
|
+
project.access = project.access.filter((a) => a.username !== username);
|
|
270
|
+
if (project.access.length === before)
|
|
271
|
+
throw new Error('User has no access to revoke');
|
|
272
|
+
await writeRegistry(projects);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/** Remove a user from all project access lists and clear ownership (cleanup on user deletion). */
|
|
276
|
+
export function removeUserFromAllProjects(username) {
|
|
277
|
+
return serialized(async () => {
|
|
278
|
+
const projects = await readRegistry();
|
|
279
|
+
let changedCount = 0;
|
|
280
|
+
for (const project of projects) {
|
|
281
|
+
const before = project.access.length;
|
|
282
|
+
project.access = project.access.filter((a) => a.username !== username);
|
|
283
|
+
if (project.access.length < before)
|
|
284
|
+
changedCount++;
|
|
285
|
+
// Clear ownership to prevent privilege escalation via username reuse
|
|
286
|
+
if (project.owner === username) {
|
|
287
|
+
project.owner = '';
|
|
288
|
+
changedCount++;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (changedCount > 0)
|
|
292
|
+
await writeRegistry(projects);
|
|
293
|
+
return changedCount;
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/** Get access list for a project. */
|
|
297
|
+
export async function getProjectAccess(projectId) {
|
|
298
|
+
const project = await getProject(projectId);
|
|
299
|
+
if (!project)
|
|
300
|
+
return null;
|
|
301
|
+
return { owner: project.owner, access: project.access };
|
|
302
|
+
}
|
|
303
|
+
// ── Linked services ─────────────────────────────────
|
|
304
|
+
/** Link two projects bidirectionally. */
|
|
305
|
+
export function linkProjects(projectIdA, projectIdB) {
|
|
306
|
+
return serialized(async () => {
|
|
307
|
+
if (projectIdA === projectIdB)
|
|
308
|
+
throw new Error('Cannot link a project to itself');
|
|
309
|
+
const projects = await readRegistry();
|
|
310
|
+
const a = projects.find((p) => p.id === projectIdA);
|
|
311
|
+
const b = projects.find((p) => p.id === projectIdB);
|
|
312
|
+
if (!a || !b)
|
|
313
|
+
throw new Error('Project not found');
|
|
314
|
+
if (!a.linkedProjects.includes(projectIdB))
|
|
315
|
+
a.linkedProjects.push(projectIdB);
|
|
316
|
+
if (!b.linkedProjects.includes(projectIdA))
|
|
317
|
+
b.linkedProjects.push(projectIdA);
|
|
318
|
+
await writeRegistry(projects);
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
/** Unlink two projects bidirectionally. */
|
|
322
|
+
export function unlinkProjects(projectIdA, projectIdB) {
|
|
323
|
+
return serialized(async () => {
|
|
324
|
+
const projects = await readRegistry();
|
|
325
|
+
const a = projects.find((p) => p.id === projectIdA);
|
|
326
|
+
const b = projects.find((p) => p.id === projectIdB);
|
|
327
|
+
if (!a || !b)
|
|
328
|
+
throw new Error('Project not found');
|
|
329
|
+
a.linkedProjects = a.linkedProjects.filter((id) => id !== projectIdB);
|
|
330
|
+
b.linkedProjects = b.linkedProjects.filter((id) => id !== projectIdA);
|
|
331
|
+
await writeRegistry(projects);
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/** Get all projects in the linked group (BFS traversal with cycle detection). */
|
|
335
|
+
export async function getLinkedGroup(projectId) {
|
|
336
|
+
const projects = await readRegistry();
|
|
337
|
+
const start = projects.find((p) => p.id === projectId);
|
|
338
|
+
if (!start)
|
|
339
|
+
return [];
|
|
340
|
+
// BFS to resolve transitive links: A→B→C means all three are in the group
|
|
341
|
+
const visited = new Set();
|
|
342
|
+
const queue = [start];
|
|
343
|
+
const group = [];
|
|
344
|
+
while (queue.length > 0) {
|
|
345
|
+
const current = queue.shift();
|
|
346
|
+
if (visited.has(current.id))
|
|
347
|
+
continue;
|
|
348
|
+
visited.add(current.id);
|
|
349
|
+
group.push(current);
|
|
350
|
+
for (const linkedId of current.linkedProjects) {
|
|
351
|
+
if (!visited.has(linkedId)) {
|
|
352
|
+
const linked = projects.find((p) => p.id === linkedId);
|
|
353
|
+
if (linked)
|
|
354
|
+
queue.push(linked);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return group;
|
|
359
|
+
}
|