thevoidforge 21.0.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/dist/scripts/vault-read.d.ts +11 -0
- package/dist/scripts/vault-read.js +89 -0
- package/dist/scripts/voidforge.d.ts +20 -0
- package/dist/scripts/voidforge.js +404 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/wizard/api/auth.d.ts +5 -0
- package/dist/wizard/api/auth.js +133 -0
- package/dist/wizard/api/blueprint.d.ts +45 -0
- package/dist/wizard/api/blueprint.js +184 -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 +258 -0
- package/dist/wizard/api/danger-room.d.ts +18 -0
- package/dist/wizard/api/danger-room.js +401 -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 +239 -0
- package/dist/wizard/api/projects.d.ts +6 -0
- package/dist/wizard/api/projects.js +648 -0
- package/dist/wizard/api/provision.d.ts +4 -0
- package/dist/wizard/api/provision.js +535 -0
- package/dist/wizard/api/terminal.d.ts +25 -0
- package/dist/wizard/api/terminal.js +241 -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 +14 -0
- package/dist/wizard/api/war-room.js +45 -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/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 +183 -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 +180 -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 +151 -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 +71 -0
- package/dist/wizard/lib/daemon-aggregator.js +204 -0
- package/dist/wizard/lib/daemon-core.d.ts +6 -0
- package/dist/wizard/lib/daemon-core.js +5 -0
- package/dist/wizard/lib/dashboard-data.d.ts +132 -0
- package/dist/wizard/lib/dashboard-data.js +336 -0
- package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
- package/dist/wizard/lib/dashboard-ws.js +91 -0
- package/dist/wizard/lib/deep-current.d.ts +77 -0
- package/dist/wizard/lib/deep-current.js +234 -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/google-campaign.d.ts +42 -0
- package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
- package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -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-campaign.d.ts +40 -0
- package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -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 +199 -0
- package/dist/wizard/lib/frontmatter.d.ts +30 -0
- package/dist/wizard/lib/frontmatter.js +96 -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.d.ts +15 -0
- package/dist/wizard/lib/heartbeat.js +827 -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 +161 -0
- package/dist/wizard/lib/patterns/financial-transaction.js +132 -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 +193 -0
- package/dist/wizard/lib/project-registry.d.ts +86 -0
- package/dist/wizard/lib/project-registry.js +359 -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-vps.d.ts +6 -0
- package/dist/wizard/lib/provisioners/aws-vps.js +643 -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.d.ts +6 -0
- package/dist/wizard/lib/provisioners/railway.js +413 -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 +231 -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 +276 -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 +126 -0
- package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
- package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
- package/dist/wizard/lib/updater.d.ts +29 -0
- package/dist/wizard/lib/updater.js +190 -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 +5 -0
- package/dist/wizard/router.js +15 -0
- package/dist/wizard/server.d.ts +18 -0
- package/dist/wizard/server.js +436 -0
- package/package.json +59 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLAUDE.md Merge Utility — Safe append of project directives.
|
|
3
|
+
*
|
|
4
|
+
* Merges project-specific directives into VoidForge's CLAUDE.md by
|
|
5
|
+
* appending them under a clearly marked section. Never replaces the
|
|
6
|
+
* methodology content. Idempotent — won't duplicate if run multiple times.
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: RFC-blueprint-path.md
|
|
9
|
+
*/
|
|
10
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
// ── Constants ───────────────────────────────────────
|
|
14
|
+
const MERGE_MARKER = '# PROJECT-SPECIFIC DIRECTIVES';
|
|
15
|
+
// ── Merge Function ──────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Append project directives to CLAUDE.md.
|
|
18
|
+
*
|
|
19
|
+
* Rules:
|
|
20
|
+
* - VoidForge's CLAUDE.md content is NEVER replaced
|
|
21
|
+
* - Project directives are appended under a clear marker section
|
|
22
|
+
* - Idempotent: if the marker already exists, the merge is skipped
|
|
23
|
+
* - The source directive file path is recorded in the merged section
|
|
24
|
+
*
|
|
25
|
+
* @param projectRoot - The project's root directory
|
|
26
|
+
* @param directivesRelativePath - Relative path to the directives file (e.g., 'docs/PROJECT-DIRECTIVES.md')
|
|
27
|
+
* @returns MergeResult describing what happened
|
|
28
|
+
*/
|
|
29
|
+
export async function mergeProjectDirectives(projectRoot, directivesRelativePath) {
|
|
30
|
+
const claudeMdPath = join(projectRoot, 'CLAUDE.md');
|
|
31
|
+
const directivesPath = join(projectRoot, directivesRelativePath);
|
|
32
|
+
// Validate both files exist
|
|
33
|
+
if (!existsSync(claudeMdPath)) {
|
|
34
|
+
return {
|
|
35
|
+
merged: false,
|
|
36
|
+
reason: 'CLAUDE.md not found in project root',
|
|
37
|
+
claudeMdPath,
|
|
38
|
+
directivesPath: directivesRelativePath,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (!existsSync(directivesPath)) {
|
|
42
|
+
return {
|
|
43
|
+
merged: false,
|
|
44
|
+
reason: `Directives file not found: ${directivesRelativePath}`,
|
|
45
|
+
claudeMdPath,
|
|
46
|
+
directivesPath: directivesRelativePath,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
// Read both files
|
|
50
|
+
const claudeMdContent = await readFile(claudeMdPath, 'utf-8');
|
|
51
|
+
const directivesContent = await readFile(directivesPath, 'utf-8');
|
|
52
|
+
// Idempotency check: already merged?
|
|
53
|
+
if (claudeMdContent.includes(MERGE_MARKER)) {
|
|
54
|
+
return {
|
|
55
|
+
merged: false,
|
|
56
|
+
reason: 'Project directives already merged (marker found)',
|
|
57
|
+
claudeMdPath,
|
|
58
|
+
directivesPath: directivesRelativePath,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Validate directives content is non-empty
|
|
62
|
+
if (directivesContent.trim().length === 0) {
|
|
63
|
+
return {
|
|
64
|
+
merged: false,
|
|
65
|
+
reason: 'Directives file is empty',
|
|
66
|
+
claudeMdPath,
|
|
67
|
+
directivesPath: directivesRelativePath,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// Merge: append directives under the marker
|
|
71
|
+
const merged = `${claudeMdContent.trimEnd()}
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
${MERGE_MARKER}
|
|
76
|
+
|
|
77
|
+
_Loaded from \`${directivesRelativePath}\` by /blueprint_
|
|
78
|
+
|
|
79
|
+
${directivesContent.trimEnd()}
|
|
80
|
+
`;
|
|
81
|
+
await writeFile(claudeMdPath, merged, 'utf-8');
|
|
82
|
+
return {
|
|
83
|
+
merged: true,
|
|
84
|
+
reason: `Project directives appended from ${directivesRelativePath}`,
|
|
85
|
+
claudeMdPath,
|
|
86
|
+
directivesPath: directivesRelativePath,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if project directives have already been merged into CLAUDE.md.
|
|
91
|
+
*/
|
|
92
|
+
export async function isAlreadyMerged(projectRoot) {
|
|
93
|
+
const claudeMdPath = join(projectRoot, 'CLAUDE.md');
|
|
94
|
+
if (!existsSync(claudeMdPath))
|
|
95
|
+
return false;
|
|
96
|
+
const content = await readFile(claudeMdPath, 'utf-8');
|
|
97
|
+
return content.includes(MERGE_MARKER);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Remove previously merged project directives from CLAUDE.md.
|
|
101
|
+
* Useful for re-merging with updated directives.
|
|
102
|
+
*/
|
|
103
|
+
export async function unmergeProjectDirectives(projectRoot) {
|
|
104
|
+
const claudeMdPath = join(projectRoot, 'CLAUDE.md');
|
|
105
|
+
if (!existsSync(claudeMdPath))
|
|
106
|
+
return false;
|
|
107
|
+
const content = await readFile(claudeMdPath, 'utf-8');
|
|
108
|
+
const markerIndex = content.indexOf(`\n---\n\n${MERGE_MARKER}`);
|
|
109
|
+
if (markerIndex === -1)
|
|
110
|
+
return false;
|
|
111
|
+
// Remove everything from the marker onwards
|
|
112
|
+
const cleaned = content.slice(0, markerIndex).trimEnd() + '\n';
|
|
113
|
+
await writeFile(claudeMdPath, cleaned, 'utf-8');
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database ERD generation from Prisma schema (ADR-025).
|
|
3
|
+
* Parses prisma/schema.prisma and produces a Mermaid entity-relationship diagram.
|
|
4
|
+
* Conditional — only runs if prisma/schema.prisma exists.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from '../provisioners/types.js';
|
|
7
|
+
export interface ERDResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
file: string;
|
|
10
|
+
modelCount: number;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate a Mermaid ERD from the Prisma schema.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateERD(projectDir: string, emit: ProvisionEmitter): Promise<ERDResult>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database ERD generation from Prisma schema (ADR-025).
|
|
3
|
+
* Parses prisma/schema.prisma and produces a Mermaid entity-relationship diagram.
|
|
4
|
+
* Conditional — only runs if prisma/schema.prisma exists.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
/**
|
|
10
|
+
* Minimal Prisma schema parser — extracts model names and fields.
|
|
11
|
+
* Not a full parser — handles the common cases for ERD generation.
|
|
12
|
+
*/
|
|
13
|
+
function parsePrismaSchema(content) {
|
|
14
|
+
const models = [];
|
|
15
|
+
const modelRegex = /model\s+(\w+)\s*\{([^}]+)\}/g;
|
|
16
|
+
let match;
|
|
17
|
+
while ((match = modelRegex.exec(content)) !== null) {
|
|
18
|
+
const name = match[1];
|
|
19
|
+
const body = match[2];
|
|
20
|
+
const fields = [];
|
|
21
|
+
for (const line of body.split('\n')) {
|
|
22
|
+
const trimmed = line.trim();
|
|
23
|
+
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('@@'))
|
|
24
|
+
continue;
|
|
25
|
+
const fieldMatch = trimmed.match(/^(\w+)\s+(\w+)(\[\])?\s*(\?)?\s*/);
|
|
26
|
+
if (fieldMatch) {
|
|
27
|
+
const fieldName = fieldMatch[1];
|
|
28
|
+
const fieldType = fieldMatch[2];
|
|
29
|
+
const isArray = !!fieldMatch[3];
|
|
30
|
+
const isOptional = !!fieldMatch[4];
|
|
31
|
+
// Skip Prisma directives like @id, @default, etc. — those are on the same line
|
|
32
|
+
const builtinTypes = ['String', 'Int', 'Float', 'Boolean', 'DateTime', 'Json', 'BigInt', 'Decimal', 'Bytes'];
|
|
33
|
+
const isRelation = !builtinTypes.includes(fieldType);
|
|
34
|
+
fields.push({ name: fieldName, type: fieldType, isRelation, isOptional, isArray });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
models.push({ name, fields });
|
|
38
|
+
}
|
|
39
|
+
return models;
|
|
40
|
+
}
|
|
41
|
+
function generateMermaidERD(models) {
|
|
42
|
+
const lines = [
|
|
43
|
+
'```mermaid',
|
|
44
|
+
'erDiagram',
|
|
45
|
+
];
|
|
46
|
+
// Generate entity definitions
|
|
47
|
+
for (const model of models) {
|
|
48
|
+
lines.push(` ${model.name} {`);
|
|
49
|
+
for (const field of model.fields) {
|
|
50
|
+
if (!field.isRelation) {
|
|
51
|
+
const optional = field.isOptional ? '?' : '';
|
|
52
|
+
lines.push(` ${field.type}${optional} ${field.name}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
lines.push(' }');
|
|
56
|
+
}
|
|
57
|
+
// Generate relationships
|
|
58
|
+
for (const model of models) {
|
|
59
|
+
for (const field of model.fields) {
|
|
60
|
+
if (field.isRelation) {
|
|
61
|
+
const cardinality = field.isArray ? '}o--||' : '}o--o|';
|
|
62
|
+
lines.push(` ${model.name} ${cardinality} ${field.type} : "${field.name}"`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
lines.push('```');
|
|
67
|
+
return lines.join('\n');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generate a Mermaid ERD from the Prisma schema.
|
|
71
|
+
*/
|
|
72
|
+
export async function generateERD(projectDir, emit) {
|
|
73
|
+
const schemaPath = join(projectDir, 'prisma', 'schema.prisma');
|
|
74
|
+
if (!existsSync(schemaPath)) {
|
|
75
|
+
emit({ step: 'erd', status: 'skipped', message: 'No prisma/schema.prisma found — ERD generation skipped' });
|
|
76
|
+
return { success: true, file: '', modelCount: 0 };
|
|
77
|
+
}
|
|
78
|
+
emit({ step: 'erd', status: 'started', message: 'Generating database ERD from Prisma schema' });
|
|
79
|
+
try {
|
|
80
|
+
const schema = await readFile(schemaPath, 'utf-8');
|
|
81
|
+
const models = parsePrismaSchema(schema);
|
|
82
|
+
if (models.length === 0) {
|
|
83
|
+
emit({ step: 'erd', status: 'skipped', message: 'No models found in Prisma schema' });
|
|
84
|
+
return { success: true, file: '', modelCount: 0 };
|
|
85
|
+
}
|
|
86
|
+
const mermaid = generateMermaidERD(models);
|
|
87
|
+
const content = `# Database Schema\n\nAuto-generated from \`prisma/schema.prisma\` by VoidForge (ADR-025).\n\n${mermaid}\n`;
|
|
88
|
+
const docsDir = join(projectDir, 'docs');
|
|
89
|
+
await mkdir(docsDir, { recursive: true });
|
|
90
|
+
await writeFile(join(docsDir, 'schema.md'), content, 'utf-8');
|
|
91
|
+
emit({ step: 'erd', status: 'done', message: `Generated docs/schema.md — ${models.length} models mapped` });
|
|
92
|
+
return { success: true, file: 'docs/schema.md', modelCount: models.length };
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
emit({ step: 'erd', status: 'error', message: 'Failed to generate ERD', detail: err.message });
|
|
96
|
+
return { success: false, file: '', modelCount: 0, error: err.message };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration templates — pre-built client wrappers (ADR-025).
|
|
3
|
+
* Selected via PRD frontmatter (payments: stripe, email: resend).
|
|
4
|
+
* Framework-aware: generates TypeScript or Python.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from '../provisioners/types.js';
|
|
7
|
+
export interface IntegrationResult {
|
|
8
|
+
generated: {
|
|
9
|
+
key: string;
|
|
10
|
+
file: string;
|
|
11
|
+
pkg: string;
|
|
12
|
+
}[];
|
|
13
|
+
skipped: string[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Generate integration templates based on PRD frontmatter flags.
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateIntegrations(projectDir: string, frontmatter: Record<string, string | undefined>, emit: ProvisionEmitter): Promise<IntegrationResult>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration templates — pre-built client wrappers (ADR-025).
|
|
3
|
+
* Selected via PRD frontmatter (payments: stripe, email: resend).
|
|
4
|
+
* Framework-aware: generates TypeScript or Python.
|
|
5
|
+
*/
|
|
6
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
// ── Stripe ──────────────────────────────────────────────
|
|
9
|
+
const STRIPE_TS = `// Stripe integration — generated by VoidForge (ADR-025)
|
|
10
|
+
// Install: npm install stripe
|
|
11
|
+
// Set STRIPE_SECRET_KEY in .env
|
|
12
|
+
|
|
13
|
+
import Stripe from 'stripe';
|
|
14
|
+
|
|
15
|
+
if (!process.env.STRIPE_SECRET_KEY) {
|
|
16
|
+
throw new Error('STRIPE_SECRET_KEY is required');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
|
|
20
|
+
apiVersion: '2024-12-18.acacia',
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/** Create a checkout session for a price. */
|
|
24
|
+
export async function createCheckoutSession(priceId: string, successUrl: string, cancelUrl: string) {
|
|
25
|
+
return stripe.checkout.sessions.create({
|
|
26
|
+
mode: 'subscription',
|
|
27
|
+
payment_method_types: ['card'],
|
|
28
|
+
line_items: [{ price: priceId, quantity: 1 }],
|
|
29
|
+
success_url: successUrl,
|
|
30
|
+
cancel_url: cancelUrl,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Create a customer portal session. */
|
|
35
|
+
export async function createPortalSession(customerId: string, returnUrl: string) {
|
|
36
|
+
return stripe.billingPortal.sessions.create({
|
|
37
|
+
customer: customerId,
|
|
38
|
+
return_url: returnUrl,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Verify a webhook signature. */
|
|
43
|
+
export function verifyWebhook(payload: string | Buffer, signature: string, secret: string): Stripe.Event {
|
|
44
|
+
return stripe.webhooks.constructEvent(payload, signature, secret);
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
// ── Resend ──────────────────────────────────────────────
|
|
48
|
+
const RESEND_TS = `// Resend email integration — generated by VoidForge (ADR-025)
|
|
49
|
+
// Install: npm install resend
|
|
50
|
+
// Set RESEND_API_KEY in .env
|
|
51
|
+
|
|
52
|
+
import { Resend } from 'resend';
|
|
53
|
+
|
|
54
|
+
if (!process.env.RESEND_API_KEY) {
|
|
55
|
+
throw new Error('RESEND_API_KEY is required');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
59
|
+
|
|
60
|
+
interface SendEmailParams {
|
|
61
|
+
to: string | string[];
|
|
62
|
+
subject: string;
|
|
63
|
+
html: string;
|
|
64
|
+
from?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Send a transactional email. */
|
|
68
|
+
export async function sendEmail({ to, subject, html, from }: SendEmailParams) {
|
|
69
|
+
return resend.emails.send({
|
|
70
|
+
from: from || process.env.RESEND_FROM || 'noreply@example.com',
|
|
71
|
+
to: Array.isArray(to) ? to : [to],
|
|
72
|
+
subject,
|
|
73
|
+
html,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Send a welcome email. */
|
|
78
|
+
export async function sendWelcomeEmail(to: string, name: string) {
|
|
79
|
+
return sendEmail({
|
|
80
|
+
to,
|
|
81
|
+
subject: 'Welcome!',
|
|
82
|
+
html: \`<h1>Welcome, \${name}!</h1><p>Thanks for signing up.</p>\`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
// ── S3 File Upload ──────────────────────────────────────
|
|
87
|
+
const S3_TS = `// S3 file upload integration — generated by VoidForge (ADR-025)
|
|
88
|
+
// Install: npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
|
|
89
|
+
// Set AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_UPLOAD_BUCKET in .env
|
|
90
|
+
|
|
91
|
+
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
92
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
93
|
+
|
|
94
|
+
if (!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY) {
|
|
95
|
+
throw new Error('AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required');
|
|
96
|
+
}
|
|
97
|
+
if (!process.env.S3_UPLOAD_BUCKET) {
|
|
98
|
+
throw new Error('S3_UPLOAD_BUCKET is required');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const s3 = new S3Client({
|
|
102
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
103
|
+
credentials: {
|
|
104
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
105
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const BUCKET = process.env.S3_UPLOAD_BUCKET;
|
|
110
|
+
|
|
111
|
+
/** Generate a pre-signed upload URL (client uploads directly to S3). */
|
|
112
|
+
export async function getUploadUrl(key: string, contentType: string, expiresIn = 3600): Promise<string> {
|
|
113
|
+
const command = new PutObjectCommand({
|
|
114
|
+
Bucket: BUCKET,
|
|
115
|
+
Key: key,
|
|
116
|
+
ContentType: contentType,
|
|
117
|
+
});
|
|
118
|
+
return getSignedUrl(s3, command, { expiresIn });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Generate a pre-signed download URL. */
|
|
122
|
+
export async function getDownloadUrl(key: string, expiresIn = 3600): Promise<string> {
|
|
123
|
+
const command = new GetObjectCommand({
|
|
124
|
+
Bucket: BUCKET,
|
|
125
|
+
Key: key,
|
|
126
|
+
});
|
|
127
|
+
return getSignedUrl(s3, command, { expiresIn });
|
|
128
|
+
}
|
|
129
|
+
`;
|
|
130
|
+
const TEMPLATES = [
|
|
131
|
+
{
|
|
132
|
+
key: 'stripe',
|
|
133
|
+
frontmatterField: 'payments',
|
|
134
|
+
frontmatterValue: 'stripe',
|
|
135
|
+
filename: 'lib/stripe.ts',
|
|
136
|
+
content: STRIPE_TS,
|
|
137
|
+
pkg: 'stripe',
|
|
138
|
+
envVars: ['STRIPE_SECRET_KEY', 'STRIPE_WEBHOOK_SECRET'],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
key: 'resend',
|
|
142
|
+
frontmatterField: 'email',
|
|
143
|
+
frontmatterValue: 'resend',
|
|
144
|
+
filename: 'lib/resend.ts',
|
|
145
|
+
content: RESEND_TS,
|
|
146
|
+
pkg: 'resend',
|
|
147
|
+
envVars: ['RESEND_API_KEY', 'RESEND_FROM'],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
key: 's3',
|
|
151
|
+
frontmatterField: 'storage',
|
|
152
|
+
frontmatterValue: 's3',
|
|
153
|
+
filename: 'lib/s3-upload.ts',
|
|
154
|
+
content: S3_TS,
|
|
155
|
+
pkg: '@aws-sdk/client-s3 @aws-sdk/s3-request-presigner',
|
|
156
|
+
envVars: ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_REGION', 'S3_UPLOAD_BUCKET'],
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
/**
|
|
160
|
+
* Generate integration templates based on PRD frontmatter flags.
|
|
161
|
+
*/
|
|
162
|
+
export async function generateIntegrations(projectDir, frontmatter, emit) {
|
|
163
|
+
const generated = [];
|
|
164
|
+
const skipped = [];
|
|
165
|
+
for (const template of TEMPLATES) {
|
|
166
|
+
const value = frontmatter[template.frontmatterField];
|
|
167
|
+
if (value === template.frontmatterValue) {
|
|
168
|
+
emit({ step: `integration-${template.key}`, status: 'started', message: `Generating ${template.key} integration` });
|
|
169
|
+
try {
|
|
170
|
+
const filePath = join(projectDir, template.filename);
|
|
171
|
+
const dir = join(projectDir, template.filename.split('/').slice(0, -1).join('/'));
|
|
172
|
+
await mkdir(dir, { recursive: true });
|
|
173
|
+
await writeFile(filePath, template.content, 'utf-8');
|
|
174
|
+
generated.push({ key: template.key, file: template.filename, pkg: template.pkg });
|
|
175
|
+
emit({ step: `integration-${template.key}`, status: 'done', message: `Generated ${template.filename} — install: npm install ${template.pkg}` });
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
emit({ step: `integration-${template.key}`, status: 'error', message: `Failed to generate ${template.key}`, detail: err.message });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
skipped.push(template.key);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (generated.length === 0) {
|
|
186
|
+
emit({ step: 'integrations', status: 'skipped', message: 'No integration templates requested in PRD frontmatter (payments: stripe, email: resend, storage: s3)' });
|
|
187
|
+
}
|
|
188
|
+
return { generated, skipped };
|
|
189
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI/Swagger spec generation (ADR-025).
|
|
3
|
+
* Generates a starter OpenAPI spec from framework conventions.
|
|
4
|
+
* Framework-aware: Express, Next.js API routes.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from '../provisioners/types.js';
|
|
7
|
+
export interface OpenAPIResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
file: string;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate an OpenAPI spec file for the project.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateOpenAPIDoc(projectDir: string, projectName: string, framework: string, emit: ProvisionEmitter): Promise<OpenAPIResult>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI/Swagger spec generation (ADR-025).
|
|
3
|
+
* Generates a starter OpenAPI spec from framework conventions.
|
|
4
|
+
* Framework-aware: Express, Next.js API routes.
|
|
5
|
+
*/
|
|
6
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
function generateOpenAPISpec(projectName, framework) {
|
|
9
|
+
const isNextjs = framework === 'next.js';
|
|
10
|
+
// Strip YAML-unsafe characters — only allow alphanumeric, spaces, hyphens, underscores
|
|
11
|
+
const safeName = projectName.replace(/[^a-zA-Z0-9 _-]/g, '').slice(0, 100) || 'My Project';
|
|
12
|
+
return `# OpenAPI Specification
|
|
13
|
+
# Generated by VoidForge (ADR-025)
|
|
14
|
+
# Edit this file to document your API endpoints
|
|
15
|
+
# Serve with: npx swagger-ui-express (Express) or next-swagger-doc (Next.js)
|
|
16
|
+
|
|
17
|
+
openapi: "3.1.0"
|
|
18
|
+
info:
|
|
19
|
+
title: "${safeName} API"
|
|
20
|
+
version: "1.0.0"
|
|
21
|
+
description: "API documentation for ${safeName}"
|
|
22
|
+
|
|
23
|
+
servers:
|
|
24
|
+
- url: http://localhost:${isNextjs ? '3000' : '3001'}
|
|
25
|
+
description: Development server
|
|
26
|
+
|
|
27
|
+
paths:
|
|
28
|
+
/api/health:
|
|
29
|
+
get:
|
|
30
|
+
summary: Health check
|
|
31
|
+
responses:
|
|
32
|
+
"200":
|
|
33
|
+
description: Service is healthy
|
|
34
|
+
content:
|
|
35
|
+
application/json:
|
|
36
|
+
schema:
|
|
37
|
+
type: object
|
|
38
|
+
properties:
|
|
39
|
+
status:
|
|
40
|
+
type: string
|
|
41
|
+
example: "ok"
|
|
42
|
+
timestamp:
|
|
43
|
+
type: string
|
|
44
|
+
format: date-time
|
|
45
|
+
|
|
46
|
+
# Add your API endpoints below
|
|
47
|
+
# Example:
|
|
48
|
+
# /api/users:
|
|
49
|
+
# get:
|
|
50
|
+
# summary: List users
|
|
51
|
+
# parameters:
|
|
52
|
+
# - in: query
|
|
53
|
+
# name: page
|
|
54
|
+
# schema:
|
|
55
|
+
# type: integer
|
|
56
|
+
# default: 1
|
|
57
|
+
# responses:
|
|
58
|
+
# "200":
|
|
59
|
+
# description: List of users
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Generate an OpenAPI spec file for the project.
|
|
64
|
+
*/
|
|
65
|
+
export async function generateOpenAPIDoc(projectDir, projectName, framework, emit) {
|
|
66
|
+
emit({ step: 'openapi', status: 'started', message: 'Generating OpenAPI spec' });
|
|
67
|
+
try {
|
|
68
|
+
const docsDir = join(projectDir, 'docs');
|
|
69
|
+
await mkdir(docsDir, { recursive: true });
|
|
70
|
+
const spec = generateOpenAPISpec(projectName, framework);
|
|
71
|
+
await writeFile(join(docsDir, 'api.yaml'), spec, 'utf-8');
|
|
72
|
+
emit({ step: 'openapi', status: 'done', message: 'Generated docs/api.yaml — edit to document your API endpoints' });
|
|
73
|
+
return { success: true, file: 'docs/api.yaml' };
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
emit({ step: 'openapi', status: 'error', message: 'Failed to generate OpenAPI spec', detail: err.message });
|
|
77
|
+
return { success: false, file: '', error: err.message };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type generation from Prisma schema (ADR-025).
|
|
3
|
+
* After Prisma schema changes, runs prisma generate and creates a barrel export.
|
|
4
|
+
* Conditional — only runs if prisma/schema.prisma exists.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from '../provisioners/types.js';
|
|
7
|
+
export interface PrismaTypesResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
files: string[];
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Run prisma generate and create a barrel export for types.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generatePrismaTypes(projectDir: string, emit: ProvisionEmitter): Promise<PrismaTypesResult>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type generation from Prisma schema (ADR-025).
|
|
3
|
+
* After Prisma schema changes, runs prisma generate and creates a barrel export.
|
|
4
|
+
* Conditional — only runs if prisma/schema.prisma exists.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
import { execCommand } from '../exec.js';
|
|
10
|
+
/**
|
|
11
|
+
* Run prisma generate and create a barrel export for types.
|
|
12
|
+
*/
|
|
13
|
+
export async function generatePrismaTypes(projectDir, emit) {
|
|
14
|
+
const schemaPath = join(projectDir, 'prisma', 'schema.prisma');
|
|
15
|
+
if (!existsSync(schemaPath)) {
|
|
16
|
+
emit({ step: 'prisma-types', status: 'skipped', message: 'No prisma/schema.prisma found — type generation skipped' });
|
|
17
|
+
return { success: true, files: [] };
|
|
18
|
+
}
|
|
19
|
+
emit({ step: 'prisma-types', status: 'started', message: 'Generating Prisma types' });
|
|
20
|
+
try {
|
|
21
|
+
// Run prisma generate
|
|
22
|
+
await execCommand('npx', ['prisma', 'generate'], {
|
|
23
|
+
cwd: projectDir,
|
|
24
|
+
timeout: 60_000,
|
|
25
|
+
});
|
|
26
|
+
// Create barrel export
|
|
27
|
+
const typesDir = join(projectDir, 'types');
|
|
28
|
+
await mkdir(typesDir, { recursive: true });
|
|
29
|
+
const barrelContent = `// Auto-generated barrel export for Prisma types
|
|
30
|
+
// Re-run: npx prisma generate
|
|
31
|
+
// Generated by VoidForge (ADR-025)
|
|
32
|
+
|
|
33
|
+
export * from '@prisma/client';
|
|
34
|
+
export type { Prisma } from '@prisma/client';
|
|
35
|
+
`;
|
|
36
|
+
await writeFile(join(typesDir, 'index.ts'), barrelContent, 'utf-8');
|
|
37
|
+
emit({ step: 'prisma-types', status: 'done', message: 'Prisma types generated — import from types/index.ts' });
|
|
38
|
+
return { success: true, files: ['types/index.ts'] };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
emit({ step: 'prisma-types', status: 'error', message: 'Failed to generate Prisma types', detail: err.message });
|
|
42
|
+
return { success: false, files: [], error: err.message };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database seeding script generation (ADR-025).
|
|
3
|
+
* Generates seed.ts with factory functions for all Prisma models.
|
|
4
|
+
* Conditional — only runs if prisma/schema.prisma exists.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from '../provisioners/types.js';
|
|
7
|
+
export interface SeedResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
file: string;
|
|
10
|
+
modelCount: number;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate a database seed script from the Prisma schema.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateSeedScript(projectDir: string, emit: ProvisionEmitter): Promise<SeedResult>;
|