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,241 @@
1
+ /**
2
+ * Terminal API — WebSocket bridge between browser (xterm.js) and server (node-pty).
3
+ * Also REST endpoints for session management.
4
+ *
5
+ * WebSocket protocol:
6
+ * Client → Server: raw keystrokes (text frames)
7
+ * Server → Client: raw terminal output (text frames)
8
+ * Client → Server: JSON control messages: { type: "resize", cols, rows }
9
+ * Server → Client: JSON control messages: { type: "exit", code }
10
+ *
11
+ * Auth: vault password required in the WebSocket URL query string.
12
+ */
13
+ import { createHmac, timingSafeEqual, randomBytes } from 'node:crypto';
14
+ // SEC-R2-108: Per-boot random HMAC key — decoupled from vault password to prevent offline brute-force
15
+ const TERMINAL_HMAC_KEY = randomBytes(32);
16
+ import { WebSocketServer, WebSocket } from 'ws';
17
+ import { access, realpath } from 'node:fs/promises';
18
+ import { join } from 'node:path';
19
+ import { addRoute } from '../router.js';
20
+ import { getSessionPassword } from './credentials.js';
21
+ import { getServerPort, getServerHost } from '../lib/server-config.js';
22
+ import { parseJsonBody } from '../lib/body-parser.js';
23
+ import { createSession, writeToSession, onSessionData, resizeSession, killSession, listSessions, } from '../lib/pty-manager.js';
24
+ import { validateSession, parseSessionCookie, getClientIp, isRemoteMode } from '../lib/tower-auth.js';
25
+ import { hasProjectAccess } from '../lib/user-manager.js';
26
+ import { findByDirectory } from '../lib/project-registry.js';
27
+ import { sendJson } from '../lib/http-helpers.js';
28
+ // ── REST endpoints for session management ──────────────
29
+ // GET /api/terminal/sessions — list active PTY sessions (filtered by project access)
30
+ addRoute('GET', '/api/terminal/sessions', async (req, res) => {
31
+ const password = getSessionPassword();
32
+ if (!password) {
33
+ sendJson(res, 401, { error: 'Vault is locked.' });
34
+ return;
35
+ }
36
+ let allSessions = listSessions();
37
+ // In remote mode, filter sessions by user's project access
38
+ if (isRemoteMode()) {
39
+ const token = parseSessionCookie(req.headers.cookie);
40
+ const ip = getClientIp(req);
41
+ const userSession = token ? validateSession(token, ip) : null;
42
+ if (userSession && userSession.role !== 'admin') {
43
+ // Non-admins only see their own sessions
44
+ allSessions = allSessions.filter((s) => s.username === userSession.username);
45
+ }
46
+ }
47
+ sendJson(res, 200, { sessions: allSessions, count: allSessions.length });
48
+ });
49
+ // POST /api/terminal/sessions — create a new PTY session
50
+ addRoute('POST', '/api/terminal/sessions', async (req, res) => {
51
+ const password = getSessionPassword();
52
+ if (!password) {
53
+ sendJson(res, 401, { error: 'Vault is locked.' });
54
+ return;
55
+ }
56
+ const body = await parseJsonBody(req);
57
+ if (!body.projectDir || !body.projectName) {
58
+ sendJson(res, 400, { error: 'projectDir and projectName are required' });
59
+ return;
60
+ }
61
+ // SEC-003/QA-002: Validate projectDir — absolute path, no traversal
62
+ if (!body.projectDir.startsWith('/') || body.projectDir.includes('..')) {
63
+ sendJson(res, 400, { error: 'projectDir must be an absolute path with no ".." segments' });
64
+ return;
65
+ }
66
+ // IG-R4: Resolve symlinks and use real path for all operations
67
+ try {
68
+ body.projectDir = await realpath(body.projectDir);
69
+ }
70
+ catch {
71
+ sendJson(res, 400, { error: 'Could not resolve project directory path' });
72
+ return;
73
+ }
74
+ // Verify this is a VoidForge project (CLAUDE.md exists)
75
+ try {
76
+ await access(join(body.projectDir, 'CLAUDE.md'));
77
+ }
78
+ catch {
79
+ sendJson(res, 400, { error: 'Not a VoidForge project — no CLAUDE.md found' });
80
+ return;
81
+ }
82
+ // Extract user context and check per-project access
83
+ let sessionUsername = '';
84
+ if (isRemoteMode()) {
85
+ const token = parseSessionCookie(req.headers.cookie);
86
+ const ip = getClientIp(req);
87
+ const userSession = token ? validateSession(token, ip) : null;
88
+ if (!userSession) {
89
+ sendJson(res, 401, { error: 'Authentication required' });
90
+ return;
91
+ }
92
+ sessionUsername = userSession.username;
93
+ // Check per-project access — deployer minimum for terminal
94
+ const project = await findByDirectory(body.projectDir);
95
+ if (!project) {
96
+ // Project not in registry — deny access (cannot verify permissions)
97
+ sendJson(res, 404, { error: 'Project not found in registry' });
98
+ return;
99
+ }
100
+ const projectAccess = await hasProjectAccess(userSession, project.id, 'deployer');
101
+ if (!projectAccess) {
102
+ sendJson(res, 404, { error: 'Project not found' });
103
+ return;
104
+ }
105
+ }
106
+ try {
107
+ const session = await createSession(body.projectDir, body.projectName, body.label || 'Shell', body.initialCommand, body.cols || 120, body.rows || 30, sessionUsername);
108
+ // SEC-001/SEC-002: Generate per-session auth token for WebSocket upgrade
109
+ const authToken = createHmac('sha256', TERMINAL_HMAC_KEY).update(session.id).digest('hex');
110
+ sendJson(res, 200, { session, authToken });
111
+ }
112
+ catch (err) {
113
+ sendJson(res, 400, { error: err.message });
114
+ }
115
+ });
116
+ // POST /api/terminal/sessions/:id/kill — kill a session (ownership check in remote mode)
117
+ addRoute('POST', '/api/terminal/kill', async (req, res) => {
118
+ const password = getSessionPassword();
119
+ if (!password) {
120
+ sendJson(res, 401, { error: 'Vault is locked.' });
121
+ return;
122
+ }
123
+ const body = await parseJsonBody(req);
124
+ if (!body.sessionId) {
125
+ sendJson(res, 400, { error: 'sessionId is required' });
126
+ return;
127
+ }
128
+ // In remote mode, non-admins can only kill their own sessions
129
+ if (isRemoteMode()) {
130
+ const token = parseSessionCookie(req.headers.cookie);
131
+ const ip = getClientIp(req);
132
+ const userSession = token ? validateSession(token, ip) : null;
133
+ if (userSession && userSession.role !== 'admin') {
134
+ const sessions = listSessions();
135
+ const target = sessions.find((s) => s.id === body.sessionId);
136
+ if (!target || target.username !== userSession.username) {
137
+ sendJson(res, 404, { error: 'Session not found' });
138
+ return;
139
+ }
140
+ }
141
+ }
142
+ killSession(body.sessionId);
143
+ sendJson(res, 200, { killed: true });
144
+ });
145
+ // ── WebSocket upgrade handler (using 'ws' library) ─────
146
+ /** Shared WebSocketServer instance — noServer mode lets us handle upgrade manually. */
147
+ const wss = new WebSocketServer({ noServer: true });
148
+ /**
149
+ * Handle a WebSocket upgrade request for a terminal session.
150
+ * URL: /ws/terminal?session=<id>&token=<authToken>
151
+ *
152
+ * Auth flow: vault password → origin check → HMAC token → session existence.
153
+ * Then ws library handles the protocol handshake.
154
+ */
155
+ export function handleTerminalUpgrade(req, socket, head, userSession) {
156
+ void userSession;
157
+ const password = getSessionPassword();
158
+ if (!password) {
159
+ socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
160
+ socket.destroy();
161
+ return;
162
+ }
163
+ // SEC-001: Origin validation
164
+ const origin = req.headers.origin || '';
165
+ const port = getServerPort();
166
+ const allowedOrigins = [`http://127.0.0.1:${port}`, `http://localhost:${port}`];
167
+ const remoteHost = getServerHost();
168
+ if (remoteHost) {
169
+ allowedOrigins.push(`https://${remoteHost}`);
170
+ }
171
+ if (!origin || !allowedOrigins.includes(origin)) {
172
+ socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
173
+ socket.destroy();
174
+ return;
175
+ }
176
+ const url = new URL(req.url || '', 'http://localhost');
177
+ const sessionId = url.searchParams.get('session');
178
+ if (!sessionId) {
179
+ socket.write('HTTP/1.1 400 Bad Request\r\n\r\n');
180
+ socket.destroy();
181
+ return;
182
+ }
183
+ // SEC-002: Validate per-session auth token
184
+ const token = url.searchParams.get('token');
185
+ const expectedToken = createHmac('sha256', TERMINAL_HMAC_KEY).update(sessionId).digest('hex');
186
+ if (!token || token.length !== expectedToken.length || !timingSafeEqual(Buffer.from(token), Buffer.from(expectedToken))) {
187
+ socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
188
+ socket.destroy();
189
+ return;
190
+ }
191
+ // Verify session exists
192
+ const sessions = listSessions();
193
+ if (!sessions.find((s) => s.id === sessionId)) {
194
+ socket.write('HTTP/1.1 404 Not Found\r\n\r\n');
195
+ socket.destroy();
196
+ return;
197
+ }
198
+ // Let the ws library handle the WebSocket handshake
199
+ wss.handleUpgrade(req, socket, head, (ws) => {
200
+ // Subscribe to PTY output → send to browser
201
+ const unsubscribe = onSessionData(sessionId, (data) => {
202
+ if (ws.readyState === WebSocket.OPEN) {
203
+ try {
204
+ ws.send(data);
205
+ }
206
+ catch { /* client gone */ }
207
+ }
208
+ });
209
+ // Browser → PTY: keystrokes and control messages
210
+ ws.on('message', (raw) => {
211
+ const msg = typeof raw === 'string' ? raw : raw.toString('utf-8');
212
+ // JSON control messages (resize)
213
+ if (msg.startsWith('{')) {
214
+ try {
215
+ const parsed = JSON.parse(msg);
216
+ // IG-R2: Validate numeric types to prevent NaN propagation to node-pty
217
+ if (parsed.type === 'resize' && typeof parsed.cols === 'number' && typeof parsed.rows === 'number'
218
+ && Number.isFinite(parsed.cols) && Number.isFinite(parsed.rows)) {
219
+ resizeSession(sessionId, parsed.cols, parsed.rows);
220
+ return;
221
+ }
222
+ }
223
+ catch { /* not JSON — treat as keystroke input */ }
224
+ }
225
+ // Regular input → PTY
226
+ try {
227
+ writeToSession(sessionId, msg);
228
+ }
229
+ catch {
230
+ ws.close();
231
+ }
232
+ });
233
+ ws.on('close', () => {
234
+ unsubscribe();
235
+ // Don't kill session — allow reconnection. Idle timeout handles cleanup.
236
+ });
237
+ ws.on('error', () => {
238
+ unsubscribe();
239
+ });
240
+ });
241
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Users API — Multi-user management endpoints.
3
+ * All user management requires admin role.
4
+ * Invite completion is public (token-authenticated).
5
+ */
6
+ export {};
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Users API — Multi-user management endpoints.
3
+ * All user management requires admin role.
4
+ * Invite completion is public (token-authenticated).
5
+ */
6
+ import { addRoute } from '../router.js';
7
+ import { parseJsonBody } from '../lib/body-parser.js';
8
+ import { validateSession, parseSessionCookie, isRemoteMode, getClientIp, checkRateLimit, isValidUsername, } from '../lib/tower-auth.js';
9
+ import { createInvite, completeInvite, removeUser, updateUserRole, listUsers, hasRole, isValidRole, } from '../lib/user-manager.js';
10
+ import { audit } from '../lib/audit-log.js';
11
+ import { removeUserFromAllProjects } from '../lib/project-registry.js';
12
+ import { sendJson } from '../lib/http-helpers.js';
13
+ /** Extract and validate session from request. Returns null if not authenticated. */
14
+ function getSession(req) {
15
+ const token = parseSessionCookie(req.headers.cookie);
16
+ const ip = getClientIp(req);
17
+ if (!token)
18
+ return null;
19
+ return validateSession(token, ip);
20
+ }
21
+ // GET /api/users — List all users (admin only)
22
+ addRoute('GET', '/api/users', async (req, res) => {
23
+ if (!isRemoteMode()) {
24
+ sendJson(res, 400, { success: false, error: 'User management requires remote mode' });
25
+ return;
26
+ }
27
+ const session = getSession(req);
28
+ if (!session) {
29
+ sendJson(res, 401, { success: false, error: 'Authentication required' });
30
+ return;
31
+ }
32
+ if (!hasRole(session, 'admin')) {
33
+ const ip = getClientIp(req);
34
+ await audit('access_denied', ip, session.username, { action: 'list_users' });
35
+ sendJson(res, 404, { success: false, error: 'Not found' });
36
+ return;
37
+ }
38
+ const users = await listUsers();
39
+ sendJson(res, 200, { success: true, data: { users } });
40
+ });
41
+ // POST /api/users/invite — Create invitation (admin only)
42
+ addRoute('POST', '/api/users/invite', async (req, res) => {
43
+ if (!isRemoteMode()) {
44
+ sendJson(res, 400, { success: false, error: 'User management requires remote mode' });
45
+ return;
46
+ }
47
+ const session = getSession(req);
48
+ if (!session) {
49
+ sendJson(res, 401, { success: false, error: 'Authentication required' });
50
+ return;
51
+ }
52
+ // Admin check at route level (defense-in-depth — createInvite also checks)
53
+ if (!hasRole(session, 'admin')) {
54
+ const ip = getClientIp(req);
55
+ await audit('access_denied', ip, session.username, { action: 'create_invite' });
56
+ sendJson(res, 404, { success: false, error: 'Not found' });
57
+ return;
58
+ }
59
+ const body = await parseJsonBody(req);
60
+ if (typeof body !== 'object' || body === null) {
61
+ sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
62
+ return;
63
+ }
64
+ const { role } = body;
65
+ if (typeof role !== 'string' || !isValidRole(role)) {
66
+ sendJson(res, 400, { success: false, error: 'role must be one of: admin, deployer, viewer' });
67
+ return;
68
+ }
69
+ const ip = getClientIp(req);
70
+ try {
71
+ const invite = await createInvite(role, session, ip);
72
+ sendJson(res, 201, { success: true, data: invite });
73
+ }
74
+ catch (err) {
75
+ const message = err instanceof Error ? err.message : 'Failed to create invite';
76
+ if (message === 'Too many pending invites' || message === 'Invalid role') {
77
+ sendJson(res, 400, { success: false, error: message });
78
+ }
79
+ else {
80
+ sendJson(res, 400, { success: false, error: 'Failed to create invite' });
81
+ }
82
+ }
83
+ });
84
+ // POST /api/users/complete-invite — New user completes invitation setup
85
+ addRoute('POST', '/api/users/complete-invite', async (req, res) => {
86
+ if (!isRemoteMode()) {
87
+ sendJson(res, 400, { success: false, error: 'User management requires remote mode' });
88
+ return;
89
+ }
90
+ // Rate limit — this is a public endpoint (auth-exempt)
91
+ const ip = getClientIp(req);
92
+ const rateCheck = checkRateLimit(ip);
93
+ if (!rateCheck.allowed) {
94
+ sendJson(res, 429, { success: false, error: 'Too many attempts. Try again later.' });
95
+ return;
96
+ }
97
+ const body = await parseJsonBody(req);
98
+ if (typeof body !== 'object' || body === null) {
99
+ sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
100
+ return;
101
+ }
102
+ const { token, username, password } = body;
103
+ if (typeof token !== 'string' || token.length !== 64) {
104
+ sendJson(res, 400, { success: false, error: 'Invalid invite token' });
105
+ return;
106
+ }
107
+ if (typeof username !== 'string' || !isValidUsername(username.trim())) {
108
+ sendJson(res, 400, { success: false, error: 'Username must be 3-64 characters (letters, numbers, . _ -)' });
109
+ return;
110
+ }
111
+ if (typeof password !== 'string' || password.length < 12 || password.length > 256) {
112
+ sendJson(res, 400, { success: false, error: 'Password must be 12-256 characters' });
113
+ return;
114
+ }
115
+ try {
116
+ const result = await completeInvite(token, username.trim(), password, ip);
117
+ sendJson(res, 201, {
118
+ success: true,
119
+ data: {
120
+ totpSecret: result.totpSecret,
121
+ totpUri: result.totpUri,
122
+ role: result.role,
123
+ message: 'Scan the QR code with your authenticator app.',
124
+ },
125
+ }, true); // no-cache — TOTP secret must not be cached
126
+ }
127
+ catch (err) {
128
+ const message = err instanceof Error ? err.message : 'Failed to complete invite';
129
+ if (message === 'Invalid or expired invite') {
130
+ sendJson(res, 404, { success: false, error: 'Invalid or expired invite' });
131
+ }
132
+ else if (message === 'Username already taken') {
133
+ sendJson(res, 409, { success: false, error: 'Username already taken' });
134
+ }
135
+ else {
136
+ sendJson(res, 400, { success: false, error: 'Failed to complete setup' });
137
+ }
138
+ }
139
+ });
140
+ // POST /api/users/remove — Remove a user (admin only)
141
+ addRoute('POST', '/api/users/remove', async (req, res) => {
142
+ if (!isRemoteMode()) {
143
+ sendJson(res, 400, { success: false, error: 'User management requires remote mode' });
144
+ return;
145
+ }
146
+ const session = getSession(req);
147
+ if (!session) {
148
+ sendJson(res, 401, { success: false, error: 'Authentication required' });
149
+ return;
150
+ }
151
+ if (!hasRole(session, 'admin')) {
152
+ const ip = getClientIp(req);
153
+ await audit('access_denied', ip, session.username, { action: 'remove_user' });
154
+ sendJson(res, 404, { success: false, error: 'Not found' });
155
+ return;
156
+ }
157
+ const body = await parseJsonBody(req);
158
+ if (typeof body !== 'object' || body === null) {
159
+ sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
160
+ return;
161
+ }
162
+ const { username } = body;
163
+ if (typeof username !== 'string' || username.trim().length === 0) {
164
+ sendJson(res, 400, { success: false, error: 'username is required' });
165
+ return;
166
+ }
167
+ // Prevent self-deletion
168
+ if (username.trim() === session.username) {
169
+ sendJson(res, 400, { success: false, error: 'Cannot remove yourself' });
170
+ return;
171
+ }
172
+ const ip = getClientIp(req);
173
+ try {
174
+ await removeUser(username.trim());
175
+ // Clean up project access entries for the removed user
176
+ const cleanedProjects = await removeUserFromAllProjects(username.trim());
177
+ await audit('user_remove', ip, session.username, { target: username.trim(), projectsCleanedUp: cleanedProjects });
178
+ sendJson(res, 200, { success: true });
179
+ }
180
+ catch (err) {
181
+ const message = err instanceof Error ? err.message : 'Failed to remove user';
182
+ if (message === 'User not found' || message === 'Cannot remove the last admin') {
183
+ sendJson(res, 400, { success: false, error: message });
184
+ }
185
+ else {
186
+ sendJson(res, 400, { success: false, error: 'Failed to remove user' });
187
+ }
188
+ }
189
+ });
190
+ // POST /api/users/role — Change a user's role (admin only)
191
+ addRoute('POST', '/api/users/role', async (req, res) => {
192
+ if (!isRemoteMode()) {
193
+ sendJson(res, 400, { success: false, error: 'User management requires remote mode' });
194
+ return;
195
+ }
196
+ const session = getSession(req);
197
+ if (!session) {
198
+ sendJson(res, 401, { success: false, error: 'Authentication required' });
199
+ return;
200
+ }
201
+ if (!hasRole(session, 'admin')) {
202
+ const ip = getClientIp(req);
203
+ await audit('access_denied', ip, session.username, { action: 'change_role' });
204
+ sendJson(res, 404, { success: false, error: 'Not found' });
205
+ return;
206
+ }
207
+ const body = await parseJsonBody(req);
208
+ if (typeof body !== 'object' || body === null) {
209
+ sendJson(res, 400, { success: false, error: 'Request body must be a JSON object' });
210
+ return;
211
+ }
212
+ const { username, role } = body;
213
+ if (typeof username !== 'string' || username.trim().length === 0) {
214
+ sendJson(res, 400, { success: false, error: 'username is required' });
215
+ return;
216
+ }
217
+ if (typeof role !== 'string' || !isValidRole(role)) {
218
+ sendJson(res, 400, { success: false, error: 'role must be one of: admin, deployer, viewer' });
219
+ return;
220
+ }
221
+ // Prevent self-demotion (accidental lockout)
222
+ if (username.trim() === session.username && role !== session.role) {
223
+ sendJson(res, 400, { success: false, error: 'Cannot change your own role' });
224
+ return;
225
+ }
226
+ const ip = getClientIp(req);
227
+ try {
228
+ await updateUserRole(username.trim(), role);
229
+ await audit('role_change', ip, session.username, {
230
+ target: username.trim(),
231
+ newRole: role,
232
+ });
233
+ sendJson(res, 200, { success: true });
234
+ }
235
+ catch (err) {
236
+ const message = err instanceof Error ? err.message : 'Failed to update role';
237
+ if (message === 'User not found' || message === 'Cannot demote the last admin') {
238
+ sendJson(res, 400, { success: false, error: message });
239
+ }
240
+ else {
241
+ sendJson(res, 400, { success: false, error: 'Failed to update role' });
242
+ }
243
+ }
244
+ });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * War Room API — Alternative dashboard view using shared data parsers.
3
+ *
4
+ * Shares all parsers and WebSocket infra with Danger Room via wizard/lib/dashboard-*.ts.
5
+ * Routes are registered under /api/war-room/* for the war-room.html frontend.
6
+ */
7
+ import type { IncomingMessage } from 'node:http';
8
+ import type { Duplex } from 'node:stream';
9
+ export declare const broadcastWarRoom: (data: {
10
+ type: string;
11
+ [key: string]: unknown;
12
+ }) => void;
13
+ export declare const closeWarRoom: () => void;
14
+ export declare const handleWarRoomUpgrade: (req: IncomingMessage, socket: Duplex, head: Buffer) => void;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * War Room API — Alternative dashboard view using shared data parsers.
3
+ *
4
+ * Shares all parsers and WebSocket infra with Danger Room via wizard/lib/dashboard-*.ts.
5
+ * Routes are registered under /api/war-room/* for the war-room.html frontend.
6
+ */
7
+ import { addRoute } from '../router.js';
8
+ import { sendJson } from '../lib/http-helpers.js';
9
+ import { parseCampaignState, parseBuildState, parseFindings, readDeployLog, readVersion, readContextStats, } from '../lib/dashboard-data.js';
10
+ import { createDashboardWs } from '../lib/dashboard-ws.js';
11
+ // ── WebSocket ───────────────────────────────────
12
+ const ws = createDashboardWs('War Room');
13
+ export const broadcastWarRoom = ws.broadcast;
14
+ export const closeWarRoom = ws.close;
15
+ export const handleWarRoomUpgrade = (req, socket, head) => ws.handleUpgrade(req, socket, head);
16
+ // ── REST endpoints ──────────────────────────────
17
+ addRoute('GET', '/api/war-room/campaign', async (_req, res) => {
18
+ sendJson(res, 200, await parseCampaignState());
19
+ });
20
+ addRoute('GET', '/api/war-room/build', async (_req, res) => {
21
+ sendJson(res, 200, await parseBuildState());
22
+ });
23
+ addRoute('GET', '/api/war-room/findings', async (_req, res) => {
24
+ sendJson(res, 200, await parseFindings());
25
+ });
26
+ addRoute('GET', '/api/war-room/version', async (_req, res) => {
27
+ sendJson(res, 200, await readVersion());
28
+ });
29
+ addRoute('GET', '/api/war-room/deploy', async (_req, res) => {
30
+ sendJson(res, 200, await readDeployLog());
31
+ });
32
+ addRoute('GET', '/api/war-room/context', async (_req, res) => {
33
+ const stats = await readContextStats();
34
+ sendJson(res, 200, stats);
35
+ });
36
+ addRoute('GET', '/api/war-room/experiments', async (_req, res) => {
37
+ try {
38
+ const { listExperiments } = await import('../lib/experiment.js');
39
+ const experiments = await listExperiments();
40
+ sendJson(res, 200, { experiments, total: experiments.length });
41
+ }
42
+ catch {
43
+ sendJson(res, 200, { experiments: [], total: 0 });
44
+ }
45
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Ad platform core — re-exports from the ad-platform-adapter pattern for wizard runtime use.
3
+ * ARCH-R2-012: Production code should not import from docs/patterns/ directly.
4
+ */
5
+ export type { AdPlatformSetup, AdPlatformAdapter, ReadOnlyAdapter, CampaignConfig, CampaignResult, CampaignUpdate, CreativeConfig, SpendReport, PerformanceMetrics, InsightData, OAuthTokens, ConnectionStatus, PlatformError, Cents, Percentage, Ratio, AdPlatform, } from './patterns/ad-platform-adapter.js';
6
+ export { toCents, toDollars } from './patterns/ad-platform-adapter.js';
@@ -0,0 +1 @@
1
+ export { toCents, toDollars } from './patterns/ad-platform-adapter.js';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Ad Platform Adapter Registry
3
+ *
4
+ * v17.0 No Stubs Doctrine: only fully-implemented adapters are exported.
5
+ * Stub files (meta, google, tiktok, linkedin, twitter, reddit, mercury, brex)
6
+ * were deleted — they contained 77 `throw new Error('Implement...')` calls.
7
+ * These adapters will be implemented when developer accounts are available (v17.1+).
8
+ * See ROADMAP.md for the planned adapter list.
9
+ *
10
+ * Available adapters:
11
+ * - SandboxSetup/SandboxAdapter — full implementation with realistic fake data
12
+ * - SandboxBankAdapter — full implementation for bank/revenue demo
13
+ * - StripeAdapter — real Stripe API via node:https (free test mode)
14
+ *
15
+ * PRD Reference: §9.5, §9.19.10, §9.20.4, §8.1 (Implementation Completeness Policy)
16
+ */
17
+ export { SandboxSetup, SandboxAdapter } from './sandbox.js';
18
+ export { SandboxBankAdapter } from './sandbox-bank.js';
19
+ export { StripeAdapter } from './stripe.js';
20
+ export type { AdPlatform } from './types.js';
21
+ import type { AdPlatform } from './types.js';
22
+ type PlatformInfo = {
23
+ name: string;
24
+ minBudgetCents: number;
25
+ sandbox?: boolean;
26
+ implemented: boolean;
27
+ };
28
+ /** Platform registry — tracks both available and planned adapters. */
29
+ export declare const PLATFORM_REGISTRY: Record<AdPlatform | 'sandbox', PlatformInfo>;
30
+ /** Revenue adapters — only those with real implementations. */
31
+ export declare const REVENUE_ADAPTERS: {
32
+ readonly sandbox: {
33
+ readonly name: "Sandbox Bank (Demo)";
34
+ readonly implemented: true;
35
+ };
36
+ readonly stripe: {
37
+ readonly name: "Stripe";
38
+ readonly implemented: true;
39
+ };
40
+ readonly paddle: {
41
+ readonly name: "Paddle";
42
+ readonly implemented: false;
43
+ };
44
+ readonly mercury: {
45
+ readonly name: "Mercury";
46
+ readonly implemented: false;
47
+ };
48
+ readonly brex: {
49
+ readonly name: "Brex";
50
+ readonly implemented: false;
51
+ };
52
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Ad Platform Adapter Registry
3
+ *
4
+ * v17.0 No Stubs Doctrine: only fully-implemented adapters are exported.
5
+ * Stub files (meta, google, tiktok, linkedin, twitter, reddit, mercury, brex)
6
+ * were deleted — they contained 77 `throw new Error('Implement...')` calls.
7
+ * These adapters will be implemented when developer accounts are available (v17.1+).
8
+ * See ROADMAP.md for the planned adapter list.
9
+ *
10
+ * Available adapters:
11
+ * - SandboxSetup/SandboxAdapter — full implementation with realistic fake data
12
+ * - SandboxBankAdapter — full implementation for bank/revenue demo
13
+ * - StripeAdapter — real Stripe API via node:https (free test mode)
14
+ *
15
+ * PRD Reference: §9.5, §9.19.10, §9.20.4, §8.1 (Implementation Completeness Policy)
16
+ */
17
+ export { SandboxSetup, SandboxAdapter } from './sandbox.js';
18
+ export { SandboxBankAdapter } from './sandbox-bank.js';
19
+ export { StripeAdapter } from './stripe.js';
20
+ /** Platform registry — tracks both available and planned adapters. */
21
+ export const PLATFORM_REGISTRY = {
22
+ sandbox: { name: 'Sandbox (Demo)', minBudgetCents: 0, sandbox: true, implemented: true },
23
+ meta: { name: 'Meta (Facebook/Instagram)', minBudgetCents: 100, implemented: false },
24
+ google: { name: 'Google Ads', minBudgetCents: 100, implemented: false },
25
+ tiktok: { name: 'TikTok', minBudgetCents: 2000, implemented: false },
26
+ linkedin: { name: 'LinkedIn', minBudgetCents: 1000, implemented: false },
27
+ twitter: { name: 'Twitter/X', minBudgetCents: 100, implemented: false },
28
+ reddit: { name: 'Reddit', minBudgetCents: 500, implemented: false },
29
+ snap: { name: 'Snapchat', minBudgetCents: 500, implemented: false },
30
+ };
31
+ /** Revenue adapters — only those with real implementations. */
32
+ export const REVENUE_ADAPTERS = {
33
+ sandbox: { name: 'Sandbox Bank (Demo)', implemented: true },
34
+ stripe: { name: 'Stripe', implemented: true },
35
+ paddle: { name: 'Paddle', implemented: false },
36
+ mercury: { name: 'Mercury', implemented: false },
37
+ brex: { name: 'Brex', implemented: false },
38
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Sandbox Bank Adapter — full implementation for development/demo.
3
+ *
4
+ * Implements RevenueSourceAdapter with realistic fake financial data.
5
+ * Every method returns valid-shaped data. No throws.
6
+ * This IS a full implementation for a sandbox bank (No Stubs Doctrine, v17.0).
7
+ */
8
+ import type { RevenueSourceAdapter, RevenueCredentials, ConnectionResult, TransactionPage, BalanceResult, DateRange } from '../revenue-types.js';
9
+ export declare class SandboxBankAdapter implements RevenueSourceAdapter {
10
+ private accountName;
11
+ private balanceCents;
12
+ constructor(label?: string, initialBalanceCents?: number);
13
+ connect(credentials: RevenueCredentials): Promise<ConnectionResult>;
14
+ getTransactions(dateRange: DateRange, cursor?: string): Promise<TransactionPage>;
15
+ getBalance(): Promise<BalanceResult>;
16
+ detectCurrency(_credentials: RevenueCredentials): Promise<string>;
17
+ }