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.
Files changed (328) hide show
  1. package/dist/scripts/vault-read.d.ts +11 -0
  2. package/dist/scripts/vault-read.js +89 -0
  3. package/dist/scripts/voidforge.d.ts +20 -0
  4. package/dist/scripts/voidforge.js +404 -0
  5. package/dist/tsconfig.tsbuildinfo +1 -0
  6. package/dist/wizard/api/auth.d.ts +5 -0
  7. package/dist/wizard/api/auth.js +133 -0
  8. package/dist/wizard/api/blueprint.d.ts +45 -0
  9. package/dist/wizard/api/blueprint.js +184 -0
  10. package/dist/wizard/api/cloud-providers.d.ts +16 -0
  11. package/dist/wizard/api/cloud-providers.js +363 -0
  12. package/dist/wizard/api/credentials.d.ts +1 -0
  13. package/dist/wizard/api/credentials.js +258 -0
  14. package/dist/wizard/api/danger-room.d.ts +18 -0
  15. package/dist/wizard/api/danger-room.js +401 -0
  16. package/dist/wizard/api/deploy.d.ts +4 -0
  17. package/dist/wizard/api/deploy.js +164 -0
  18. package/dist/wizard/api/prd.d.ts +1 -0
  19. package/dist/wizard/api/prd.js +363 -0
  20. package/dist/wizard/api/project.d.ts +1 -0
  21. package/dist/wizard/api/project.js +239 -0
  22. package/dist/wizard/api/projects.d.ts +6 -0
  23. package/dist/wizard/api/projects.js +648 -0
  24. package/dist/wizard/api/provision.d.ts +4 -0
  25. package/dist/wizard/api/provision.js +535 -0
  26. package/dist/wizard/api/terminal.d.ts +25 -0
  27. package/dist/wizard/api/terminal.js +241 -0
  28. package/dist/wizard/api/users.d.ts +6 -0
  29. package/dist/wizard/api/users.js +244 -0
  30. package/dist/wizard/api/war-room.d.ts +14 -0
  31. package/dist/wizard/api/war-room.js +45 -0
  32. package/dist/wizard/lib/ad-platform-core.d.ts +6 -0
  33. package/dist/wizard/lib/ad-platform-core.js +1 -0
  34. package/dist/wizard/lib/adapters/index.d.ts +52 -0
  35. package/dist/wizard/lib/adapters/index.js +38 -0
  36. package/dist/wizard/lib/adapters/sandbox-bank.d.ts +17 -0
  37. package/dist/wizard/lib/adapters/sandbox-bank.js +77 -0
  38. package/dist/wizard/lib/adapters/sandbox.d.ts +39 -0
  39. package/dist/wizard/lib/adapters/sandbox.js +174 -0
  40. package/dist/wizard/lib/adapters/stripe.d.ts +19 -0
  41. package/dist/wizard/lib/adapters/stripe.js +143 -0
  42. package/dist/wizard/lib/adapters/types.d.ts +9 -0
  43. package/dist/wizard/lib/adapters/types.js +10 -0
  44. package/dist/wizard/lib/agent-memory.d.ts +36 -0
  45. package/dist/wizard/lib/agent-memory.js +114 -0
  46. package/dist/wizard/lib/anomaly-detection.d.ts +59 -0
  47. package/dist/wizard/lib/anomaly-detection.js +122 -0
  48. package/dist/wizard/lib/anthropic.d.ts +21 -0
  49. package/dist/wizard/lib/anthropic.js +105 -0
  50. package/dist/wizard/lib/asset-scanner.d.ts +23 -0
  51. package/dist/wizard/lib/asset-scanner.js +107 -0
  52. package/dist/wizard/lib/audit-log.d.ts +23 -0
  53. package/dist/wizard/lib/audit-log.js +70 -0
  54. package/dist/wizard/lib/autonomy-controller.d.ts +76 -0
  55. package/dist/wizard/lib/autonomy-controller.js +183 -0
  56. package/dist/wizard/lib/body-parser.d.ts +2 -0
  57. package/dist/wizard/lib/body-parser.js +36 -0
  58. package/dist/wizard/lib/build-analytics.d.ts +39 -0
  59. package/dist/wizard/lib/build-analytics.js +91 -0
  60. package/dist/wizard/lib/build-step.d.ts +21 -0
  61. package/dist/wizard/lib/build-step.js +104 -0
  62. package/dist/wizard/lib/campaign-proposer.d.ts +39 -0
  63. package/dist/wizard/lib/campaign-proposer.js +180 -0
  64. package/dist/wizard/lib/campaign-state-machine.d.ts +63 -0
  65. package/dist/wizard/lib/campaign-state-machine.js +114 -0
  66. package/dist/wizard/lib/ci-generator.d.ts +14 -0
  67. package/dist/wizard/lib/ci-generator.js +187 -0
  68. package/dist/wizard/lib/claude-merge.d.ts +38 -0
  69. package/dist/wizard/lib/claude-merge.js +115 -0
  70. package/dist/wizard/lib/codegen/erd-gen.d.ts +16 -0
  71. package/dist/wizard/lib/codegen/erd-gen.js +98 -0
  72. package/dist/wizard/lib/codegen/integrations.d.ts +18 -0
  73. package/dist/wizard/lib/codegen/integrations.js +189 -0
  74. package/dist/wizard/lib/codegen/openapi-gen.d.ts +15 -0
  75. package/dist/wizard/lib/codegen/openapi-gen.js +79 -0
  76. package/dist/wizard/lib/codegen/prisma-types.d.ts +15 -0
  77. package/dist/wizard/lib/codegen/prisma-types.js +44 -0
  78. package/dist/wizard/lib/codegen/seed-gen.d.ts +16 -0
  79. package/dist/wizard/lib/codegen/seed-gen.js +128 -0
  80. package/dist/wizard/lib/compliance.d.ts +51 -0
  81. package/dist/wizard/lib/compliance.js +112 -0
  82. package/dist/wizard/lib/correlation-engine.d.ts +59 -0
  83. package/dist/wizard/lib/correlation-engine.js +151 -0
  84. package/dist/wizard/lib/cost-estimator.d.ts +22 -0
  85. package/dist/wizard/lib/cost-estimator.js +72 -0
  86. package/dist/wizard/lib/cost-tracker.d.ts +27 -0
  87. package/dist/wizard/lib/cost-tracker.js +37 -0
  88. package/dist/wizard/lib/daemon-aggregator.d.ts +71 -0
  89. package/dist/wizard/lib/daemon-aggregator.js +204 -0
  90. package/dist/wizard/lib/daemon-core.d.ts +6 -0
  91. package/dist/wizard/lib/daemon-core.js +5 -0
  92. package/dist/wizard/lib/dashboard-data.d.ts +132 -0
  93. package/dist/wizard/lib/dashboard-data.js +336 -0
  94. package/dist/wizard/lib/dashboard-ws.d.ts +25 -0
  95. package/dist/wizard/lib/dashboard-ws.js +91 -0
  96. package/dist/wizard/lib/deep-current.d.ts +77 -0
  97. package/dist/wizard/lib/deep-current.js +234 -0
  98. package/dist/wizard/lib/deploy-coordinator.d.ts +40 -0
  99. package/dist/wizard/lib/deploy-coordinator.js +86 -0
  100. package/dist/wizard/lib/deploy-log.d.ts +28 -0
  101. package/dist/wizard/lib/deploy-log.js +52 -0
  102. package/dist/wizard/lib/desktop-notify.d.ts +27 -0
  103. package/dist/wizard/lib/desktop-notify.js +98 -0
  104. package/dist/wizard/lib/dns/cloudflare-dns.d.ts +35 -0
  105. package/dist/wizard/lib/dns/cloudflare-dns.js +216 -0
  106. package/dist/wizard/lib/dns/cloudflare-registrar.d.ts +31 -0
  107. package/dist/wizard/lib/dns/cloudflare-registrar.js +148 -0
  108. package/dist/wizard/lib/dns/types.d.ts +22 -0
  109. package/dist/wizard/lib/dns/types.js +4 -0
  110. package/dist/wizard/lib/document-discovery.d.ts +33 -0
  111. package/dist/wizard/lib/document-discovery.js +145 -0
  112. package/dist/wizard/lib/env-validator.d.ts +14 -0
  113. package/dist/wizard/lib/env-validator.js +205 -0
  114. package/dist/wizard/lib/env-writer.d.ts +13 -0
  115. package/dist/wizard/lib/env-writer.js +26 -0
  116. package/dist/wizard/lib/exec.d.ts +30 -0
  117. package/dist/wizard/lib/exec.js +52 -0
  118. package/dist/wizard/lib/experiment.d.ts +70 -0
  119. package/dist/wizard/lib/experiment.js +169 -0
  120. package/dist/wizard/lib/extensions.d.ts +20 -0
  121. package/dist/wizard/lib/extensions.js +183 -0
  122. package/dist/wizard/lib/financial/adapter-factory.d.ts +47 -0
  123. package/dist/wizard/lib/financial/adapter-factory.js +225 -0
  124. package/dist/wizard/lib/financial/billing/base.d.ts +6 -0
  125. package/dist/wizard/lib/financial/billing/base.js +1 -0
  126. package/dist/wizard/lib/financial/billing/google-billing.d.ts +56 -0
  127. package/dist/wizard/lib/financial/billing/google-billing.js +298 -0
  128. package/dist/wizard/lib/financial/billing/meta-billing.d.ts +54 -0
  129. package/dist/wizard/lib/financial/billing/meta-billing.js +243 -0
  130. package/dist/wizard/lib/financial/billing/tiktok-billing.d.ts +54 -0
  131. package/dist/wizard/lib/financial/billing/tiktok-billing.js +260 -0
  132. package/dist/wizard/lib/financial/campaign/base.d.ts +13 -0
  133. package/dist/wizard/lib/financial/campaign/base.js +1 -0
  134. package/dist/wizard/lib/financial/campaign/google-campaign.d.ts +42 -0
  135. package/dist/wizard/lib/financial/campaign/google-campaign.js +388 -0
  136. package/dist/wizard/lib/financial/campaign/meta-campaign.d.ts +41 -0
  137. package/dist/wizard/lib/financial/campaign/meta-campaign.js +311 -0
  138. package/dist/wizard/lib/financial/campaign/sandbox-campaign.d.ts +45 -0
  139. package/dist/wizard/lib/financial/campaign/sandbox-campaign.js +261 -0
  140. package/dist/wizard/lib/financial/campaign/tiktok-campaign.d.ts +40 -0
  141. package/dist/wizard/lib/financial/campaign/tiktok-campaign.js +350 -0
  142. package/dist/wizard/lib/financial/funding-auto.d.ts +44 -0
  143. package/dist/wizard/lib/financial/funding-auto.js +52 -0
  144. package/dist/wizard/lib/financial/funding-policy.d.ts +60 -0
  145. package/dist/wizard/lib/financial/funding-policy.js +179 -0
  146. package/dist/wizard/lib/financial/platform-planner.d.ts +47 -0
  147. package/dist/wizard/lib/financial/platform-planner.js +134 -0
  148. package/dist/wizard/lib/financial/reconciliation-engine.d.ts +78 -0
  149. package/dist/wizard/lib/financial/reconciliation-engine.js +193 -0
  150. package/dist/wizard/lib/financial/registry.d.ts +22 -0
  151. package/dist/wizard/lib/financial/registry.js +26 -0
  152. package/dist/wizard/lib/financial/reporting.d.ts +96 -0
  153. package/dist/wizard/lib/financial/reporting.js +198 -0
  154. package/dist/wizard/lib/financial/stablecoin/base.d.ts +6 -0
  155. package/dist/wizard/lib/financial/stablecoin/base.js +1 -0
  156. package/dist/wizard/lib/financial/stablecoin/circle.d.ts +54 -0
  157. package/dist/wizard/lib/financial/stablecoin/circle.js +367 -0
  158. package/dist/wizard/lib/financial/stablecoin/mercury.d.ts +24 -0
  159. package/dist/wizard/lib/financial/stablecoin/mercury.js +171 -0
  160. package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.d.ts +47 -0
  161. package/dist/wizard/lib/financial/stablecoin/sandbox-stablecoin.js +202 -0
  162. package/dist/wizard/lib/financial/treasury-planner.d.ts +52 -0
  163. package/dist/wizard/lib/financial/treasury-planner.js +128 -0
  164. package/dist/wizard/lib/financial-core.d.ts +6 -0
  165. package/dist/wizard/lib/financial-core.js +5 -0
  166. package/dist/wizard/lib/financial-vault.d.ts +34 -0
  167. package/dist/wizard/lib/financial-vault.js +199 -0
  168. package/dist/wizard/lib/frontmatter.d.ts +30 -0
  169. package/dist/wizard/lib/frontmatter.js +96 -0
  170. package/dist/wizard/lib/gap-analysis.d.ts +37 -0
  171. package/dist/wizard/lib/gap-analysis.js +218 -0
  172. package/dist/wizard/lib/github.d.ts +22 -0
  173. package/dist/wizard/lib/github.js +261 -0
  174. package/dist/wizard/lib/headless-deploy.d.ts +14 -0
  175. package/dist/wizard/lib/headless-deploy.js +452 -0
  176. package/dist/wizard/lib/health-monitor.d.ts +15 -0
  177. package/dist/wizard/lib/health-monitor.js +91 -0
  178. package/dist/wizard/lib/health-poller.d.ts +9 -0
  179. package/dist/wizard/lib/health-poller.js +123 -0
  180. package/dist/wizard/lib/heartbeat.d.ts +15 -0
  181. package/dist/wizard/lib/heartbeat.js +827 -0
  182. package/dist/wizard/lib/http-helpers.d.ts +9 -0
  183. package/dist/wizard/lib/http-helpers.js +24 -0
  184. package/dist/wizard/lib/image-gen.d.ts +56 -0
  185. package/dist/wizard/lib/image-gen.js +159 -0
  186. package/dist/wizard/lib/instance-sizing.d.ts +26 -0
  187. package/dist/wizard/lib/instance-sizing.js +51 -0
  188. package/dist/wizard/lib/kongo/analytics.d.ts +29 -0
  189. package/dist/wizard/lib/kongo/analytics.js +179 -0
  190. package/dist/wizard/lib/kongo/campaigns.d.ts +52 -0
  191. package/dist/wizard/lib/kongo/campaigns.js +91 -0
  192. package/dist/wizard/lib/kongo/client.d.ts +58 -0
  193. package/dist/wizard/lib/kongo/client.js +221 -0
  194. package/dist/wizard/lib/kongo/jobs.d.ts +57 -0
  195. package/dist/wizard/lib/kongo/jobs.js +122 -0
  196. package/dist/wizard/lib/kongo/pages.d.ts +60 -0
  197. package/dist/wizard/lib/kongo/pages.js +150 -0
  198. package/dist/wizard/lib/kongo/provisioner.d.ts +64 -0
  199. package/dist/wizard/lib/kongo/provisioner.js +116 -0
  200. package/dist/wizard/lib/kongo/seed.d.ts +49 -0
  201. package/dist/wizard/lib/kongo/seed.js +237 -0
  202. package/dist/wizard/lib/kongo/types.d.ts +323 -0
  203. package/dist/wizard/lib/kongo/types.js +11 -0
  204. package/dist/wizard/lib/kongo/variants.d.ts +57 -0
  205. package/dist/wizard/lib/kongo/variants.js +88 -0
  206. package/dist/wizard/lib/kongo/webhooks.d.ts +41 -0
  207. package/dist/wizard/lib/kongo/webhooks.js +112 -0
  208. package/dist/wizard/lib/marker.d.ts +28 -0
  209. package/dist/wizard/lib/marker.js +79 -0
  210. package/dist/wizard/lib/migrator.d.ts +35 -0
  211. package/dist/wizard/lib/migrator.js +190 -0
  212. package/dist/wizard/lib/natural-language-deploy.d.ts +30 -0
  213. package/dist/wizard/lib/natural-language-deploy.js +186 -0
  214. package/dist/wizard/lib/network.d.ts +22 -0
  215. package/dist/wizard/lib/network.js +72 -0
  216. package/dist/wizard/lib/oauth-core.d.ts +6 -0
  217. package/dist/wizard/lib/oauth-core.js +5 -0
  218. package/dist/wizard/lib/open-browser.d.ts +1 -0
  219. package/dist/wizard/lib/open-browser.js +26 -0
  220. package/dist/wizard/lib/patterns/ad-billing-adapter.d.ts +209 -0
  221. package/dist/wizard/lib/patterns/ad-billing-adapter.js +269 -0
  222. package/dist/wizard/lib/patterns/ad-platform-adapter.d.ts +200 -0
  223. package/dist/wizard/lib/patterns/ad-platform-adapter.js +212 -0
  224. package/dist/wizard/lib/patterns/daemon-process.d.ts +88 -0
  225. package/dist/wizard/lib/patterns/daemon-process.js +271 -0
  226. package/dist/wizard/lib/patterns/financial-transaction.d.ts +161 -0
  227. package/dist/wizard/lib/patterns/financial-transaction.js +132 -0
  228. package/dist/wizard/lib/patterns/funding-plan.d.ts +136 -0
  229. package/dist/wizard/lib/patterns/funding-plan.js +200 -0
  230. package/dist/wizard/lib/patterns/oauth-token-lifecycle.d.ts +94 -0
  231. package/dist/wizard/lib/patterns/oauth-token-lifecycle.js +139 -0
  232. package/dist/wizard/lib/patterns/outbound-rate-limiter.d.ts +67 -0
  233. package/dist/wizard/lib/patterns/outbound-rate-limiter.js +216 -0
  234. package/dist/wizard/lib/patterns/revenue-source-adapter.d.ts +96 -0
  235. package/dist/wizard/lib/patterns/revenue-source-adapter.js +182 -0
  236. package/dist/wizard/lib/patterns/stablecoin-adapter.d.ts +218 -0
  237. package/dist/wizard/lib/patterns/stablecoin-adapter.js +264 -0
  238. package/dist/wizard/lib/prd-validator.d.ts +39 -0
  239. package/dist/wizard/lib/prd-validator.js +137 -0
  240. package/dist/wizard/lib/project-init.d.ts +24 -0
  241. package/dist/wizard/lib/project-init.js +193 -0
  242. package/dist/wizard/lib/project-registry.d.ts +86 -0
  243. package/dist/wizard/lib/project-registry.js +359 -0
  244. package/dist/wizard/lib/provision-manifest.d.ts +44 -0
  245. package/dist/wizard/lib/provision-manifest.js +164 -0
  246. package/dist/wizard/lib/provisioner-registry.d.ts +15 -0
  247. package/dist/wizard/lib/provisioner-registry.js +34 -0
  248. package/dist/wizard/lib/provisioners/aws-vps.d.ts +6 -0
  249. package/dist/wizard/lib/provisioners/aws-vps.js +643 -0
  250. package/dist/wizard/lib/provisioners/cloudflare.d.ts +6 -0
  251. package/dist/wizard/lib/provisioners/cloudflare.js +300 -0
  252. package/dist/wizard/lib/provisioners/docker.d.ts +6 -0
  253. package/dist/wizard/lib/provisioners/docker.js +75 -0
  254. package/dist/wizard/lib/provisioners/http-client.d.ts +20 -0
  255. package/dist/wizard/lib/provisioners/http-client.js +79 -0
  256. package/dist/wizard/lib/provisioners/railway.d.ts +6 -0
  257. package/dist/wizard/lib/provisioners/railway.js +413 -0
  258. package/dist/wizard/lib/provisioners/scripts/caddyfile.d.ts +10 -0
  259. package/dist/wizard/lib/provisioners/scripts/caddyfile.js +54 -0
  260. package/dist/wizard/lib/provisioners/scripts/deploy-vps.d.ts +10 -0
  261. package/dist/wizard/lib/provisioners/scripts/deploy-vps.js +112 -0
  262. package/dist/wizard/lib/provisioners/scripts/docker-compose.d.ts +11 -0
  263. package/dist/wizard/lib/provisioners/scripts/docker-compose.js +91 -0
  264. package/dist/wizard/lib/provisioners/scripts/dockerfile.d.ts +5 -0
  265. package/dist/wizard/lib/provisioners/scripts/dockerfile.js +185 -0
  266. package/dist/wizard/lib/provisioners/scripts/ecosystem-config.d.ts +10 -0
  267. package/dist/wizard/lib/provisioners/scripts/ecosystem-config.js +36 -0
  268. package/dist/wizard/lib/provisioners/scripts/provision-vps.d.ts +14 -0
  269. package/dist/wizard/lib/provisioners/scripts/provision-vps.js +202 -0
  270. package/dist/wizard/lib/provisioners/scripts/rollback-vps.d.ts +10 -0
  271. package/dist/wizard/lib/provisioners/scripts/rollback-vps.js +67 -0
  272. package/dist/wizard/lib/provisioners/self-deploy.d.ts +41 -0
  273. package/dist/wizard/lib/provisioners/self-deploy.js +185 -0
  274. package/dist/wizard/lib/provisioners/static-s3.d.ts +6 -0
  275. package/dist/wizard/lib/provisioners/static-s3.js +235 -0
  276. package/dist/wizard/lib/provisioners/types.d.ts +40 -0
  277. package/dist/wizard/lib/provisioners/types.js +4 -0
  278. package/dist/wizard/lib/provisioners/vercel.d.ts +6 -0
  279. package/dist/wizard/lib/provisioners/vercel.js +287 -0
  280. package/dist/wizard/lib/pty-manager.d.ts +42 -0
  281. package/dist/wizard/lib/pty-manager.js +231 -0
  282. package/dist/wizard/lib/rate-limiter-core.d.ts +5 -0
  283. package/dist/wizard/lib/rate-limiter-core.js +5 -0
  284. package/dist/wizard/lib/reconciliation.d.ts +43 -0
  285. package/dist/wizard/lib/reconciliation.js +173 -0
  286. package/dist/wizard/lib/revenue-types.d.ts +5 -0
  287. package/dist/wizard/lib/revenue-types.js +1 -0
  288. package/dist/wizard/lib/route-optimizer.d.ts +28 -0
  289. package/dist/wizard/lib/route-optimizer.js +93 -0
  290. package/dist/wizard/lib/s3-deploy.d.ts +19 -0
  291. package/dist/wizard/lib/s3-deploy.js +156 -0
  292. package/dist/wizard/lib/safety-tiers.d.ts +76 -0
  293. package/dist/wizard/lib/safety-tiers.js +134 -0
  294. package/dist/wizard/lib/sentry-generator.d.ts +15 -0
  295. package/dist/wizard/lib/sentry-generator.js +116 -0
  296. package/dist/wizard/lib/server-config.d.ts +13 -0
  297. package/dist/wizard/lib/server-config.js +23 -0
  298. package/dist/wizard/lib/service-install.d.ts +18 -0
  299. package/dist/wizard/lib/service-install.js +182 -0
  300. package/dist/wizard/lib/site-scanner.d.ts +80 -0
  301. package/dist/wizard/lib/site-scanner.js +262 -0
  302. package/dist/wizard/lib/ssh-deploy.d.ts +25 -0
  303. package/dist/wizard/lib/ssh-deploy.js +225 -0
  304. package/dist/wizard/lib/templates.d.ts +24 -0
  305. package/dist/wizard/lib/templates.js +219 -0
  306. package/dist/wizard/lib/totp.d.ts +35 -0
  307. package/dist/wizard/lib/totp.js +276 -0
  308. package/dist/wizard/lib/tower-auth.d.ts +43 -0
  309. package/dist/wizard/lib/tower-auth.js +352 -0
  310. package/dist/wizard/lib/tower-rate-limit.d.ts +14 -0
  311. package/dist/wizard/lib/tower-rate-limit.js +61 -0
  312. package/dist/wizard/lib/tower-session.d.ts +28 -0
  313. package/dist/wizard/lib/tower-session.js +119 -0
  314. package/dist/wizard/lib/treasury-backup.d.ts +23 -0
  315. package/dist/wizard/lib/treasury-backup.js +126 -0
  316. package/dist/wizard/lib/treasury-heartbeat.d.ts +82 -0
  317. package/dist/wizard/lib/treasury-heartbeat.js +1104 -0
  318. package/dist/wizard/lib/updater.d.ts +29 -0
  319. package/dist/wizard/lib/updater.js +190 -0
  320. package/dist/wizard/lib/user-manager.d.ts +39 -0
  321. package/dist/wizard/lib/user-manager.js +182 -0
  322. package/dist/wizard/lib/vault.d.ts +26 -0
  323. package/dist/wizard/lib/vault.js +161 -0
  324. package/dist/wizard/router.d.ts +5 -0
  325. package/dist/wizard/router.js +15 -0
  326. package/dist/wizard/server.d.ts +18 -0
  327. package/dist/wizard/server.js +436 -0
  328. package/package.json +59 -0
