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,212 @@
1
+ /**
2
+ * Pattern: Ad Platform Adapter (Split Interface)
3
+ *
4
+ * Key principles:
5
+ * - Separate interactive setup (browser OAuth) from runtime operations (daemon)
6
+ * - AdPlatformSetup runs in CLI/Danger Room (interactive, user-present)
7
+ * - AdPlatformAdapter runs in heartbeat daemon (non-interactive, autonomous)
8
+ * - All amounts in integer cents (Cents branded type) — never float
9
+ * - Rate limiting per-platform with token bucket
10
+ * - Errors normalized to common PlatformError format
11
+ * - Idempotency keys on all write operations (WAL pattern per ADR-3)
12
+ *
13
+ * Agents: Breeze (platform relations), Wax (paid ads), Dockson (treasury)
14
+ *
15
+ * PRD Reference: §9.5, §9.19.10, §9.20.4
16
+ *
17
+ * Authorization Guard (§9.20.4):
18
+ * Daemon Tier 1 jobs receive ReadOnlyAdapter (pause, read operations only).
19
+ * Authenticated external commands receive full AdPlatformAdapter.
20
+ * See financial-transaction.ts for the Cents branded type.
21
+ */
22
+ function toCents(dollars) {
23
+ return Math.round(dollars * 100);
24
+ }
25
+ function toDollars(cents) {
26
+ return cents / 100;
27
+ }
28
+ // Authenticated external commands receive the full AdPlatformAdapter
29
+ //
30
+ // ── Adapter Caching Rule (field report #258) ────────────
31
+ // Stateful adapters (in-memory campaign store, e.g. sandbox) MUST be cached
32
+ // per platform — one instance per platform key. Creating a new instance per
33
+ // call loses state between operations (campaigns created become invisible).
34
+ // Stateless adapters (HTTP clients calling external APIs) can be created per
35
+ // call since they hold no local state. Use a module-level Map<string, Adapter>
36
+ // for caching when the adapter's constructor initializes mutable collections.
37
+ // ── Reference Implementation: Meta Marketing API ──────
38
+ class MetaAdapter {
39
+ adAccountId;
40
+ baseUrl = 'https://graph.facebook.com/v19.0';
41
+ rateLimiter;
42
+ constructor(adAccountId) {
43
+ this.adAccountId = adAccountId;
44
+ // Meta: 200 calls/hr/ad account (sliding window)
45
+ this.rateLimiter = new TokenBucketLimiter({ capacity: 200, refillRate: 200 / 3600 });
46
+ }
47
+ // ── Setup (interactive) ──────────
48
+ async authenticate() {
49
+ // 1. Open browser to Facebook Login
50
+ // 2. User authorizes → callback with short-lived token
51
+ // 3. Exchange for long-lived token (60 days)
52
+ // 4. Return OAuthTokens
53
+ throw new Error('Interactive OAuth — implement per platform');
54
+ }
55
+ async verifyConnection(tokens) {
56
+ const res = await this.apiCall('GET', `/act_${this.adAccountId}`, tokens, {
57
+ fields: 'name,currency,account_status'
58
+ });
59
+ return {
60
+ connected: true,
61
+ accountId: this.adAccountId,
62
+ accountName: res.name,
63
+ currency: res.currency,
64
+ };
65
+ }
66
+ async detectCurrency(tokens) {
67
+ const status = await this.verifyConnection(tokens);
68
+ return status.currency ?? 'USD';
69
+ }
70
+ // ── Runtime (daemon) ─────────────
71
+ async refreshToken(token) {
72
+ // Meta long-lived tokens: exchange at 80% of 60-day TTL
73
+ const res = await this.apiCall('GET', '/oauth/access_token', token, {
74
+ grant_type: 'fb_exchange_token',
75
+ fb_exchange_token: token.accessToken,
76
+ });
77
+ return { ...token, accessToken: res.access_token, expiresAt: res.expires_at };
78
+ }
79
+ async createCampaign(config) {
80
+ await this.rateLimiter.acquire();
81
+ const res = await this.apiCall('POST', `/act_${this.adAccountId}/campaigns`, undefined, {
82
+ name: config.name,
83
+ objective: this.mapObjective(config.objective),
84
+ status: 'PAUSED', // Create paused, activate after ad set + ad creation
85
+ special_ad_categories: [],
86
+ });
87
+ return {
88
+ externalId: res.id,
89
+ platform: 'meta',
90
+ status: 'created',
91
+ dashboardUrl: `https://www.facebook.com/adsmanager/manage/campaigns?act=${this.adAccountId}&campaign_ids=${res.id}`,
92
+ };
93
+ }
94
+ async pauseCampaign(id) {
95
+ await this.rateLimiter.acquire();
96
+ await this.apiCall('POST', `/${id}`, undefined, { status: 'PAUSED' });
97
+ }
98
+ async resumeCampaign(id) {
99
+ await this.rateLimiter.acquire();
100
+ await this.apiCall('POST', `/${id}`, undefined, { status: 'ACTIVE' });
101
+ }
102
+ async deleteCampaign(id) {
103
+ await this.rateLimiter.acquire();
104
+ await this.apiCall('DELETE', `/${id}`, undefined, {});
105
+ }
106
+ async updateCampaign(id, changes) {
107
+ await this.rateLimiter.acquire();
108
+ const params = {};
109
+ if (changes.name)
110
+ params.name = changes.name;
111
+ // Budget changes go through ad set, not campaign on Meta
112
+ await this.apiCall('POST', `/${id}`, undefined, params);
113
+ }
114
+ async updateBudget(id, dailyBudget) {
115
+ await this.rateLimiter.acquire();
116
+ // Meta budgets are in the account's currency smallest unit (cents for USD)
117
+ await this.apiCall('POST', `/${id}`, undefined, { daily_budget: dailyBudget });
118
+ }
119
+ async updateCreative(id, creative) {
120
+ await this.rateLimiter.acquire();
121
+ // Creative updates go through the ad object, not campaign
122
+ throw new Error('Creative update requires ad-level API call — implement per ad structure');
123
+ }
124
+ async getSpend(dateRange) {
125
+ await this.rateLimiter.acquire();
126
+ const res = await this.apiCall('GET', `/act_${this.adAccountId}/insights`, undefined, {
127
+ fields: 'campaign_id,spend,impressions,clicks,conversions',
128
+ time_range: JSON.stringify({ since: dateRange.start, until: dateRange.end }),
129
+ level: 'campaign',
130
+ });
131
+ const resData = res.data;
132
+ return {
133
+ platform: 'meta',
134
+ dateRange,
135
+ totalSpend: toCents(resData.reduce((sum, r) => sum + parseFloat(r.spend), 0)),
136
+ campaigns: resData.map((r) => ({
137
+ externalId: r.campaign_id,
138
+ spend: toCents(parseFloat(r.spend)),
139
+ impressions: parseInt(r.impressions),
140
+ clicks: parseInt(r.clicks),
141
+ conversions: parseInt(r.conversions || '0'),
142
+ })),
143
+ };
144
+ }
145
+ async getPerformance(campaignId) {
146
+ await this.rateLimiter.acquire();
147
+ const res = await this.apiCall('GET', `/${campaignId}/insights`, undefined, {
148
+ fields: 'impressions,clicks,conversions,spend,ctr,cpc',
149
+ });
150
+ const d = res.data[0];
151
+ const spend = toCents(parseFloat(d.spend));
152
+ const conversions = parseInt(d.conversions || '0');
153
+ const revenue = 0; // Revenue comes from Stripe, not the ad platform
154
+ return {
155
+ campaignId,
156
+ impressions: parseInt(d.impressions),
157
+ clicks: parseInt(d.clicks),
158
+ conversions,
159
+ spend,
160
+ ctr: parseFloat(d.ctr),
161
+ cpc: toCents(parseFloat(d.cpc)),
162
+ roas: (revenue > 0 ? toDollars(revenue) / toDollars(spend) : 0),
163
+ };
164
+ }
165
+ async getInsights(campaignId, metrics) {
166
+ await this.rateLimiter.acquire();
167
+ const res = await this.apiCall('GET', `/${campaignId}/insights`, undefined, {
168
+ fields: metrics.join(','),
169
+ });
170
+ return { campaignId, metrics: res.data[0] ?? {} };
171
+ }
172
+ // ── Helpers ──────────────────────
173
+ mapObjective(obj) {
174
+ const map = { awareness: 'OUTCOME_AWARENESS', traffic: 'OUTCOME_TRAFFIC', conversions: 'OUTCOME_SALES' };
175
+ return map[obj];
176
+ }
177
+ async apiCall(method, path, tokens, params) {
178
+ // Sanitize platform response data per §9.19.16
179
+ // All string fields: strip HTML tags, escape <>&"', truncate to 500 chars
180
+ // Use idempotency key for POST/DELETE per ADR-3
181
+ throw new Error('HTTP implementation — use node:https, no SDK dependencies');
182
+ }
183
+ }
184
+ // ── Token Bucket Rate Limiter ─────────────────────────
185
+ class TokenBucketLimiter {
186
+ tokens;
187
+ lastRefill;
188
+ capacity;
189
+ refillRate; // tokens per second
190
+ constructor(opts) {
191
+ this.capacity = opts.capacity;
192
+ this.refillRate = opts.refillRate;
193
+ this.tokens = opts.capacity;
194
+ this.lastRefill = Date.now();
195
+ }
196
+ async acquire() {
197
+ this.refill();
198
+ if (this.tokens < 1) {
199
+ const waitMs = (1 / this.refillRate) * 1000;
200
+ await new Promise(resolve => setTimeout(resolve, waitMs));
201
+ this.refill();
202
+ }
203
+ this.tokens -= 1;
204
+ }
205
+ refill() {
206
+ const now = Date.now();
207
+ const elapsed = (now - this.lastRefill) / 1000;
208
+ this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
209
+ this.lastRefill = now;
210
+ }
211
+ }
212
+ export { toCents, toDollars, MetaAdapter, TokenBucketLimiter };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Pattern: Daemon Process (Heartbeat)
3
+ *
4
+ * Key principles:
5
+ * - PID file with flock to prevent concurrent instances
6
+ * - Unix domain socket for IPC (ADR-1: single writer)
7
+ * - Session token auth (rotated every 24 hours)
8
+ * - Graceful shutdown on SIGTERM (10s deadline)
9
+ * - Sleep/wake recovery with tiered catch-up
10
+ * - Core dumps disabled for processes holding vault keys
11
+ * - Log rotation: daily or at 10MB, retain 7 days
12
+ * - macOS: F_FULLFSYNC for financial files
13
+ *
14
+ * Agents: Dockson (treasury), Heartbeat daemon
15
+ *
16
+ * PRD Reference: §9.7, §9.18, §9.19.2, §9.20.11
17
+ */
18
+ import { createServer } from 'node:net';
19
+ declare const PID_FILE: string;
20
+ declare const SOCKET_PATH: string;
21
+ declare const TOKEN_FILE: string;
22
+ declare const STATE_FILE: string;
23
+ declare const LOG_FILE: string;
24
+ type DaemonState = 'starting' | 'healthy' | 'degraded' | 'recovering' | 'recovery_failed' | 'shutting_down' | 'stopped';
25
+ interface HeartbeatState {
26
+ pid: number;
27
+ state: DaemonState;
28
+ startedAt: string;
29
+ lastHeartbeat: string;
30
+ lastEventId: number;
31
+ cultivationState: string;
32
+ activePlatforms: string[];
33
+ activeCampaigns: number;
34
+ todaySpend: number;
35
+ dailyBudget: number;
36
+ alerts: string[];
37
+ tokenHealth: Record<string, {
38
+ status: string;
39
+ expiresAt: string;
40
+ }>;
41
+ lastAgentMessage?: {
42
+ agent: string;
43
+ text: string;
44
+ timestamp: string;
45
+ };
46
+ stablecoinBalanceCents?: number;
47
+ bankBalanceCents?: number;
48
+ runwayDays?: number;
49
+ fundingFrozen?: boolean;
50
+ pendingTransferCount?: number;
51
+ }
52
+ declare function writePidFile(): Promise<void>;
53
+ declare function checkStalePid(): Promise<boolean>;
54
+ declare function removePidFile(): Promise<void>;
55
+ declare function generateSessionToken(): Promise<string>;
56
+ declare function validateToken(provided: string, expected: string): boolean;
57
+ declare function createSocketServer(sessionToken: string, handleRequest: (method: string, path: string, body: unknown, auth: {
58
+ hasToken: boolean;
59
+ vaultPassword: string;
60
+ totpCode: string;
61
+ }) => Promise<{
62
+ status: number;
63
+ body: unknown;
64
+ }>): ReturnType<typeof createServer>;
65
+ declare function startSocketServer(server: ReturnType<typeof createServer>): Promise<void>;
66
+ declare function writeState(state: HeartbeatState): Promise<void>;
67
+ declare function setupSignalHandlers(cleanup: () => Promise<void>, server: ReturnType<typeof createServer>): void;
68
+ interface ScheduledJob {
69
+ name: string;
70
+ intervalMs: number;
71
+ handler: () => Promise<void>;
72
+ lastRun: number;
73
+ }
74
+ declare class JobScheduler {
75
+ private jobs;
76
+ private timer;
77
+ private lastTick;
78
+ add(name: string, intervalMs: number, handler: () => Promise<void>): void;
79
+ start(): void;
80
+ stop(): void;
81
+ private tick;
82
+ }
83
+ declare function createLogger(logPath: string): {
84
+ log: (msg: string) => void;
85
+ close: () => void;
86
+ };
87
+ export { writePidFile, checkStalePid, removePidFile, generateSessionToken, validateToken, createSocketServer, startSocketServer, writeState, setupSignalHandlers, JobScheduler, createLogger, PID_FILE, SOCKET_PATH, TOKEN_FILE, STATE_FILE, LOG_FILE, };
88
+ export type { DaemonState, HeartbeatState, ScheduledJob };
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Pattern: Daemon Process (Heartbeat)
3
+ *
4
+ * Key principles:
5
+ * - PID file with flock to prevent concurrent instances
6
+ * - Unix domain socket for IPC (ADR-1: single writer)
7
+ * - Session token auth (rotated every 24 hours)
8
+ * - Graceful shutdown on SIGTERM (10s deadline)
9
+ * - Sleep/wake recovery with tiered catch-up
10
+ * - Core dumps disabled for processes holding vault keys
11
+ * - Log rotation: daily or at 10MB, retain 7 days
12
+ * - macOS: F_FULLFSYNC for financial files
13
+ *
14
+ * Agents: Dockson (treasury), Heartbeat daemon
15
+ *
16
+ * PRD Reference: §9.7, §9.18, §9.19.2, §9.20.11
17
+ */
18
+ import { createServer } from 'node:net';
19
+ import { randomBytes } from 'node:crypto';
20
+ import { readFile, unlink, mkdir, open, rename } from 'node:fs/promises';
21
+ import { existsSync, createWriteStream } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ import { homedir, platform } from 'node:os';
24
+ const VOIDFORGE_DIR = join(homedir(), '.voidforge');
25
+ const RUN_DIR = join(VOIDFORGE_DIR, 'run');
26
+ const PID_FILE = join(RUN_DIR, 'heartbeat.pid');
27
+ const SOCKET_PATH = join(RUN_DIR, 'heartbeat.sock');
28
+ const TOKEN_FILE = join(VOIDFORGE_DIR, 'heartbeat.token');
29
+ const STATE_FILE = join(VOIDFORGE_DIR, 'heartbeat.json');
30
+ const LOG_FILE = join(VOIDFORGE_DIR, 'heartbeat.log');
31
+ // ── PID Management ────────────────────────────────────
32
+ async function writePidFile() {
33
+ await mkdir(RUN_DIR, { recursive: true, mode: 0o700 });
34
+ const fh = await open(PID_FILE, 'w', 0o600);
35
+ try {
36
+ await fh.writeFile(String(process.pid));
37
+ await fh.sync();
38
+ }
39
+ finally {
40
+ await fh.close();
41
+ }
42
+ }
43
+ async function checkStalePid() {
44
+ if (!existsSync(PID_FILE))
45
+ return false;
46
+ try {
47
+ const pid = parseInt(await readFile(PID_FILE, 'utf-8'));
48
+ process.kill(pid, 0); // Check if process exists (throws if not)
49
+ return true; // Another daemon is alive
50
+ }
51
+ catch {
52
+ await unlink(PID_FILE).catch(() => { });
53
+ return false; // Stale PID — cleaned up
54
+ }
55
+ }
56
+ async function removePidFile() {
57
+ await unlink(PID_FILE).catch(() => { });
58
+ }
59
+ // ── Session Token ─────────────────────────────────────
60
+ // Rotated every 24 hours (§9.19.15)
61
+ async function generateSessionToken() {
62
+ const token = randomBytes(32).toString('hex');
63
+ await mkdir(RUN_DIR, { recursive: true, mode: 0o700 });
64
+ const tmpPath = TOKEN_FILE + '.tmp.' + process.pid;
65
+ const fh = await open(tmpPath, 'w', 0o600);
66
+ try {
67
+ await fh.writeFile(token);
68
+ await fh.sync();
69
+ }
70
+ finally {
71
+ await fh.close();
72
+ }
73
+ await rename(tmpPath, TOKEN_FILE);
74
+ return token;
75
+ }
76
+ function validateToken(provided, expected) {
77
+ if (provided.length !== expected.length)
78
+ return false;
79
+ const a = Buffer.from(provided);
80
+ const b = Buffer.from(expected);
81
+ const { timingSafeEqual } = require('node:crypto');
82
+ return timingSafeEqual(a, b);
83
+ }
84
+ // ── Socket Server ─────────────────────────────────────
85
+ // JSON-over-HTTP on Unix domain socket (§9.20.11)
86
+ function createSocketServer(sessionToken, handleRequest) {
87
+ const MAX_REQUEST_SIZE = 1024 * 1024; // 1MB — R2-NIGHTWING-003: enforce during streaming
88
+ const server = createServer(async (conn) => {
89
+ let data = '';
90
+ let rejected = false;
91
+ conn.on('data', (chunk) => {
92
+ data += chunk.toString();
93
+ if (data.length > MAX_REQUEST_SIZE && !rejected) {
94
+ rejected = true;
95
+ conn.write('HTTP/1.1 413 Payload Too Large\r\nContent-Type: application/json\r\n\r\n{"ok":false,"error":"Request too large"}');
96
+ conn.end();
97
+ }
98
+ });
99
+ conn.on('end', async () => {
100
+ try {
101
+ // Parse HTTP-like request from the socket
102
+ const lines = data.split('\r\n');
103
+ const [method, path] = (lines[0] || 'GET /').split(' ');
104
+ // Extract auth headers — pass VALUES, not just presence (SEC-001 fix)
105
+ const authHeader = lines.find(l => l.toLowerCase().startsWith('authorization:'));
106
+ const token = authHeader ? authHeader.split(' ').pop() || '' : '';
107
+ const hasToken = validateToken(token, sessionToken);
108
+ const vaultHeader = lines.find(l => l.toLowerCase().startsWith('x-vault-password:'));
109
+ const vaultPassword = vaultHeader ? vaultHeader.substring(vaultHeader.indexOf(':') + 1).trim() : '';
110
+ const totpHeader = lines.find(l => l.toLowerCase().startsWith('x-totp-code:'));
111
+ const totpCode = totpHeader ? totpHeader.substring(totpHeader.indexOf(':') + 1).trim() : '';
112
+ // Parse body (after blank line)
113
+ const bodyStart = data.indexOf('\r\n\r\n');
114
+ if (rejected)
115
+ return; // Already rejected during streaming
116
+ const body = bodyStart >= 0 ? JSON.parse(data.substring(bodyStart + 4) || '{}') : {};
117
+ const result = await handleRequest(method, path, body, {
118
+ hasToken,
119
+ vaultPassword, // Actual value for verification by handler
120
+ totpCode, // Actual value for verification by handler
121
+ });
122
+ conn.write(`HTTP/1.1 ${result.status} OK\r\nContent-Type: application/json\r\n\r\n${JSON.stringify(result.body)}`);
123
+ }
124
+ catch (err) {
125
+ conn.write(`HTTP/1.1 500 Error\r\nContent-Type: application/json\r\n\r\n${JSON.stringify({ ok: false, error: 'Internal error' })}`);
126
+ }
127
+ conn.end();
128
+ });
129
+ });
130
+ return server;
131
+ }
132
+ async function startSocketServer(server) {
133
+ // Clean up stale socket
134
+ if (existsSync(SOCKET_PATH)) {
135
+ try {
136
+ const { connect } = require('node:net');
137
+ const testConn = connect(SOCKET_PATH);
138
+ await new Promise((resolve, reject) => {
139
+ testConn.on('connect', () => { testConn.destroy(); reject(new Error('Another daemon is running')); });
140
+ testConn.on('error', () => { resolve(); }); // ECONNREFUSED = stale socket
141
+ });
142
+ await unlink(SOCKET_PATH);
143
+ }
144
+ catch (err) {
145
+ if (err.message === 'Another daemon is running')
146
+ throw err;
147
+ }
148
+ }
149
+ await new Promise((resolve, reject) => {
150
+ server.listen(SOCKET_PATH, () => {
151
+ // Set socket permissions (§9.18)
152
+ require('node:fs').chmodSync(SOCKET_PATH, 0o600);
153
+ resolve();
154
+ });
155
+ server.on('error', reject);
156
+ });
157
+ }
158
+ // ── State File ────────────────────────────────────────
159
+ async function writeState(state) {
160
+ const tmpPath = STATE_FILE + '.tmp.' + process.pid;
161
+ const fh = await open(tmpPath, 'w');
162
+ try {
163
+ await fh.writeFile(JSON.stringify(state, null, 2));
164
+ if (platform() === 'darwin') {
165
+ await fh.datasync(); // Best-effort on macOS; see §9.18 F_FULLFSYNC caveat
166
+ }
167
+ else {
168
+ await fh.sync();
169
+ }
170
+ }
171
+ finally {
172
+ await fh.close();
173
+ }
174
+ await rename(tmpPath, STATE_FILE);
175
+ }
176
+ // ── Signal Handling ───────────────────────────────────
177
+ function setupSignalHandlers(cleanup, server) {
178
+ let shuttingDown = false;
179
+ async function shutdown(signal) {
180
+ if (shuttingDown)
181
+ return;
182
+ shuttingDown = true;
183
+ // 10-second deadline for in-flight requests
184
+ const deadline = setTimeout(() => {
185
+ process.exit(1);
186
+ }, 10000);
187
+ try {
188
+ server.close();
189
+ await cleanup();
190
+ await removePidFile();
191
+ await unlink(SOCKET_PATH).catch(() => { });
192
+ clearTimeout(deadline);
193
+ process.exit(0);
194
+ }
195
+ catch {
196
+ clearTimeout(deadline);
197
+ process.exit(1);
198
+ }
199
+ }
200
+ process.on('SIGTERM', () => shutdown('SIGTERM'));
201
+ process.on('SIGINT', () => shutdown('SIGINT'));
202
+ // Disable core dumps — vault key in memory (§9.18)
203
+ try {
204
+ // @ts-expect-error — setrlimit not in Node.js types
205
+ if (process.setrlimit)
206
+ process.setrlimit('core', { soft: 0, hard: 0 });
207
+ }
208
+ catch { /* not available on all platforms */ }
209
+ }
210
+ class JobScheduler {
211
+ jobs = [];
212
+ timer = null;
213
+ lastTick = Date.now();
214
+ add(name, intervalMs, handler) {
215
+ this.jobs.push({ name, intervalMs, handler, lastRun: 0 });
216
+ }
217
+ start() {
218
+ this.lastTick = Date.now();
219
+ this.timer = setInterval(() => this.tick(), 1000);
220
+ }
221
+ stop() {
222
+ if (this.timer)
223
+ clearInterval(this.timer);
224
+ }
225
+ async tick() {
226
+ const now = Date.now();
227
+ const delta = now - this.lastTick;
228
+ this.lastTick = now;
229
+ // Sleep/wake detection (§9.18): if delta > 2x expected (2s), catch-up mode
230
+ if (delta > 2000) {
231
+ // Stagger overdue jobs over 5 minutes, prioritize token refresh
232
+ const overdue = this.jobs.filter(j => now - j.lastRun > j.intervalMs);
233
+ const sorted = overdue.sort((a, b) => {
234
+ if (a.name.includes('token'))
235
+ return -1;
236
+ if (b.name.includes('token'))
237
+ return 1;
238
+ return 0;
239
+ });
240
+ for (const job of sorted) {
241
+ try {
242
+ await job.handler();
243
+ }
244
+ catch { /* logged by handler */ }
245
+ job.lastRun = now;
246
+ }
247
+ return;
248
+ }
249
+ // Normal tick: run due jobs
250
+ for (const job of this.jobs) {
251
+ if (now - job.lastRun >= job.intervalMs) {
252
+ try {
253
+ await job.handler();
254
+ }
255
+ catch { /* logged by handler */ }
256
+ job.lastRun = now;
257
+ }
258
+ }
259
+ }
260
+ }
261
+ // ── Log Rotation ──────────────────────────────────────
262
+ function createLogger(logPath) {
263
+ let stream = createWriteStream(logPath, { flags: 'a' });
264
+ return {
265
+ log(msg) {
266
+ stream.write(JSON.stringify({ ts: new Date().toISOString(), msg }) + '\n');
267
+ },
268
+ close() { stream.end(); }
269
+ };
270
+ }
271
+ export { writePidFile, checkStalePid, removePidFile, generateSessionToken, validateToken, createSocketServer, startSocketServer, writeState, setupSignalHandlers, JobScheduler, createLogger, PID_FILE, SOCKET_PATH, TOKEN_FILE, STATE_FILE, LOG_FILE, };