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,363 @@
1
+ import { request as httpsRequest } from 'node:https';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { addRoute } from '../router.js';
5
+ import { vaultGet } from '../lib/vault.js';
6
+ import { getSessionPassword } from './credentials.js';
7
+ import { resolveModelWithLimits } from '../lib/anthropic.js';
8
+ import { parseFrontmatter, validateFrontmatter } from '../lib/frontmatter.js';
9
+ import { parseJsonBody } from '../lib/body-parser.js';
10
+ import { listTemplates, getTemplate } from '../lib/templates.js';
11
+ import { sendJson } from '../lib/http-helpers.js';
12
+ /**
13
+ * Extract the prompt from inside the outer ``` fence after "## The Prompt".
14
+ * Tracks fence nesting so inner ```yaml / ``` pairs don't end extraction early.
15
+ */
16
+ function extractFencedPrompt(markdown) {
17
+ const promptIdx = markdown.indexOf('## The Prompt');
18
+ if (promptIdx === -1)
19
+ return markdown;
20
+ const afterHeading = markdown.slice(promptIdx);
21
+ // Find the opening fence (a line that is exactly ```)
22
+ const openMatch = afterHeading.match(/\n```\s*\n/);
23
+ if (!openMatch || openMatch.index === undefined)
24
+ return markdown;
25
+ const contentStart = promptIdx + openMatch.index + openMatch[0].length;
26
+ const lines = markdown.slice(contentStart).split('\n');
27
+ const resultLines = [];
28
+ let depth = 0;
29
+ for (const line of lines) {
30
+ // Opening fence: ```something or just ```
31
+ if (/^```\S/.test(line)) {
32
+ depth++;
33
+ resultLines.push(line);
34
+ continue;
35
+ }
36
+ // Closing fence: exactly ```
37
+ if (/^```\s*$/.test(line)) {
38
+ if (depth > 0) {
39
+ depth--;
40
+ resultLines.push(line);
41
+ continue;
42
+ }
43
+ // depth === 0 means this closes the outer fence
44
+ break;
45
+ }
46
+ resultLines.push(line);
47
+ }
48
+ return resultLines.join('\n').trim();
49
+ }
50
+ // POST /api/prd/validate — validate PRD content
51
+ addRoute('POST', '/api/prd/validate', async (req, res) => {
52
+ const body = await parseJsonBody(req);
53
+ if (!body.content || typeof body.content !== 'string') {
54
+ sendJson(res, 400, { error: 'content is required' });
55
+ return;
56
+ }
57
+ const { frontmatter } = parseFrontmatter(body.content);
58
+ const errors = validateFrontmatter(frontmatter);
59
+ sendJson(res, 200, {
60
+ valid: errors.length === 0,
61
+ errors,
62
+ frontmatter,
63
+ });
64
+ });
65
+ // POST /api/prd/generate — generate PRD from idea using Claude
66
+ addRoute('POST', '/api/prd/generate', async (req, res) => {
67
+ const body = await parseJsonBody(req);
68
+ if (!body.idea || typeof body.idea !== 'string') {
69
+ sendJson(res, 400, { error: 'idea is required' });
70
+ return;
71
+ }
72
+ const password = getSessionPassword();
73
+ if (!password) {
74
+ sendJson(res, 401, { error: 'Vault is locked. Unlock with your password first.' });
75
+ return;
76
+ }
77
+ const apiKey = await vaultGet(password, 'anthropic-api-key');
78
+ if (!apiKey) {
79
+ sendJson(res, 400, { error: 'Anthropic API key not configured. Complete step 1 first.' });
80
+ return;
81
+ }
82
+ // Load the PRD generator prompt
83
+ const promptPath = join(import.meta.dirname, '..', '..', 'docs', 'methods', 'PRD_GENERATOR.md');
84
+ let generatorPrompt;
85
+ try {
86
+ generatorPrompt = await readFile(promptPath, 'utf-8');
87
+ }
88
+ catch {
89
+ sendJson(res, 500, { error: 'Could not load PRD generator prompt' });
90
+ return;
91
+ }
92
+ // Extract prompt from inside the outer ``` fence block after "## The Prompt"
93
+ const basePrompt = extractFencedPrompt(generatorPrompt);
94
+ // Build the idea with any preferences
95
+ let userIdea = body.idea;
96
+ const prefs = [];
97
+ if (body.name)
98
+ prefs.push(`Project name: ${body.name}`);
99
+ if (body.framework)
100
+ prefs.push(`Framework preference: ${body.framework}`);
101
+ if (body.database)
102
+ prefs.push(`Database preference: ${body.database}`);
103
+ if (body.deploy)
104
+ prefs.push(`Deploy target: ${body.deploy}`);
105
+ if (prefs.length > 0) {
106
+ userIdea += '\n\nPreferences:\n' + prefs.join('\n');
107
+ }
108
+ // Resolve the best available model with its max output capacity
109
+ const { id: model, maxTokens } = await resolveModelWithLimits(apiKey);
110
+ // Stream response via SSE
111
+ res.writeHead(200, {
112
+ 'Content-Type': 'text/event-stream',
113
+ 'Cache-Control': 'no-cache',
114
+ 'Connection': 'keep-alive',
115
+ });
116
+ const postData = JSON.stringify({
117
+ model,
118
+ max_tokens: maxTokens,
119
+ stream: true,
120
+ messages: [
121
+ {
122
+ role: 'user',
123
+ content: `${basePrompt}\n\nTHE PRODUCT IDEA:\n${userIdea}`,
124
+ },
125
+ ],
126
+ });
127
+ let clientDisconnected = false;
128
+ /** Safe write — no-op if client already disconnected */
129
+ function sseWrite(chunk) {
130
+ if (clientDisconnected || res.writableEnded)
131
+ return;
132
+ try {
133
+ res.write(chunk);
134
+ }
135
+ catch {
136
+ clientDisconnected = true;
137
+ }
138
+ }
139
+ function sseEnd() {
140
+ if (clientDisconnected || res.writableEnded)
141
+ return;
142
+ try {
143
+ res.end();
144
+ }
145
+ catch { /* already closed */ }
146
+ }
147
+ req.on('close', () => {
148
+ clientDisconnected = true;
149
+ clearInterval(keepaliveTimer);
150
+ apiReq.destroy();
151
+ });
152
+ // SSE keepalive — prevents proxy/VPN/browser timeout during generation
153
+ const keepaliveTimer = setInterval(() => {
154
+ sseWrite(': keepalive\n\n');
155
+ }, 15000);
156
+ const apiReq = httpsRequest({
157
+ hostname: 'api.anthropic.com',
158
+ path: '/v1/messages',
159
+ method: 'POST',
160
+ headers: {
161
+ 'Content-Type': 'application/json',
162
+ 'x-api-key': apiKey,
163
+ 'anthropic-version': '2023-06-01',
164
+ 'Content-Length': Buffer.byteLength(postData),
165
+ },
166
+ timeout: 120000,
167
+ }, (apiRes) => {
168
+ if (apiRes.statusCode !== 200) {
169
+ let errBody = '';
170
+ apiRes.on('data', (chunk) => { errBody += chunk.toString(); });
171
+ apiRes.on('end', () => {
172
+ clearInterval(keepaliveTimer);
173
+ sseWrite(`data: ${JSON.stringify({ error: `API error: ${apiRes.statusCode}` })}\n\n`);
174
+ sseWrite('data: [DONE]\n\n');
175
+ sseEnd();
176
+ });
177
+ return;
178
+ }
179
+ let buffer = '';
180
+ let stopReason = null;
181
+ apiRes.on('data', (chunk) => {
182
+ buffer += chunk.toString();
183
+ const lines = buffer.split('\n');
184
+ buffer = lines.pop() ?? '';
185
+ for (const line of lines) {
186
+ if (!line.startsWith('data: '))
187
+ continue;
188
+ const data = line.slice(6);
189
+ if (data === '[DONE]')
190
+ continue;
191
+ try {
192
+ const event = JSON.parse(data);
193
+ if (event.type === 'content_block_delta' && event.delta?.text) {
194
+ sseWrite(`data: ${JSON.stringify({ text: event.delta.text })}\n\n`);
195
+ }
196
+ if (event.type === 'message_delta' && event.delta?.stop_reason) {
197
+ stopReason = event.delta.stop_reason;
198
+ }
199
+ }
200
+ catch {
201
+ // Skip unparseable chunks
202
+ }
203
+ }
204
+ });
205
+ apiRes.on('end', () => {
206
+ clearInterval(keepaliveTimer);
207
+ if (stopReason === 'max_tokens') {
208
+ sseWrite(`data: ${JSON.stringify({ truncated: true })}\n\n`);
209
+ }
210
+ sseWrite('data: [DONE]\n\n');
211
+ sseEnd();
212
+ });
213
+ });
214
+ apiReq.on('error', (err) => {
215
+ clearInterval(keepaliveTimer);
216
+ sseWrite(`data: ${JSON.stringify({ error: 'Generation failed' })}\n\n`);
217
+ sseWrite('data: [DONE]\n\n');
218
+ sseEnd();
219
+ });
220
+ apiReq.write(postData);
221
+ apiReq.end();
222
+ });
223
+ // POST /api/prd/env-requirements — parse PRD for project-specific credentials
224
+ addRoute('POST', '/api/prd/env-requirements', async (req, res) => {
225
+ const body = await parseJsonBody(req);
226
+ if (!body.content || typeof body.content !== 'string') {
227
+ sendJson(res, 400, { error: 'content is required' });
228
+ return;
229
+ }
230
+ const groups = parseEnvRequirements(body.content);
231
+ sendJson(res, 200, { groups });
232
+ });
233
+ /**
234
+ * Env vars that are auto-generated, infrastructure, or app config — never collect from user.
235
+ * These are either provisioned by the deploy pipeline, generated at build time,
236
+ * or derived from project config. Generic across all projects.
237
+ */
238
+ const SKIP_VARS = new Set([
239
+ // App config (derived from project setup)
240
+ 'NODE_ENV', 'PORT',
241
+ 'NEXT_PUBLIC_APP_URL', 'NEXT_PUBLIC_APP_NAME',
242
+ // Infrastructure (provisioned by deploy pipeline)
243
+ 'DATABASE_URL', 'REDIS_URL', 'REDIS_PASSWORD',
244
+ // Secrets (auto-generated at build time)
245
+ 'SESSION_SECRET', 'SESSION_COOKIE_NAME', 'SESSION_TTL_DAYS',
246
+ 'CSRF_SECRET',
247
+ // Storage (provisioned by deploy pipeline)
248
+ 'S3_ENDPOINT', 'S3_ACCESS_KEY', 'S3_SECRET_KEY', 'S3_BUCKET_NAME',
249
+ 'S3_REGION', 'S3_PUBLIC_URL',
250
+ ]);
251
+ /** Prefixes that indicate feature flags — always skip. */
252
+ const SKIP_PREFIXES = ['ENABLE_'];
253
+ function parseEnvRequirements(prdContent) {
254
+ // Find the env vars section — look for a block with multiple VAR="value" lines
255
+ const lines = prdContent.split('\n');
256
+ const groups = [];
257
+ let currentGroup = null;
258
+ for (const line of lines) {
259
+ // Detect section headers like "# ─── WhatsApp Business API ───────"
260
+ const headerMatch = line.match(/^#\s*[─\-]+\s*(.+?)\s*[─\-]*$/);
261
+ if (headerMatch) {
262
+ const name = headerMatch[1].trim();
263
+ currentGroup = { name, fields: [] };
264
+ groups.push(currentGroup);
265
+ continue;
266
+ }
267
+ // Detect env var assignments: VAR_NAME="value" or VAR_NAME=value
268
+ const varMatch = line.match(/^([A-Z][A-Z0-9_]+)=["']?(.*?)["']?\s*(?:#.*)?$/);
269
+ if (!varMatch || !currentGroup)
270
+ continue;
271
+ const [, key, rawValue] = varMatch;
272
+ // Skip auto-generated / infrastructure / tuning vars
273
+ if (SKIP_VARS.has(key))
274
+ continue;
275
+ if (SKIP_PREFIXES.some((p) => key.startsWith(p)))
276
+ continue;
277
+ const value = rawValue.trim();
278
+ // Skip tuning params — values that are purely numeric, boolean, or duration-like
279
+ // These are config knobs, not API credentials (e.g., MAX_RETRIES="5", TIMEOUT_MS="30000")
280
+ if (/^\d+$/.test(value) || value === 'true' || value === 'false')
281
+ continue;
282
+ // Skip if the value looks like a real config URL (not a placeholder)
283
+ const isApiUrl = key.endsWith('_API_URL') || key.endsWith('_URL');
284
+ if (isApiUrl && value.startsWith('http'))
285
+ continue;
286
+ // Only collect vars that look like they need user-provided values
287
+ // (empty, placeholder prefixes, or common API key patterns)
288
+ const isPlaceholder = !value
289
+ || value.includes('your-')
290
+ || value.includes('your_')
291
+ || /^(sk-|pk\.|AIza|re_|ghp_)/.test(value)
292
+ || value.endsWith('...')
293
+ || value.startsWith('Bearer ');
294
+ if (!isPlaceholder && value.length > 0)
295
+ continue;
296
+ // Determine if this is a secret field
297
+ const secretPatterns = ['KEY', 'SECRET', 'TOKEN', 'PASSWORD'];
298
+ const isSecret = secretPatterns.some((p) => key.includes(p));
299
+ // Generate human-readable label from var name
300
+ const label = key
301
+ .replace(/_/g, ' ')
302
+ .replace(/\b\w/g, (c) => c.toUpperCase())
303
+ .replace(/\bApi\b/g, 'API')
304
+ .replace(/\bUrl\b/g, 'URL')
305
+ .replace(/\bId\b/g, 'ID')
306
+ .replace(/\bSdk\b/g, 'SDK')
307
+ .replace(/\bApp\b/g, 'App');
308
+ currentGroup.fields.push({
309
+ key,
310
+ label,
311
+ placeholder: value || key.toLowerCase().replace(/_/g, '-'),
312
+ secret: isSecret,
313
+ });
314
+ }
315
+ // Filter out empty groups
316
+ return groups.filter((g) => g.fields.length > 0);
317
+ }
318
+ // GET /api/prd/template — return the PRD template
319
+ addRoute('GET', '/api/prd/template', async (_req, res) => {
320
+ const templatePath = join(import.meta.dirname, '..', '..', 'docs', 'PRD.md');
321
+ try {
322
+ const content = await readFile(templatePath, 'utf-8');
323
+ sendJson(res, 200, { content });
324
+ }
325
+ catch {
326
+ sendJson(res, 500, { error: 'Could not load PRD template' });
327
+ }
328
+ });
329
+ // GET /api/prd/prompt — return the PRD generator prompt for use with other AIs
330
+ addRoute('GET', '/api/prd/prompt', async (_req, res) => {
331
+ const promptPath = join(import.meta.dirname, '..', '..', 'docs', 'methods', 'PRD_GENERATOR.md');
332
+ try {
333
+ const content = await readFile(promptPath, 'utf-8');
334
+ sendJson(res, 200, { prompt: extractFencedPrompt(content) });
335
+ }
336
+ catch {
337
+ sendJson(res, 500, { error: 'Could not load PRD generator prompt' });
338
+ }
339
+ });
340
+ // GET /api/prd/templates — list available project templates
341
+ addRoute('GET', '/api/prd/templates', async (_req, res) => {
342
+ sendJson(res, 200, { templates: listTemplates() });
343
+ });
344
+ // GET /api/prd/templates/:id — get a specific template's full PRD content
345
+ addRoute('GET', '/api/prd/templates/get', async (req, res) => {
346
+ const url = new URL(req.url || '', 'http://localhost');
347
+ const id = url.searchParams.get('id');
348
+ if (!id) {
349
+ sendJson(res, 400, { error: 'id query parameter is required' });
350
+ return;
351
+ }
352
+ const template = getTemplate(id);
353
+ if (!template) {
354
+ sendJson(res, 404, { error: `Template not found: ${id}` });
355
+ return;
356
+ }
357
+ // Build a complete PRD with frontmatter
358
+ const frontmatterYaml = Object.entries(template.frontmatter)
359
+ .map(([k, v]) => `${k}: "${v}"`)
360
+ .join('\n');
361
+ const prd = `\`\`\`yaml\nname: "[PROJECT_NAME]"\n${frontmatterYaml}\n\`\`\`\n\n---\n\n${template.prdSections}`;
362
+ sendJson(res, 200, { template: { ...template, prd } });
363
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,239 @@
1
+ import { mkdir, readFile, writeFile, copyFile, readdir, stat } from 'node:fs/promises';
2
+ import { join, resolve } from 'node:path';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { addRoute } from '../router.js';
6
+ import { parseJsonBody } from '../lib/body-parser.js';
7
+ import { addProject } from '../lib/project-registry.js';
8
+ import { validateSession, parseSessionCookie, getClientIp, isRemoteMode } from '../lib/tower-auth.js';
9
+ import { sendJson } from '../lib/http-helpers.js';
10
+ const execFileAsync = promisify(execFile);
11
+ const SCAFFOLD_DIR = resolve(import.meta.dirname, '..', '..');
12
+ function sanitizeDirName(name) {
13
+ return name
14
+ .toLowerCase()
15
+ .replace(/[^a-z0-9\-_]/g, '-')
16
+ .replace(/-+/g, '-')
17
+ .replace(/^-|-$/g, '');
18
+ }
19
+ // POST /api/project/validate — validate project config
20
+ addRoute('POST', '/api/project/validate', async (req, res) => {
21
+ const body = await parseJsonBody(req);
22
+ const errors = [];
23
+ if (!body.name || body.name.trim().length === 0) {
24
+ errors.push('Project name is required');
25
+ }
26
+ if (!body.directory || body.directory.trim().length === 0) {
27
+ errors.push('Project directory is required');
28
+ }
29
+ else {
30
+ const dir = resolve(body.directory);
31
+ try {
32
+ const s = await stat(dir);
33
+ if (s.isDirectory()) {
34
+ const entries = await readdir(dir);
35
+ if (entries.length > 0) {
36
+ errors.push('Directory already exists and is not empty');
37
+ }
38
+ }
39
+ }
40
+ catch {
41
+ // Directory doesn't exist — that's fine
42
+ }
43
+ }
44
+ const suggestedDir = body.name
45
+ ? resolve(process.cwd(), '..', sanitizeDirName(body.name))
46
+ : undefined;
47
+ sendJson(res, 200, { valid: errors.length === 0, errors, suggestedDir });
48
+ });
49
+ /** Recursively copy a directory, excluding specified paths */
50
+ async function copyDir(src, dest, exclude = []) {
51
+ await mkdir(dest, { recursive: true });
52
+ const entries = await readdir(src, { withFileTypes: true });
53
+ for (const entry of entries) {
54
+ const srcPath = join(src, entry.name);
55
+ const destPath = join(dest, entry.name);
56
+ // Check exclusions
57
+ const relative = srcPath.slice(SCAFFOLD_DIR.length + 1);
58
+ if (exclude.some(ex => relative.startsWith(ex))) {
59
+ continue;
60
+ }
61
+ if (entry.isDirectory()) {
62
+ await copyDir(srcPath, destPath, exclude);
63
+ }
64
+ else {
65
+ await copyFile(srcPath, destPath);
66
+ }
67
+ }
68
+ }
69
+ // POST /api/project/create — create the project
70
+ addRoute('POST', '/api/project/create', async (req, res) => {
71
+ const raw = await parseJsonBody(req);
72
+ if (typeof raw !== 'object' || raw === null) {
73
+ sendJson(res, 400, { error: 'Request body must be a JSON object' });
74
+ return;
75
+ }
76
+ const body = raw;
77
+ if (typeof body.name !== 'string' || body.name.trim().length === 0 ||
78
+ typeof body.directory !== 'string' || body.directory.trim().length === 0) {
79
+ sendJson(res, 400, { error: 'name and directory are required strings' });
80
+ return;
81
+ }
82
+ // Coerce optional fields to safe strings (strip newlines for .env injection prevention)
83
+ const safeName = String(body.name).replace(/[\r\n]/g, ' ').trim();
84
+ const safeDir = String(body.directory).trim();
85
+ const safeDescription = typeof body.description === 'string' ? body.description.replace(/[\r\n]/g, ' ').trim() : '';
86
+ const safeDomain = typeof body.domain === 'string' ? body.domain.replace(/[\r\n]/g, '').trim() : '';
87
+ const safeHostname = typeof body.hostname === 'string' ? body.hostname.replace(/[\r\n]/g, '').trim() : '';
88
+ const safeDeploy = typeof body.deploy === 'string' ? body.deploy.replace(/[\r\n]/g, '').trim() : '';
89
+ const safePrd = typeof body.prd === 'string' ? body.prd : '';
90
+ const projectDir = resolve(safeDir);
91
+ try {
92
+ // Create project directory
93
+ await mkdir(projectDir, { recursive: true });
94
+ // Copy CLAUDE.md
95
+ await copyFile(join(SCAFFOLD_DIR, 'CLAUDE.md'), join(projectDir, 'CLAUDE.md'));
96
+ // Copy docs/
97
+ await copyDir(join(SCAFFOLD_DIR, 'docs'), join(projectDir, 'docs'));
98
+ // Copy .claude/
99
+ const claudeDir = join(SCAFFOLD_DIR, '.claude');
100
+ try {
101
+ await copyDir(claudeDir, join(projectDir, '.claude'));
102
+ }
103
+ catch {
104
+ // .claude dir might not exist
105
+ }
106
+ // Copy .gitignore
107
+ try {
108
+ await copyFile(join(SCAFFOLD_DIR, '.gitignore'), join(projectDir, '.gitignore'));
109
+ }
110
+ catch {
111
+ // OK
112
+ }
113
+ // Create logs directory with build-state.md
114
+ await mkdir(join(projectDir, 'logs'), { recursive: true });
115
+ const buildState = `# Build State
116
+
117
+ **Project:** ${safeName}
118
+ **Current Phase:** 0 (not started)
119
+ **Last Updated:** ${new Date().toISOString()}
120
+ **Active Agent:** None
121
+
122
+ ## Phase Status
123
+ | Phase | Status | Gate Passed |
124
+ |-------|--------|-------------|
125
+ | 0-13 | not started | — |
126
+
127
+ ## Current Blockers
128
+ - None — ready to start. Run /build to begin.
129
+
130
+ ## Next Steps
131
+ 1. Review docs/PRD.md
132
+ 2. Run /build to start Phase 0
133
+ `;
134
+ await writeFile(join(projectDir, 'logs', 'build-state.md'), buildState);
135
+ // Replace placeholder in CLAUDE.md
136
+ const claudeMdPath = join(projectDir, 'CLAUDE.md');
137
+ let claudeMd = await readFile(claudeMdPath, 'utf-8');
138
+ claudeMd = claudeMd.replace(/\[PROJECT_NAME\]/g, safeName);
139
+ if (safeDescription) {
140
+ claudeMd = claudeMd.replace(/\[ONE_LINE_DESCRIPTION\]/g, safeDescription);
141
+ }
142
+ if (safeDomain) {
143
+ claudeMd = claudeMd.replace(/\[DOMAIN\]/g, safeDomain);
144
+ }
145
+ await writeFile(claudeMdPath, claudeMd);
146
+ // Write PRD if provided
147
+ if (safePrd) {
148
+ await writeFile(join(projectDir, 'docs', 'PRD.md'), safePrd);
149
+ }
150
+ // Create .env from template (newlines stripped from values to prevent injection)
151
+ const deployLine = safeDeploy ? `\n# Deploy target: ${safeDeploy}\nDEPLOY_TARGET=${safeDeploy}\n` : '';
152
+ const hostnameLine = safeHostname ? `\n# DNS hostname (Cloudflare)\nHOSTNAME=${safeHostname}\n` : '';
153
+ const envContent = `# ${safeName} — Environment Variables
154
+ # Generated by VoidForge wizard on ${new Date().toISOString()}
155
+ ${deployLine}${hostnameLine}
156
+ # Add your environment variables here
157
+ # NODE_ENV=development
158
+ `;
159
+ await writeFile(join(projectDir, '.env'), envContent);
160
+ // Initialize git repo
161
+ try {
162
+ await execFileAsync('git', ['init'], { cwd: projectDir });
163
+ await execFileAsync('git', ['add', '-A'], { cwd: projectDir });
164
+ await execFileAsync('git', ['commit', '-m', `Initial commit: ${safeName} via VoidForge`], { cwd: projectDir });
165
+ }
166
+ catch (err) {
167
+ // Git init is best-effort
168
+ console.warn('Git initialization warning:', err);
169
+ }
170
+ // Register in project registry for The Lobby
171
+ try {
172
+ await addProject({
173
+ name: safeName,
174
+ directory: projectDir,
175
+ deployTarget: safeDeploy || 'unknown',
176
+ deployUrl: safeHostname ? `https://${safeHostname}` : '',
177
+ sshHost: '',
178
+ framework: 'unknown',
179
+ database: 'none',
180
+ createdAt: new Date().toISOString(),
181
+ lastBuildPhase: 0,
182
+ lastDeployAt: '',
183
+ healthCheckUrl: '',
184
+ monthlyCost: 0,
185
+ owner: (() => {
186
+ if (!isRemoteMode())
187
+ return 'local';
188
+ const token = parseSessionCookie(req.headers.cookie);
189
+ const ip = getClientIp(req);
190
+ const session = token ? validateSession(token, ip) : null;
191
+ return session?.username ?? '';
192
+ })(),
193
+ access: [],
194
+ linkedProjects: [],
195
+ });
196
+ }
197
+ catch {
198
+ // Registry write is best-effort — don't fail project creation
199
+ }
200
+ // Write .voidforge marker file for CLI compatibility
201
+ try {
202
+ const { createMarker, writeMarker } = await import('../lib/marker.js');
203
+ const marker = createMarker('21.0.0', 'full');
204
+ await writeMarker(projectDir, marker);
205
+ }
206
+ catch {
207
+ // Marker write is best-effort — don't fail project creation
208
+ }
209
+ sendJson(res, 200, {
210
+ created: true,
211
+ directory: projectDir,
212
+ files: [
213
+ 'CLAUDE.md',
214
+ '.claude/commands/',
215
+ '.claude/settings.json',
216
+ 'docs/PRD.md',
217
+ 'docs/methods/',
218
+ 'docs/patterns/',
219
+ 'docs/LESSONS.md',
220
+ 'logs/build-state.md',
221
+ '.env',
222
+ '.gitignore',
223
+ ],
224
+ });
225
+ }
226
+ catch (err) {
227
+ const message = err instanceof Error ? err.message : 'Failed to create project';
228
+ console.error('Project creation error:', message);
229
+ sendJson(res, 500, { error: 'Failed to create project' });
230
+ }
231
+ });
232
+ // GET /api/project/defaults — return default values
233
+ addRoute('GET', '/api/project/defaults', async (_req, res) => {
234
+ const homeDir = process.env['HOME'] ?? '/tmp';
235
+ sendJson(res, 200, {
236
+ baseDir: resolve(homeDir, 'Projects'),
237
+ scaffoldDir: SCAFFOLD_DIR,
238
+ });
239
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Projects API — Multi-project CRUD for The Lobby.
3
+ * Endpoints: list, get, import, delete, access management.
4
+ * All queries filtered by per-project access control (v7.0).
5
+ */
6
+ export {};