@@ -0,0 +1,452 @@
1
+ /**
2
+ * Headless deploy — runs the same provisioner pipeline as Haku,
3
+ * but outputs progress to stdout instead of SSE to a browser.
4
+ * Called by: `npx voidforge deploy --headless`
5
+ * Used by: /build Phase 12 (Kusanagi)
6
+ */
7
+ import { readFile, access } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ import { randomUUID } from 'node:crypto';
10
+ import { createInterface } from 'node:readline';
11
+ import { parseFrontmatter } from './frontmatter.js';
12
+ import { recommendInstanceType } from './instance-sizing.js';
13
+ import { vaultUnlock, vaultGet, vaultKeys } from './vault.js';
14
+ import { createManifest, updateManifestStatus } from './provision-manifest.js';
15
+ import { emitCostEstimate } from './cost-estimator.js';
16
+ import { runBuildStep, getBuildOutputDir } from './build-step.js';
17
+ import { generateEnvValidator } from './env-validator.js';
18
+ import { logDeploy } from './deploy-log.js';
19
+ import { setupHealthMonitoring } from './health-monitor.js';
20
+ import { sshDeploy } from './ssh-deploy.js';
21
+ import { s3Deploy } from './s3-deploy.js';
22
+ import { prepareGithub } from './github.js';
23
+ import { provisionDns } from './dns/cloudflare-dns.js';
24
+ import { generateSentryInit } from './sentry-generator.js';
25
+ import { provisioners, provisionKeys, GITHUB_LINKED_TARGETS, GITHUB_OPTIONAL_TARGETS } from './provisioner-registry.js';
26
+ function log(icon, message) {
27
+ console.log(` ${icon} ${message}`);
28
+ }
29
+ function emit(event) {
30
+ const icons = {
31
+ done: '\x1b[32m✓\x1b[0m',
32
+ error: '\x1b[31m✗\x1b[0m',
33
+ skipped: '\x1b[33m→\x1b[0m',
34
+ pending: '\x1b[36m…\x1b[0m',
35
+ };
36
+ const icon = icons[event.status] || '·';
37
+ const detail = event.detail ? ` (${event.detail})` : '';
38
+ console.log(` ${icon} [${event.step}] ${event.message}${detail}`);
39
+ }
40
+ async function promptPassword() {
41
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
42
+ return new Promise((resolve) => {
43
+ // Hide input for password
44
+ process.stdout.write(' Vault password: ');
45
+ const stdin = process.stdin;
46
+ const wasRaw = stdin.isRaw;
47
+ if (stdin.isTTY && stdin.setRawMode) {
48
+ stdin.setRawMode(true);
49
+ }
50
+ let password = '';
51
+ const onData = (ch) => {
52
+ const c = ch.toString();
53
+ if (c === '\n' || c === '\r') {
54
+ stdin.removeListener('data', onData);
55
+ if (stdin.isTTY && stdin.setRawMode)
56
+ stdin.setRawMode(wasRaw ?? false);
57
+ process.stdout.write('\n');
58
+ rl.close();
59
+ resolve(password);
60
+ }
61
+ else if (c === '\u007f' || c === '\b') {
62
+ password = password.slice(0, -1);
63
+ }
64
+ else if (c === '\u0003') {
65
+ // Ctrl+C
66
+ process.exit(1);
67
+ }
68
+ else {
69
+ password += c;
70
+ }
71
+ };
72
+ stdin.on('data', onData);
73
+ });
74
+ }
75
+ /**
76
+ * Env-only deploy — write vault credentials to .env without provisioning infrastructure.
77
+ * Reads PRD frontmatter to identify required env vars, pulls matching values from the vault,
78
+ * and appends them to the project's .env file.
79
+ * Called by: `npx voidforge deploy --env-only`
80
+ */
81
+ export async function envOnlyDeploy(projectDir) {
82
+ const dir = projectDir || process.cwd();
83
+ console.log('');
84
+ console.log(' \x1b[1mVoidForge — Env-Only Deploy (Vault → .env)\x1b[0m');
85
+ console.log('');
86
+ // Verify this is a VoidForge project
87
+ try {
88
+ await access(join(dir, 'CLAUDE.md'));
89
+ }
90
+ catch {
91
+ log('✗', 'Not a VoidForge project — no CLAUDE.md found');
92
+ process.exit(1);
93
+ }
94
+ // Verify PRD exists (env-only still requires a project with a PRD)
95
+ try {
96
+ await access(join(dir, 'docs', 'PRD.md'));
97
+ }
98
+ catch {
99
+ log('✗', 'No PRD found at docs/PRD.md');
100
+ process.exit(1);
101
+ }
102
+ // Unlock vault
103
+ const password = process.env['VOIDFORGE_VAULT_PASSWORD'] || await promptPassword();
104
+ const valid = await vaultUnlock(password);
105
+ if (!valid) {
106
+ log('✗', 'Wrong vault password');
107
+ process.exit(1);
108
+ }
109
+ log('🔓', 'Vault unlocked');
110
+ // Load all vault keys
111
+ const keys = await vaultKeys(password);
112
+ const envKeys = keys.filter(k => k.startsWith('env:'));
113
+ const infraKeys = keys.filter(k => !k.startsWith('env:'));
114
+ if (envKeys.length === 0 && infraKeys.length === 0) {
115
+ log('→', 'Vault is empty — nothing to write');
116
+ return;
117
+ }
118
+ // Read existing .env to avoid duplicates
119
+ const envPath = join(dir, '.env');
120
+ let existingEnv = '';
121
+ try {
122
+ existingEnv = await readFile(envPath, 'utf-8');
123
+ }
124
+ catch { /* no .env yet */ }
125
+ // Build env entries from vault
126
+ const lines = [];
127
+ // Track written env names to prevent env:/infra collision duplicates
128
+ const writtenNames = new Set();
129
+ let written = 0;
130
+ let skipped = 0;
131
+ /** Check if an env var name already exists in the .env file (line-anchored match) */
132
+ function envExists(name) {
133
+ return new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}=`, 'm').test(existingEnv);
134
+ }
135
+ /** Quote a value for .env — escape newlines, quotes, and backslashes */
136
+ function quoteValue(val) {
137
+ if (/[\n\r"\\$`#\s]/.test(val)) {
138
+ return `"${val.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`').replace(/\n/g, '\\n').replace(/\r/g, '\\r')}"`;
139
+ }
140
+ return val;
141
+ }
142
+ // env:-prefixed keys → strip prefix, use as env var name directly
143
+ const envNamePattern = /^[A-Z_][A-Z0-9_]*$/;
144
+ for (const key of envKeys) {
145
+ const envName = key.slice(4); // strip "env:"
146
+ if (!envNamePattern.test(envName)) {
147
+ log('→', `Skipping malformed vault key: ${key} (name must match [A-Z_][A-Z0-9_]*)`);
148
+ continue;
149
+ }
150
+ if (envExists(envName) || writtenNames.has(envName)) {
151
+ skipped++;
152
+ continue;
153
+ }
154
+ const val = await vaultGet(password, key);
155
+ if (val !== null) {
156
+ lines.push(`${envName}=${quoteValue(val)}`);
157
+ writtenNames.add(envName);
158
+ written++;
159
+ }
160
+ }
161
+ // Hyphenated infra keys → map to env var equivalents
162
+ const infraMap = {
163
+ 'anthropic-api-key': 'ANTHROPIC_API_KEY',
164
+ 'aws-access-key-id': 'AWS_ACCESS_KEY_ID',
165
+ 'aws-secret-access-key': 'AWS_SECRET_ACCESS_KEY',
166
+ 'aws-region': 'AWS_REGION',
167
+ 'vercel-token': 'VERCEL_TOKEN',
168
+ 'railway-token': 'RAILWAY_TOKEN',
169
+ 'cloudflare-api-token': 'CLOUDFLARE_API_TOKEN',
170
+ 'cloudflare-account-id': 'CLOUDFLARE_ACCOUNT_ID',
171
+ 'cloudflare-zone-id': 'CLOUDFLARE_ZONE_ID',
172
+ 'github-token': 'GITHUB_TOKEN',
173
+ 'sentry-dsn': 'SENTRY_DSN',
174
+ };
175
+ for (const key of infraKeys) {
176
+ const envName = infraMap[key];
177
+ if (!envName)
178
+ continue; // unknown infra key, skip
179
+ if (envExists(envName) || writtenNames.has(envName)) {
180
+ skipped++;
181
+ continue;
182
+ }
183
+ const val = await vaultGet(password, key);
184
+ if (val !== null) {
185
+ lines.push(`${envName}=${quoteValue(val)}`);
186
+ writtenNames.add(envName);
187
+ written++;
188
+ }
189
+ }
190
+ if (lines.length === 0) {
191
+ log('→', `All ${skipped} vault keys already in .env — nothing to write`);
192
+ return;
193
+ }
194
+ // Append to .env with restricted permissions (0o600 — owner only, matches vault.ts)
195
+ const section = `\n# --- VoidForge vault (${new Date().toISOString().slice(0, 10)}) ---\n${lines.join('\n')}\n`;
196
+ const { open: openFile } = await import('node:fs/promises');
197
+ const content = existingEnv + section;
198
+ const fh = await openFile(envPath, 'w', 0o600);
199
+ try {
200
+ await fh.writeFile(content, 'utf-8');
201
+ await fh.sync();
202
+ }
203
+ finally {
204
+ await fh.close();
205
+ }
206
+ log('✓', `Wrote ${written} env vars to .env (${skipped} already present)`);
207
+ console.log('');
208
+ }
209
+ export async function headlessDeploy(projectDir) {
210
+ const dir = projectDir || process.cwd();
211
+ console.log('');
212
+ console.log(' \x1b[1mVoidForge — Headless Deploy (Haku CLI)\x1b[0m');
213
+ console.log('');
214
+ // --- Scan project ---
215
+ log('📂', `Scanning project: ${dir}`);
216
+ try {
217
+ await access(join(dir, 'CLAUDE.md'));
218
+ }
219
+ catch {
220
+ log('✗', 'Not a VoidForge project — no CLAUDE.md found');
221
+ process.exit(1);
222
+ }
223
+ // Read project name
224
+ let name = 'Unknown';
225
+ try {
226
+ const claudeMd = await readFile(join(dir, 'CLAUDE.md'), 'utf-8');
227
+ const nameMatch = claudeMd.match(/\*\*Name:\*\*\s*(.+)/);
228
+ if (nameMatch) {
229
+ const extracted = nameMatch[1].trim();
230
+ if (!extracted.startsWith('['))
231
+ name = extracted;
232
+ }
233
+ }
234
+ catch { /* use default */ }
235
+ // Read deploy target from .env
236
+ let deploy = '';
237
+ let hostname = '';
238
+ try {
239
+ const envContent = await readFile(join(dir, '.env'), 'utf-8');
240
+ const deployMatch = envContent.match(/DEPLOY_TARGET=["']?([^"'\s#]+)/);
241
+ if (deployMatch)
242
+ deploy = deployMatch[1];
243
+ const hostnameMatch = envContent.match(/HOSTNAME=["']?([^"'\s#]+)/);
244
+ if (hostnameMatch)
245
+ hostname = hostnameMatch[1];
246
+ }
247
+ catch { /* no .env */ }
248
+ // Read PRD frontmatter
249
+ let framework = '';
250
+ let database = 'none';
251
+ let cache = 'none';
252
+ let instanceType = '';
253
+ let prdFrontmatter = {};
254
+ try {
255
+ const prd = await readFile(join(dir, 'docs', 'PRD.md'), 'utf-8');
256
+ const { frontmatter } = parseFrontmatter(prd);
257
+ prdFrontmatter = frontmatter;
258
+ if (frontmatter.framework)
259
+ framework = frontmatter.framework;
260
+ if (frontmatter.database)
261
+ database = frontmatter.database;
262
+ if (frontmatter.cache)
263
+ cache = frontmatter.cache;
264
+ if (frontmatter.deploy && !deploy)
265
+ deploy = frontmatter.deploy;
266
+ if (frontmatter.hostname && !hostname)
267
+ hostname = frontmatter.hostname;
268
+ if (frontmatter.instance_type)
269
+ instanceType = frontmatter.instance_type;
270
+ }
271
+ catch { /* no PRD */ }
272
+ if (!deploy)
273
+ deploy = 'docker';
274
+ if (!instanceType && (deploy === 'vps' || !deploy)) {
275
+ instanceType = recommendInstanceType({
276
+ type: prdFrontmatter.type,
277
+ framework,
278
+ database,
279
+ cache,
280
+ workers: prdFrontmatter.workers,
281
+ payments: prdFrontmatter.payments,
282
+ });
283
+ }
284
+ log('📋', `Project: ${name}`);
285
+ log('🔧', `Framework: ${framework || 'auto-detect'} | DB: ${database} | Cache: ${cache}`);
286
+ log('🎯', `Deploy target: ${deploy} | Instance: ${instanceType || 'N/A'}`);
287
+ if (hostname)
288
+ log('🌐', `Hostname: ${hostname}`);
289
+ console.log('');
290
+ // --- Unlock vault ---
291
+ const password = await promptPassword();
292
+ const valid = await vaultUnlock(password);
293
+ if (!valid) {
294
+ log('✗', 'Wrong vault password');
295
+ process.exit(1);
296
+ }
297
+ log('🔓', 'Vault unlocked');
298
+ // --- Load credentials ---
299
+ const keys = await vaultKeys(password);
300
+ const allCredentials = {};
301
+ for (const key of keys) {
302
+ const val = await vaultGet(password, key);
303
+ if (val)
304
+ allCredentials[key] = val;
305
+ }
306
+ // Scope credentials
307
+ const allowed = provisionKeys[deploy] || [];
308
+ const scopedCreds = {};
309
+ for (const key of allowed) {
310
+ if (allCredentials[key])
311
+ scopedCreds[key] = allCredentials[key];
312
+ }
313
+ // --- Provision ---
314
+ const provisioner = provisioners[deploy];
315
+ if (!provisioner) {
316
+ log('✗', `Unknown deploy target: ${deploy}`);
317
+ process.exit(1);
318
+ }
319
+ const runId = randomUUID();
320
+ const ctx = {
321
+ runId,
322
+ projectDir: dir,
323
+ projectName: name,
324
+ deployTarget: deploy,
325
+ framework: framework || 'express',
326
+ database,
327
+ cache,
328
+ instanceType: instanceType || 't3.micro',
329
+ hostname,
330
+ credentials: scopedCreds,
331
+ };
332
+ const errors = await provisioner.validate(ctx);
333
+ if (errors.length > 0) {
334
+ log('✗', `Validation failed: ${errors.join('; ')}`);
335
+ process.exit(1);
336
+ }
337
+ const region = allCredentials['aws-region'] || 'us-east-1';
338
+ await createManifest(runId, deploy, region, name);
339
+ console.log('');
340
+ log('🚀', 'Starting provisioning...');
341
+ console.log('');
342
+ // Cost estimate
343
+ emitCostEstimate(deploy, ctx.instanceType, database, cache, emit);
344
+ // GitHub pre-step
345
+ const sharedOutputs = {};
346
+ const hasGithub = allCredentials['github-token'];
347
+ const needsGithub = GITHUB_LINKED_TARGETS.includes(deploy);
348
+ const wantsGithub = GITHUB_OPTIONAL_TARGETS.includes(deploy);
349
+ if (hasGithub && (needsGithub || wantsGithub)) {
350
+ const ghResult = await prepareGithub(runId, allCredentials['github-token'], allCredentials['github-owner'] || null, name, dir, emit, AbortSignal.timeout(120000), framework, deploy);
351
+ if (ghResult.success) {
352
+ sharedOutputs['GITHUB_REPO_URL'] = ghResult.repoUrl;
353
+ sharedOutputs['GITHUB_OWNER'] = ghResult.owner;
354
+ sharedOutputs['GITHUB_REPO_NAME'] = ghResult.repoName;
355
+ }
356
+ }
357
+ if (sharedOutputs['GITHUB_OWNER']) {
358
+ ctx.credentials['_github-owner'] = sharedOutputs['GITHUB_OWNER'];
359
+ ctx.credentials['_github-repo-name'] = sharedOutputs['GITHUB_REPO_NAME'];
360
+ }
361
+ // Provision infrastructure
362
+ let result;
363
+ try {
364
+ result = await provisioner.provision(ctx, emit);
365
+ }
366
+ catch (err) {
367
+ await updateManifestStatus(runId, 'failed');
368
+ log('✗', `Provisioning failed: ${err.message}`);
369
+ process.exit(1);
370
+ }
371
+ if (!result.success) {
372
+ await updateManifestStatus(runId, 'failed');
373
+ log('✗', `Provisioning failed: ${result.error || 'Unknown error'}`);
374
+ process.exit(1);
375
+ }
376
+ // Merge GitHub outputs
377
+ for (const [k, v] of Object.entries(sharedOutputs)) {
378
+ result.outputs[k] = v;
379
+ }
380
+ // Pre-deploy build step
381
+ if (deploy !== 'docker') {
382
+ const buildResult = await runBuildStep(dir, framework, emit, AbortSignal.timeout(300000));
383
+ if (!buildResult.success) {
384
+ emit({ step: 'build-warning', status: 'error', message: 'Build failed — deploy may be incomplete', detail: buildResult.error });
385
+ }
386
+ }
387
+ // Deploy post-step
388
+ if (deploy === 'vps') {
389
+ const sshHost = result.outputs['SSH_HOST'];
390
+ const sshUser = result.outputs['SSH_USER'] || 'ec2-user';
391
+ const sshKey = result.outputs['SSH_KEY_PATH'] || '.ssh/deploy-key.pem';
392
+ if (sshHost) {
393
+ const deployResult = await sshDeploy(dir, sshHost, sshUser, sshKey, hostname || undefined, framework, emit, AbortSignal.timeout(300000));
394
+ if (deployResult.deployUrl)
395
+ result.outputs['DEPLOY_URL'] = deployResult.deployUrl;
396
+ }
397
+ }
398
+ else if (deploy === 'static') {
399
+ const bucket = result.outputs['S3_BUCKET'];
400
+ const websiteUrl = result.outputs['S3_WEBSITE_URL'];
401
+ if (bucket && websiteUrl && allCredentials['aws-access-key-id'] && allCredentials['aws-secret-access-key']) {
402
+ const s3Result = await s3Deploy(bucket, join(dir, getBuildOutputDir(framework)), region, { accessKeyId: allCredentials['aws-access-key-id'], secretAccessKey: allCredentials['aws-secret-access-key'] }, websiteUrl, emit);
403
+ if (s3Result.deployUrl)
404
+ result.outputs['DEPLOY_URL'] = s3Result.deployUrl;
405
+ }
406
+ }
407
+ else {
408
+ const deployUrl = result.outputs['DEPLOY_URL'] || result.outputs['VERCEL_DOMAIN'] || result.outputs['CF_PROJECT_URL'] || result.outputs['RAILWAY_DOMAIN'];
409
+ if (deployUrl && !result.outputs['DEPLOY_URL']) {
410
+ result.outputs['DEPLOY_URL'] = deployUrl.startsWith('http') ? deployUrl : `https://${deployUrl}`;
411
+ }
412
+ }
413
+ // DNS
414
+ if (hostname && allCredentials['cloudflare-api-token']) {
415
+ await provisionDns(runId, allCredentials['cloudflare-api-token'], hostname, deploy, result.outputs, emit);
416
+ }
417
+ // Sentry
418
+ await generateSentryInit(dir, framework, allCredentials['sentry-dsn'], emit);
419
+ // Env validator
420
+ await generateEnvValidator(dir, framework);
421
+ // Health monitoring
422
+ await setupHealthMonitoring(deploy, dir, name, result.outputs['DEPLOY_URL'] || '', result.outputs, emit);
423
+ // Deploy log
424
+ try {
425
+ await logDeploy({
426
+ runId,
427
+ timestamp: new Date().toISOString(),
428
+ target: deploy,
429
+ projectName: name,
430
+ framework,
431
+ deployUrl: result.outputs['DEPLOY_URL'] || '',
432
+ hostname,
433
+ region,
434
+ resources: result.resources.map(r => ({ type: r.type, id: r.id })),
435
+ outputs: Object.fromEntries(Object.entries(result.outputs).filter(([k]) => !k.toLowerCase().includes('password') && !k.toLowerCase().includes('secret') && !k.toLowerCase().includes('token'))),
436
+ });
437
+ }
438
+ catch { /* non-fatal */ }
439
+ await updateManifestStatus(runId, 'complete');
440
+ // --- Done ---
441
+ console.log('');
442
+ console.log(' \x1b[32m═══════════════════════════════════════════\x1b[0m');
443
+ console.log(' \x1b[32m Deploy complete!\x1b[0m');
444
+ if (result.outputs['DEPLOY_URL']) {
445
+ console.log(` \x1b[32m URL: ${result.outputs['DEPLOY_URL']}\x1b[0m`);
446
+ }
447
+ if (result.outputs['SSH_HOST']) {
448
+ console.log(` \x1b[36m SSH: ssh ${result.outputs['SSH_USER'] || 'ec2-user'}@${result.outputs['SSH_HOST']}\x1b[0m`);
449
+ }
450
+ console.log(' \x1b[32m═══════════════════════════════════════════\x1b[0m');
451
+ console.log('');
452
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Post-deploy health monitoring (ADR-023).
3
+ * VPS: generates a cron-based health check script.
4
+ * Platforms: emits dashboard links.
5
+ */
6
+ import type { ProvisionEmitter } from './provisioners/types.js';
7
+ export interface HealthMonitorResult {
8
+ file?: string;
9
+ dashboardUrl?: string;
10
+ }
11
+ /**
12
+ * Set up post-deploy health monitoring.
13
+ * VPS: generates health check script. Platforms: returns dashboard URL.
14
+ */
15
+ export declare function setupHealthMonitoring(deployTarget: string, projectDir: string, projectName: string, deployUrl: string, outputs: Record<string, string>, emit: ProvisionEmitter): Promise<HealthMonitorResult>;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Post-deploy health monitoring (ADR-023).
3
+ * VPS: generates a cron-based health check script.
4
+ * Platforms: emits dashboard links.
5
+ */
6
+ import { writeFile, mkdir } from 'node:fs/promises';
7
+ import { join } from 'node:path';
8
+ /** Platform monitoring dashboard URL patterns. */
9
+ const DASHBOARD_URLS = {
10
+ vercel: (o) => o['VERCEL_PROJECT_NAME']
11
+ ? `https://vercel.com/~/projects/${o['VERCEL_PROJECT_NAME']}/analytics`
12
+ : null,
13
+ railway: (o) => o['RAILWAY_PROJECT_ID']
14
+ ? `https://railway.app/project/${o['RAILWAY_PROJECT_ID']}`
15
+ : null,
16
+ cloudflare: (o) => o['CF_PROJECT_NAME']
17
+ ? `https://dash.cloudflare.com/?to=/:account/pages/view/${o['CF_PROJECT_NAME']}`
18
+ : null,
19
+ };
20
+ /**
21
+ * Generate a VPS health check cron script.
22
+ */
23
+ function generateHealthCheckScript(deployUrl, projectName) {
24
+ // Sanitize inputs for shell safety — strip anything that's not alphanumeric, dash, or dot
25
+ const safeName = projectName.replace(/[^a-zA-Z0-9._-]/g, '-').slice(0, 64);
26
+ const safeUrl = deployUrl.replace(/[^a-zA-Z0-9:/.?&=_-]/g, '');
27
+ return `#!/usr/bin/env bash
28
+ # healthcheck.sh — Basic uptime monitor for ${safeName}
29
+ # Generated by VoidForge (ADR-023)
30
+ # Install: crontab -e, add: */5 * * * * /opt/app/infra/healthcheck.sh
31
+ set -euo pipefail
32
+
33
+ URL="${safeUrl}"
34
+ LOG="/var/log/${safeName}-health.log"
35
+ TIMESTAMP=\$(date '+%Y-%m-%d %H:%M:%S')
36
+
37
+ HTTP_CODE=\$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "\$URL" 2>/dev/null || echo "000")
38
+
39
+ if [ "\$HTTP_CODE" -ge 200 ] && [ "\$HTTP_CODE" -lt 400 ]; then
40
+ echo "\$TIMESTAMP OK \$HTTP_CODE \$URL" >> "\$LOG"
41
+ else
42
+ echo "\$TIMESTAMP FAIL \$HTTP_CODE \$URL" >> "\$LOG"
43
+ # Uncomment to add email alerting:
44
+ # echo "Health check failed: \$URL returned \$HTTP_CODE at \$TIMESTAMP" | mail -s "[ALERT] \$URL down" your@email.com
45
+ fi
46
+
47
+ # Keep log under 10k lines
48
+ tail -n 10000 "\$LOG" > "\$LOG.tmp" && mv "\$LOG.tmp" "\$LOG" 2>/dev/null || true
49
+ `;
50
+ }
51
+ /**
52
+ * Set up post-deploy health monitoring.
53
+ * VPS: generates health check script. Platforms: returns dashboard URL.
54
+ */
55
+ export async function setupHealthMonitoring(deployTarget, projectDir, projectName, deployUrl, outputs, emit) {
56
+ if (deployTarget === 'vps' && !deployUrl) {
57
+ emit({ step: 'health-monitor', status: 'skipped', message: 'VPS deployed but no URL available yet — run healthcheck.sh manually after DNS propagates' });
58
+ return {};
59
+ }
60
+ if (deployTarget === 'vps' && deployUrl) {
61
+ emit({ step: 'health-monitor', status: 'started', message: 'Generating health check script' });
62
+ try {
63
+ const infraDir = join(projectDir, 'infra');
64
+ await mkdir(infraDir, { recursive: true });
65
+ const script = generateHealthCheckScript(deployUrl, projectName);
66
+ const scriptPath = join(infraDir, 'healthcheck.sh');
67
+ await writeFile(scriptPath, script, { mode: 0o755 });
68
+ emit({ step: 'health-monitor', status: 'done', message: 'Generated infra/healthcheck.sh — add to crontab: */5 * * * * /opt/app/infra/healthcheck.sh' });
69
+ return { file: 'infra/healthcheck.sh' };
70
+ }
71
+ catch (err) {
72
+ emit({ step: 'health-monitor', status: 'error', message: 'Failed to generate health check script', detail: err.message });
73
+ return {};
74
+ }
75
+ }
76
+ if (deployTarget === 'docker') {
77
+ emit({ step: 'health-monitor', status: 'skipped', message: 'Docker — add a healthcheck to your Dockerfile or docker-compose.yml' });
78
+ return {};
79
+ }
80
+ // Platform targets — emit dashboard link
81
+ const getDashboardUrl = DASHBOARD_URLS[deployTarget];
82
+ if (getDashboardUrl) {
83
+ const dashboardUrl = getDashboardUrl(outputs);
84
+ if (dashboardUrl) {
85
+ emit({ step: 'health-monitor', status: 'done', message: `Monitor your app: ${dashboardUrl}` });
86
+ return { dashboardUrl };
87
+ }
88
+ }
89
+ emit({ step: 'health-monitor', status: 'skipped', message: 'No monitoring configured for this target' });
90
+ return {};
91
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Health Poller — Background service that pings project health endpoints.
3
+ * Runs every 5 minutes when the server is active.
4
+ * Non-blocking: uses fetch with 5-second timeout per project.
5
+ */
6
+ /** Start the background health poller. Idempotent — calling twice is safe. */
7
+ export declare function startHealthPoller(): void;
8
+ /** Stop the background health poller. */
9
+ export declare function stopHealthPoller(): void;