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,128 @@
|
|
|
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 { existsSync } from 'node:fs';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
9
|
+
/** Map Prisma types to TypeScript factory values. */
|
|
10
|
+
const FACTORY_VALUES = {
|
|
11
|
+
'String': "'Test value'",
|
|
12
|
+
'Int': '1',
|
|
13
|
+
'Float': '1.0',
|
|
14
|
+
'Boolean': 'true',
|
|
15
|
+
'DateTime': 'new Date()',
|
|
16
|
+
'Json': '{}',
|
|
17
|
+
'BigInt': 'BigInt(1)',
|
|
18
|
+
'Decimal': '1.0',
|
|
19
|
+
};
|
|
20
|
+
function parseSeedModels(content) {
|
|
21
|
+
const models = [];
|
|
22
|
+
const modelRegex = /model\s+(\w+)\s*\{([^}]+)\}/g;
|
|
23
|
+
let match;
|
|
24
|
+
while ((match = modelRegex.exec(content)) !== null) {
|
|
25
|
+
const name = match[1];
|
|
26
|
+
const body = match[2];
|
|
27
|
+
const fields = [];
|
|
28
|
+
const builtinTypes = ['String', 'Int', 'Float', 'Boolean', 'DateTime', 'Json', 'BigInt', 'Decimal', 'Bytes'];
|
|
29
|
+
for (const line of body.split('\n')) {
|
|
30
|
+
const trimmed = line.trim();
|
|
31
|
+
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('@@'))
|
|
32
|
+
continue;
|
|
33
|
+
const fieldMatch = trimmed.match(/^(\w+)\s+(\w+)(\[\])?\s*(\?)?\s*(.*)/);
|
|
34
|
+
if (fieldMatch) {
|
|
35
|
+
const fieldName = fieldMatch[1];
|
|
36
|
+
const fieldType = fieldMatch[2];
|
|
37
|
+
const isOptional = !!fieldMatch[4];
|
|
38
|
+
const rest = fieldMatch[5] || '';
|
|
39
|
+
const hasDefault = rest.includes('@default');
|
|
40
|
+
const isId = rest.includes('@id');
|
|
41
|
+
const isRelation = !builtinTypes.includes(fieldType);
|
|
42
|
+
if (!isRelation && !fieldMatch[3]) { // Skip arrays (relations)
|
|
43
|
+
fields.push({ name: fieldName, type: fieldType, isOptional, hasDefault, isId, isRelation });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
models.push({ name, fields });
|
|
48
|
+
}
|
|
49
|
+
return models;
|
|
50
|
+
}
|
|
51
|
+
function buildSeedContent(models) {
|
|
52
|
+
const factories = [];
|
|
53
|
+
const seedCalls = [];
|
|
54
|
+
for (const model of models) {
|
|
55
|
+
const lowerName = model.name.charAt(0).toLowerCase() + model.name.slice(1);
|
|
56
|
+
const factoryFields = model.fields
|
|
57
|
+
.filter(f => !f.isId && !f.hasDefault && !f.isOptional)
|
|
58
|
+
.map(f => ` ${f.name}: ${FACTORY_VALUES[f.type] || "'TODO'"},`)
|
|
59
|
+
.join('\n');
|
|
60
|
+
factories.push(`function create${model.name}(overrides: Partial<Prisma.${model.name}CreateInput> = {}): Prisma.${model.name}CreateInput {
|
|
61
|
+
return {
|
|
62
|
+
${factoryFields}
|
|
63
|
+
...overrides,
|
|
64
|
+
};
|
|
65
|
+
}`);
|
|
66
|
+
seedCalls.push(` // ${model.name}
|
|
67
|
+
const ${lowerName} = await prisma.${lowerName}.create({ data: create${model.name}() });
|
|
68
|
+
console.log('Created ${model.name}:', ${lowerName}.id ?? '(no id)');`);
|
|
69
|
+
}
|
|
70
|
+
return `// Database seed script — generated by VoidForge (ADR-025)
|
|
71
|
+
// Run: npx tsx prisma/seed.ts
|
|
72
|
+
// Or: npm run seed (add "seed": "npx tsx prisma/seed.ts" to package.json scripts)
|
|
73
|
+
|
|
74
|
+
import { PrismaClient, Prisma } from '@prisma/client';
|
|
75
|
+
|
|
76
|
+
const prisma = new PrismaClient();
|
|
77
|
+
|
|
78
|
+
// ── Factory Functions ────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
${factories.join('\n\n')}
|
|
81
|
+
|
|
82
|
+
// ── Seed ─────────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
async function seed() {
|
|
85
|
+
console.log('Seeding database...');
|
|
86
|
+
|
|
87
|
+
${seedCalls.join('\n\n')}
|
|
88
|
+
|
|
89
|
+
console.log('Seeding complete.');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
seed()
|
|
93
|
+
.catch((e) => {
|
|
94
|
+
console.error('Seed failed:', e);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
})
|
|
97
|
+
.finally(() => prisma.$disconnect());
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Generate a database seed script from the Prisma schema.
|
|
102
|
+
*/
|
|
103
|
+
export async function generateSeedScript(projectDir, emit) {
|
|
104
|
+
const schemaPath = join(projectDir, 'prisma', 'schema.prisma');
|
|
105
|
+
if (!existsSync(schemaPath)) {
|
|
106
|
+
emit({ step: 'seed', status: 'skipped', message: 'No prisma/schema.prisma found — seed generation skipped' });
|
|
107
|
+
return { success: true, file: '', modelCount: 0 };
|
|
108
|
+
}
|
|
109
|
+
emit({ step: 'seed', status: 'started', message: 'Generating database seed script' });
|
|
110
|
+
try {
|
|
111
|
+
const schema = await readFile(schemaPath, 'utf-8');
|
|
112
|
+
const models = parseSeedModels(schema);
|
|
113
|
+
if (models.length === 0) {
|
|
114
|
+
emit({ step: 'seed', status: 'skipped', message: 'No models found in Prisma schema' });
|
|
115
|
+
return { success: true, file: '', modelCount: 0 };
|
|
116
|
+
}
|
|
117
|
+
const prismaDir = join(projectDir, 'prisma');
|
|
118
|
+
await mkdir(prismaDir, { recursive: true });
|
|
119
|
+
const script = buildSeedContent(models);
|
|
120
|
+
await writeFile(join(prismaDir, 'seed.ts'), script, 'utf-8');
|
|
121
|
+
emit({ step: 'seed', status: 'done', message: `Generated prisma/seed.ts — ${models.length} model factories. Run: npx tsx prisma/seed.ts` });
|
|
122
|
+
return { success: true, file: 'prisma/seed.ts', modelCount: models.length };
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
emit({ step: 'seed', status: 'error', message: 'Failed to generate seed script', detail: err.message });
|
|
126
|
+
return { success: false, file: '', modelCount: 0, error: err.message };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Szeth's Compliance Framework — Campaign compliance checks (§9.12).
|
|
3
|
+
*
|
|
4
|
+
* Every campaign is audited before launch. Critical compliance issues block launch.
|
|
5
|
+
* Covers: privacy (GDPR, cookie consent), email (CAN-SPAM), ad platform ToS,
|
|
6
|
+
* and financial reporting requirements.
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: §9.12 (Compliance Framework), §9.3 Phase 5
|
|
9
|
+
*/
|
|
10
|
+
type AdPlatform = 'meta' | 'google' | 'tiktok' | 'linkedin' | 'twitter' | 'reddit';
|
|
11
|
+
type ComplianceSeverity = 'critical' | 'high' | 'medium' | 'low';
|
|
12
|
+
type ComplianceCategory = 'privacy' | 'email' | 'platform_tos' | 'financial';
|
|
13
|
+
interface ComplianceFinding {
|
|
14
|
+
id: string;
|
|
15
|
+
category: ComplianceCategory;
|
|
16
|
+
severity: ComplianceSeverity;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
remediation: string;
|
|
20
|
+
platform?: AdPlatform;
|
|
21
|
+
blocking: boolean;
|
|
22
|
+
}
|
|
23
|
+
interface ComplianceReport {
|
|
24
|
+
projectId: string;
|
|
25
|
+
timestamp: string;
|
|
26
|
+
findings: ComplianceFinding[];
|
|
27
|
+
passed: boolean;
|
|
28
|
+
summary: {
|
|
29
|
+
critical: number;
|
|
30
|
+
high: number;
|
|
31
|
+
medium: number;
|
|
32
|
+
low: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
interface CreativeContent {
|
|
36
|
+
headlines: string[];
|
|
37
|
+
descriptions: string[];
|
|
38
|
+
landingUrl: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function runComplianceAudit(projectId: string, options: {
|
|
41
|
+
hasTracking: boolean;
|
|
42
|
+
targetsEU: boolean;
|
|
43
|
+
hasOutreach: boolean;
|
|
44
|
+
hasUnsubscribe: boolean;
|
|
45
|
+
hasPhysicalAddress: boolean;
|
|
46
|
+
campaigns: Array<{
|
|
47
|
+
platform: AdPlatform;
|
|
48
|
+
creative: CreativeContent;
|
|
49
|
+
}>;
|
|
50
|
+
}): ComplianceReport;
|
|
51
|
+
export type { ComplianceFinding, ComplianceReport, ComplianceSeverity, ComplianceCategory, CreativeContent };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Szeth's Compliance Framework — Campaign compliance checks (§9.12).
|
|
3
|
+
*
|
|
4
|
+
* Every campaign is audited before launch. Critical compliance issues block launch.
|
|
5
|
+
* Covers: privacy (GDPR, cookie consent), email (CAN-SPAM), ad platform ToS,
|
|
6
|
+
* and financial reporting requirements.
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: §9.12 (Compliance Framework), §9.3 Phase 5
|
|
9
|
+
*/
|
|
10
|
+
// ── Privacy Checks (GDPR) ─────────────────────────────
|
|
11
|
+
function checkPrivacy(hasTracking, targetsEU) {
|
|
12
|
+
const findings = [];
|
|
13
|
+
if (hasTracking && targetsEU) {
|
|
14
|
+
findings.push({
|
|
15
|
+
id: 'PRIV-001',
|
|
16
|
+
category: 'privacy',
|
|
17
|
+
severity: 'critical',
|
|
18
|
+
title: 'Cookie consent required',
|
|
19
|
+
description: 'Growth tracking (GA/Meta Pixel) targets EU users but no cookie consent banner detected.',
|
|
20
|
+
remediation: 'Generate a cookie consent banner with essential-only default, granular opt-in per tracking type.',
|
|
21
|
+
blocking: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return findings;
|
|
25
|
+
}
|
|
26
|
+
// ── Email Checks (CAN-SPAM) ──────────────────────────
|
|
27
|
+
function checkEmail(hasOutreach, hasUnsubscribe, hasPhysicalAddress) {
|
|
28
|
+
const findings = [];
|
|
29
|
+
if (hasOutreach && !hasUnsubscribe) {
|
|
30
|
+
findings.push({
|
|
31
|
+
id: 'EMAIL-001',
|
|
32
|
+
category: 'email',
|
|
33
|
+
severity: 'critical',
|
|
34
|
+
title: 'Unsubscribe mechanism required',
|
|
35
|
+
description: 'Email outreach planned but no unsubscribe link in templates.',
|
|
36
|
+
remediation: 'Add unsubscribe link to every email template. Must be functional within 10 days.',
|
|
37
|
+
blocking: true,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (hasOutreach && !hasPhysicalAddress) {
|
|
41
|
+
findings.push({
|
|
42
|
+
id: 'EMAIL-002',
|
|
43
|
+
category: 'email',
|
|
44
|
+
severity: 'high',
|
|
45
|
+
title: 'Physical address required',
|
|
46
|
+
description: 'CAN-SPAM requires a physical mailing address in every commercial email.',
|
|
47
|
+
remediation: 'Prompt user for business address during /grow Phase 5.',
|
|
48
|
+
blocking: false,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return findings;
|
|
52
|
+
}
|
|
53
|
+
function checkPlatformToS(platform, creative) {
|
|
54
|
+
const findings = [];
|
|
55
|
+
// Meta: no misleading claims, no before/after (health), no personal attributes
|
|
56
|
+
if (platform === 'meta') {
|
|
57
|
+
for (const headline of creative.headlines) {
|
|
58
|
+
if (/you (are|have|suffer|struggle)/i.test(headline)) {
|
|
59
|
+
findings.push({
|
|
60
|
+
id: 'TOS-META-001',
|
|
61
|
+
category: 'platform_tos',
|
|
62
|
+
severity: 'high',
|
|
63
|
+
title: 'Meta: personal attributes in ad copy',
|
|
64
|
+
description: `Headline "${headline}" may violate Meta's personal attributes policy.`,
|
|
65
|
+
remediation: 'Rewrite to avoid direct personal assertions. Use "People who..." instead of "You are..."',
|
|
66
|
+
platform: 'meta',
|
|
67
|
+
blocking: false,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// TikTok: age-gating for certain categories
|
|
73
|
+
if (platform === 'tiktok') {
|
|
74
|
+
// Check would require category classification — flag as a reminder
|
|
75
|
+
findings.push({
|
|
76
|
+
id: 'TOS-TIKTOK-001',
|
|
77
|
+
category: 'platform_tos',
|
|
78
|
+
severity: 'low',
|
|
79
|
+
title: 'TikTok: verify age restrictions',
|
|
80
|
+
description: 'TikTok requires age-gating for certain categories. Review targeting settings.',
|
|
81
|
+
remediation: 'Verify campaign targeting includes appropriate age restrictions for the product category.',
|
|
82
|
+
platform: 'tiktok',
|
|
83
|
+
blocking: false,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return findings;
|
|
87
|
+
}
|
|
88
|
+
// ── Main Compliance Audit ─────────────────────────────
|
|
89
|
+
export function runComplianceAudit(projectId, options) {
|
|
90
|
+
const findings = [];
|
|
91
|
+
// Privacy checks
|
|
92
|
+
findings.push(...checkPrivacy(options.hasTracking, options.targetsEU));
|
|
93
|
+
// Email checks
|
|
94
|
+
findings.push(...checkEmail(options.hasOutreach, options.hasUnsubscribe, options.hasPhysicalAddress));
|
|
95
|
+
// Platform ToS checks per campaign
|
|
96
|
+
for (const campaign of options.campaigns) {
|
|
97
|
+
findings.push(...checkPlatformToS(campaign.platform, campaign.creative));
|
|
98
|
+
}
|
|
99
|
+
const summary = {
|
|
100
|
+
critical: findings.filter(f => f.severity === 'critical').length,
|
|
101
|
+
high: findings.filter(f => f.severity === 'high').length,
|
|
102
|
+
medium: findings.filter(f => f.severity === 'medium').length,
|
|
103
|
+
low: findings.filter(f => f.severity === 'low').length,
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
projectId,
|
|
107
|
+
timestamp: new Date().toISOString(),
|
|
108
|
+
findings,
|
|
109
|
+
passed: summary.critical === 0,
|
|
110
|
+
summary,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chakotay's Correlation Engine — connects product changes to metric outcomes (v12.2).
|
|
3
|
+
*
|
|
4
|
+
* Maintains an event log of product changes (campaigns, deploys) and metric
|
|
5
|
+
* observations (traffic, conversions, revenue, performance scores). Computes
|
|
6
|
+
* before/after comparisons to identify which changes drove which outcomes.
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: ROADMAP v12.2, DEEP_CURRENT.md LEARN step
|
|
9
|
+
*/
|
|
10
|
+
import type { CampaignProposal } from './campaign-proposer.js';
|
|
11
|
+
interface ChangeEvent {
|
|
12
|
+
type: 'campaign_complete' | 'deploy' | 'config_change';
|
|
13
|
+
date: string;
|
|
14
|
+
campaign?: string;
|
|
15
|
+
missions?: number;
|
|
16
|
+
dimension?: string;
|
|
17
|
+
description: string;
|
|
18
|
+
}
|
|
19
|
+
interface MetricObservation {
|
|
20
|
+
type: 'metric';
|
|
21
|
+
date: string;
|
|
22
|
+
metric: string;
|
|
23
|
+
value: number;
|
|
24
|
+
source: string;
|
|
25
|
+
}
|
|
26
|
+
interface Correlation {
|
|
27
|
+
type: 'correlation';
|
|
28
|
+
date: string;
|
|
29
|
+
productChange: string;
|
|
30
|
+
metric: string;
|
|
31
|
+
valueBefore: number;
|
|
32
|
+
valueAfter: number;
|
|
33
|
+
delta: string;
|
|
34
|
+
confidence: 'high' | 'medium' | 'low';
|
|
35
|
+
lagDays: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function logCampaignComplete(name: string, missions: number, dimension: string): Promise<void>;
|
|
38
|
+
export declare function logMetric(metric: string, value: number, source: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Detect correlations between recent campaigns and metric changes.
|
|
41
|
+
* Uses before/after comparison with configurable lag windows.
|
|
42
|
+
*/
|
|
43
|
+
export declare function detectCorrelations(lagDays?: number): Promise<Correlation[]>;
|
|
44
|
+
interface PredictionRecord {
|
|
45
|
+
proposalId: string;
|
|
46
|
+
proposalName: string;
|
|
47
|
+
predictedImpact: string;
|
|
48
|
+
actualImpact?: string;
|
|
49
|
+
accuracy?: number;
|
|
50
|
+
recordedAt: string;
|
|
51
|
+
evaluatedAt?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare function recordPrediction(proposal: CampaignProposal): Promise<void>;
|
|
54
|
+
export declare function evaluatePrediction(proposalId: string, actualImpact: string, accuracy: number): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Calculate average prediction accuracy across all evaluated predictions.
|
|
57
|
+
*/
|
|
58
|
+
export declare function getAveragePredictionAccuracy(): Promise<number>;
|
|
59
|
+
export type { ChangeEvent, MetricObservation, Correlation, PredictionRecord };
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chakotay's Correlation Engine — connects product changes to metric outcomes (v12.2).
|
|
3
|
+
*
|
|
4
|
+
* Maintains an event log of product changes (campaigns, deploys) and metric
|
|
5
|
+
* observations (traffic, conversions, revenue, performance scores). Computes
|
|
6
|
+
* before/after comparisons to identify which changes drove which outcomes.
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: ROADMAP v12.2, DEEP_CURRENT.md LEARN step
|
|
9
|
+
*/
|
|
10
|
+
import { appendFile, readFile, mkdir } from 'node:fs/promises';
|
|
11
|
+
import { existsSync } from 'node:fs';
|
|
12
|
+
import { CORRELATIONS_PATH, PREDICTIONS_PATH, DEEP_CURRENT_DIR } from './deep-current.js';
|
|
13
|
+
// ── Event Logging ─────────────────────────────────────
|
|
14
|
+
async function appendEvent(entry) {
|
|
15
|
+
await mkdir(DEEP_CURRENT_DIR, { recursive: true });
|
|
16
|
+
await appendFile(CORRELATIONS_PATH, JSON.stringify(entry) + '\n', 'utf-8');
|
|
17
|
+
}
|
|
18
|
+
export async function logCampaignComplete(name, missions, dimension) {
|
|
19
|
+
await appendEvent({
|
|
20
|
+
type: 'campaign_complete',
|
|
21
|
+
date: new Date().toISOString(),
|
|
22
|
+
campaign: name,
|
|
23
|
+
missions,
|
|
24
|
+
dimension,
|
|
25
|
+
description: `Campaign "${name}" completed (${missions} missions, targeting ${dimension})`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export async function logMetric(metric, value, source) {
|
|
29
|
+
await appendEvent({
|
|
30
|
+
type: 'metric',
|
|
31
|
+
date: new Date().toISOString(),
|
|
32
|
+
metric,
|
|
33
|
+
value,
|
|
34
|
+
source,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// ── Correlation Detection ─────────────────────────────
|
|
38
|
+
/**
|
|
39
|
+
* Detect correlations between recent campaigns and metric changes.
|
|
40
|
+
* Uses before/after comparison with configurable lag windows.
|
|
41
|
+
*/
|
|
42
|
+
export async function detectCorrelations(lagDays = 7) {
|
|
43
|
+
if (!existsSync(CORRELATIONS_PATH))
|
|
44
|
+
return [];
|
|
45
|
+
const content = await readFile(CORRELATIONS_PATH, 'utf-8');
|
|
46
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
47
|
+
const events = lines.map(l => { try {
|
|
48
|
+
return JSON.parse(l);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
} }).filter(Boolean);
|
|
53
|
+
const changes = events.filter(e => e.type === 'campaign_complete');
|
|
54
|
+
const metrics = events.filter(e => e.type === 'metric');
|
|
55
|
+
const correlations = [];
|
|
56
|
+
for (const change of changes) {
|
|
57
|
+
const changeDate = new Date(change.date).getTime();
|
|
58
|
+
// Find metrics of the same type before and after the change
|
|
59
|
+
const metricNames = [...new Set(metrics.map(m => m.metric))];
|
|
60
|
+
for (const metricName of metricNames) {
|
|
61
|
+
const metricsOfType = metrics.filter(m => m.metric === metricName);
|
|
62
|
+
// Before: last metric reading before the change
|
|
63
|
+
const before = metricsOfType
|
|
64
|
+
.filter(m => new Date(m.date).getTime() < changeDate)
|
|
65
|
+
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())[0];
|
|
66
|
+
// After: first metric reading lagDays after the change
|
|
67
|
+
const afterCutoff = changeDate + lagDays * 24 * 60 * 60 * 1000;
|
|
68
|
+
const after = metricsOfType
|
|
69
|
+
.filter(m => {
|
|
70
|
+
const t = new Date(m.date).getTime();
|
|
71
|
+
return t > changeDate && t <= afterCutoff;
|
|
72
|
+
})
|
|
73
|
+
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())[0];
|
|
74
|
+
if (before && after && before.value !== after.value) {
|
|
75
|
+
const delta = after.value - before.value;
|
|
76
|
+
const pctChange = before.value !== 0 ? Math.round((delta / before.value) * 100) : 0;
|
|
77
|
+
const significance = Math.abs(pctChange);
|
|
78
|
+
// Only record meaningful changes (>5%)
|
|
79
|
+
if (significance > 5) {
|
|
80
|
+
const correlation = {
|
|
81
|
+
type: 'correlation',
|
|
82
|
+
date: new Date().toISOString(),
|
|
83
|
+
productChange: change.campaign || change.description,
|
|
84
|
+
metric: metricName,
|
|
85
|
+
valueBefore: before.value,
|
|
86
|
+
valueAfter: after.value,
|
|
87
|
+
delta: `${delta > 0 ? '+' : ''}${pctChange}%`,
|
|
88
|
+
confidence: significance > 30 ? 'high' : significance > 15 ? 'medium' : 'low',
|
|
89
|
+
lagDays,
|
|
90
|
+
};
|
|
91
|
+
correlations.push(correlation);
|
|
92
|
+
await appendEvent(correlation); // Record the correlation in the log
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return correlations;
|
|
98
|
+
}
|
|
99
|
+
export async function recordPrediction(proposal) {
|
|
100
|
+
await mkdir(DEEP_CURRENT_DIR, { recursive: true });
|
|
101
|
+
const record = {
|
|
102
|
+
proposalId: proposal.id,
|
|
103
|
+
proposalName: proposal.name,
|
|
104
|
+
predictedImpact: proposal.expectedImpact,
|
|
105
|
+
recordedAt: new Date().toISOString(),
|
|
106
|
+
};
|
|
107
|
+
await appendFile(PREDICTIONS_PATH, JSON.stringify(record) + '\n', 'utf-8');
|
|
108
|
+
}
|
|
109
|
+
export async function evaluatePrediction(proposalId, actualImpact, accuracy) {
|
|
110
|
+
// Read existing predictions, find the matching one, update it
|
|
111
|
+
if (!existsSync(PREDICTIONS_PATH))
|
|
112
|
+
return;
|
|
113
|
+
const content = await readFile(PREDICTIONS_PATH, 'utf-8');
|
|
114
|
+
const lines = content.trim().split('\n').filter(Boolean);
|
|
115
|
+
const updated = lines.map(line => {
|
|
116
|
+
try {
|
|
117
|
+
const record = JSON.parse(line);
|
|
118
|
+
if (record.proposalId === proposalId) {
|
|
119
|
+
record.actualImpact = actualImpact;
|
|
120
|
+
record.accuracy = accuracy;
|
|
121
|
+
record.evaluatedAt = new Date().toISOString();
|
|
122
|
+
}
|
|
123
|
+
return JSON.stringify(record);
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return line;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const { writeFile: wf } = await import('node:fs/promises');
|
|
130
|
+
await wf(PREDICTIONS_PATH, updated.join('\n') + '\n');
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Calculate average prediction accuracy across all evaluated predictions.
|
|
134
|
+
*/
|
|
135
|
+
export async function getAveragePredictionAccuracy() {
|
|
136
|
+
if (!existsSync(PREDICTIONS_PATH))
|
|
137
|
+
return 0;
|
|
138
|
+
const content = await readFile(PREDICTIONS_PATH, 'utf-8');
|
|
139
|
+
const records = content.trim().split('\n').filter(Boolean)
|
|
140
|
+
.map(l => { try {
|
|
141
|
+
return JSON.parse(l);
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return null;
|
|
145
|
+
} })
|
|
146
|
+
.filter(Boolean);
|
|
147
|
+
const evaluated = records.filter(r => r.accuracy !== undefined);
|
|
148
|
+
if (evaluated.length === 0)
|
|
149
|
+
return 0;
|
|
150
|
+
return evaluated.reduce((sum, r) => sum + (r.accuracy || 0), 0) / evaluated.length;
|
|
151
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS cost estimation before provisioning (ADR-022).
|
|
3
|
+
* Rough monthly cost estimate based on instance type, database, and cache.
|
|
4
|
+
* On-demand pricing — no reserved/spot. Informational only.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from './provisioners/types.js';
|
|
7
|
+
export interface CostEstimate {
|
|
8
|
+
total: number;
|
|
9
|
+
breakdown: {
|
|
10
|
+
item: string;
|
|
11
|
+
monthly: number;
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Estimate monthly AWS cost for a provisioning request.
|
|
16
|
+
* Returns null for non-AWS targets.
|
|
17
|
+
*/
|
|
18
|
+
export declare function estimateCost(deployTarget: string, instanceType: string, database: string, cache: string): CostEstimate | null;
|
|
19
|
+
/**
|
|
20
|
+
* Emit a cost estimation SSE event before provisioning.
|
|
21
|
+
*/
|
|
22
|
+
export declare function emitCostEstimate(deployTarget: string, instanceType: string, database: string, cache: string, emit: ProvisionEmitter): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS cost estimation before provisioning (ADR-022).
|
|
3
|
+
* Rough monthly cost estimate based on instance type, database, and cache.
|
|
4
|
+
* On-demand pricing — no reserved/spot. Informational only.
|
|
5
|
+
*/
|
|
6
|
+
/** Monthly on-demand pricing (us-east-1, USD). Approximate as of 2025. */
|
|
7
|
+
const EC2_MONTHLY = {
|
|
8
|
+
't3.micro': 8.50,
|
|
9
|
+
't3.small': 17.00,
|
|
10
|
+
't3.medium': 34.00,
|
|
11
|
+
't3.large': 67.00,
|
|
12
|
+
};
|
|
13
|
+
const RDS_MONTHLY = {
|
|
14
|
+
'db.t3.micro': 13.00,
|
|
15
|
+
'db.t3.small': 26.00,
|
|
16
|
+
'db.t3.medium': 52.00,
|
|
17
|
+
'db.t3.large': 104.00,
|
|
18
|
+
};
|
|
19
|
+
const CACHE_MONTHLY = {
|
|
20
|
+
'cache.t3.micro': 12.00,
|
|
21
|
+
'cache.t3.small': 24.00,
|
|
22
|
+
'cache.t3.medium': 48.00,
|
|
23
|
+
'cache.t3.large': 96.00,
|
|
24
|
+
};
|
|
25
|
+
/** S3 static hosting — rough estimate for a small site. */
|
|
26
|
+
const S3_MONTHLY_BASE = 1.00;
|
|
27
|
+
/**
|
|
28
|
+
* Estimate monthly AWS cost for a provisioning request.
|
|
29
|
+
* Returns null for non-AWS targets.
|
|
30
|
+
*/
|
|
31
|
+
export function estimateCost(deployTarget, instanceType, database, cache) {
|
|
32
|
+
if (deployTarget === 'vps') {
|
|
33
|
+
const breakdown = [];
|
|
34
|
+
const ec2Cost = EC2_MONTHLY[instanceType] || EC2_MONTHLY['t3.micro'];
|
|
35
|
+
breakdown.push({ item: `EC2 ${instanceType}`, monthly: ec2Cost });
|
|
36
|
+
if (database === 'postgres' || database === 'mysql') {
|
|
37
|
+
const rdsClass = `db.${instanceType}`;
|
|
38
|
+
const rdsCost = RDS_MONTHLY[rdsClass] || RDS_MONTHLY['db.t3.micro'];
|
|
39
|
+
breakdown.push({ item: `RDS ${rdsClass} (${database})`, monthly: rdsCost });
|
|
40
|
+
}
|
|
41
|
+
if (cache === 'redis') {
|
|
42
|
+
const cacheType = `cache.${instanceType}`;
|
|
43
|
+
const cacheCost = CACHE_MONTHLY[cacheType] || CACHE_MONTHLY['cache.t3.micro'];
|
|
44
|
+
breakdown.push({ item: `ElastiCache ${cacheType}`, monthly: cacheCost });
|
|
45
|
+
}
|
|
46
|
+
const total = breakdown.reduce((sum, b) => sum + b.monthly, 0);
|
|
47
|
+
return { total, breakdown };
|
|
48
|
+
}
|
|
49
|
+
if (deployTarget === 'static') {
|
|
50
|
+
return {
|
|
51
|
+
total: S3_MONTHLY_BASE,
|
|
52
|
+
breakdown: [{ item: 'S3 static hosting + data transfer', monthly: S3_MONTHLY_BASE }],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Non-AWS targets — no cost estimate
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Emit a cost estimation SSE event before provisioning.
|
|
60
|
+
*/
|
|
61
|
+
export function emitCostEstimate(deployTarget, instanceType, database, cache, emit) {
|
|
62
|
+
const estimate = estimateCost(deployTarget, instanceType, database, cache);
|
|
63
|
+
if (!estimate) {
|
|
64
|
+
if (['vercel', 'railway', 'cloudflare'].includes(deployTarget)) {
|
|
65
|
+
emit({ step: 'cost-estimate', status: 'done', message: `${deployTarget} pricing is usage-based — check their pricing page for details` });
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const lines = estimate.breakdown.map(b => `${b.item}: ~$${b.monthly.toFixed(2)}/mo`);
|
|
70
|
+
const message = `Estimated AWS cost: ~$${estimate.total.toFixed(2)}/month (${lines.join(', ')})`;
|
|
71
|
+
emit({ step: 'cost-estimate', status: 'done', message });
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Tracker — Aggregate monthly costs across projects.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the project registry's existing monthlyCost field.
|
|
5
|
+
* No separate store — data lives where it's already maintained.
|
|
6
|
+
*/
|
|
7
|
+
export interface ProjectCost {
|
|
8
|
+
projectId: string;
|
|
9
|
+
name: string;
|
|
10
|
+
monthlyCost: number;
|
|
11
|
+
deployTarget: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AggregateCosts {
|
|
14
|
+
totalMonthlyCost: number;
|
|
15
|
+
projects: ProjectCost[];
|
|
16
|
+
alertThreshold: number;
|
|
17
|
+
isOverThreshold: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Get aggregate costs for all projects visible to a user.
|
|
21
|
+
* Admins see all projects; others see owned + shared.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getAggregateCosts(username: string, globalRole: string, alertThreshold?: number): Promise<AggregateCosts>;
|
|
24
|
+
/**
|
|
25
|
+
* Update monthly cost for a project (called after deploy or manual update).
|
|
26
|
+
*/
|
|
27
|
+
export declare function setProjectCost(projectId: string, monthlyCost: number): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cost Tracker — Aggregate monthly costs across projects.
|
|
3
|
+
*
|
|
4
|
+
* Reads from the project registry's existing monthlyCost field.
|
|
5
|
+
* No separate store — data lives where it's already maintained.
|
|
6
|
+
*/
|
|
7
|
+
import { getProjectsForUser, updateProject } from './project-registry.js';
|
|
8
|
+
const DEFAULT_ALERT_THRESHOLD = 100; // $100/mo
|
|
9
|
+
/**
|
|
10
|
+
* Get aggregate costs for all projects visible to a user.
|
|
11
|
+
* Admins see all projects; others see owned + shared.
|
|
12
|
+
*/
|
|
13
|
+
export async function getAggregateCosts(username, globalRole, alertThreshold = DEFAULT_ALERT_THRESHOLD) {
|
|
14
|
+
const projects = await getProjectsForUser(username, globalRole);
|
|
15
|
+
const costs = projects.map((p) => ({
|
|
16
|
+
projectId: p.id,
|
|
17
|
+
name: p.name,
|
|
18
|
+
monthlyCost: p.monthlyCost || 0,
|
|
19
|
+
deployTarget: p.deployTarget,
|
|
20
|
+
}));
|
|
21
|
+
const totalMonthlyCost = costs.reduce((sum, c) => sum + c.monthlyCost, 0);
|
|
22
|
+
return {
|
|
23
|
+
totalMonthlyCost,
|
|
24
|
+
projects: costs,
|
|
25
|
+
alertThreshold,
|
|
26
|
+
isOverThreshold: totalMonthlyCost > alertThreshold,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Update monthly cost for a project (called after deploy or manual update).
|
|
31
|
+
*/
|
|
32
|
+
export async function setProjectCost(projectId, monthlyCost) {
|
|
33
|
+
if (!Number.isFinite(monthlyCost) || monthlyCost < 0) {
|
|
34
|
+
throw new Error('monthlyCost must be a non-negative finite number');
|
|
35
|
+
}
|
|
36
|
+
await updateProject(projectId, { monthlyCost });
|
|
37
|
+
}
|