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,287 @@
1
+ /**
2
+ * Vercel provisioner — creates a real Vercel project via API + generates vercel.json.
3
+ * v3.8.0: Links GitHub repo, sets env vars, polls deploy (ADR-015).
4
+ */
5
+ import { writeFile, readFile } from 'node:fs/promises';
6
+ import { join } from 'node:path';
7
+ import { httpsPost, httpsGet, httpsDelete, safeJsonParse, slugify } from './http-client.js';
8
+ import { recordResourcePending, recordResourceCreated } from '../provision-manifest.js';
9
+ import { appendEnvSection } from '../env-writer.js';
10
+ const DEPLOY_POLL_INTERVAL_MS = 5000;
11
+ const DEPLOY_POLL_TIMEOUT_MS = 300_000; // 5 minutes
12
+ export const vercelProvisioner = {
13
+ async validate(ctx) {
14
+ const errors = [];
15
+ if (!ctx.projectDir)
16
+ errors.push('Project directory is required');
17
+ if (!ctx.credentials['vercel-token'])
18
+ errors.push('Vercel API token is required');
19
+ return errors;
20
+ },
21
+ async provision(ctx, emit) {
22
+ const files = [];
23
+ const resources = [];
24
+ const outputs = {};
25
+ const token = ctx.credentials['vercel-token'];
26
+ const slug = slugify(ctx.projectName);
27
+ const framework = ctx.framework || 'next.js';
28
+ const headers = {
29
+ 'Authorization': `Bearer ${token}`,
30
+ 'Content-Type': 'application/json',
31
+ };
32
+ // Step 1: Create Vercel project
33
+ emit({ step: 'vercel-project', status: 'started', message: 'Creating Vercel project' });
34
+ let projectId = '';
35
+ try {
36
+ await recordResourcePending(ctx.runId, 'vercel-project', slug, 'global');
37
+ // Only pass framework if it's a Vercel-recognized value — otherwise omit and let Vercel auto-detect
38
+ const vercelFrameworks = {
39
+ 'next.js': 'nextjs',
40
+ 'nuxt': 'nuxtjs',
41
+ 'svelte': 'sveltekit',
42
+ 'remix': 'remix',
43
+ 'gatsby': 'gatsby',
44
+ 'astro': 'astro',
45
+ 'vite': 'vite',
46
+ };
47
+ const projectBody = { name: slug };
48
+ const vercelFw = vercelFrameworks[framework];
49
+ if (vercelFw)
50
+ projectBody.framework = vercelFw;
51
+ const body = JSON.stringify(projectBody);
52
+ const res = await httpsPost('api.vercel.com', '/v10/projects', headers, body);
53
+ if (res.status === 200 || res.status === 201) {
54
+ const data = safeJsonParse(res.body);
55
+ projectId = data?.id ?? '';
56
+ if (!projectId)
57
+ throw new Error('Vercel returned no project ID');
58
+ resources.push({ type: 'vercel-project', id: projectId, region: 'global' });
59
+ await recordResourceCreated(ctx.runId, 'vercel-project', projectId, 'global');
60
+ outputs['VERCEL_PROJECT_ID'] = projectId;
61
+ outputs['VERCEL_PROJECT_NAME'] = data?.name ?? slug;
62
+ emit({ step: 'vercel-project', status: 'done', message: `Project "${data?.name}" created on Vercel` });
63
+ }
64
+ else if (res.status === 409) {
65
+ // Project already exists — fetch its ID for subsequent steps
66
+ try {
67
+ const existingRes = await httpsGet('api.vercel.com', `/v10/projects/${slug}`, headers);
68
+ if (existingRes.status === 200) {
69
+ const existingData = safeJsonParse(existingRes.body);
70
+ projectId = existingData?.id ?? '';
71
+ if (projectId) {
72
+ resources.push({ type: 'vercel-project', id: projectId, region: 'global' });
73
+ await recordResourceCreated(ctx.runId, 'vercel-project', projectId, 'global');
74
+ outputs['VERCEL_PROJECT_ID'] = projectId;
75
+ }
76
+ }
77
+ }
78
+ catch { /* fetch failed, proceed without ID */ }
79
+ outputs['VERCEL_PROJECT_NAME'] = slug;
80
+ emit({ step: 'vercel-project', status: 'done', message: `Project "${slug}" already exists on Vercel — will use existing`, detail: projectId ? `ID: ${projectId}` : 'Could not fetch project ID' });
81
+ }
82
+ else {
83
+ const errBody = safeJsonParse(res.body);
84
+ throw new Error(errBody?.error?.message || `Vercel API returned ${res.status}`);
85
+ }
86
+ }
87
+ catch (err) {
88
+ emit({ step: 'vercel-project', status: 'error', message: 'Failed to create Vercel project', detail: err.message });
89
+ return { success: false, resources, outputs, files, error: err.message };
90
+ }
91
+ // Step 2: Add custom domain if hostname provided
92
+ if (ctx.hostname && projectId) {
93
+ emit({ step: 'vercel-domain', status: 'started', message: `Adding domain ${ctx.hostname} to Vercel project` });
94
+ try {
95
+ const domainBody = JSON.stringify({ name: ctx.hostname });
96
+ const domainRes = await httpsPost('api.vercel.com', `/v10/projects/${projectId}/domains`, headers, domainBody);
97
+ if (domainRes.status === 200 || domainRes.status === 201) {
98
+ outputs['VERCEL_DOMAIN'] = ctx.hostname;
99
+ emit({ step: 'vercel-domain', status: 'done', message: `Domain "${ctx.hostname}" added to Vercel project` });
100
+ }
101
+ else if (domainRes.status === 409) {
102
+ emit({ step: 'vercel-domain', status: 'done', message: `Domain "${ctx.hostname}" already configured on Vercel` });
103
+ outputs['VERCEL_DOMAIN'] = ctx.hostname;
104
+ }
105
+ else {
106
+ const errBody = safeJsonParse(domainRes.body);
107
+ throw new Error(errBody?.error?.message || `Vercel domains API returned ${domainRes.status}`);
108
+ }
109
+ }
110
+ catch (err) {
111
+ emit({ step: 'vercel-domain', status: 'error', message: 'Failed to add domain to Vercel', detail: err.message });
112
+ // Non-fatal — DNS wiring will still work, user can add domain manually
113
+ }
114
+ }
115
+ else if (ctx.hostname && !projectId) {
116
+ emit({ step: 'vercel-domain', status: 'skipped', message: 'Cannot add domain — no project ID (existing project)' });
117
+ }
118
+ // Step 3: Generate vercel.json
119
+ emit({ step: 'vercel-config', status: 'started', message: 'Generating vercel.json' });
120
+ try {
121
+ const config = {
122
+ $schema: 'https://openapi.vercel.sh/vercel.json',
123
+ };
124
+ if (framework === 'express') {
125
+ config.builds = [{ src: 'dist/index.js', use: '@vercel/node' }];
126
+ config.routes = [{ src: '/(.*)', dest: 'dist/index.js' }];
127
+ }
128
+ await writeFile(join(ctx.projectDir, 'vercel.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
129
+ files.push('vercel.json');
130
+ emit({ step: 'vercel-config', status: 'done', message: 'Generated vercel.json' });
131
+ }
132
+ catch (err) {
133
+ emit({ step: 'vercel-config', status: 'error', message: 'Failed to write vercel.json', detail: err.message });
134
+ // Non-fatal — project was still created
135
+ }
136
+ // Step 4: Link GitHub repo (ADR-015 — auto-deploy on push)
137
+ const ghOwner = ctx.credentials['_github-owner'];
138
+ const ghRepo = ctx.credentials['_github-repo-name'];
139
+ if (projectId && ghOwner && ghRepo) {
140
+ emit({ step: 'vercel-link', status: 'started', message: `Linking GitHub repo ${ghOwner}/${ghRepo} to Vercel` });
141
+ try {
142
+ const linkBody = JSON.stringify({
143
+ type: 'github',
144
+ repo: `${ghOwner}/${ghRepo}`,
145
+ sourceless: false,
146
+ productionBranch: 'main',
147
+ });
148
+ const linkRes = await httpsPost('api.vercel.com', `/v10/projects/${projectId}/link`, headers, linkBody);
149
+ if (linkRes.status === 200 || linkRes.status === 201) {
150
+ emit({ step: 'vercel-link', status: 'done', message: `GitHub repo linked — auto-deploy enabled on push to main` });
151
+ }
152
+ else {
153
+ const errBody = safeJsonParse(linkRes.body);
154
+ emit({ step: 'vercel-link', status: 'error', message: 'Failed to link GitHub repo', detail: errBody?.error?.message || `API returned ${linkRes.status}` });
155
+ }
156
+ }
157
+ catch (err) {
158
+ emit({ step: 'vercel-link', status: 'error', message: 'Failed to link GitHub repo', detail: err.message });
159
+ // Non-fatal — user can link manually
160
+ }
161
+ }
162
+ // Step 5: Set environment variables
163
+ if (projectId) {
164
+ emit({ step: 'vercel-envvars', status: 'started', message: 'Setting environment variables' });
165
+ try {
166
+ // Collect env vars from .env file (skip comments, empty lines, and VoidForge metadata)
167
+ let envContent = '';
168
+ try {
169
+ envContent = await readFile(join(ctx.projectDir, '.env'), 'utf-8');
170
+ }
171
+ catch { /* no .env */ }
172
+ const envVars = envContent
173
+ .split('\n')
174
+ .filter(line => line.includes('=') && !line.startsWith('#'))
175
+ .map(line => {
176
+ const idx = line.indexOf('=');
177
+ return { key: line.slice(0, idx).trim(), value: line.slice(idx + 1).trim().replace(/^["']|["']$/g, '') };
178
+ })
179
+ .filter(v => v.key && !v.key.startsWith('VERCEL_')); // Don't set Vercel metadata as env vars
180
+ if (envVars.length > 0) {
181
+ const envBody = JSON.stringify(envVars.map(v => ({
182
+ key: v.key,
183
+ value: v.value,
184
+ type: 'encrypted',
185
+ target: ['production', 'preview', 'development'],
186
+ })));
187
+ const envRes = await httpsPost('api.vercel.com', `/v10/projects/${projectId}/env`, headers, envBody);
188
+ if (envRes.status === 200 || envRes.status === 201) {
189
+ emit({ step: 'vercel-envvars', status: 'done', message: `Set ${envVars.length} environment variables` });
190
+ }
191
+ else {
192
+ emit({ step: 'vercel-envvars', status: 'error', message: 'Failed to set env vars', detail: `API returned ${envRes.status}` });
193
+ }
194
+ }
195
+ else {
196
+ emit({ step: 'vercel-envvars', status: 'done', message: 'No environment variables to set' });
197
+ }
198
+ }
199
+ catch (err) {
200
+ emit({ step: 'vercel-envvars', status: 'error', message: 'Failed to set env vars', detail: err.message });
201
+ }
202
+ }
203
+ // Step 6: Poll for deployment (triggered by GitHub push, ADR-015)
204
+ if (projectId && ghOwner && ghRepo) {
205
+ emit({ step: 'vercel-deploy', status: 'started', message: 'Waiting for deployment (triggered by git push)...' });
206
+ try {
207
+ const start = Date.now();
208
+ let deployUrl = '';
209
+ while (Date.now() - start < DEPLOY_POLL_TIMEOUT_MS) {
210
+ await new Promise(r => setTimeout(r, DEPLOY_POLL_INTERVAL_MS));
211
+ if (ctx.abortSignal?.aborted)
212
+ break;
213
+ const depRes = await httpsGet('api.vercel.com', `/v6/deployments?projectId=${projectId}&limit=1`, headers);
214
+ if (depRes.status !== 200)
215
+ continue;
216
+ const depData = safeJsonParse(depRes.body);
217
+ const latest = depData?.deployments?.[0];
218
+ if (!latest)
219
+ continue;
220
+ if (latest.readyState === 'READY' || latest.state === 'READY') {
221
+ deployUrl = latest.url ? `https://${latest.url}` : '';
222
+ break;
223
+ }
224
+ if (latest.readyState === 'ERROR' || latest.state === 'ERROR') {
225
+ emit({ step: 'vercel-deploy', status: 'error', message: 'Deployment failed on Vercel', detail: 'Check the Vercel dashboard for build logs' });
226
+ break;
227
+ }
228
+ const elapsed = Math.round((Date.now() - start) / 1000);
229
+ if (elapsed % 15 === 0) {
230
+ emit({ step: 'vercel-deploy', status: 'started', message: `Deployment status: ${latest.readyState || latest.state || 'building'}... (${elapsed}s)` });
231
+ }
232
+ }
233
+ if (deployUrl) {
234
+ outputs['DEPLOY_URL'] = deployUrl;
235
+ emit({ step: 'vercel-deploy', status: 'done', message: `Live at ${deployUrl}` });
236
+ }
237
+ else if (!ctx.abortSignal?.aborted) {
238
+ emit({ step: 'vercel-deploy', status: 'error', message: 'Deployment polling timed out — check Vercel dashboard', detail: 'The deployment may still be building' });
239
+ }
240
+ }
241
+ catch (err) {
242
+ emit({ step: 'vercel-deploy', status: 'error', message: 'Failed to poll deployment', detail: err.message });
243
+ }
244
+ }
245
+ else if (!ghOwner || !ghRepo) {
246
+ emit({ step: 'vercel-deploy', status: 'skipped', message: 'No GitHub repo linked — deploy manually with: npx vercel deploy' });
247
+ }
248
+ // Step 7: Write .env
249
+ emit({ step: 'vercel-env', status: 'started', message: 'Writing Vercel config to .env' });
250
+ try {
251
+ const envLines = [
252
+ `# VoidForge Vercel — generated ${new Date().toISOString()}`,
253
+ `VERCEL_PROJECT_NAME=${outputs['VERCEL_PROJECT_NAME'] || slug}`,
254
+ ];
255
+ if (outputs['VERCEL_PROJECT_ID']) {
256
+ envLines.push(`VERCEL_PROJECT_ID=${outputs['VERCEL_PROJECT_ID']}`);
257
+ }
258
+ if (outputs['DEPLOY_URL']) {
259
+ envLines.push(`DEPLOY_URL=${outputs['DEPLOY_URL']}`);
260
+ }
261
+ envLines.push('# Auto-deploys on push to main');
262
+ await appendEnvSection(ctx.projectDir, envLines);
263
+ emit({ step: 'vercel-env', status: 'done', message: 'Vercel config written to .env' });
264
+ }
265
+ catch (err) {
266
+ emit({ step: 'vercel-env', status: 'error', message: 'Failed to write .env', detail: err.message });
267
+ }
268
+ return { success: true, resources, outputs, files };
269
+ },
270
+ async cleanup(resources, credentials) {
271
+ const token = credentials['vercel-token'];
272
+ if (!token)
273
+ return;
274
+ for (const resource of resources) {
275
+ if (resource.type === 'vercel-project') {
276
+ try {
277
+ await httpsDelete('api.vercel.com', `/v9/projects/${resource.id}`, {
278
+ 'Authorization': `Bearer ${token}`,
279
+ });
280
+ }
281
+ catch (err) {
282
+ console.error(`Failed to delete Vercel project ${resource.id}:`, err.message);
283
+ }
284
+ }
285
+ }
286
+ },
287
+ };
@@ -0,0 +1,42 @@
1
+ /**
2
+ * PTY Manager — spawns and manages real pseudo-terminal processes.
3
+ * Uses node-pty (same lib as VS Code, Gitpod, GitHub Codespaces).
4
+ * Each PTY is a real shell with full capabilities.
5
+ *
6
+ * Haku moves between worlds seamlessly.
7
+ */
8
+ export interface PtySession {
9
+ id: string;
10
+ projectName: string;
11
+ projectDir: string;
12
+ label: string;
13
+ username: string;
14
+ createdAt: number;
15
+ lastActivityAt: number;
16
+ cols: number;
17
+ rows: number;
18
+ }
19
+ /**
20
+ * Spawn a new PTY session.
21
+ * @param projectDir — directory to cd into
22
+ * @param projectName — human-readable project name
23
+ * @param label — tab label (e.g., "Claude Code", "Shell", "SSH: prod")
24
+ * @param initialCommand — optional command to auto-run after shell starts
25
+ * @param cols — terminal columns (default 120)
26
+ * @param rows — terminal rows (default 30)
27
+ */
28
+ export declare function createSession(projectDir: string, projectName: string, label: string, initialCommand?: string, cols?: number, rows?: number, username?: string): Promise<PtySession>;
29
+ /** Write input (keystrokes) to a PTY session. */
30
+ export declare function writeToSession(sessionId: string, data: string): void;
31
+ /** Subscribe to PTY output. Returns an unsubscribe function. */
32
+ export declare function onSessionData(sessionId: string, listener: (data: string) => void): () => void;
33
+ /** Resize a PTY session. */
34
+ export declare function resizeSession(sessionId: string, cols: number, rows: number): void;
35
+ /** Kill a PTY session. */
36
+ export declare function killSession(sessionId: string): void;
37
+ /** List all active sessions. */
38
+ export declare function listSessions(): PtySession[];
39
+ /** Kill all sessions (graceful shutdown). */
40
+ export declare function killAllSessions(): void;
41
+ /** Get session count. */
42
+ export declare function sessionCount(): number;
@@ -0,0 +1,231 @@
1
+ /**
2
+ * PTY Manager — spawns and manages real pseudo-terminal processes.
3
+ * Uses node-pty (same lib as VS Code, Gitpod, GitHub Codespaces).
4
+ * Each PTY is a real shell with full capabilities.
5
+ *
6
+ * Haku moves between worlds seamlessly.
7
+ */
8
+ import { randomUUID } from 'node:crypto';
9
+ import { isRemoteMode } from './tower-auth.js';
10
+ import { audit } from './audit-log.js';
11
+ // node-pty is a native module — dynamic import to handle missing installs gracefully
12
+ let pty = null;
13
+ async function loadPty() {
14
+ if (pty)
15
+ return pty;
16
+ try {
17
+ pty = await import('node-pty');
18
+ return pty;
19
+ }
20
+ catch {
21
+ throw new Error('node-pty is not installed. Run: npm install node-pty');
22
+ }
23
+ }
24
+ const sessions = new Map();
25
+ const MAX_SESSIONS_LOCAL = 5;
26
+ const MAX_SESSIONS_REMOTE = 20; // 5 per project, 20 total across all projects
27
+ const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
28
+ // SEC-004/QA-003: Whitelist of allowed initial commands — prevent arbitrary command injection
29
+ const ALLOWED_INITIAL_COMMANDS = ['claude', 'claude --dangerously-skip-permissions', 'bash', 'zsh', 'sh', 'npm run dev', 'npm start', 'npm test'];
30
+ // SEC-013: Safe environment keys — no credential leakage into PTY sessions
31
+ // ANTHROPIC_API_KEY included only in local mode (user's own key).
32
+ // In remote mode, operator's API key must NOT leak to deployer-role users.
33
+ // Includes TMPDIR/SSH_AUTH_SOCK for tool compatibility.
34
+ const BASE_SAFE_ENV_KEYS = ['PATH', 'HOME', 'SHELL', 'USER', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TERM_PROGRAM', 'EDITOR', 'VISUAL', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'NVM_DIR', 'NVM_BIN', 'NVM_INC', 'TMPDIR', 'TEMP', 'SSH_AUTH_SOCK', 'COLORTERM'];
35
+ // FLOW-R2-007: Only pass ANTHROPIC_API_KEY in local mode
36
+ function getSafeEnvKeys() {
37
+ if (isRemoteMode())
38
+ return BASE_SAFE_ENV_KEYS;
39
+ return [...BASE_SAFE_ENV_KEYS, 'ANTHROPIC_API_KEY'];
40
+ }
41
+ function resetIdleTimer(session) {
42
+ if (session.idleTimer)
43
+ clearTimeout(session.idleTimer);
44
+ session.idleTimer = setTimeout(() => {
45
+ console.log(` PTY session ${session.id} idle for 30 min — killing`);
46
+ killSession(session.id);
47
+ }, IDLE_TIMEOUT_MS);
48
+ }
49
+ /**
50
+ * Spawn a new PTY session.
51
+ * @param projectDir — directory to cd into
52
+ * @param projectName — human-readable project name
53
+ * @param label — tab label (e.g., "Claude Code", "Shell", "SSH: prod")
54
+ * @param initialCommand — optional command to auto-run after shell starts
55
+ * @param cols — terminal columns (default 120)
56
+ * @param rows — terminal rows (default 30)
57
+ */
58
+ export async function createSession(projectDir, projectName, label, initialCommand, cols = 120, rows = 30, username = '') {
59
+ const maxSessions = isRemoteMode() ? MAX_SESSIONS_REMOTE : MAX_SESSIONS_LOCAL;
60
+ if (sessions.size >= maxSessions) {
61
+ // QA-007/UX-018: Prefer killing sessions with no connected listeners (disconnected tabs)
62
+ const disconnected = [...sessions.values()].filter(s => s.onData.size === 0);
63
+ if (disconnected.length > 0) {
64
+ killSession(disconnected.sort((a, b) => a.lastActivityAt - b.lastActivityAt)[0].id);
65
+ }
66
+ else {
67
+ // All sessions have active listeners — reject instead of killing active work
68
+ throw new Error(`Maximum ${maxSessions} concurrent terminal sessions. Close a tab first.`);
69
+ }
70
+ }
71
+ const nodePty = await loadPty();
72
+ const shell = process.env['SHELL'] || '/bin/zsh';
73
+ const id = randomUUID();
74
+ // SEC-013: Build clean environment — no credential leakage into PTY
75
+ const safeEnv = {};
76
+ for (const key of getSafeEnvKeys()) {
77
+ if (process.env[key])
78
+ safeEnv[key] = process.env[key];
79
+ }
80
+ safeEnv['TERM'] = 'xterm-256color';
81
+ safeEnv['VOIDFORGE_SESSION'] = id;
82
+ // QA-R2-010 + QA-R3-002: Clamp cols/rows BEFORE spawnOptions construction
83
+ cols = Math.max(1, Math.min(500, Math.floor(cols)));
84
+ rows = Math.max(1, Math.min(200, Math.floor(rows)));
85
+ // Remote mode: spawn as forge-user for sandboxing (Layer 4)
86
+ const spawnOptions = {
87
+ name: 'xterm-256color',
88
+ cols,
89
+ rows,
90
+ cwd: projectDir,
91
+ env: safeEnv,
92
+ };
93
+ if (isRemoteMode()) {
94
+ // In remote mode, PTY spawns as forge-user (non-root sandboxing)
95
+ // The uid/gid would be set here in production: spawnOptions.uid = forgeUserUid;
96
+ // For scaffold/spec purposes, we document the intent
97
+ safeEnv['VOIDFORGE_REMOTE'] = '1';
98
+ }
99
+ const ptyProcess = nodePty.spawn(shell, [], spawnOptions);
100
+ const session = {
101
+ id,
102
+ projectName,
103
+ projectDir,
104
+ label,
105
+ username,
106
+ createdAt: Date.now(),
107
+ lastActivityAt: Date.now(),
108
+ cols,
109
+ rows,
110
+ process: ptyProcess,
111
+ onData: new Set(),
112
+ idleTimer: null,
113
+ };
114
+ // Forward PTY output to all listeners
115
+ ptyProcess.onData((data) => {
116
+ session.lastActivityAt = Date.now();
117
+ resetIdleTimer(session);
118
+ for (const listener of session.onData) {
119
+ try {
120
+ listener(data);
121
+ }
122
+ catch { /* listener error, ignore */ }
123
+ }
124
+ });
125
+ // Handle PTY exit
126
+ ptyProcess.onExit(({ exitCode }) => {
127
+ console.log(` PTY session ${id} exited (code ${exitCode})`);
128
+ if (session.idleTimer)
129
+ clearTimeout(session.idleTimer);
130
+ sessions.delete(id);
131
+ // Audit: log terminal end in remote mode
132
+ if (isRemoteMode()) {
133
+ audit('terminal_end', '', session.username, { sessionId: id, exitCode }).catch(() => { });
134
+ }
135
+ });
136
+ sessions.set(id, session);
137
+ resetIdleTimer(session);
138
+ // Audit: log terminal start in remote mode
139
+ if (isRemoteMode()) {
140
+ audit('terminal_start', '', username, { sessionId: id, project: projectName, label }).catch(() => { });
141
+ }
142
+ // SEC-004/QA-003: Validate initial command against whitelist
143
+ if (initialCommand && !ALLOWED_INITIAL_COMMANDS.includes(initialCommand)) {
144
+ initialCommand = undefined;
145
+ }
146
+ // Auto-run initial command after a short delay (let shell init complete)
147
+ if (initialCommand) {
148
+ setTimeout(() => {
149
+ if (sessions.has(id)) {
150
+ ptyProcess.write(initialCommand + '\r');
151
+ }
152
+ }, 500);
153
+ }
154
+ return {
155
+ id: session.id,
156
+ projectName: session.projectName,
157
+ projectDir: session.projectDir,
158
+ label: session.label,
159
+ username: session.username,
160
+ createdAt: session.createdAt,
161
+ lastActivityAt: session.lastActivityAt,
162
+ cols: session.cols,
163
+ rows: session.rows,
164
+ };
165
+ }
166
+ /** Write input (keystrokes) to a PTY session. */
167
+ export function writeToSession(sessionId, data) {
168
+ const session = sessions.get(sessionId);
169
+ if (!session)
170
+ throw new Error(`Session not found: ${sessionId}`);
171
+ session.lastActivityAt = Date.now();
172
+ resetIdleTimer(session);
173
+ session.process.write(data);
174
+ }
175
+ /** Subscribe to PTY output. Returns an unsubscribe function. */
176
+ export function onSessionData(sessionId, listener) {
177
+ const session = sessions.get(sessionId);
178
+ if (!session)
179
+ throw new Error(`Session not found: ${sessionId}`);
180
+ session.onData.add(listener);
181
+ return () => { session.onData.delete(listener); };
182
+ }
183
+ /** Resize a PTY session. */
184
+ export function resizeSession(sessionId, cols, rows) {
185
+ const session = sessions.get(sessionId);
186
+ if (!session)
187
+ return;
188
+ // QA-016/SEC-007: Clamp resize values to sane bounds
189
+ cols = Math.max(1, Math.min(500, Math.floor(cols)));
190
+ rows = Math.max(1, Math.min(200, Math.floor(rows)));
191
+ session.cols = cols;
192
+ session.rows = rows;
193
+ session.process.resize(cols, rows);
194
+ }
195
+ /** Kill a PTY session. */
196
+ export function killSession(sessionId) {
197
+ const session = sessions.get(sessionId);
198
+ if (!session)
199
+ return;
200
+ if (session.idleTimer)
201
+ clearTimeout(session.idleTimer);
202
+ try {
203
+ session.process.kill();
204
+ }
205
+ catch { /* already dead */ }
206
+ sessions.delete(sessionId);
207
+ }
208
+ /** List all active sessions. */
209
+ export function listSessions() {
210
+ return [...sessions.values()].map((s) => ({
211
+ id: s.id,
212
+ projectName: s.projectName,
213
+ projectDir: s.projectDir,
214
+ label: s.label,
215
+ username: s.username,
216
+ createdAt: s.createdAt,
217
+ lastActivityAt: s.lastActivityAt,
218
+ cols: s.cols,
219
+ rows: s.rows,
220
+ }));
221
+ }
222
+ /** Kill all sessions (graceful shutdown). */
223
+ export function killAllSessions() {
224
+ for (const id of sessions.keys()) {
225
+ killSession(id);
226
+ }
227
+ }
228
+ /** Get session count. */
229
+ export function sessionCount() {
230
+ return sessions.size;
231
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Rate limiter core — re-exports from the outbound-rate-limiter pattern for wizard runtime use.
3
+ * ARCH-R2-012: Production code should not import from docs/patterns/ directly.
4
+ */
5
+ export { OutboundRateLimiter, getLimiter } from './patterns/outbound-rate-limiter.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Rate limiter core — re-exports from the outbound-rate-limiter pattern for wizard runtime use.
3
+ * ARCH-R2-012: Production code should not import from docs/patterns/ directly.
4
+ */
5
+ export { OutboundRateLimiter, getLimiter } from './patterns/outbound-rate-limiter.js';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Reconciliation Engine — Two-pass financial reconciliation (§9.17).
3
+ *
4
+ * Compares VoidForge's recorded spend/revenue against platform-reported values.
5
+ * Runs daily: preliminary at midnight UTC, authoritative at 06:00 UTC.
6
+ *
7
+ * PRD Reference: §9.4 (reconciliation), §9.9 (ReconciliationReport), §9.17 (two-pass)
8
+ */
9
+ type Cents = number & {
10
+ readonly __brand: 'Cents';
11
+ };
12
+ type Ratio = number & {
13
+ readonly __brand: 'Ratio';
14
+ };
15
+ type AdPlatform = 'meta' | 'google' | 'tiktok' | 'linkedin' | 'twitter' | 'reddit';
16
+ type RevenueSource = 'stripe' | 'paddle';
17
+ interface ReconciliationReport {
18
+ id: string;
19
+ date: string;
20
+ type: 'preliminary' | 'final';
21
+ projectId: string;
22
+ spend: Array<{
23
+ platform: AdPlatform;
24
+ voidforgeRecorded: Cents;
25
+ platformReported: Cents;
26
+ discrepancy: Cents;
27
+ status: 'matched' | 'discrepancy' | 'unavailable';
28
+ }>;
29
+ revenue: Array<{
30
+ source: RevenueSource;
31
+ recorded: Cents;
32
+ reported: Cents;
33
+ discrepancy: Cents;
34
+ status: 'matched' | 'discrepancy' | 'unavailable';
35
+ }>;
36
+ netPosition: Cents;
37
+ blendedRoas: Ratio;
38
+ alerts: string[];
39
+ }
40
+ export declare function runReconciliation(projectId: string, date: string, type: 'preliminary' | 'final', platformSpendReports: Map<string, Cents>, // Platform-reported spend per platform
41
+ revenueSourceReports: Map<string, Cents>): Promise<ReconciliationReport>;
42
+ export declare function enforceCurrency(currency: string, platform: string): void;
43
+ export type { ReconciliationReport };