@planu/cli 4.14.1 → 5.1.1

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 (452) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/LICENSE +55 -12
  3. package/README.md +10 -2
  4. package/dist/cli/commands/install.d.ts +1 -12
  5. package/dist/cli/commands/install.js +9 -65
  6. package/dist/cli/commands/job.js +4 -3
  7. package/dist/cli/commands/spec.js +12 -3
  8. package/dist/cli/commands/validate.js +2 -2
  9. package/dist/cli/router.js +1 -3
  10. package/dist/config/environment-schema.json +1 -3
  11. package/dist/config/official-sdd-tools.d.ts +4 -0
  12. package/dist/config/official-sdd-tools.js +35 -0
  13. package/dist/config/product-public.d.ts +139 -3
  14. package/dist/config/product-public.js +8 -1
  15. package/dist/config/product-public.json +7 -36
  16. package/dist/config/registries/hosts/codex.json +20 -363
  17. package/dist/config/release-policy.json +84 -2
  18. package/dist/config/runtime-policy.json +12 -1
  19. package/dist/config/skill-templates/planu-resume-work.md +2 -2
  20. package/dist/core/index.d.ts +1 -1
  21. package/dist/core/spec-validator.d.ts +4 -4
  22. package/dist/core/spec-validator.js +33 -19
  23. package/dist/engine/abortable-process-runner.d.ts +20 -2
  24. package/dist/engine/abortable-process-runner.js +243 -74
  25. package/dist/engine/ambiguity-scorer.js +4 -26
  26. package/dist/engine/auth/scope-mapper.js +1 -7
  27. package/dist/engine/autopilot/state-updater.js +4 -4
  28. package/dist/engine/cascade-hooks/hooks/review-enricher.hook.js +9 -6
  29. package/dist/engine/cascade-hooks/state-drift-detector.d.ts +3 -3
  30. package/dist/engine/cascade-hooks/state-drift-detector.js +1 -1
  31. package/dist/engine/ci-generator/planu-config.js +1 -7
  32. package/dist/engine/clarification-gate/gate.d.ts +3 -3
  33. package/dist/engine/code-scanner/layer-scanner.js +6 -22
  34. package/dist/engine/core-bridge.d.ts +3 -3
  35. package/dist/engine/cost-guardrails.d.ts +1 -1
  36. package/dist/engine/cost-guardrails.js +1 -1
  37. package/dist/engine/criterion-identity.d.ts +1 -0
  38. package/dist/engine/criterion-identity.js +7 -0
  39. package/dist/engine/dashboard/data-loader.js +2 -7
  40. package/dist/engine/dashboard/templates-layout.js +0 -3
  41. package/dist/engine/dashboard/templates-project.js +1 -13
  42. package/dist/engine/docs-site-generator/data-collector.d.ts +1 -1
  43. package/dist/engine/docs-site-generator/data-collector.js +7 -28
  44. package/dist/engine/docs-site-generator/tools-renderer.js +3 -10
  45. package/dist/engine/evidence-gates/artifact-reader.d.ts +12 -1
  46. package/dist/engine/evidence-gates/artifact-reader.js +174 -4
  47. package/dist/engine/evidence-gates/evidence-autofill.d.ts +10 -0
  48. package/dist/engine/evidence-gates/evidence-autofill.js +148 -0
  49. package/dist/engine/evidence-gates/evidence-skeletons.d.ts +19 -0
  50. package/dist/engine/evidence-gates/evidence-skeletons.js +69 -0
  51. package/dist/engine/evidence-gates/lifecycle-gate.js +4 -3
  52. package/dist/engine/evidence-gates/reconciliation-freshness.d.ts +11 -0
  53. package/dist/engine/evidence-gates/reconciliation-freshness.js +72 -0
  54. package/dist/engine/evidence-index/done-drift.d.ts +1 -1
  55. package/dist/engine/evidence-index/done-drift.js +40 -18
  56. package/dist/engine/execution/context.js +3 -0
  57. package/dist/engine/execution/durable-job-heartbeat-runtime.d.ts +4 -0
  58. package/dist/engine/execution/durable-job-heartbeat-runtime.js +400 -0
  59. package/dist/engine/execution/job-runtime.d.ts +30 -0
  60. package/dist/engine/execution/job-runtime.js +114 -6
  61. package/dist/engine/execution/operation-journal.js +10 -4
  62. package/dist/engine/execution/public-job-sanitizer.d.ts +4 -0
  63. package/dist/engine/execution/public-job-sanitizer.js +31 -0
  64. package/dist/engine/execution/validate-job-executor.d.ts +12 -1
  65. package/dist/engine/execution/validate-job-executor.js +549 -86
  66. package/dist/engine/execution/validate-job-payload.js +107 -50
  67. package/dist/engine/execution/validate-job-recovery.js +1 -1
  68. package/dist/engine/execution/validate-worker-runtime.d.ts +5 -0
  69. package/dist/engine/execution/validate-worker-runtime.js +90 -2
  70. package/dist/engine/execution/validate-worker-thread.js +17 -24
  71. package/dist/engine/handoff-artifacts/schemas.d.ts +2 -1
  72. package/dist/engine/handoff-artifacts/schemas.js +33 -0
  73. package/dist/engine/handoff-packager.d.ts +19 -0
  74. package/dist/engine/handoff-packager.js +415 -13
  75. package/dist/engine/hooks/effort-configurator.js +1 -1
  76. package/dist/engine/impact-detector/test-break-predictor.js +3 -3
  77. package/dist/engine/impact-detector/tool-registration.js +1 -1
  78. package/dist/engine/implementation-contract/renderer.js +23 -8
  79. package/dist/engine/lifecycle-reconciliation-io.d.ts +11 -0
  80. package/dist/engine/lifecycle-reconciliation-io.js +180 -0
  81. package/dist/engine/lifecycle-reconciliation.d.ts +16 -0
  82. package/dist/engine/lifecycle-reconciliation.js +406 -0
  83. package/dist/engine/local-first/tool-classification.js +2 -0
  84. package/dist/engine/macos-keychain-native-port.d.ts +5 -0
  85. package/dist/engine/macos-keychain-native-port.js +19 -7
  86. package/dist/engine/migrations/remove-commercial-state.d.ts +3 -0
  87. package/dist/engine/migrations/remove-commercial-state.js +343 -0
  88. package/dist/engine/minimality/policy-loader.js +247 -6
  89. package/dist/engine/network-policy.js +1 -0
  90. package/dist/engine/planu-core.darwin-arm64.node.manifest.json +7 -7
  91. package/dist/engine/planu-core.darwin-arm64.node.sbom.json +20 -20
  92. package/dist/engine/planu-core.darwin-x64.node.manifest.json +7 -7
  93. package/dist/engine/planu-core.darwin-x64.node.sbom.json +20 -20
  94. package/dist/engine/planu-core.linux-arm64-gnu.node.manifest.json +7 -7
  95. package/dist/engine/planu-core.linux-arm64-gnu.node.sbom.json +20 -20
  96. package/dist/engine/planu-core.linux-arm64-musl.node.manifest.json +7 -7
  97. package/dist/engine/planu-core.linux-arm64-musl.node.sbom.json +20 -20
  98. package/dist/engine/planu-core.linux-x64-gnu.node.manifest.json +7 -7
  99. package/dist/engine/planu-core.linux-x64-gnu.node.sbom.json +20 -20
  100. package/dist/engine/planu-core.linux-x64-musl.node.manifest.json +7 -7
  101. package/dist/engine/planu-core.linux-x64-musl.node.sbom.json +20 -20
  102. package/dist/engine/planu-core.win32-arm64-msvc.node.manifest.json +7 -7
  103. package/dist/engine/planu-core.win32-arm64-msvc.node.sbom.json +20 -20
  104. package/dist/engine/planu-core.win32-x64-msvc.node.manifest.json +7 -7
  105. package/dist/engine/planu-core.win32-x64-msvc.node.sbom.json +20 -20
  106. package/dist/engine/readiness-checker.d.ts +1 -16
  107. package/dist/engine/readiness-checker.js +27 -88
  108. package/dist/engine/reverse-engineer/api-detector.js +2 -13
  109. package/dist/engine/reverse-engineer/complexity-analyzer.js +2 -13
  110. package/dist/engine/reverse-engineer/config-analyzer.js +2 -13
  111. package/dist/engine/reverse-engineer/dependency-graph.js +2 -13
  112. package/dist/engine/reverse-engineer/test-analyzer.js +2 -13
  113. package/dist/engine/reverse-engineer/walk-ignore.d.ts +3 -0
  114. package/dist/engine/reverse-engineer/walk-ignore.js +26 -0
  115. package/dist/engine/runtime-policy.d.ts +2 -0
  116. package/dist/engine/runtime-policy.js +42 -5
  117. package/dist/engine/runtime-security/rate-limiter.js +0 -1
  118. package/dist/engine/safety/contained-project-file.d.ts +3 -0
  119. package/dist/engine/safety/contained-project-file.js +23 -0
  120. package/dist/engine/scope-boundaries/contradiction-checker.js +63 -1
  121. package/dist/engine/scope-boundaries/scope-validator.js +45 -7
  122. package/dist/engine/session/checkpoint-writer.js +0 -9
  123. package/dist/engine/spec-format/acceptance-criteria.d.ts +6 -2
  124. package/dist/engine/spec-format/acceptance-criteria.js +82 -22
  125. package/dist/engine/spec-format/markdown-sections.d.ts +14 -0
  126. package/dist/engine/spec-format/markdown-sections.js +105 -0
  127. package/dist/engine/spec-format/read-technical-section.js +33 -5
  128. package/dist/engine/spec-format/technical-md-populator.js +3 -2
  129. package/dist/engine/spec-format/text-fences.js +20 -2
  130. package/dist/engine/spec-format/unified-spec-builder.d.ts +7 -0
  131. package/dist/engine/spec-format/unified-spec-builder.js +202 -0
  132. package/dist/engine/spec-migrator/canonical-deduplicator.d.ts +18 -0
  133. package/dist/engine/spec-migrator/canonical-deduplicator.js +479 -0
  134. package/dist/engine/spec-migrator/filesystem-import.d.ts +4 -8
  135. package/dist/engine/spec-migrator/filesystem-import.js +121 -14
  136. package/dist/engine/spec-migrator/frontmatter-parser.js +32 -15
  137. package/dist/engine/spec-migrator/index.d.ts +1 -0
  138. package/dist/engine/spec-migrator/index.js +1 -0
  139. package/dist/engine/spec-state-machine/transition-spec.d.ts +6 -1
  140. package/dist/engine/spec-state-machine/transition-spec.js +10 -1
  141. package/dist/engine/spec-state-syncer.js +1 -1
  142. package/dist/engine/technical-enricher/index.js +16 -8
  143. package/dist/engine/technical-enricher/render-enriched.d.ts +1 -0
  144. package/dist/engine/technical-enricher/render-enriched.js +42 -14
  145. package/dist/engine/telemetry/health-checker.js +53 -17
  146. package/dist/engine/telemetry/telemetry-client.js +26 -8
  147. package/dist/engine/text-signal-boundaries.d.ts +2 -0
  148. package/dist/engine/text-signal-boundaries.js +25 -2
  149. package/dist/engine/time/relative-date.d.ts +3 -0
  150. package/dist/engine/time/relative-date.js +16 -0
  151. package/dist/engine/timing/budget.d.ts +11 -0
  152. package/dist/engine/timing/budget.js +31 -9
  153. package/dist/engine/token-optimizer/analytics.d.ts +1 -1
  154. package/dist/engine/token-optimizer/analytics.js +5 -6
  155. package/dist/engine/usage-tracker/core.d.ts +2 -2
  156. package/dist/engine/usage-tracker/core.js +1 -2
  157. package/dist/engine/usage-tracker/index.d.ts +0 -3
  158. package/dist/engine/usage-tracker/index.js +0 -3
  159. package/dist/engine/usage-tracker/stats.d.ts +2 -2
  160. package/dist/engine/usage-tracker/stats.js +1 -28
  161. package/dist/engine/validation/durable-validation.d.ts +1 -1
  162. package/dist/engine/validation/durable-validation.js +3 -82
  163. package/dist/engine/validation/validation-freshness.d.ts +11 -1
  164. package/dist/engine/validation/validation-freshness.js +231 -91
  165. package/dist/engine/validation/validation-receipt.d.ts +9 -6
  166. package/dist/engine/validation/validation-receipt.js +84 -24
  167. package/dist/engine/validation/validation-source-digest.d.ts +2 -0
  168. package/dist/engine/validation/validation-source-digest.js +86 -0
  169. package/dist/engine/validation/validation-submission.d.ts +5 -4
  170. package/dist/engine/validation/validation-submission.js +25 -11
  171. package/dist/engine/validation/validation-worktree.d.ts +21 -0
  172. package/dist/engine/validation/validation-worktree.js +260 -0
  173. package/dist/engine/validation-impact-planner.d.ts +14 -2
  174. package/dist/engine/validation-impact-planner.js +0 -3
  175. package/dist/engine/validator/dor-dod.d.ts +1 -0
  176. package/dist/engine/validator/dor-dod.js +5 -3
  177. package/dist/engine/validator/extractors.d.ts +1 -5
  178. package/dist/engine/validator/extractors.js +24 -69
  179. package/dist/engine/validator/spec-compliance-runner.d.ts +12 -24
  180. package/dist/engine/validator/spec-compliance-runner.js +429 -211
  181. package/dist/engine/validator.js +35 -22
  182. package/dist/index.js +4 -16
  183. package/dist/resources/usage-stats-resource.js +2 -18
  184. package/dist/security/adapters/linux-secret-service.js +7 -3
  185. package/dist/security/adapters/windows-credential-manager.js +6 -4
  186. package/dist/server/routes/specs.js +13 -1
  187. package/dist/storage/base-store.d.ts +1 -1
  188. package/dist/storage/base-store.js +1 -1
  189. package/dist/storage/feedback-remote.d.ts +2 -3
  190. package/dist/storage/feedback-remote.js +45 -31
  191. package/dist/storage/global-store.d.ts +1 -17
  192. package/dist/storage/global-store.js +1 -42
  193. package/dist/storage/index.d.ts +0 -2
  194. package/dist/storage/index.js +0 -2
  195. package/dist/storage/migrations/canonical-storage.js +124 -11
  196. package/dist/storage/runtime-db.d.ts +9 -0
  197. package/dist/storage/runtime-db.js +64 -8
  198. package/dist/storage/spec-store.d.ts +14 -2
  199. package/dist/storage/spec-store.js +104 -14
  200. package/dist/storage/status-store/atomic-status-write.d.ts +5 -0
  201. package/dist/storage/status-store/atomic-status-write.js +57 -0
  202. package/dist/storage/status-store/file-lock.js +30 -11
  203. package/dist/storage/status-store/self-healing.js +3 -3
  204. package/dist/storage/status-store/version-sync.d.ts +2 -1
  205. package/dist/storage/status-store/version-sync.js +35 -40
  206. package/dist/storage/usage-store.d.ts +1 -5
  207. package/dist/storage/usage-store.js +0 -35
  208. package/dist/tools/auto-update-handler.d.ts +3 -3
  209. package/dist/tools/auto-update-handler.js +3 -3
  210. package/dist/tools/challenge-spec/resilience-challenge-scenarios.d.ts +2 -1
  211. package/dist/tools/challenge-spec/resilience-challenge-scenarios.js +10 -7
  212. package/dist/tools/challenge-spec/scenario-collector.js +1 -1
  213. package/dist/tools/challenge-spec/scenarios-data.js +1 -1
  214. package/dist/tools/challenge-spec/scenarios-utils.d.ts +1 -1
  215. package/dist/tools/challenge-spec/scenarios-utils.js +35 -11
  216. package/dist/tools/challenge-spec-helpers.d.ts +10 -1
  217. package/dist/tools/challenge-spec-helpers.js +63 -22
  218. package/dist/tools/challenge-spec.js +23 -8
  219. package/dist/tools/check-readiness.js +38 -14
  220. package/dist/tools/configure-telemetry.js +30 -2
  221. package/dist/tools/create-spec/spec-builder.d.ts +7 -0
  222. package/dist/tools/create-spec/spec-builder.js +19 -15
  223. package/dist/tools/create-spec.d.ts +1 -0
  224. package/dist/tools/create-spec.js +584 -309
  225. package/dist/tools/git/branch-ops.d.ts +1 -1
  226. package/dist/tools/git/branch-ops.js +3 -2
  227. package/dist/tools/init-project/handler.js +10 -12
  228. package/dist/tools/init-project/host-assets-writer.js +26 -1
  229. package/dist/tools/init-project/lint-scaffolder.d.ts +3 -3
  230. package/dist/tools/init-project/migration-runner.d.ts +2 -4
  231. package/dist/tools/init-project/migration-runner.js +3 -2
  232. package/dist/tools/init-project/portable-index-reconciler.d.ts +4 -0
  233. package/dist/tools/init-project/portable-index-reconciler.js +14 -0
  234. package/dist/tools/init-project/result-builder.js +1 -3
  235. package/dist/tools/jobs/handlers.js +38 -6
  236. package/dist/tools/list-specs.js +5 -26
  237. package/dist/tools/merge-risk-handler.js +2 -2
  238. package/dist/tools/package-handoff.js +2 -0
  239. package/dist/tools/reconcile-spec.js +0 -27
  240. package/dist/tools/register-agent-squad-tools.js +2 -2
  241. package/dist/tools/register-platform-tools/design-stack-tools.js +11 -11
  242. package/dist/tools/register-platform-tools/lifecycle-infra-tools.js +7 -7
  243. package/dist/tools/register-sdd-tools.d.ts +1 -1
  244. package/dist/tools/register-sdd-tools.js +2 -29
  245. package/dist/tools/register-spec-tools/analysis-tools.js +8 -8
  246. package/dist/tools/register-spec-tools/core-spec-tools.js +29 -19
  247. package/dist/tools/safe-handler.d.ts +5 -13
  248. package/dist/tools/safe-handler.js +7 -23
  249. package/dist/tools/schemas/index.d.ts +1 -1
  250. package/dist/tools/schemas/index.js +1 -1
  251. package/dist/tools/schemas/output-schemas.d.ts +0 -23
  252. package/dist/tools/schemas/output-schemas.js +0 -28
  253. package/dist/tools/schemas/spec.d.ts +4 -0
  254. package/dist/tools/schemas/spec.js +3 -0
  255. package/dist/tools/schemas/validate-output-schema.d.ts +11 -0
  256. package/dist/tools/schemas/validate-output-schema.js +7 -0
  257. package/dist/tools/spec-prompt-handler.js +3 -3
  258. package/dist/tools/sync-spec-state-handler.d.ts +1 -1
  259. package/dist/tools/sync-spec-state-handler.js +50 -2
  260. package/dist/tools/tool-entry.d.ts +4 -4
  261. package/dist/tools/tool-entry.js +3 -3
  262. package/dist/tools/tool-registry/core-tools.js +31 -15
  263. package/dist/tools/tool-registry/group-infra.js +27 -110
  264. package/dist/tools/tool-registry/group-quality-compliance.js +26 -26
  265. package/dist/tools/tool-registry/inventory.d.ts +2 -0
  266. package/dist/tools/tool-registry/inventory.js +2 -0
  267. package/dist/tools/tool-registry-helpers.d.ts +3 -3
  268. package/dist/tools/tool-registry-helpers.js +3 -3
  269. package/dist/tools/tool-usage-report/registered-tools.d.ts +1 -1
  270. package/dist/tools/tool-usage-report/registered-tools.js +3 -15
  271. package/dist/tools/update-status/approval-gates.js +3 -0
  272. package/dist/tools/update-status/batch.d.ts +6 -2
  273. package/dist/tools/update-status/batch.js +58 -1
  274. package/dist/tools/update-status/dod-gates.d.ts +16 -1
  275. package/dist/tools/update-status/dod-gates.js +191 -1
  276. package/dist/tools/update-status/done-receipt-verifier.d.ts +8 -0
  277. package/dist/tools/update-status/done-receipt-verifier.js +75 -27
  278. package/dist/tools/update-status/evidence-gate.d.ts +4 -0
  279. package/dist/tools/update-status/evidence-gate.js +103 -3
  280. package/dist/tools/update-status/file-sync.d.ts +4 -3
  281. package/dist/tools/update-status/file-sync.js +57 -6
  282. package/dist/tools/update-status/index.d.ts +25 -1
  283. package/dist/tools/update-status/index.js +292 -78
  284. package/dist/tools/update-status/response-builder.js +3 -3
  285. package/dist/tools/update-status/side-effects.d.ts +2 -0
  286. package/dist/tools/update-status/side-effects.js +2 -2
  287. package/dist/tools/update-status/transition-guard.js +45 -16
  288. package/dist/tools/update-status-actions.d.ts +4 -2
  289. package/dist/tools/update-status-actions.js +16 -14
  290. package/dist/tools/usage-report.js +1 -16
  291. package/dist/tools/usage-stats.js +1 -18
  292. package/dist/tools/usage-tracking.d.ts +4 -0
  293. package/dist/tools/usage-tracking.js +20 -0
  294. package/dist/tools/validate-lint.d.ts +1 -0
  295. package/dist/tools/validate-lint.js +1 -1
  296. package/dist/tools/validate.d.ts +2 -1
  297. package/dist/tools/validate.js +114 -34
  298. package/dist/tools/workspace-dashboard-handler.js +38 -0
  299. package/dist/transports/http-transport.js +6 -8
  300. package/dist/transports/mcp-types.d.ts +0 -2
  301. package/dist/transports/session-context.js +1 -1
  302. package/dist/types/cascade-hooks.d.ts +1 -1
  303. package/dist/types/ci.d.ts +0 -4
  304. package/dist/types/clarification-token.d.ts +1 -1
  305. package/dist/types/claude-code-runtime.d.ts +0 -27
  306. package/dist/types/commercial-migration.d.ts +17 -0
  307. package/dist/types/commercial-migration.js +2 -0
  308. package/dist/types/common/primitives.d.ts +0 -2
  309. package/dist/types/core-bridge.d.ts +4 -10
  310. package/dist/types/dashboard.d.ts +3 -7
  311. package/dist/types/docs.d.ts +0 -1
  312. package/dist/types/durable-job.d.ts +4 -4
  313. package/dist/types/durable-validation.d.ts +100 -2
  314. package/dist/types/durable-validation.js +165 -1
  315. package/dist/types/errors/structured-error.d.ts +3 -3
  316. package/dist/types/estimation.d.ts +2 -0
  317. package/dist/types/evidence-autofill.d.ts +34 -0
  318. package/dist/types/evidence-autofill.js +2 -0
  319. package/dist/types/evidence-gates.d.ts +9 -1
  320. package/dist/types/execution.d.ts +2 -0
  321. package/dist/types/gemini-integration.d.ts +0 -11
  322. package/dist/types/handoff-artifacts.d.ts +41 -0
  323. package/dist/types/hooks-advanced.d.ts +0 -13
  324. package/dist/types/impact-detection.d.ts +2 -2
  325. package/dist/types/index.d.ts +3 -6
  326. package/dist/types/index.js +2 -5
  327. package/dist/types/kiro-integration.d.ts +0 -6
  328. package/dist/types/network-policy.d.ts +1 -1
  329. package/dist/types/project/lint-scaffolder.d.ts +1 -1
  330. package/dist/types/runtime-policy.d.ts +11 -0
  331. package/dist/types/session-safeguard.d.ts +0 -31
  332. package/dist/types/spec/canonical-repair.d.ts +81 -0
  333. package/dist/types/spec/canonical-repair.js +2 -0
  334. package/dist/types/spec/core.d.ts +20 -0
  335. package/dist/types/spec/index.d.ts +1 -0
  336. package/dist/types/spec/index.js +1 -0
  337. package/dist/types/spec/inputs.d.ts +35 -1
  338. package/dist/types/spec-format.d.ts +25 -1
  339. package/dist/types/telemetry.d.ts +4 -1
  340. package/dist/types/transition-log.d.ts +1 -1
  341. package/dist/types/transport.d.ts +0 -2
  342. package/dist/types/usage.d.ts +1 -36
  343. package/dist/types/usage.js +1 -1
  344. package/dist/types/validate-worker.d.ts +6 -0
  345. package/dist/types/validation-receipt.d.ts +1 -1
  346. package/dist/types/validation.d.ts +10 -4
  347. package/package.json +17 -12
  348. package/planu-native.json +1 -1
  349. package/planu-plugin.json +23 -40
  350. package/scripts/lib/pending-release-file.mjs +93 -0
  351. package/src/i18n/messages/en.json +0 -41
  352. package/src/i18n/messages/es.json +0 -41
  353. package/src/i18n/messages/pt.json +0 -41
  354. package/dist/cli/commands/activate.d.ts +0 -14
  355. package/dist/cli/commands/activate.js +0 -174
  356. package/dist/config/license-plans.json +0 -251
  357. package/dist/config/product-public.ts +0 -148
  358. package/dist/config/server-instructions.ts +0 -121
  359. package/dist/config/version-defaults.ts +0 -76
  360. package/dist/config/version.ts +0 -21
  361. package/dist/engine/ai-integration/gemini/settings-generator.d.ts +0 -4
  362. package/dist/engine/ai-integration/gemini/settings-generator.js +0 -195
  363. package/dist/engine/ai-integration/kiro/hooks-generator.d.ts +0 -6
  364. package/dist/engine/ai-integration/kiro/hooks-generator.js +0 -75
  365. package/dist/engine/hooks/full-spectrum-generator.d.ts +0 -32
  366. package/dist/engine/hooks/full-spectrum-generator.js +0 -117
  367. package/dist/engine/license-validator/config-loader.d.ts +0 -5
  368. package/dist/engine/license-validator/config-loader.js +0 -16
  369. package/dist/engine/license-validator/core.d.ts +0 -15
  370. package/dist/engine/license-validator/core.js +0 -151
  371. package/dist/engine/license-validator/fingerprint.d.ts +0 -3
  372. package/dist/engine/license-validator/fingerprint.js +0 -17
  373. package/dist/engine/license-validator/lemon-squeezy.d.ts +0 -5
  374. package/dist/engine/license-validator/lemon-squeezy.js +0 -55
  375. package/dist/engine/license-validator.d.ts +0 -5
  376. package/dist/engine/license-validator.js +0 -6
  377. package/dist/engine/product-intelligence/index.d.ts +0 -7
  378. package/dist/engine/product-intelligence/index.js +0 -211
  379. package/dist/engine/session/auto-save.d.ts +0 -18
  380. package/dist/engine/session/auto-save.js +0 -98
  381. package/dist/engine/session/context-snapshot.d.ts +0 -8
  382. package/dist/engine/session/context-snapshot.js +0 -49
  383. package/dist/engine/session/memory-sync.d.ts +0 -12
  384. package/dist/engine/session/memory-sync.js +0 -34
  385. package/dist/engine/session/session-diff.d.ts +0 -11
  386. package/dist/engine/session/session-diff.js +0 -42
  387. package/dist/engine/session/session-merge.d.ts +0 -12
  388. package/dist/engine/session/session-merge.js +0 -55
  389. package/dist/engine/session-safeguard/checkpoint-runner.d.ts +0 -4
  390. package/dist/engine/session-safeguard/checkpoint-runner.js +0 -70
  391. package/dist/engine/session-safeguard/learnings-buffer.d.ts +0 -15
  392. package/dist/engine/session-safeguard/learnings-buffer.js +0 -91
  393. package/dist/engine/session-safeguard/precompaction-drain.d.ts +0 -10
  394. package/dist/engine/session-safeguard/precompaction-drain.js +0 -82
  395. package/dist/engine/session-safeguard/unpushed-detector.d.ts +0 -7
  396. package/dist/engine/session-safeguard/unpushed-detector.js +0 -59
  397. package/dist/engine/spec-changelog/core.d.ts +0 -16
  398. package/dist/engine/spec-changelog/core.js +0 -176
  399. package/dist/engine/spec-changelog/diff.d.ts +0 -18
  400. package/dist/engine/spec-changelog/diff.js +0 -121
  401. package/dist/engine/spec-changelog/index.d.ts +0 -3
  402. package/dist/engine/spec-changelog/index.js +0 -4
  403. package/dist/engine/trial-engine.d.ts +0 -5
  404. package/dist/engine/trial-engine.js +0 -14
  405. package/dist/engine/usage-tracker/rate-check.d.ts +0 -7
  406. package/dist/engine/usage-tracker/rate-check.js +0 -18
  407. package/dist/engine/usage-tracker/rate-limiter.d.ts +0 -14
  408. package/dist/engine/usage-tracker/rate-limiter.js +0 -73
  409. package/dist/engine/usage-tracker/trial.d.ts +0 -27
  410. package/dist/engine/usage-tracker/trial.js +0 -49
  411. package/dist/engine/webhook/event-handlers.d.ts +0 -25
  412. package/dist/engine/webhook/event-handlers.js +0 -89
  413. package/dist/engine/webhook/index.d.ts +0 -4
  414. package/dist/engine/webhook/index.js +0 -5
  415. package/dist/engine/webhook/server.d.ts +0 -12
  416. package/dist/engine/webhook/server.js +0 -249
  417. package/dist/engine/webhook/signature.d.ts +0 -16
  418. package/dist/engine/webhook/signature.js +0 -49
  419. package/dist/storage/license-store.d.ts +0 -6
  420. package/dist/storage/license-store.js +0 -63
  421. package/dist/storage/session-store.d.ts +0 -20
  422. package/dist/storage/session-store.js +0 -136
  423. package/dist/tools/activate-license.d.ts +0 -6
  424. package/dist/tools/activate-license.js +0 -132
  425. package/dist/tools/checkpoint-handler.d.ts +0 -3
  426. package/dist/tools/checkpoint-handler.js +0 -130
  427. package/dist/tools/export-session.d.ts +0 -3
  428. package/dist/tools/export-session.js +0 -90
  429. package/dist/tools/license-gate.d.ts +0 -18
  430. package/dist/tools/license-gate.js +0 -222
  431. package/dist/tools/license-status.d.ts +0 -3
  432. package/dist/tools/license-status.js +0 -93
  433. package/dist/tools/list-sessions.d.ts +0 -3
  434. package/dist/tools/list-sessions.js +0 -46
  435. package/dist/tools/planu-session-checkpoint.d.ts +0 -6
  436. package/dist/tools/planu-session-checkpoint.js +0 -42
  437. package/dist/tools/restore-session.d.ts +0 -3
  438. package/dist/tools/restore-session.js +0 -71
  439. package/dist/tools/spec-history.d.ts +0 -3
  440. package/dist/tools/spec-history.js +0 -59
  441. package/dist/tools/webhook.d.ts +0 -6
  442. package/dist/tools/webhook.js +0 -150
  443. package/dist/types/changelog.d.ts +0 -49
  444. package/dist/types/changelog.js +0 -3
  445. package/dist/types/licensing.d.ts +0 -109
  446. package/dist/types/licensing.js +0 -4
  447. package/dist/types/product-intelligence.d.ts +0 -60
  448. package/dist/types/product-intelligence.js +0 -3
  449. package/dist/types/session.d.ts +0 -84
  450. package/dist/types/session.js +0 -3
  451. package/dist/types/webhook.d.ts +0 -62
  452. package/dist/types/webhook.js +0 -4
