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,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safety Tier Schema — Budget authorization and spend control.
|
|
3
|
+
*
|
|
4
|
+
* Half-open intervals for budget tiers (§9.17):
|
|
5
|
+
* [0, 2500) cents/day: auto-approve (ongoing spend only — new campaigns need vault password)
|
|
6
|
+
* [2500, 10000) cents/day: agent approval (Dockson + Steris)
|
|
7
|
+
* [10000, 50000) cents/day: human confirmation + TOTP
|
|
8
|
+
* >= 50000 cents/day: hard stop + TOTP + vault password
|
|
9
|
+
*
|
|
10
|
+
* Aggregate auto-approve limit: $100/day across all campaigns (§9.17)
|
|
11
|
+
* Hard stop buffer: platform cap set 10% below VoidForge hard stop (§9.17)
|
|
12
|
+
*
|
|
13
|
+
* Campaign creation rate limits (§9.19.14 + §9.20.3d):
|
|
14
|
+
* Max 5 daemon-initiated campaigns per 24h
|
|
15
|
+
* Max 10 active campaigns per platform
|
|
16
|
+
* Burst detection: >3 within 15 minutes → pause and alert
|
|
17
|
+
*
|
|
18
|
+
* PRD Reference: §9.4, §9.17, §9.19.5, §9.19.14, §9.20.5
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_TIERS = {
|
|
21
|
+
autoApproveBelow: 2500,
|
|
22
|
+
agentApproveBelow: 10000,
|
|
23
|
+
humanConfirmBelow: 50000,
|
|
24
|
+
hardStopAbove: 50000,
|
|
25
|
+
aggregateAutoApproveMax: 10000,
|
|
26
|
+
hardStopBuffer: 0.10,
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Classify a daily budget amount into its safety tier.
|
|
30
|
+
* Also considers aggregate spend across all campaigns.
|
|
31
|
+
*/
|
|
32
|
+
function classifyTier(dailyBudget, aggregateDailySpend, config = DEFAULT_TIERS) {
|
|
33
|
+
// Check if aggregate would push into a higher tier
|
|
34
|
+
const newAggregate = (aggregateDailySpend + dailyBudget);
|
|
35
|
+
if (dailyBudget >= config.hardStopAbove) {
|
|
36
|
+
return {
|
|
37
|
+
tier: 'hard_stop',
|
|
38
|
+
requiresVaultPassword: true,
|
|
39
|
+
requiresTotp: true,
|
|
40
|
+
reason: `Daily budget $${dailyBudget / 100} exceeds hard stop ($${config.hardStopAbove / 100}/day)`,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (dailyBudget >= config.humanConfirmBelow || newAggregate >= config.humanConfirmBelow) {
|
|
44
|
+
return {
|
|
45
|
+
tier: 'human_confirm',
|
|
46
|
+
requiresVaultPassword: true,
|
|
47
|
+
requiresTotp: true,
|
|
48
|
+
reason: dailyBudget >= config.humanConfirmBelow
|
|
49
|
+
? `Daily budget $${dailyBudget / 100} requires human confirmation`
|
|
50
|
+
: `Aggregate $${newAggregate / 100}/day pushes into human confirmation tier`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (dailyBudget >= config.agentApproveBelow || newAggregate >= config.agentApproveBelow) {
|
|
54
|
+
return {
|
|
55
|
+
tier: 'agent_approve',
|
|
56
|
+
requiresVaultPassword: true,
|
|
57
|
+
requiresTotp: false,
|
|
58
|
+
reason: dailyBudget >= config.agentApproveBelow
|
|
59
|
+
? `Daily budget $${dailyBudget / 100} requires agent approval (Dockson + Steris)`
|
|
60
|
+
: `Aggregate $${newAggregate / 100}/day pushes into agent approval tier`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// Auto-approve tier — but check aggregate cap
|
|
64
|
+
if (newAggregate > config.aggregateAutoApproveMax) {
|
|
65
|
+
return {
|
|
66
|
+
tier: 'agent_approve',
|
|
67
|
+
requiresVaultPassword: true,
|
|
68
|
+
requiresTotp: false,
|
|
69
|
+
reason: `Individual budget $${dailyBudget / 100} is auto-approve, but aggregate $${newAggregate / 100}/day exceeds $${config.aggregateAutoApproveMax / 100} cap`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
tier: 'auto_approve',
|
|
74
|
+
requiresVaultPassword: false, // For ONGOING spend. New campaign creation always needs vault password.
|
|
75
|
+
requiresTotp: false,
|
|
76
|
+
reason: `Daily budget $${dailyBudget / 100} within auto-approve tier`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Calculate the platform-level daily cap (10% below VoidForge hard stop).
|
|
81
|
+
* This is set on the ad platform side so the platform enforces the cap
|
|
82
|
+
* even if VoidForge crashes.
|
|
83
|
+
*/
|
|
84
|
+
function platformDailyCap(config = DEFAULT_TIERS) {
|
|
85
|
+
return Math.floor(config.hardStopAbove * (1 - config.hardStopBuffer));
|
|
86
|
+
}
|
|
87
|
+
const DEFAULT_RATE_LIMITS = {
|
|
88
|
+
maxPerDay: 5,
|
|
89
|
+
maxActivePerPlatform: 10,
|
|
90
|
+
burstThreshold: 3,
|
|
91
|
+
burstWindowMs: 15 * 60 * 1000,
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Check if a campaign creation is allowed by rate limits.
|
|
95
|
+
* Only applies to daemon-initiated creation (Tier 1/3).
|
|
96
|
+
* Human-triggered /grow Phase 4 is exempt (§9.20.3d).
|
|
97
|
+
*/
|
|
98
|
+
function checkCreationRateLimit(state, platform, isDaemonInitiated, config = DEFAULT_RATE_LIMITS) {
|
|
99
|
+
// Human-triggered is exempt from per-day limit
|
|
100
|
+
if (!isDaemonInitiated) {
|
|
101
|
+
// Still check per-platform active limit and burst detection
|
|
102
|
+
if ((state.activeCampaignsByPlatform[platform] ?? 0) >= config.maxActivePerPlatform) {
|
|
103
|
+
return { allowed: false, reason: `Maximum ${config.maxActivePerPlatform} active campaigns on ${platform}` };
|
|
104
|
+
}
|
|
105
|
+
// Burst detection applies to all sources
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
const recentCount = state.creationTimestamps.filter(t => now - t < config.burstWindowMs).length;
|
|
108
|
+
if (recentCount >= config.burstThreshold) {
|
|
109
|
+
return { allowed: false, reason: `Burst detected: ${recentCount} campaigns in ${config.burstWindowMs / 60000} minutes`, burst: true };
|
|
110
|
+
}
|
|
111
|
+
return { allowed: true };
|
|
112
|
+
}
|
|
113
|
+
// Daemon-initiated — full rate limit check
|
|
114
|
+
if (state.creationsToday >= config.maxPerDay) {
|
|
115
|
+
return { allowed: false, reason: `Maximum ${config.maxPerDay} daemon-initiated campaigns per 24 hours` };
|
|
116
|
+
}
|
|
117
|
+
if ((state.activeCampaignsByPlatform[platform] ?? 0) >= config.maxActivePerPlatform) {
|
|
118
|
+
return { allowed: false, reason: `Maximum ${config.maxActivePerPlatform} active campaigns on ${platform}` };
|
|
119
|
+
}
|
|
120
|
+
const now = Date.now();
|
|
121
|
+
const recentCount = state.creationTimestamps.filter(t => now - t < config.burstWindowMs).length;
|
|
122
|
+
if (recentCount >= config.burstThreshold) {
|
|
123
|
+
return { allowed: false, reason: `Burst detected: ${recentCount} campaigns in ${config.burstWindowMs / 60000} minutes`, burst: true };
|
|
124
|
+
}
|
|
125
|
+
return { allowed: true };
|
|
126
|
+
}
|
|
127
|
+
function isAutonomouslyAllowed(action) {
|
|
128
|
+
const allowed = [
|
|
129
|
+
'pause_campaign', 'kill_campaign', 'evaluate_ab_test',
|
|
130
|
+
'rebalance_budget', 'generate_report', 'refresh_token',
|
|
131
|
+
];
|
|
132
|
+
return allowed.includes(action);
|
|
133
|
+
}
|
|
134
|
+
export { DEFAULT_TIERS, DEFAULT_RATE_LIMITS, classifyTier, platformDailyCap, checkCreationRateLimit, isAutonomouslyAllowed };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional Sentry error tracking integration (ADR-024).
|
|
3
|
+
* Generates SDK initialization code when sentry-dsn exists in vault.
|
|
4
|
+
* Framework-aware: Next.js, Express, Django.
|
|
5
|
+
*/
|
|
6
|
+
import type { ProvisionEmitter } from './provisioners/types.js';
|
|
7
|
+
export interface SentryResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
file?: string;
|
|
10
|
+
pkg?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Generate Sentry initialization code if sentry-dsn exists in credentials.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateSentryInit(projectDir: string, framework: string, sentryDsn: string | undefined, emit: ProvisionEmitter): Promise<SentryResult>;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional Sentry error tracking integration (ADR-024).
|
|
3
|
+
* Generates SDK initialization code when sentry-dsn exists in vault.
|
|
4
|
+
* Framework-aware: Next.js, Express, Django.
|
|
5
|
+
*/
|
|
6
|
+
import { writeFile } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { appendEnvSection } from './env-writer.js';
|
|
9
|
+
function generateNodeSentry(framework) {
|
|
10
|
+
if (framework === 'next.js') {
|
|
11
|
+
return {
|
|
12
|
+
filename: 'sentry.client.config.ts',
|
|
13
|
+
pkg: '@sentry/nextjs',
|
|
14
|
+
content: `// Sentry client-side initialization — generated by VoidForge (ADR-024)
|
|
15
|
+
// Install: npm install @sentry/nextjs
|
|
16
|
+
// See: https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
17
|
+
|
|
18
|
+
import * as Sentry from '@sentry/nextjs';
|
|
19
|
+
|
|
20
|
+
Sentry.init({
|
|
21
|
+
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN || process.env.SENTRY_DSN,
|
|
22
|
+
tracesSampleRate: 0.1, // 10% of transactions — increase for debugging, decrease for cost
|
|
23
|
+
environment: process.env.NODE_ENV,
|
|
24
|
+
});
|
|
25
|
+
`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
filename: 'sentry.ts',
|
|
30
|
+
pkg: '@sentry/node',
|
|
31
|
+
content: `// Sentry server-side initialization — generated by VoidForge (ADR-024)
|
|
32
|
+
// Install: npm install @sentry/node
|
|
33
|
+
// Import this file at the top of your entry point (e.g., index.ts)
|
|
34
|
+
|
|
35
|
+
import * as Sentry from '@sentry/node';
|
|
36
|
+
|
|
37
|
+
Sentry.init({
|
|
38
|
+
dsn: process.env.SENTRY_DSN,
|
|
39
|
+
tracesSampleRate: 0.1, // 10% of transactions — increase for debugging, decrease for cost
|
|
40
|
+
environment: process.env.NODE_ENV || 'production',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export { Sentry };
|
|
44
|
+
`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function generatePythonSentry(framework) {
|
|
48
|
+
if (framework === 'django') {
|
|
49
|
+
return {
|
|
50
|
+
filename: 'sentry_config.py',
|
|
51
|
+
pkg: 'sentry-sdk[django]',
|
|
52
|
+
content: `# Sentry Django initialization — generated by VoidForge (ADR-024)
|
|
53
|
+
# Install: pip install sentry-sdk[django]
|
|
54
|
+
# Add to settings.py: import sentry_config # noqa: F401
|
|
55
|
+
|
|
56
|
+
import os
|
|
57
|
+
import sentry_sdk
|
|
58
|
+
from sentry_sdk.integrations.django import DjangoIntegration
|
|
59
|
+
|
|
60
|
+
sentry_sdk.init(
|
|
61
|
+
dsn=os.environ.get("SENTRY_DSN", ""),
|
|
62
|
+
integrations=[DjangoIntegration()],
|
|
63
|
+
traces_sample_rate=0.1, # 10% — increase for debugging, decrease for cost
|
|
64
|
+
environment=os.environ.get("DJANGO_ENV", "production"),
|
|
65
|
+
)
|
|
66
|
+
`,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
filename: 'sentry_config.py',
|
|
71
|
+
pkg: 'sentry-sdk[flask]',
|
|
72
|
+
content: `# Sentry Flask initialization — generated by VoidForge (ADR-024)
|
|
73
|
+
# Install: pip install sentry-sdk[flask]
|
|
74
|
+
# Import at the top of your app: import sentry_config # noqa: F401
|
|
75
|
+
|
|
76
|
+
import os
|
|
77
|
+
import sentry_sdk
|
|
78
|
+
from sentry_sdk.integrations.flask import FlaskIntegration
|
|
79
|
+
|
|
80
|
+
sentry_sdk.init(
|
|
81
|
+
dsn=os.environ.get("SENTRY_DSN", ""),
|
|
82
|
+
integrations=[FlaskIntegration()],
|
|
83
|
+
traces_sample_rate=0.1, # 10% — increase for debugging, decrease for cost
|
|
84
|
+
environment=os.environ.get("FLASK_ENV", "production"),
|
|
85
|
+
)
|
|
86
|
+
`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generate Sentry initialization code if sentry-dsn exists in credentials.
|
|
91
|
+
*/
|
|
92
|
+
export async function generateSentryInit(projectDir, framework, sentryDsn, emit) {
|
|
93
|
+
if (!sentryDsn) {
|
|
94
|
+
emit({ step: 'sentry', status: 'skipped', message: 'No Sentry DSN in vault — error tracking skipped. Add sentry-dsn to enable.' });
|
|
95
|
+
return { success: true };
|
|
96
|
+
}
|
|
97
|
+
emit({ step: 'sentry', status: 'started', message: 'Generating Sentry error tracking initialization' });
|
|
98
|
+
const isPython = framework === 'django' || framework === 'flask';
|
|
99
|
+
try {
|
|
100
|
+
const config = isPython
|
|
101
|
+
? generatePythonSentry(framework)
|
|
102
|
+
: generateNodeSentry(framework);
|
|
103
|
+
await writeFile(join(projectDir, config.filename), config.content, 'utf-8');
|
|
104
|
+
// Write SENTRY_DSN to .env so the generated code can read it
|
|
105
|
+
await appendEnvSection(projectDir, [
|
|
106
|
+
`# Sentry error tracking — generated by VoidForge (ADR-024)`,
|
|
107
|
+
`SENTRY_DSN=${sentryDsn}`,
|
|
108
|
+
]);
|
|
109
|
+
emit({ step: 'sentry', status: 'done', message: `Generated ${config.filename} — install: ${isPython ? 'pip' : 'npm'} install ${config.pkg}` });
|
|
110
|
+
return { success: true, file: config.filename, pkg: config.pkg };
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
emit({ step: 'sentry', status: 'error', message: 'Failed to generate Sentry config', detail: err.message });
|
|
114
|
+
return { success: false };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server configuration — port and host state, shared across modules.
|
|
3
|
+
* Extracted from server.ts to break circular import:
|
|
4
|
+
* server.ts → danger-room.ts → dashboard-ws.ts → server.ts
|
|
5
|
+
* Now: server.ts → server-config.ts ← dashboard-ws.ts (no cycle)
|
|
6
|
+
* (Gauntlet Picard DR-02)
|
|
7
|
+
*/
|
|
8
|
+
export declare function setServerPort(port: number): void;
|
|
9
|
+
export declare function setServerHost(host: string): void;
|
|
10
|
+
/** Get the server port for WebSocket origin validation. */
|
|
11
|
+
export declare function getServerPort(): number;
|
|
12
|
+
/** Get the server host for remote-mode WebSocket origin validation. */
|
|
13
|
+
export declare function getServerHost(): string;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server configuration — port and host state, shared across modules.
|
|
3
|
+
* Extracted from server.ts to break circular import:
|
|
4
|
+
* server.ts → danger-room.ts → dashboard-ws.ts → server.ts
|
|
5
|
+
* Now: server.ts → server-config.ts ← dashboard-ws.ts (no cycle)
|
|
6
|
+
* (Gauntlet Picard DR-02)
|
|
7
|
+
*/
|
|
8
|
+
let serverPort = 0;
|
|
9
|
+
let serverHost = '';
|
|
10
|
+
export function setServerPort(port) {
|
|
11
|
+
serverPort = port;
|
|
12
|
+
}
|
|
13
|
+
export function setServerHost(host) {
|
|
14
|
+
serverHost = host;
|
|
15
|
+
}
|
|
16
|
+
/** Get the server port for WebSocket origin validation. */
|
|
17
|
+
export function getServerPort() {
|
|
18
|
+
return serverPort;
|
|
19
|
+
}
|
|
20
|
+
/** Get the server host for remote-mode WebSocket origin validation. */
|
|
21
|
+
export function getServerHost() {
|
|
22
|
+
return serverHost;
|
|
23
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Install — launchd/systemd/Task Scheduler integration (§9.18, §9.19.2).
|
|
3
|
+
*
|
|
4
|
+
* Creates system services for:
|
|
5
|
+
* 1. Heartbeat daemon (com.voidforge.heartbeat)
|
|
6
|
+
* 2. Wizard server (com.voidforge.server) — persistent when Cultivation is installed
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: §9.18 (macOS LaunchAgent), §9.19.2 (two services)
|
|
9
|
+
*/
|
|
10
|
+
export declare function installHeartbeatService(): Promise<{
|
|
11
|
+
method: string;
|
|
12
|
+
path: string;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function installServerService(port?: number): Promise<{
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function uninstallServices(): Promise<void>;
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Install — launchd/systemd/Task Scheduler integration (§9.18, §9.19.2).
|
|
3
|
+
*
|
|
4
|
+
* Creates system services for:
|
|
5
|
+
* 1. Heartbeat daemon (com.voidforge.heartbeat)
|
|
6
|
+
* 2. Wizard server (com.voidforge.server) — persistent when Cultivation is installed
|
|
7
|
+
*
|
|
8
|
+
* PRD Reference: §9.18 (macOS LaunchAgent), §9.19.2 (two services)
|
|
9
|
+
*/
|
|
10
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { homedir, platform } from 'node:os';
|
|
13
|
+
import { execSync } from 'node:child_process';
|
|
14
|
+
const VOIDFORGE_DIR = join(homedir(), '.voidforge');
|
|
15
|
+
// ── macOS LaunchAgent ─────────────────────────────────
|
|
16
|
+
function heartbeatPlist() {
|
|
17
|
+
const nodePath = process.execPath;
|
|
18
|
+
// Assuming the heartbeat entry point is at wizard/lib/heartbeat.js
|
|
19
|
+
// In production, this would be the installed package path
|
|
20
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
21
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
22
|
+
<plist version="1.0">
|
|
23
|
+
<dict>
|
|
24
|
+
<key>Label</key>
|
|
25
|
+
<string>com.voidforge.heartbeat</string>
|
|
26
|
+
<key>ProgramArguments</key>
|
|
27
|
+
<array>
|
|
28
|
+
<string>${nodePath}</string>
|
|
29
|
+
<string>${join(VOIDFORGE_DIR, 'heartbeat-entry.js')}</string>
|
|
30
|
+
</array>
|
|
31
|
+
<key>KeepAlive</key>
|
|
32
|
+
<true/>
|
|
33
|
+
<key>RunAtLoad</key>
|
|
34
|
+
<true/>
|
|
35
|
+
<key>ProcessType</key>
|
|
36
|
+
<string>Background</string>
|
|
37
|
+
<key>ThrottleInterval</key>
|
|
38
|
+
<integer>10</integer>
|
|
39
|
+
<key>StandardOutPath</key>
|
|
40
|
+
<string>${join(VOIDFORGE_DIR, 'heartbeat-launchd.log')}</string>
|
|
41
|
+
<key>StandardErrorPath</key>
|
|
42
|
+
<string>${join(VOIDFORGE_DIR, 'heartbeat-launchd.log')}</string>
|
|
43
|
+
</dict>
|
|
44
|
+
</plist>`;
|
|
45
|
+
}
|
|
46
|
+
function serverPlist(port = 3141) {
|
|
47
|
+
const nodePath = process.execPath;
|
|
48
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
49
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
50
|
+
<plist version="1.0">
|
|
51
|
+
<dict>
|
|
52
|
+
<key>Label</key>
|
|
53
|
+
<string>com.voidforge.server</string>
|
|
54
|
+
<key>ProgramArguments</key>
|
|
55
|
+
<array>
|
|
56
|
+
<string>${nodePath}</string>
|
|
57
|
+
<string>${join(VOIDFORGE_DIR, 'server-entry.js')}</string>
|
|
58
|
+
</array>
|
|
59
|
+
<key>KeepAlive</key>
|
|
60
|
+
<true/>
|
|
61
|
+
<key>RunAtLoad</key>
|
|
62
|
+
<true/>
|
|
63
|
+
<key>ProcessType</key>
|
|
64
|
+
<string>Background</string>
|
|
65
|
+
<key>ThrottleInterval</key>
|
|
66
|
+
<integer>10</integer>
|
|
67
|
+
<key>EnvironmentVariables</key>
|
|
68
|
+
<dict>
|
|
69
|
+
<key>VOIDFORGE_PORT</key>
|
|
70
|
+
<string>${port}</string>
|
|
71
|
+
</dict>
|
|
72
|
+
<key>StandardOutPath</key>
|
|
73
|
+
<string>${join(VOIDFORGE_DIR, 'server-launchd.log')}</string>
|
|
74
|
+
<key>StandardErrorPath</key>
|
|
75
|
+
<string>${join(VOIDFORGE_DIR, 'server-launchd.log')}</string>
|
|
76
|
+
</dict>
|
|
77
|
+
</plist>`;
|
|
78
|
+
}
|
|
79
|
+
// ── Linux systemd ─────────────────────────────────────
|
|
80
|
+
function heartbeatSystemdUnit() {
|
|
81
|
+
return `[Unit]
|
|
82
|
+
Description=VoidForge Heartbeat Daemon
|
|
83
|
+
After=network.target
|
|
84
|
+
|
|
85
|
+
[Service]
|
|
86
|
+
Type=simple
|
|
87
|
+
ExecStart=${process.execPath} ${join(VOIDFORGE_DIR, 'heartbeat-entry.js')}
|
|
88
|
+
Restart=always
|
|
89
|
+
RestartSec=10
|
|
90
|
+
StandardOutput=append:${join(VOIDFORGE_DIR, 'heartbeat-systemd.log')}
|
|
91
|
+
StandardError=append:${join(VOIDFORGE_DIR, 'heartbeat-systemd.log')}
|
|
92
|
+
|
|
93
|
+
[Install]
|
|
94
|
+
WantedBy=default.target`;
|
|
95
|
+
}
|
|
96
|
+
function serverSystemdUnit(port = 3141) {
|
|
97
|
+
return `[Unit]
|
|
98
|
+
Description=VoidForge Server (Danger Room + Cultivation)
|
|
99
|
+
After=network.target
|
|
100
|
+
|
|
101
|
+
[Service]
|
|
102
|
+
Type=simple
|
|
103
|
+
ExecStart=${process.execPath} ${join(VOIDFORGE_DIR, 'server-entry.js')}
|
|
104
|
+
Environment=VOIDFORGE_PORT=${port}
|
|
105
|
+
Restart=always
|
|
106
|
+
RestartSec=10
|
|
107
|
+
StandardOutput=append:${join(VOIDFORGE_DIR, 'server-systemd.log')}
|
|
108
|
+
StandardError=append:${join(VOIDFORGE_DIR, 'server-systemd.log')}
|
|
109
|
+
|
|
110
|
+
[Install]
|
|
111
|
+
WantedBy=default.target`;
|
|
112
|
+
}
|
|
113
|
+
// ── Install Functions ─────────────────────────────────
|
|
114
|
+
export async function installHeartbeatService() {
|
|
115
|
+
if (platform() === 'darwin') {
|
|
116
|
+
const plistDir = join(homedir(), 'Library', 'LaunchAgents');
|
|
117
|
+
const plistPath = join(plistDir, 'com.voidforge.heartbeat.plist');
|
|
118
|
+
await mkdir(plistDir, { recursive: true });
|
|
119
|
+
await writeFile(plistPath, heartbeatPlist());
|
|
120
|
+
execSync(`launchctl load "${plistPath}" 2>/dev/null || true`);
|
|
121
|
+
return { method: 'launchd', path: plistPath };
|
|
122
|
+
}
|
|
123
|
+
if (platform() === 'linux') {
|
|
124
|
+
const unitDir = join(homedir(), '.config', 'systemd', 'user');
|
|
125
|
+
const unitPath = join(unitDir, 'voidforge-heartbeat.service');
|
|
126
|
+
await mkdir(unitDir, { recursive: true });
|
|
127
|
+
await writeFile(unitPath, heartbeatSystemdUnit());
|
|
128
|
+
execSync('systemctl --user daemon-reload 2>/dev/null || true');
|
|
129
|
+
execSync('systemctl --user enable voidforge-heartbeat 2>/dev/null || true');
|
|
130
|
+
return { method: 'systemd', path: unitPath };
|
|
131
|
+
}
|
|
132
|
+
// Windows: Task Scheduler (recommend WSL2 for full support per §9.17)
|
|
133
|
+
return { method: 'manual', path: 'Windows: use WSL2 or run `voidforge heartbeat start --daemon` manually' };
|
|
134
|
+
}
|
|
135
|
+
export async function installServerService(port = 3141) {
|
|
136
|
+
if (platform() === 'darwin') {
|
|
137
|
+
const plistDir = join(homedir(), 'Library', 'LaunchAgents');
|
|
138
|
+
const plistPath = join(plistDir, 'com.voidforge.server.plist');
|
|
139
|
+
await mkdir(plistDir, { recursive: true });
|
|
140
|
+
await writeFile(plistPath, serverPlist(port));
|
|
141
|
+
execSync(`launchctl load "${plistPath}" 2>/dev/null || true`);
|
|
142
|
+
return { method: 'launchd', path: plistPath };
|
|
143
|
+
}
|
|
144
|
+
if (platform() === 'linux') {
|
|
145
|
+
const unitDir = join(homedir(), '.config', 'systemd', 'user');
|
|
146
|
+
const unitPath = join(unitDir, 'voidforge-server.service');
|
|
147
|
+
await mkdir(unitDir, { recursive: true });
|
|
148
|
+
await writeFile(unitPath, serverSystemdUnit(port));
|
|
149
|
+
execSync('systemctl --user daemon-reload 2>/dev/null || true');
|
|
150
|
+
execSync('systemctl --user enable voidforge-server 2>/dev/null || true');
|
|
151
|
+
return { method: 'systemd', path: unitPath };
|
|
152
|
+
}
|
|
153
|
+
return { method: 'manual', path: 'Windows: use WSL2 or run the wizard server manually' };
|
|
154
|
+
}
|
|
155
|
+
export async function uninstallServices() {
|
|
156
|
+
if (platform() === 'darwin') {
|
|
157
|
+
const agents = ['com.voidforge.heartbeat', 'com.voidforge.server'];
|
|
158
|
+
for (const label of agents) {
|
|
159
|
+
const path = join(homedir(), 'Library', 'LaunchAgents', `${label}.plist`);
|
|
160
|
+
try {
|
|
161
|
+
execSync(`launchctl unload "${path}" 2>/dev/null`);
|
|
162
|
+
const { unlink } = await import('node:fs/promises');
|
|
163
|
+
await unlink(path);
|
|
164
|
+
}
|
|
165
|
+
catch { /* not installed */ }
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (platform() === 'linux') {
|
|
169
|
+
const units = ['voidforge-heartbeat', 'voidforge-server'];
|
|
170
|
+
for (const unit of units) {
|
|
171
|
+
try {
|
|
172
|
+
execSync(`systemctl --user stop ${unit} 2>/dev/null`);
|
|
173
|
+
execSync(`systemctl --user disable ${unit} 2>/dev/null`);
|
|
174
|
+
const path = join(homedir(), '.config', 'systemd', 'user', `${unit}.service`);
|
|
175
|
+
const { unlink } = await import('node:fs/promises');
|
|
176
|
+
await unlink(path);
|
|
177
|
+
}
|
|
178
|
+
catch { /* not installed */ }
|
|
179
|
+
}
|
|
180
|
+
execSync('systemctl --user daemon-reload 2>/dev/null || true');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Torres's Site Scanner — HTTP-based technical reconnaissance.
|
|
3
|
+
*
|
|
4
|
+
* Scans a deployed site without browser dependencies:
|
|
5
|
+
* - Response times and status codes on main routes
|
|
6
|
+
* - Meta tags (title, description, OG, JSON-LD)
|
|
7
|
+
* - Security headers (HTTPS, HSTS, CSP, CORS, X-Frame-Options)
|
|
8
|
+
* - Cache headers, compression (gzip/brotli)
|
|
9
|
+
* - Analytics detection (GA4, Plausible, PostHog snippets)
|
|
10
|
+
* - Mobile viewport, favicon, sitemap.xml, robots.txt
|
|
11
|
+
* - Growth infrastructure (email capture forms, cookie consent)
|
|
12
|
+
*
|
|
13
|
+
* Zero dependencies — uses node:https only.
|
|
14
|
+
*
|
|
15
|
+
* PRD Reference: ROADMAP v12.0 deliverables (Torres's site scanner)
|
|
16
|
+
*/
|
|
17
|
+
interface SiteScanResult {
|
|
18
|
+
url: string;
|
|
19
|
+
scannedAt: string;
|
|
20
|
+
reachable: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
performance: PerformanceScan;
|
|
23
|
+
seo: SeoScan;
|
|
24
|
+
security: SecurityScan;
|
|
25
|
+
growth: GrowthScan;
|
|
26
|
+
health: HealthScan;
|
|
27
|
+
}
|
|
28
|
+
interface PerformanceScan {
|
|
29
|
+
ttfbMs: number | null;
|
|
30
|
+
totalTimeMs: number | null;
|
|
31
|
+
contentLength: number | null;
|
|
32
|
+
compressed: boolean;
|
|
33
|
+
cacheControl: string | null;
|
|
34
|
+
}
|
|
35
|
+
interface SeoScan {
|
|
36
|
+
title: string | null;
|
|
37
|
+
description: string | null;
|
|
38
|
+
ogTitle: string | null;
|
|
39
|
+
ogDescription: string | null;
|
|
40
|
+
ogImage: string | null;
|
|
41
|
+
canonicalUrl: string | null;
|
|
42
|
+
viewport: boolean;
|
|
43
|
+
favicon: boolean;
|
|
44
|
+
jsonLd: boolean;
|
|
45
|
+
sitemapExists: boolean;
|
|
46
|
+
robotsExists: boolean;
|
|
47
|
+
h1Count: number;
|
|
48
|
+
}
|
|
49
|
+
interface SecurityScan {
|
|
50
|
+
https: boolean;
|
|
51
|
+
hsts: boolean;
|
|
52
|
+
csp: string | null;
|
|
53
|
+
xFrameOptions: string | null;
|
|
54
|
+
xContentTypeOptions: boolean;
|
|
55
|
+
referrerPolicy: string | null;
|
|
56
|
+
corsAllowOrigin: string | null;
|
|
57
|
+
}
|
|
58
|
+
interface GrowthScan {
|
|
59
|
+
analyticsDetected: string[];
|
|
60
|
+
cookieConsentDetected: boolean;
|
|
61
|
+
emailCaptureDetected: boolean;
|
|
62
|
+
socialMetaComplete: boolean;
|
|
63
|
+
}
|
|
64
|
+
interface HealthScan {
|
|
65
|
+
statusCode: number | null;
|
|
66
|
+
redirectChain: string[];
|
|
67
|
+
responseHeaders: Record<string, string>;
|
|
68
|
+
}
|
|
69
|
+
export declare function scanSite(siteUrl: string): Promise<SiteScanResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Score the scan result across the 5 Deep Current dimensions.
|
|
72
|
+
* Returns partial scores for performance, SEO (part of growth), and security.
|
|
73
|
+
*/
|
|
74
|
+
export declare function scoreScan(scan: SiteScanResult): {
|
|
75
|
+
performance: number;
|
|
76
|
+
seoScore: number;
|
|
77
|
+
securityScore: number;
|
|
78
|
+
growthReadiness: number;
|
|
79
|
+
};
|
|
80
|
+
export type { SiteScanResult, PerformanceScan, SeoScan, SecurityScan, GrowthScan, HealthScan };
|