@@ -1,4 +0,0 @@
1
- // engine/spec-changelog/index.ts — Barrel export for spec-changelog module
2
- export * from './core.js';
3
- export * from './diff.js';
4
- //# sourceMappingURL=index.js.map
@@ -1,5 +0,0 @@
1
- export declare function getInstallationId(): string;
2
- export declare function getTrialStatus(_projectId?: string): null;
3
- export declare function isTrialActive(_projectId?: string): boolean;
4
- export declare function requestTrial(_projectId?: string): Promise<void>;
5
- //# sourceMappingURL=trial-engine.d.ts.map
@@ -1,14 +0,0 @@
1
- // engine/trial-engine.ts — Trial stub (trial tools removed in SPEC-533)
2
- export function getInstallationId() {
3
- return 'n/a';
4
- }
5
- export function getTrialStatus(_projectId) {
6
- return null;
7
- }
8
- export function isTrialActive(_projectId) {
9
- return false;
10
- }
11
- export async function requestTrial(_projectId) {
12
- // No-op: trial tools removed
13
- }
14
- //# sourceMappingURL=trial-engine.js.map
@@ -1,7 +0,0 @@
1
- import type { RateLimitResult } from '../../types/index.js';
2
- /**
3
- * Evaluates both daily limit and cooldown in a single call.
4
- * Returns the first failing check, or an allowed result if both pass.
5
- */
6
- export declare function evaluateRateLimit(callCount: number, maxCalls: number, lastCallAt: string | null, now: Date): RateLimitResult;
7
- //# sourceMappingURL=rate-check.d.ts.map
@@ -1,18 +0,0 @@
1
- // engine/usage-tracker/rate-check.ts — Composed rate-limit evaluation (pure, no I/O).
2
- import { checkDailyLimit, checkCooldown } from './rate-limiter.js';
3
- /**
4
- * Evaluates both daily limit and cooldown in a single call.
5
- * Returns the first failing check, or an allowed result if both pass.
6
- */
7
- export function evaluateRateLimit(callCount, maxCalls, lastCallAt, now) {
8
- const daily = checkDailyLimit(callCount, maxCalls);
9
- if (!daily.allowed) {
10
- return daily;
11
- }
12
- const cooldown = checkCooldown(lastCallAt, now);
13
- if (!cooldown.allowed) {
14
- return cooldown;
15
- }
16
- return daily;
17
- }
18
- //# sourceMappingURL=rate-check.js.map
@@ -1,14 +0,0 @@
1
- import type { RateLimitResult } from '../../types/index.js';
2
- /** Minimum milliseconds required between consecutive tool calls. */
3
- export declare const COOLDOWN_MS = 2000;
4
- /**
5
- * Checks whether the caller has exceeded the daily call limit.
6
- * Returns an allowed result when maxCalls is -1 (unlimited).
7
- */
8
- export declare function checkDailyLimit(callCount: number, maxCalls: number): RateLimitResult;
9
- /**
10
- * Checks whether enough time has passed since the last tool call.
11
- * Passes when lastCallAt is null (no previous call recorded).
12
- */
13
- export declare function checkCooldown(lastCallAt: string | null, now: Date): RateLimitResult;
14
- //# sourceMappingURL=rate-limiter.d.ts.map
@@ -1,73 +0,0 @@
1
- // engine/usage-tracker/rate-limiter.ts — Rate limiting logic (pure functions, no I/O).
2
- // ---------------------------------------------------------------------------
3
- // Constants
4
- // ---------------------------------------------------------------------------
5
- /** Minimum milliseconds required between consecutive tool calls. */
6
- export const COOLDOWN_MS = 2000;
7
- // ---------------------------------------------------------------------------
8
- // Daily limit check
9
- // ---------------------------------------------------------------------------
10
- /**
11
- * Checks whether the caller has exceeded the daily call limit.
12
- * Returns an allowed result when maxCalls is -1 (unlimited).
13
- */
14
- export function checkDailyLimit(callCount, maxCalls) {
15
- if (maxCalls === -1) {
16
- return {
17
- allowed: true,
18
- reason: null,
19
- message: 'Unlimited calls available.',
20
- remainingCalls: -1,
21
- };
22
- }
23
- const remaining = maxCalls - callCount;
24
- if (remaining <= 0) {
25
- return {
26
- allowed: false,
27
- reason: 'daily_limit',
28
- message: `Daily call limit of ${String(maxCalls)} reached. Limit resets at midnight UTC.`,
29
- remainingCalls: 0,
30
- };
31
- }
32
- return {
33
- allowed: true,
34
- reason: null,
35
- message: `${String(remaining)} of ${String(maxCalls)} daily calls remaining.`,
36
- remainingCalls: remaining,
37
- };
38
- }
39
- // ---------------------------------------------------------------------------
40
- // Cooldown check
41
- // ---------------------------------------------------------------------------
42
- /**
43
- * Checks whether enough time has passed since the last tool call.
44
- * Passes when lastCallAt is null (no previous call recorded).
45
- */
46
- export function checkCooldown(lastCallAt, now) {
47
- if (lastCallAt === null) {
48
- return {
49
- allowed: true,
50
- reason: null,
51
- message: 'No previous call recorded.',
52
- remainingCalls: -1,
53
- };
54
- }
55
- const lastCallMs = new Date(lastCallAt).getTime();
56
- const elapsedMs = now.getTime() - lastCallMs;
57
- if (elapsedMs < COOLDOWN_MS) {
58
- const waitMs = COOLDOWN_MS - elapsedMs;
59
- return {
60
- allowed: false,
61
- reason: 'cooldown',
62
- message: `Rate limit: please wait ${String(waitMs)}ms before the next call.`,
63
- remainingCalls: -1,
64
- };
65
- }
66
- return {
67
- allowed: true,
68
- reason: null,
69
- message: 'Cooldown period elapsed.',
70
- remainingCalls: -1,
71
- };
72
- }
73
- //# sourceMappingURL=rate-limiter.js.map
@@ -1,27 +0,0 @@
1
- /** Number of days in the full trial period. */
2
- export declare const TRIAL_DAYS = 30;
3
- /**
4
- * Returns the number of whole days elapsed since the given ISO 8601 timestamp.
5
- */
6
- export declare function calculateDaysSinceFirstRun(firstRunAt: string): number;
7
- /**
8
- * Returns true if the installation is still within the 30-day trial period.
9
- */
10
- export declare function isTrialActive(firstRunAt: string): boolean;
11
- /**
12
- * Returns the number of days remaining in the trial period.
13
- * Returns 0 if the trial has already expired.
14
- */
15
- export declare function trialDaysRemaining(firstRunAt: string): number;
16
- /**
17
- * Returns tool/spec/daily-call limits based on the current trial status.
18
- *
19
- * - Day 1–30 (trial active): { tools: 20, specs: 5, dailyCalls: 50 }
20
- * - Day 31+ (trial expired): { tools: 10, specs: 3, dailyCalls: 30 }
21
- */
22
- export declare function getTrialLimits(firstRunAt: string): {
23
- tools: number;
24
- specs: number;
25
- dailyCalls: number;
26
- };
27
- //# sourceMappingURL=trial.d.ts.map
@@ -1,49 +0,0 @@
1
- // engine/usage-tracker/trial.ts — Trial period logic (pure functions, no I/O).
2
- // ---------------------------------------------------------------------------
3
- // Constants
4
- // ---------------------------------------------------------------------------
5
- /** Number of days in the full trial period. */
6
- export const TRIAL_DAYS = 30;
7
- const MS_PER_DAY = 24 * 60 * 60 * 1000;
8
- // ---------------------------------------------------------------------------
9
- // Trial calculations
10
- // ---------------------------------------------------------------------------
11
- /**
12
- * Returns the number of whole days elapsed since the given ISO 8601 timestamp.
13
- */
14
- export function calculateDaysSinceFirstRun(firstRunAt) {
15
- const firstRunMs = new Date(firstRunAt).getTime();
16
- const nowMs = Date.now();
17
- const elapsedMs = nowMs - firstRunMs;
18
- return Math.floor(elapsedMs / MS_PER_DAY);
19
- }
20
- /**
21
- * Returns true if the installation is still within the 30-day trial period.
22
- */
23
- export function isTrialActive(firstRunAt) {
24
- return calculateDaysSinceFirstRun(firstRunAt) < TRIAL_DAYS;
25
- }
26
- /**
27
- * Returns the number of days remaining in the trial period.
28
- * Returns 0 if the trial has already expired.
29
- */
30
- export function trialDaysRemaining(firstRunAt) {
31
- const elapsed = calculateDaysSinceFirstRun(firstRunAt);
32
- return Math.max(0, TRIAL_DAYS - elapsed);
33
- }
34
- // ---------------------------------------------------------------------------
35
- // Limit resolution
36
- // ---------------------------------------------------------------------------
37
- /**
38
- * Returns tool/spec/daily-call limits based on the current trial status.
39
- *
40
- * - Day 1–30 (trial active): { tools: 20, specs: 5, dailyCalls: 50 }
41
- * - Day 31+ (trial expired): { tools: 10, specs: 3, dailyCalls: 30 }
42
- */
43
- export function getTrialLimits(firstRunAt) {
44
- if (isTrialActive(firstRunAt)) {
45
- return { tools: 20, specs: 5, dailyCalls: 50 };
46
- }
47
- return { tools: 10, specs: 3, dailyCalls: 30 };
48
- }
49
- //# sourceMappingURL=trial.js.map
@@ -1,25 +0,0 @@
1
- import type { LemonSqueezyWebhookPayload, WebhookProcessResult } from '../../types/index.js';
2
- /**
3
- * Handles subscription_cancelled: the customer cancelled their subscription.
4
- * The tier should be reverted to free when the subscription period ends.
5
- */
6
- export declare function handleSubscriptionCancelled(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
7
- /**
8
- * Handles subscription_updated: plan tier may have changed (upgrade/downgrade).
9
- */
10
- export declare function handleSubscriptionUpdated(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
11
- /**
12
- * Handles license_key_created: a new license key was issued (after purchase).
13
- * This is informational — the user will activate the key via activate_license tool.
14
- */
15
- export declare function handleLicenseKeyCreated(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
16
- /**
17
- * Returns a generic "acknowledged" result for unhandled but recognised events.
18
- */
19
- export declare function handleUnknownEvent(eventType: string): WebhookProcessResult;
20
- /**
21
- * Dispatches a parsed webhook payload to the appropriate event handler.
22
- * Unhandled but valid events are acknowledged with a 200 response.
23
- */
24
- export declare function dispatchWebhookEvent(payload: LemonSqueezyWebhookPayload): WebhookProcessResult;
25
- //# sourceMappingURL=event-handlers.d.ts.map
@@ -1,89 +0,0 @@
1
- // engine/webhook/event-handlers.ts — Handles individual Lemon Squeezy webhook events.
2
- // Each handler receives parsed payload and applies the corresponding business logic.
3
- // ---------------------------------------------------------------------------
4
- // Individual event handlers
5
- // ---------------------------------------------------------------------------
6
- /**
7
- * Handles subscription_cancelled: the customer cancelled their subscription.
8
- * The tier should be reverted to free when the subscription period ends.
9
- */
10
- export function handleSubscriptionCancelled(payload) {
11
- const attrs = payload.data.attributes;
12
- const endsAt = attrs.ends_at ?? 'unknown date';
13
- const productName = attrs.product_name ?? 'Planu subscription';
14
- return {
15
- success: true,
16
- eventType: 'subscription_cancelled',
17
- statusCode: 200,
18
- message: [
19
- `Subscription cancellation recorded: ${productName}`,
20
- `Access continues until: ${endsAt}`,
21
- 'Tier will revert to free upon expiry.',
22
- ].join(' | '),
23
- };
24
- }
25
- /**
26
- * Handles subscription_updated: plan tier may have changed (upgrade/downgrade).
27
- */
28
- export function handleSubscriptionUpdated(payload) {
29
- const attrs = payload.data.attributes;
30
- const variantName = attrs.variant_name ?? 'unknown variant';
31
- const status = attrs.status ?? 'unknown';
32
- return {
33
- success: true,
34
- eventType: 'subscription_updated',
35
- statusCode: 200,
36
- message: [`Subscription updated: variant=${variantName}`, `status=${status}`].join(' | '),
37
- };
38
- }
39
- /**
40
- * Handles license_key_created: a new license key was issued (after purchase).
41
- * This is informational — the user will activate the key via activate_license tool.
42
- */
43
- export function handleLicenseKeyCreated(payload) {
44
- const attrs = payload.data.attributes;
45
- const productName = attrs.product_name ?? 'Planu';
46
- const userEmail = attrs.user_email ?? 'unknown';
47
- return {
48
- success: true,
49
- eventType: 'license_key_created',
50
- statusCode: 200,
51
- message: [
52
- `License key created for: ${productName}`,
53
- `customer=${userEmail}`,
54
- 'Key can be activated using activate_license tool.',
55
- ].join(' | '),
56
- };
57
- }
58
- /**
59
- * Returns a generic "acknowledged" result for unhandled but recognised events.
60
- */
61
- export function handleUnknownEvent(eventType) {
62
- return {
63
- success: true,
64
- eventType,
65
- statusCode: 200,
66
- message: `Event acknowledged (no handler): ${eventType}`,
67
- };
68
- }
69
- // ---------------------------------------------------------------------------
70
- // Dispatcher
71
- // ---------------------------------------------------------------------------
72
- const HANDLERS = {
73
- subscription_cancelled: handleSubscriptionCancelled,
74
- subscription_updated: handleSubscriptionUpdated,
75
- license_key_created: handleLicenseKeyCreated,
76
- };
77
- /**
78
- * Dispatches a parsed webhook payload to the appropriate event handler.
79
- * Unhandled but valid events are acknowledged with a 200 response.
80
- */
81
- export function dispatchWebhookEvent(payload) {
82
- const eventType = payload.meta.event_name;
83
- const handler = HANDLERS[eventType];
84
- if (handler) {
85
- return handler(payload);
86
- }
87
- return handleUnknownEvent(eventType);
88
- }
89
- //# sourceMappingURL=event-handlers.js.map
@@ -1,4 +0,0 @@
1
- export { startWebhookServer, stopWebhookServer, getWebhookState, setWebhookSecret, } from './server.js';
2
- export { validateSignature, extractSignatureHeader } from './signature.js';
3
- export { dispatchWebhookEvent, handleSubscriptionCancelled, handleSubscriptionUpdated, handleLicenseKeyCreated, handleUnknownEvent, } from './event-handlers.js';
4
- //# sourceMappingURL=index.d.ts.map
@@ -1,5 +0,0 @@
1
- // engine/webhook/index.ts — Barrel re-export for the webhook engine module.
2
- export { startWebhookServer, stopWebhookServer, getWebhookState, setWebhookSecret, } from './server.js';
3
- export { validateSignature, extractSignatureHeader } from './signature.js';
4
- export { dispatchWebhookEvent, handleSubscriptionCancelled, handleSubscriptionUpdated, handleLicenseKeyCreated, handleUnknownEvent, } from './event-handlers.js';
5
- //# sourceMappingURL=index.js.map
@@ -1,12 +0,0 @@
1
- import type { WebhookServerState } from '../../types/index.js';
2
- /** Returns the current webhook server state (immutable snapshot). */
3
- export declare function getWebhookState(): WebhookServerState;
4
- /** Replaces the webhook secret used for HMAC-SHA256 validation. */
5
- export declare function setWebhookSecret(secret: string): void;
6
- /** Starts the HTTP webhook server on the given port. Idempotent. */
7
- export declare function startWebhookServer(port?: number): Promise<WebhookServerState>;
8
- /** Stops the running webhook server gracefully. Idempotent. */
9
- export declare function stopWebhookServer(): Promise<WebhookServerState>;
10
- /** Reset replay protection state (for testing only). */
11
- export declare function _resetReplayState(): void;
12
- //# sourceMappingURL=server.d.ts.map
@@ -1,249 +0,0 @@
1
- // engine/webhook/server.ts — Lightweight HTTP webhook receiver using node:http.
2
- // No framework dependencies — only built-in Node.js modules.
3
- import { createServer } from 'node:http';
4
- import { randomUUID, createHash } from 'node:crypto';
5
- import { validateSignature, extractSignatureHeader } from './signature.js';
6
- import { dispatchWebhookEvent } from './event-handlers.js';
7
- // Constants
8
- const DEFAULT_PORT = 2358;
9
- const MAX_RECENT_EVENTS = 20;
10
- const MAX_BODY_SIZE = 1024 * 1024; // 1 MB
11
- const NONCE_CACHE_SIZE = 1000;
12
- const MAX_TIMESTAMP_AGE_MS = 5 * 60 * 1000; // 5 minutes
13
- const RATE_LIMIT_WINDOW_MS = 60 * 1000;
14
- const RATE_LIMIT_MAX = 10;
15
- // Module state
16
- let activeServer = null;
17
- let serverState = makeIdleState();
18
- let webhookSecret = '';
19
- const recentNonces = new Set();
20
- const nonceQueue = [];
21
- const rateLimitMap = new Map();
22
- // Public API
23
- /** Returns the current webhook server state (immutable snapshot). */
24
- export function getWebhookState() {
25
- return serverState;
26
- }
27
- /** Replaces the webhook secret used for HMAC-SHA256 validation. */
28
- export function setWebhookSecret(secret) {
29
- webhookSecret = secret;
30
- }
31
- /** Starts the HTTP webhook server on the given port. Idempotent. */
32
- export async function startWebhookServer(port = DEFAULT_PORT) {
33
- if (activeServer !== null) {
34
- return serverState;
35
- }
36
- return new Promise((resolve, reject) => {
37
- const server = createServer(handleRequest);
38
- server.on('error', (err) => {
39
- reject(err);
40
- });
41
- server.listen(port, () => {
42
- activeServer = server;
43
- serverState = {
44
- running: true,
45
- port,
46
- startedAt: new Date().toISOString(),
47
- eventsProcessed: 0,
48
- recentEvents: [],
49
- };
50
- if (!webhookSecret) {
51
- console.warn('[Planu] Warning: Webhook server started without a secret. All incoming requests will be accepted without signature verification. Set a secret via configure_webhook.');
52
- }
53
- resolve(serverState);
54
- });
55
- });
56
- }
57
- /** Stops the running webhook server gracefully. Idempotent. */
58
- export async function stopWebhookServer() {
59
- if (activeServer === null) {
60
- serverState = makeIdleState();
61
- return serverState;
62
- }
63
- const server = activeServer;
64
- return new Promise((resolve, reject) => {
65
- server.close((err) => {
66
- /* v8 ignore start */
67
- if (err) {
68
- reject(err);
69
- return;
70
- }
71
- /* v8 ignore stop */
72
- activeServer = null;
73
- serverState = makeIdleState();
74
- resolve(serverState);
75
- });
76
- });
77
- }
78
- // HTTP request handler
79
- function handleRequest(req, res) {
80
- if (req.method !== 'POST') {
81
- res.writeHead(405, { 'Content-Type': 'text/plain' });
82
- res.end('Method Not Allowed');
83
- return;
84
- }
85
- collectBody(req)
86
- .then((rawBody) => {
87
- processWebhookRequest(rawBody, req.headers, res);
88
- })
89
- .catch(() => {
90
- res.writeHead(400, { 'Content-Type': 'text/plain' });
91
- res.end('Bad Request');
92
- });
93
- }
94
- function collectBody(req) {
95
- return new Promise((resolve, reject) => {
96
- const chunks = [];
97
- let totalSize = 0;
98
- req.on('data', (chunk) => {
99
- totalSize += chunk.length;
100
- if (totalSize > MAX_BODY_SIZE) {
101
- reject(new Error('Payload too large'));
102
- return;
103
- }
104
- chunks.push(chunk);
105
- });
106
- req.on('end', () => {
107
- resolve(Buffer.concat(chunks));
108
- });
109
- req.on('error', reject);
110
- });
111
- }
112
- // Replay & rate-limit protection (SPEC-094 AC-7)
113
- function isReplayAttack(headers, bodyStr) {
114
- const tsHeader = headers['x-webhook-timestamp'] ?? headers['X-Webhook-Timestamp'];
115
- const timestamp = typeof tsHeader === 'string' ? tsHeader : undefined;
116
- if (timestamp) {
117
- const age = Date.now() - new Date(timestamp).getTime();
118
- if (age > MAX_TIMESTAMP_AGE_MS || age < -MAX_TIMESTAMP_AGE_MS) {
119
- return 'Webhook timestamp too old or in the future';
120
- }
121
- }
122
- const nonce = extractNonce(headers, bodyStr);
123
- if (nonce && recentNonces.has(nonce)) {
124
- return 'Duplicate webhook (replay detected)';
125
- }
126
- if (nonce) {
127
- trackNonce(nonce);
128
- }
129
- return null;
130
- }
131
- function extractNonce(headers, bodyStr) {
132
- const idHeader = headers['x-webhook-id'] ?? headers['X-Webhook-Id'];
133
- if (typeof idHeader === 'string') {
134
- return idHeader;
135
- }
136
- return createHash('sha256').update(bodyStr).digest('hex').slice(0, 32);
137
- }
138
- function trackNonce(nonce) {
139
- recentNonces.add(nonce);
140
- nonceQueue.push(nonce);
141
- while (nonceQueue.length > NONCE_CACHE_SIZE) {
142
- const old = nonceQueue.shift();
143
- if (old) {
144
- recentNonces.delete(old);
145
- }
146
- }
147
- }
148
- function isRateLimited(source) {
149
- const now = Date.now();
150
- const entry = rateLimitMap.get(source);
151
- if (!entry || now - entry.windowStart > RATE_LIMIT_WINDOW_MS) {
152
- rateLimitMap.set(source, { count: 1, windowStart: now });
153
- return false;
154
- }
155
- entry.count++;
156
- return entry.count > RATE_LIMIT_MAX;
157
- }
158
- /** Reset replay protection state (for testing only). */
159
- export function _resetReplayState() {
160
- recentNonces.clear();
161
- nonceQueue.length = 0;
162
- rateLimitMap.clear();
163
- }
164
- function processWebhookRequest(rawBody, headers, res) {
165
- // Rate limiting
166
- const source = String(headers['x-forwarded-for'] ?? headers['x-real-ip'] ?? 'unknown');
167
- if (isRateLimited(source)) {
168
- res.writeHead(429, { 'Content-Type': 'text/plain' });
169
- res.end('Too Many Requests');
170
- return;
171
- }
172
- // Replay protection
173
- const replayReason = isReplayAttack(headers, rawBody.toString('utf8'));
174
- if (replayReason) {
175
- recordEvent('replay_rejected', false, replayReason, '');
176
- res.writeHead(409, { 'Content-Type': 'text/plain' });
177
- res.end(replayReason);
178
- return;
179
- }
180
- // Signature validation (only if a secret is configured)
181
- if (webhookSecret) {
182
- const sig = extractSignatureHeader(headers);
183
- if (!validateSignature(rawBody, sig, webhookSecret)) {
184
- recordEvent('signature_invalid', false, 'Signature validation failed', '');
185
- res.writeHead(401, { 'Content-Type': 'text/plain' });
186
- res.end('Unauthorized');
187
- return;
188
- }
189
- }
190
- // Parse JSON body
191
- let payload;
192
- try {
193
- payload = JSON.parse(rawBody.toString('utf8'));
194
- }
195
- catch {
196
- res.writeHead(400, { 'Content-Type': 'text/plain' });
197
- res.end('Invalid JSON');
198
- return;
199
- }
200
- if (!payload.meta?.event_name) {
201
- res.writeHead(400, { 'Content-Type': 'text/plain' });
202
- res.end('Invalid payload: missing meta.event_name');
203
- return;
204
- }
205
- // Dispatch event
206
- const eventType = payload.meta.event_name;
207
- try {
208
- const result = dispatchWebhookEvent(payload);
209
- recordEvent(eventType, result.success, result.message, result.eventType);
210
- res.writeHead(result.statusCode, { 'Content-Type': 'application/json' });
211
- res.end(JSON.stringify({ ok: true, message: result.message }));
212
- /* v8 ignore start */
213
- }
214
- catch (err) {
215
- const errMsg = err instanceof Error ? err.message : 'Unknown error';
216
- recordEvent(eventType, false, errMsg, eventType);
217
- res.writeHead(500, { 'Content-Type': 'text/plain' });
218
- res.end('Internal Server Error');
219
- }
220
- /* v8 ignore stop */
221
- }
222
- // Event recording
223
- function recordEvent(_eventType, processed, summary, resolvedType) {
224
- const record = {
225
- id: randomUUID(),
226
- eventType: resolvedType,
227
- receivedAt: new Date().toISOString(),
228
- processed,
229
- summary,
230
- ...(processed ? {} : { error: summary }),
231
- };
232
- const recentEvents = [record, ...serverState.recentEvents].slice(0, MAX_RECENT_EVENTS);
233
- serverState = {
234
- ...serverState,
235
- eventsProcessed: serverState.eventsProcessed + 1,
236
- recentEvents,
237
- };
238
- }
239
- // Helpers
240
- function makeIdleState() {
241
- return {
242
- running: false,
243
- port: DEFAULT_PORT,
244
- startedAt: null,
245
- eventsProcessed: 0,
246
- recentEvents: [],
247
- };
248
- }
249
- //# sourceMappingURL=server.js.map
@@ -1,16 +0,0 @@
1
- /**
2
- * Validates an HMAC-SHA256 signature from a Lemon Squeezy webhook request.
3
- * Uses timing-safe comparison to prevent timing attacks.
4
- *
5
- * @param rawBody - The raw request body bytes (NOT parsed JSON)
6
- * @param signatureHeader - The value of the X-Signature header
7
- * @param secret - The webhook secret configured in Lemon Squeezy dashboard
8
- * @returns true if signature is valid, false otherwise
9
- */
10
- export declare function validateSignature(rawBody: Buffer, signatureHeader: string, secret: string): boolean;
11
- /**
12
- * Extracts the signature header value from a map of HTTP headers.
13
- * Header names are case-insensitive in HTTP/1.1.
14
- */
15
- export declare function extractSignatureHeader(headers: Record<string, string | string[] | undefined>): string;
16
- //# sourceMappingURL=signature.d.ts.map