@planu/cli 1.11.0 → 1.13.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 (298) hide show
  1. package/dist/config/ai-tool-registry.json +71 -0
  2. package/dist/config/autopilot-config.json +21 -0
  3. package/dist/config/competitive-catalog.json +83 -0
  4. package/dist/config/license-plans.json +43 -2
  5. package/dist/engine/agent-registry/lifecycle-manager.d.ts +8 -0
  6. package/dist/engine/agent-registry/lifecycle-manager.d.ts.map +1 -0
  7. package/dist/engine/agent-registry/lifecycle-manager.js +81 -0
  8. package/dist/engine/agent-registry/lifecycle-manager.js.map +1 -0
  9. package/dist/engine/agent-registry/role-catalog.d.ts +17 -0
  10. package/dist/engine/agent-registry/role-catalog.d.ts.map +1 -0
  11. package/dist/engine/agent-registry/role-catalog.js +55 -0
  12. package/dist/engine/agent-registry/role-catalog.js.map +1 -0
  13. package/dist/engine/api-compat/compatibility-checker.d.ts +4 -0
  14. package/dist/engine/api-compat/compatibility-checker.d.ts.map +1 -0
  15. package/dist/engine/api-compat/compatibility-checker.js +118 -0
  16. package/dist/engine/api-compat/compatibility-checker.js.map +1 -0
  17. package/dist/engine/autopilot/action-executor.d.ts +18 -0
  18. package/dist/engine/autopilot/action-executor.d.ts.map +1 -0
  19. package/dist/engine/autopilot/action-executor.js +91 -0
  20. package/dist/engine/autopilot/action-executor.js.map +1 -0
  21. package/dist/engine/autopilot/event-bus.d.ts +8 -0
  22. package/dist/engine/autopilot/event-bus.d.ts.map +1 -0
  23. package/dist/engine/autopilot/event-bus.js +28 -0
  24. package/dist/engine/autopilot/event-bus.js.map +1 -0
  25. package/dist/engine/autopilot/trigger-rules.d.ts +3 -0
  26. package/dist/engine/autopilot/trigger-rules.d.ts.map +1 -0
  27. package/dist/engine/autopilot/trigger-rules.js +125 -0
  28. package/dist/engine/autopilot/trigger-rules.js.map +1 -0
  29. package/dist/engine/checkpoint/checkpoint-manager.d.ts +22 -0
  30. package/dist/engine/checkpoint/checkpoint-manager.d.ts.map +1 -0
  31. package/dist/engine/checkpoint/checkpoint-manager.js +76 -0
  32. package/dist/engine/checkpoint/checkpoint-manager.js.map +1 -0
  33. package/dist/engine/checkpoint/policy-engine.d.ts +10 -0
  34. package/dist/engine/checkpoint/policy-engine.d.ts.map +1 -0
  35. package/dist/engine/checkpoint/policy-engine.js +87 -0
  36. package/dist/engine/checkpoint/policy-engine.js.map +1 -0
  37. package/dist/engine/competitive/gap-analyzer.d.ts +12 -0
  38. package/dist/engine/competitive/gap-analyzer.d.ts.map +1 -0
  39. package/dist/engine/competitive/gap-analyzer.js +214 -0
  40. package/dist/engine/competitive/gap-analyzer.js.map +1 -0
  41. package/dist/engine/compliance/auto-remediator.d.ts +9 -0
  42. package/dist/engine/compliance/auto-remediator.d.ts.map +1 -0
  43. package/dist/engine/compliance/auto-remediator.js +118 -0
  44. package/dist/engine/compliance/auto-remediator.js.map +1 -0
  45. package/dist/engine/context-profile/profile-catalog.d.ts +5 -0
  46. package/dist/engine/context-profile/profile-catalog.d.ts.map +1 -0
  47. package/dist/engine/context-profile/profile-catalog.js +145 -0
  48. package/dist/engine/context-profile/profile-catalog.js.map +1 -0
  49. package/dist/engine/critical-path/path-analyzer.d.ts +3 -0
  50. package/dist/engine/critical-path/path-analyzer.d.ts.map +1 -0
  51. package/dist/engine/critical-path/path-analyzer.js +145 -0
  52. package/dist/engine/critical-path/path-analyzer.js.map +1 -0
  53. package/dist/engine/drift/violation-resolver.d.ts +9 -0
  54. package/dist/engine/drift/violation-resolver.d.ts.map +1 -0
  55. package/dist/engine/drift/violation-resolver.js +128 -0
  56. package/dist/engine/drift/violation-resolver.js.map +1 -0
  57. package/dist/engine/ears/criterion-scorer.d.ts +7 -0
  58. package/dist/engine/ears/criterion-scorer.d.ts.map +1 -0
  59. package/dist/engine/ears/criterion-scorer.js +87 -0
  60. package/dist/engine/ears/criterion-scorer.js.map +1 -0
  61. package/dist/engine/ears/pattern-matcher.d.ts +5 -0
  62. package/dist/engine/ears/pattern-matcher.d.ts.map +1 -0
  63. package/dist/engine/ears/pattern-matcher.js +48 -0
  64. package/dist/engine/ears/pattern-matcher.js.map +1 -0
  65. package/dist/engine/ears/rewriter.d.ts +7 -0
  66. package/dist/engine/ears/rewriter.d.ts.map +1 -0
  67. package/dist/engine/ears/rewriter.js +45 -0
  68. package/dist/engine/ears/rewriter.js.map +1 -0
  69. package/dist/engine/ears/spec-linter.d.ts +7 -0
  70. package/dist/engine/ears/spec-linter.d.ts.map +1 -0
  71. package/dist/engine/ears/spec-linter.js +127 -0
  72. package/dist/engine/ears/spec-linter.js.map +1 -0
  73. package/dist/engine/health/auto-fixer.d.ts +7 -0
  74. package/dist/engine/health/auto-fixer.d.ts.map +1 -0
  75. package/dist/engine/health/auto-fixer.js +130 -0
  76. package/dist/engine/health/auto-fixer.js.map +1 -0
  77. package/dist/engine/hook-generator/ai-hook-templates.d.ts +8 -0
  78. package/dist/engine/hook-generator/ai-hook-templates.d.ts.map +1 -0
  79. package/dist/engine/hook-generator/ai-hook-templates.js +43 -0
  80. package/dist/engine/hook-generator/ai-hook-templates.js.map +1 -0
  81. package/dist/engine/hook-generator/hook-merger.d.ts +13 -0
  82. package/dist/engine/hook-generator/hook-merger.d.ts.map +1 -0
  83. package/dist/engine/hook-generator/hook-merger.js +148 -0
  84. package/dist/engine/hook-generator/hook-merger.js.map +1 -0
  85. package/dist/engine/hook-generator/stack-hook-templates.d.ts +10 -0
  86. package/dist/engine/hook-generator/stack-hook-templates.d.ts.map +1 -0
  87. package/dist/engine/hook-generator/stack-hook-templates.js +105 -0
  88. package/dist/engine/hook-generator/stack-hook-templates.js.map +1 -0
  89. package/dist/engine/mcp-catalog/catalog-advisor.d.ts +3 -0
  90. package/dist/engine/mcp-catalog/catalog-advisor.d.ts.map +1 -0
  91. package/dist/engine/mcp-catalog/catalog-advisor.js +180 -0
  92. package/dist/engine/mcp-catalog/catalog-advisor.js.map +1 -0
  93. package/dist/engine/project-dna/ai-tool-detector.d.ts +12 -0
  94. package/dist/engine/project-dna/ai-tool-detector.d.ts.map +1 -0
  95. package/dist/engine/project-dna/ai-tool-detector.js +103 -0
  96. package/dist/engine/project-dna/ai-tool-detector.js.map +1 -0
  97. package/dist/engine/project-dna/rules-generator.d.ts +18 -0
  98. package/dist/engine/project-dna/rules-generator.d.ts.map +1 -0
  99. package/dist/engine/project-dna/rules-generator.js +193 -0
  100. package/dist/engine/project-dna/rules-generator.js.map +1 -0
  101. package/dist/engine/project-dna/stack-detector.d.ts +24 -0
  102. package/dist/engine/project-dna/stack-detector.d.ts.map +1 -0
  103. package/dist/engine/project-dna/stack-detector.js +309 -0
  104. package/dist/engine/project-dna/stack-detector.js.map +1 -0
  105. package/dist/engine/similar-problems/similarity-finder.d.ts +3 -0
  106. package/dist/engine/similar-problems/similarity-finder.d.ts.map +1 -0
  107. package/dist/engine/similar-problems/similarity-finder.js +144 -0
  108. package/dist/engine/similar-problems/similarity-finder.js.map +1 -0
  109. package/dist/engine/sync/asana-puller.d.ts +9 -0
  110. package/dist/engine/sync/asana-puller.d.ts.map +1 -0
  111. package/dist/engine/sync/asana-puller.js +91 -0
  112. package/dist/engine/sync/asana-puller.js.map +1 -0
  113. package/dist/engine/sync/conflict-resolver.d.ts +17 -0
  114. package/dist/engine/sync/conflict-resolver.d.ts.map +1 -0
  115. package/dist/engine/sync/conflict-resolver.js +58 -0
  116. package/dist/engine/sync/conflict-resolver.js.map +1 -0
  117. package/dist/engine/sync/monday-puller.d.ts +9 -0
  118. package/dist/engine/sync/monday-puller.d.ts.map +1 -0
  119. package/dist/engine/sync/monday-puller.js +110 -0
  120. package/dist/engine/sync/monday-puller.js.map +1 -0
  121. package/dist/engine/sync/notion-puller.d.ts +15 -0
  122. package/dist/engine/sync/notion-puller.d.ts.map +1 -0
  123. package/dist/engine/sync/notion-puller.js +101 -0
  124. package/dist/engine/sync/notion-puller.js.map +1 -0
  125. package/dist/engine/verifier/code-scanner.d.ts +8 -0
  126. package/dist/engine/verifier/code-scanner.d.ts.map +1 -0
  127. package/dist/engine/verifier/code-scanner.js +73 -0
  128. package/dist/engine/verifier/code-scanner.js.map +1 -0
  129. package/dist/engine/verifier/compliance-scorer.d.ts +17 -0
  130. package/dist/engine/verifier/compliance-scorer.d.ts.map +1 -0
  131. package/dist/engine/verifier/compliance-scorer.js +131 -0
  132. package/dist/engine/verifier/compliance-scorer.js.map +1 -0
  133. package/dist/engine/verifier/criterion-matcher.d.ts +15 -0
  134. package/dist/engine/verifier/criterion-matcher.d.ts.map +1 -0
  135. package/dist/engine/verifier/criterion-matcher.js +210 -0
  136. package/dist/engine/verifier/criterion-matcher.js.map +1 -0
  137. package/dist/index.js +24 -0
  138. package/dist/index.js.map +1 -1
  139. package/dist/storage/agent-registry-store.d.ts +11 -0
  140. package/dist/storage/agent-registry-store.d.ts.map +1 -0
  141. package/dist/storage/agent-registry-store.js +45 -0
  142. package/dist/storage/agent-registry-store.js.map +1 -0
  143. package/dist/storage/compliance-score-store.d.ts +16 -0
  144. package/dist/storage/compliance-score-store.d.ts.map +1 -0
  145. package/dist/storage/compliance-score-store.js +30 -0
  146. package/dist/storage/compliance-score-store.js.map +1 -0
  147. package/dist/storage/context-profile-store.d.ts +14 -0
  148. package/dist/storage/context-profile-store.d.ts.map +1 -0
  149. package/dist/storage/context-profile-store.js +34 -0
  150. package/dist/storage/context-profile-store.js.map +1 -0
  151. package/dist/storage/workflow-checkpoint-store.d.ts +16 -0
  152. package/dist/storage/workflow-checkpoint-store.d.ts.map +1 -0
  153. package/dist/storage/workflow-checkpoint-store.js +71 -0
  154. package/dist/storage/workflow-checkpoint-store.js.map +1 -0
  155. package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts +3 -0
  156. package/dist/tools/checkpoint/approve-checkpoint-handler.d.ts.map +1 -0
  157. package/dist/tools/checkpoint/approve-checkpoint-handler.js +32 -0
  158. package/dist/tools/checkpoint/approve-checkpoint-handler.js.map +1 -0
  159. package/dist/tools/checkpoint/configure-policy-handler.d.ts +3 -0
  160. package/dist/tools/checkpoint/configure-policy-handler.d.ts.map +1 -0
  161. package/dist/tools/checkpoint/configure-policy-handler.js +60 -0
  162. package/dist/tools/checkpoint/configure-policy-handler.js.map +1 -0
  163. package/dist/tools/checkpoint/list-checkpoints-handler.d.ts +3 -0
  164. package/dist/tools/checkpoint/list-checkpoints-handler.d.ts.map +1 -0
  165. package/dist/tools/checkpoint/list-checkpoints-handler.js +25 -0
  166. package/dist/tools/checkpoint/list-checkpoints-handler.js.map +1 -0
  167. package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts +3 -0
  168. package/dist/tools/checkpoint/reject-checkpoint-handler.d.ts.map +1 -0
  169. package/dist/tools/checkpoint/reject-checkpoint-handler.js +32 -0
  170. package/dist/tools/checkpoint/reject-checkpoint-handler.js.map +1 -0
  171. package/dist/tools/checkpoint/require-checkpoint-handler.d.ts +3 -0
  172. package/dist/tools/checkpoint/require-checkpoint-handler.d.ts.map +1 -0
  173. package/dist/tools/checkpoint/require-checkpoint-handler.js +44 -0
  174. package/dist/tools/checkpoint/require-checkpoint-handler.js.map +1 -0
  175. package/dist/tools/competitive-handlers.d.ts +30 -0
  176. package/dist/tools/competitive-handlers.d.ts.map +1 -0
  177. package/dist/tools/competitive-handlers.js +155 -0
  178. package/dist/tools/competitive-handlers.js.map +1 -0
  179. package/dist/tools/create-spec/post-creation.d.ts +1 -1
  180. package/dist/tools/create-spec/post-creation.d.ts.map +1 -1
  181. package/dist/tools/create-spec/post-creation.js +13 -1
  182. package/dist/tools/create-spec/post-creation.js.map +1 -1
  183. package/dist/tools/create-spec.js +1 -1
  184. package/dist/tools/create-spec.js.map +1 -1
  185. package/dist/tools/hook-generator-handler.d.ts +8 -0
  186. package/dist/tools/hook-generator-handler.d.ts.map +1 -0
  187. package/dist/tools/hook-generator-handler.js +154 -0
  188. package/dist/tools/hook-generator-handler.js.map +1 -0
  189. package/dist/tools/project-dna-handler.d.ts +34 -0
  190. package/dist/tools/project-dna-handler.d.ts.map +1 -0
  191. package/dist/tools/project-dna-handler.js +261 -0
  192. package/dist/tools/project-dna-handler.js.map +1 -0
  193. package/dist/tools/pull-sync-handler.d.ts +25 -0
  194. package/dist/tools/pull-sync-handler.d.ts.map +1 -0
  195. package/dist/tools/pull-sync-handler.js +161 -0
  196. package/dist/tools/pull-sync-handler.js.map +1 -0
  197. package/dist/tools/register-agent-registry.d.ts +5 -0
  198. package/dist/tools/register-agent-registry.d.ts.map +1 -0
  199. package/dist/tools/register-agent-registry.js +254 -0
  200. package/dist/tools/register-agent-registry.js.map +1 -0
  201. package/dist/tools/register-auto-remediation.d.ts +3 -0
  202. package/dist/tools/register-auto-remediation.d.ts.map +1 -0
  203. package/dist/tools/register-auto-remediation.js +174 -0
  204. package/dist/tools/register-auto-remediation.js.map +1 -0
  205. package/dist/tools/register-autopilot.d.ts +3 -0
  206. package/dist/tools/register-autopilot.d.ts.map +1 -0
  207. package/dist/tools/register-autopilot.js +78 -0
  208. package/dist/tools/register-autopilot.js.map +1 -0
  209. package/dist/tools/register-checkpoints.d.ts +3 -0
  210. package/dist/tools/register-checkpoints.d.ts.map +1 -0
  211. package/dist/tools/register-checkpoints.js +134 -0
  212. package/dist/tools/register-checkpoints.js.map +1 -0
  213. package/dist/tools/register-competitive.d.ts +3 -0
  214. package/dist/tools/register-competitive.d.ts.map +1 -0
  215. package/dist/tools/register-competitive.js +88 -0
  216. package/dist/tools/register-competitive.js.map +1 -0
  217. package/dist/tools/register-context-profile.d.ts +3 -0
  218. package/dist/tools/register-context-profile.d.ts.map +1 -0
  219. package/dist/tools/register-context-profile.js +106 -0
  220. package/dist/tools/register-context-profile.js.map +1 -0
  221. package/dist/tools/register-ears.d.ts +3 -0
  222. package/dist/tools/register-ears.d.ts.map +1 -0
  223. package/dist/tools/register-ears.js +148 -0
  224. package/dist/tools/register-ears.js.map +1 -0
  225. package/dist/tools/register-enterprise-compliance.js +1 -1
  226. package/dist/tools/register-enterprise-compliance.js.map +1 -1
  227. package/dist/tools/register-hook-generator.d.ts +3 -0
  228. package/dist/tools/register-hook-generator.d.ts.map +1 -0
  229. package/dist/tools/register-hook-generator.js +96 -0
  230. package/dist/tools/register-hook-generator.js.map +1 -0
  231. package/dist/tools/register-project-dna.d.ts +3 -0
  232. package/dist/tools/register-project-dna.d.ts.map +1 -0
  233. package/dist/tools/register-project-dna.js +43 -0
  234. package/dist/tools/register-project-dna.js.map +1 -0
  235. package/dist/tools/register-pull-sync.d.ts +3 -0
  236. package/dist/tools/register-pull-sync.d.ts.map +1 -0
  237. package/dist/tools/register-pull-sync.js +71 -0
  238. package/dist/tools/register-pull-sync.js.map +1 -0
  239. package/dist/tools/register-spec405-tools.d.ts +7 -0
  240. package/dist/tools/register-spec405-tools.d.ts.map +1 -0
  241. package/dist/tools/register-spec405-tools.js +194 -0
  242. package/dist/tools/register-spec405-tools.js.map +1 -0
  243. package/dist/tools/register-verifier.d.ts +3 -0
  244. package/dist/tools/register-verifier.d.ts.map +1 -0
  245. package/dist/tools/register-verifier.js +141 -0
  246. package/dist/tools/register-verifier.js.map +1 -0
  247. package/dist/tools/update-status/side-effects.d.ts.map +1 -1
  248. package/dist/tools/update-status/side-effects.js +32 -0
  249. package/dist/tools/update-status/side-effects.js.map +1 -1
  250. package/dist/types/agent-registry.d.ts +53 -0
  251. package/dist/types/agent-registry.d.ts.map +1 -0
  252. package/dist/types/agent-registry.js +2 -0
  253. package/dist/types/agent-registry.js.map +1 -0
  254. package/dist/types/analysis.d.ts +98 -0
  255. package/dist/types/analysis.d.ts.map +1 -1
  256. package/dist/types/autopilot.d.ts +36 -0
  257. package/dist/types/autopilot.d.ts.map +1 -0
  258. package/dist/types/autopilot.js +3 -0
  259. package/dist/types/autopilot.js.map +1 -0
  260. package/dist/types/competitive.d.ts +41 -0
  261. package/dist/types/competitive.d.ts.map +1 -0
  262. package/dist/types/competitive.js +3 -0
  263. package/dist/types/competitive.js.map +1 -0
  264. package/dist/types/context-profile.d.ts +22 -0
  265. package/dist/types/context-profile.d.ts.map +1 -0
  266. package/dist/types/context-profile.js +2 -0
  267. package/dist/types/context-profile.js.map +1 -0
  268. package/dist/types/ears.d.ts +34 -0
  269. package/dist/types/ears.d.ts.map +1 -0
  270. package/dist/types/ears.js +3 -0
  271. package/dist/types/ears.js.map +1 -0
  272. package/dist/types/health.d.ts +40 -0
  273. package/dist/types/health.d.ts.map +1 -0
  274. package/dist/types/health.js +3 -0
  275. package/dist/types/health.js.map +1 -0
  276. package/dist/types/hook-generator.d.ts +49 -0
  277. package/dist/types/hook-generator.d.ts.map +1 -0
  278. package/dist/types/hook-generator.js +3 -0
  279. package/dist/types/hook-generator.js.map +1 -0
  280. package/dist/types/index.d.ts +9 -0
  281. package/dist/types/index.d.ts.map +1 -1
  282. package/dist/types/index.js +9 -0
  283. package/dist/types/index.js.map +1 -1
  284. package/dist/types/notion-asana-monday.d.ts +38 -0
  285. package/dist/types/notion-asana-monday.d.ts.map +1 -1
  286. package/dist/types/project-dna.d.ts +46 -0
  287. package/dist/types/project-dna.d.ts.map +1 -0
  288. package/dist/types/project-dna.js +4 -0
  289. package/dist/types/project-dna.js.map +1 -0
  290. package/dist/types/workflow-checkpoint.d.ts +66 -0
  291. package/dist/types/workflow-checkpoint.d.ts.map +1 -0
  292. package/dist/types/workflow-checkpoint.js +4 -0
  293. package/dist/types/workflow-checkpoint.js.map +1 -0
  294. package/package.json +1 -1
  295. package/src/config/ai-tool-registry.json +71 -0
  296. package/src/config/autopilot-config.json +21 -0
  297. package/src/config/competitive-catalog.json +83 -0
  298. package/src/config/license-plans.json +43 -2
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Resolve a single conflict using the given strategy.
3
+ *
4
+ * Strategies:
5
+ * - spec-wins → Planu value is authoritative; external change is discarded.
6
+ * - external-wins → External PM value is authoritative; applied to Planu.
7
+ * - newest-wins → The most recently updated side wins. Falls back to spec-wins
8
+ * when timestamps are equal or unparseable.
9
+ * - manual → Conflict is flagged for human review; no automatic resolution.
10
+ */
11
+ export function resolveConflict(conflict, strategy) {
12
+ const resolution = determineResolution(conflict, strategy);
13
+ return { ...conflict, resolution };
14
+ }
15
+ function determineResolution(conflict, strategy) {
16
+ switch (strategy) {
17
+ case 'spec-wins':
18
+ return 'planu-kept';
19
+ case 'external-wins':
20
+ return 'external-applied';
21
+ case 'newest-wins':
22
+ return resolveByTimestamp(conflict.planuValue, conflict.externalValue);
23
+ case 'manual':
24
+ return 'pending-manual';
25
+ }
26
+ }
27
+ /**
28
+ * Parse ISO timestamp from a value string of the form "status|2024-01-01T00:00:00.000Z".
29
+ * If the value does not contain a timestamp suffix, returns null.
30
+ */
31
+ function extractTimestamp(value) {
32
+ const idx = value.lastIndexOf('|');
33
+ if (idx === -1) {
34
+ return null;
35
+ }
36
+ const ts = value.slice(idx + 1);
37
+ const d = new Date(ts);
38
+ return Number.isNaN(d.getTime()) ? null : d;
39
+ }
40
+ function resolveByTimestamp(planuValue, externalValue) {
41
+ const planuTs = extractTimestamp(planuValue);
42
+ const externalTs = extractTimestamp(externalValue);
43
+ if (planuTs === null || externalTs === null) {
44
+ // Cannot compare — default to spec-wins for safety
45
+ return 'planu-kept';
46
+ }
47
+ if (externalTs > planuTs) {
48
+ return 'external-applied';
49
+ }
50
+ return 'planu-kept';
51
+ }
52
+ /**
53
+ * Resolve a list of conflicts using the given strategy.
54
+ */
55
+ export function resolveConflicts(conflicts, strategy) {
56
+ return conflicts.map((c) => resolveConflict(c, strategy));
57
+ }
58
+ //# sourceMappingURL=conflict-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict-resolver.js","sourceRoot":"","sources":["../../../src/engine/sync/conflict-resolver.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,QAA4C,EAC5C,QAA4B;IAE5B,MAAM,UAAU,GAAG,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3D,OAAO,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,mBAAmB,CAC1B,QAA4C,EAC5C,QAA4B;IAE5B,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,WAAW;YACd,OAAO,YAAY,CAAC;QAEtB,KAAK,eAAe;YAClB,OAAO,kBAAkB,CAAC;QAE5B,KAAK,aAAa;YAChB,OAAO,kBAAkB,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEzE,KAAK,QAAQ;YACX,OAAO,gBAAgB,CAAC;IAC5B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,kBAAkB,CACzB,UAAkB,EAClB,aAAqB;IAErB,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,gBAAgB,CAAC,aAAa,CAAC,CAAC;IAEnD,IAAI,OAAO,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QAC5C,mDAAmD;QACnD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,UAAU,GAAG,OAAO,EAAE,CAAC;QACzB,OAAO,kBAAkB,CAAC;IAC5B,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAA+C,EAC/C,QAA4B;IAE5B,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { PmPullSyncResult, PmConflictStrategy } from '../../types/index.js';
2
+ /**
3
+ * Pull updates from Monday.com into Planu.
4
+ *
5
+ * Compares current Planu spec status against Monday.com item column values,
6
+ * detecting divergence and resolving conflicts per the chosen strategy.
7
+ */
8
+ export declare function pullFromMonday(projectPath: string, conflictStrategy: PmConflictStrategy): Promise<PmPullSyncResult>;
9
+ //# sourceMappingURL=monday-puller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monday-puller.d.ts","sourceRoot":"","sources":["../../../src/engine/sync/monday-puller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAM9B;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,kBAAkB,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAgE3B"}
@@ -0,0 +1,110 @@
1
+ import { getMondayConfig, getMondaySyncMap } from '../../storage/monday-config-store.js';
2
+ import { getSpec } from '../../storage/spec-store.js';
3
+ import { hashProjectPath } from '../../storage/base-store.js';
4
+ import { resolveConflicts } from './conflict-resolver.js';
5
+ /**
6
+ * Pull updates from Monday.com into Planu.
7
+ *
8
+ * Compares current Planu spec status against Monday.com item column values,
9
+ * detecting divergence and resolving conflicts per the chosen strategy.
10
+ */
11
+ export async function pullFromMonday(projectPath, conflictStrategy) {
12
+ const config = await getMondayConfig(projectPath);
13
+ if (config === null) {
14
+ throw new Error('Monday.com not configured. Run configure_monday first.');
15
+ }
16
+ const projectId = hashProjectPath(projectPath);
17
+ const syncMap = await getMondaySyncMap(projectPath);
18
+ const entries = Object.values(syncMap);
19
+ const pulled = [];
20
+ const rawConflicts = [];
21
+ const now = new Date().toISOString();
22
+ for (const entry of entries) {
23
+ const spec = await getSpec(projectId, entry.specId);
24
+ if (spec === null) {
25
+ continue;
26
+ }
27
+ // eslint-disable-next-line @typescript-eslint/dot-notation
28
+ const columnId = config.columnMapping?.['status'] ?? 'status';
29
+ const liveStatus = await fetchMondayItemStatus(config.apiKey, entry.itemId, columnId);
30
+ if (liveStatus === null) {
31
+ continue;
32
+ }
33
+ if (liveStatus === spec.status) {
34
+ continue;
35
+ }
36
+ rawConflicts.push({
37
+ specId: spec.id,
38
+ field: 'status',
39
+ planuValue: spec.status,
40
+ externalValue: liveStatus,
41
+ strategy: conflictStrategy,
42
+ });
43
+ }
44
+ const conflicts = resolveConflicts(rawConflicts, conflictStrategy);
45
+ for (const conflict of conflicts) {
46
+ if (conflict.resolution === 'external-applied') {
47
+ pulled.push({
48
+ externalId: syncMap[conflict.specId]?.itemId ?? '',
49
+ externalTitle: conflict.specId,
50
+ specId: conflict.specId,
51
+ field: conflict.field,
52
+ oldValue: conflict.planuValue,
53
+ newValue: conflict.externalValue,
54
+ appliedAt: now,
55
+ });
56
+ }
57
+ }
58
+ return {
59
+ integration: 'monday',
60
+ pulled,
61
+ conflicts,
62
+ newSpecsCreated: [],
63
+ executedAt: now,
64
+ };
65
+ }
66
+ /**
67
+ * Fetch the status column value of a Monday.com item via GraphQL API.
68
+ * Returns a normalized string or null on failure.
69
+ */
70
+ async function fetchMondayItemStatus(apiKey, itemId, columnId) {
71
+ const query = `
72
+ query {
73
+ items(ids: [${itemId}]) {
74
+ column_values(ids: ["${columnId}"]) {
75
+ id
76
+ text
77
+ }
78
+ }
79
+ }
80
+ `;
81
+ try {
82
+ const response = await fetch('https://api.monday.com/v2', {
83
+ method: 'POST',
84
+ headers: {
85
+ Authorization: apiKey,
86
+ 'Content-Type': 'application/json',
87
+ },
88
+ body: JSON.stringify({ query }),
89
+ });
90
+ if (!response.ok) {
91
+ return null;
92
+ }
93
+ const data = (await response.json());
94
+ const items = data.data?.items;
95
+ if (items === undefined || items.length === 0) {
96
+ return null;
97
+ }
98
+ const firstItem = items[0];
99
+ if (firstItem === undefined) {
100
+ return null;
101
+ }
102
+ const colValues = firstItem.column_values ?? [];
103
+ const col = colValues.find((cv) => cv.id === columnId);
104
+ return col?.text ?? null;
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ }
110
+ //# sourceMappingURL=monday-puller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monday-puller.js","sourceRoot":"","sources":["../../../src/engine/sync/monday-puller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { PmPullSyncResult, PmConflictStrategy } from '../../types/index.js';
2
+ /**
3
+ * Pull updates from Notion into Planu.
4
+ *
5
+ * Implementation note: Planu operates as an MCP server without persistent
6
+ * HTTP credentials at runtime. Actual Notion API reads would require the
7
+ * user's token to be available in the current process. This implementation
8
+ * performs a local-cache diff: it compares the current Planu spec status
9
+ * against the last-synced status stored in the sync map, surfacing any
10
+ * local changes that have not been pushed yet as "conflicts" from the
11
+ * perspective of the external system. A full bidirectional pull (reading
12
+ * live Notion pages) is performed when the token is available via fetch.
13
+ */
14
+ export declare function pullFromNotion(projectPath: string, conflictStrategy: PmConflictStrategy): Promise<PmPullSyncResult>;
15
+ //# sourceMappingURL=notion-puller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-puller.d.ts","sourceRoot":"","sources":["../../../src/engine/sync/notion-puller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAM9B;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,kBAAkB,GACnC,OAAO,CAAC,gBAAgB,CAAC,CAmE3B"}
@@ -0,0 +1,101 @@
1
+ import { getNotionConfig, getNotionSyncMap } from '../../storage/notion-config-store.js';
2
+ import { getSpec } from '../../storage/spec-store.js';
3
+ import { hashProjectPath } from '../../storage/base-store.js';
4
+ import { resolveConflicts } from './conflict-resolver.js';
5
+ /**
6
+ * Pull updates from Notion into Planu.
7
+ *
8
+ * Implementation note: Planu operates as an MCP server without persistent
9
+ * HTTP credentials at runtime. Actual Notion API reads would require the
10
+ * user's token to be available in the current process. This implementation
11
+ * performs a local-cache diff: it compares the current Planu spec status
12
+ * against the last-synced status stored in the sync map, surfacing any
13
+ * local changes that have not been pushed yet as "conflicts" from the
14
+ * perspective of the external system. A full bidirectional pull (reading
15
+ * live Notion pages) is performed when the token is available via fetch.
16
+ */
17
+ export async function pullFromNotion(projectPath, conflictStrategy) {
18
+ const config = await getNotionConfig(projectPath);
19
+ if (config === null) {
20
+ throw new Error('Notion not configured. Run configure_notion first.');
21
+ }
22
+ const projectId = hashProjectPath(projectPath);
23
+ const syncMap = await getNotionSyncMap(projectPath);
24
+ const entries = Object.values(syncMap);
25
+ const pulled = [];
26
+ const rawConflicts = [];
27
+ const now = new Date().toISOString();
28
+ for (const entry of entries) {
29
+ const spec = await getSpec(projectId, entry.specId);
30
+ if (spec === null) {
31
+ continue;
32
+ }
33
+ // Attempt live fetch from Notion API
34
+ const liveStatus = await fetchNotionPageStatus(config.token, entry.pageId);
35
+ if (liveStatus === null) {
36
+ // API unavailable or page not found — skip this entry
37
+ continue;
38
+ }
39
+ if (liveStatus === spec.status) {
40
+ // No divergence
41
+ continue;
42
+ }
43
+ // Divergence detected: spec status differs from Notion page status
44
+ rawConflicts.push({
45
+ specId: spec.id,
46
+ field: 'status',
47
+ planuValue: spec.status,
48
+ externalValue: liveStatus,
49
+ strategy: conflictStrategy,
50
+ });
51
+ }
52
+ const conflicts = resolveConflicts(rawConflicts, conflictStrategy);
53
+ // Record applied updates
54
+ for (const conflict of conflicts) {
55
+ if (conflict.resolution === 'external-applied') {
56
+ pulled.push({
57
+ externalId: syncMap[conflict.specId]?.pageId ?? '',
58
+ externalTitle: conflict.specId,
59
+ specId: conflict.specId,
60
+ field: conflict.field,
61
+ oldValue: conflict.planuValue,
62
+ newValue: conflict.externalValue,
63
+ appliedAt: now,
64
+ });
65
+ }
66
+ }
67
+ return {
68
+ integration: 'notion',
69
+ pulled,
70
+ conflicts,
71
+ newSpecsCreated: [],
72
+ executedAt: now,
73
+ };
74
+ }
75
+ /**
76
+ * Fetch the current status of a Notion page via the Notion API.
77
+ * Returns null if the request fails (token missing, network error, etc.)
78
+ */
79
+ async function fetchNotionPageStatus(token, pageId) {
80
+ try {
81
+ const response = await fetch(`https://api.notion.com/v1/pages/${pageId}`, {
82
+ headers: {
83
+ Authorization: `Bearer ${token}`,
84
+ 'Notion-Version': '2022-06-28',
85
+ },
86
+ });
87
+ if (!response.ok) {
88
+ return null;
89
+ }
90
+ const data = (await response.json());
91
+ // Try common status property names
92
+ const props = data.properties ?? {};
93
+ // eslint-disable-next-line @typescript-eslint/dot-notation
94
+ const statusProp = props['status'] ?? props['Status'] ?? props['select'] ?? props['Select'];
95
+ return statusProp?.select?.name ?? null;
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ }
101
+ //# sourceMappingURL=notion-puller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notion-puller.js","sourceRoot":"","sources":["../../../src/engine/sync/notion-puller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,gBAAoC;IAEpC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACpD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,MAAM,YAAY,GAAyC,EAAE,CAAC;IAC9D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QAED,qCAAqC;QACrC,MAAM,UAAU,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QAE3E,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACxB,sDAAsD;YACtD,SAAS;QACX,CAAC;QAED,IAAI,UAAU,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/B,gBAAgB;YAChB,SAAS;QACX,CAAC;QAED,mEAAmE;QACnE,YAAY,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE,IAAI,CAAC,MAAM;YACvB,aAAa,EAAE,UAAU;YACzB,QAAQ,EAAE,gBAAgB;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAEnE,yBAAyB;IACzB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,UAAU,KAAK,kBAAkB,EAAE,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC;gBACV,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,EAAE;gBAClD,aAAa,EAAE,QAAQ,CAAC,MAAM;gBAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,QAAQ,EAAE,QAAQ,CAAC,UAAU;gBAC7B,QAAQ,EAAE,QAAQ,CAAC,aAAa;gBAChC,SAAS,EAAE,GAAG;aACf,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,WAAW,EAAE,QAAQ;QACrB,MAAM;QACN,SAAS;QACT,eAAe,EAAE,EAAE;QACnB,UAAU,EAAE,GAAG;KAChB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,qBAAqB,CAAC,KAAa,EAAE,MAAc;IAChE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,mCAAmC,MAAM,EAAE,EAAE;YACxE,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,KAAK,EAAE;gBAChC,gBAAgB,EAAE,YAAY;aAC/B;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAElC,CAAC;QAEF,mCAAmC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;QACpC,2DAA2D;QAC3D,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5F,OAAO,UAAU,EAAE,MAAM,EAAE,IAAI,IAAI,IAAI,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { VerifierScanResult } from '../../types/index.js';
2
+ export type { VerifierScanResult };
3
+ /**
4
+ * Scans the codebase for evidence that a spec has been implemented.
5
+ * Searches source files, git commits, and test files.
6
+ */
7
+ export declare function scanForSpecEvidence(specId: string, projectPath: string): Promise<VerifierScanResult>;
8
+ //# sourceMappingURL=code-scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-scanner.d.ts","sourceRoot":"","sources":["../../../src/engine/verifier/code-scanner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAsCnC;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,kBAAkB,CAAC,CAwC7B"}
@@ -0,0 +1,73 @@
1
+ // engine/verifier/code-scanner.ts — Spec evidence scanner (SPEC-406)
2
+ import { readFile } from 'node:fs/promises';
3
+ import { exec } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ import { glob } from 'glob';
6
+ const execAsync = promisify(exec);
7
+ const SOURCE_GLOBS = ['**/*.ts', '**/*.js', '**/*.py', '**/*.go', '**/*.java', '**/*.rs'];
8
+ const TEST_GLOBS = ['**/*.test.ts', '**/*.spec.ts', '**/*.test.js', '**/*.spec.js'];
9
+ const IGNORE_PATTERNS = ['**/node_modules/**', '**/dist/**', '**/.git/**', '**/build/**'];
10
+ /**
11
+ * Searches a file for a string reference.
12
+ */
13
+ async function fileContains(filePath, term) {
14
+ try {
15
+ const content = await readFile(filePath, 'utf-8');
16
+ return content.includes(term);
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ /**
23
+ * Retrieves git commit messages that reference the spec ID.
24
+ */
25
+ async function findGitCommits(specId, projectPath) {
26
+ try {
27
+ const { stdout } = await execAsync(`git log --oneline --all --grep="${specId}" 2>/dev/null | head -20`, { cwd: projectPath });
28
+ return stdout
29
+ .split('\n')
30
+ .map((l) => l.trim())
31
+ .filter(Boolean);
32
+ }
33
+ catch {
34
+ return [];
35
+ }
36
+ }
37
+ /**
38
+ * Scans the codebase for evidence that a spec has been implemented.
39
+ * Searches source files, git commits, and test files.
40
+ */
41
+ export async function scanForSpecEvidence(specId, projectPath) {
42
+ // Find all source files containing the spec ID
43
+ const allFiles = await glob(SOURCE_GLOBS, {
44
+ cwd: projectPath,
45
+ ignore: IGNORE_PATTERNS,
46
+ absolute: true,
47
+ });
48
+ const filesFoundResults = await Promise.all(allFiles.map(async (f) => {
49
+ const found = await fileContains(f, specId);
50
+ return found ? f : null;
51
+ }));
52
+ const filesFound = filesFoundResults.filter((f) => f !== null);
53
+ // Find git commits mentioning the spec ID
54
+ const gitCommitsFound = await findGitCommits(specId, projectPath);
55
+ // Find test files referencing the spec ID or its slug
56
+ const testFiles = await glob(TEST_GLOBS, {
57
+ cwd: projectPath,
58
+ ignore: IGNORE_PATTERNS,
59
+ absolute: true,
60
+ });
61
+ const testFilesResults = await Promise.all(testFiles.map(async (f) => {
62
+ const found = await fileContains(f, specId);
63
+ return found ? f : null;
64
+ }));
65
+ const testFilesFound = testFilesResults.filter((f) => f !== null);
66
+ return {
67
+ specId,
68
+ filesFound,
69
+ gitCommitsFound,
70
+ testFilesFound,
71
+ };
72
+ }
73
+ //# sourceMappingURL=code-scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-scanner.js","sourceRoot":"","sources":["../../../src/engine/verifier/code-scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { SpecComplianceScore } from '../../types/index.js';
2
+ /**
3
+ * Parses acceptance criteria lines from spec.md content.
4
+ * Recognizes both "- [ ]" (unchecked) and "- [x]" (checked) task list items.
5
+ */
6
+ export declare function parseCriteria(content: string): string[];
7
+ /**
8
+ * Computes a compliance score for a spec by matching each acceptance criterion
9
+ * against the codebase.
10
+ *
11
+ * Scoring formula:
12
+ * - verified criterion = 100/N points
13
+ * - partial criterion = 50/N points
14
+ * - unverified criterion = 0 points
15
+ */
16
+ export declare function scoreCompliance(specId: string, projectPath: string): Promise<SpecComplianceScore>;
17
+ //# sourceMappingURL=compliance-scorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance-scorer.d.ts","sourceRoot":"","sources":["../../../src/engine/verifier/compliance-scorer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAgBhE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBvD;AAuBD;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,mBAAmB,CAAC,CA0E9B"}
@@ -0,0 +1,131 @@
1
+ // engine/verifier/compliance-scorer.ts — Spec compliance scoring (SPEC-406)
2
+ import { readFile } from 'node:fs/promises';
3
+ import { glob } from 'glob';
4
+ import { matchCriterion } from './criterion-matcher.js';
5
+ /**
6
+ * Determines compliance level based on score.
7
+ */
8
+ function toLevel(score) {
9
+ if (score >= 80) {
10
+ return 'compliant';
11
+ }
12
+ if (score >= 60) {
13
+ return 'partial';
14
+ }
15
+ return 'non-compliant';
16
+ }
17
+ /**
18
+ * Parses acceptance criteria lines from spec.md content.
19
+ * Recognizes both "- [ ]" (unchecked) and "- [x]" (checked) task list items.
20
+ */
21
+ export function parseCriteria(content) {
22
+ const lines = content.split('\n');
23
+ const criteria = [];
24
+ for (const line of lines) {
25
+ const trimmed = line.trim();
26
+ // Match "- [ ] ..." or "- [x] ..." or "- [X] ..."
27
+ if (/^-\s*\[[xX ]\]\s+/.test(trimmed)) {
28
+ const text = trimmed.replace(/^-\s*\[[xX ]\]\s+/, '').trim();
29
+ if (text.length > 0) {
30
+ criteria.push(text);
31
+ }
32
+ }
33
+ }
34
+ return criteria;
35
+ }
36
+ /**
37
+ * Locates the spec.md file for a given specId within the projectPath.
38
+ * Searches in common locations: planu/specs/SPEC-NNN-slug or specs/SPEC-NNN-slug.
39
+ */
40
+ async function findSpecFile(specId, projectPath) {
41
+ const patterns = [
42
+ `planu/specs/${specId}-*/spec.md`,
43
+ `specs/${specId}-*/spec.md`,
44
+ `planu/specs/${specId}/spec.md`,
45
+ `specs/${specId}/spec.md`,
46
+ ];
47
+ for (const pattern of patterns) {
48
+ const matches = await glob(pattern, { cwd: projectPath, absolute: true });
49
+ if (matches.length > 0 && matches[0] !== undefined) {
50
+ return matches[0];
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ /**
56
+ * Computes a compliance score for a spec by matching each acceptance criterion
57
+ * against the codebase.
58
+ *
59
+ * Scoring formula:
60
+ * - verified criterion = 100/N points
61
+ * - partial criterion = 50/N points
62
+ * - unverified criterion = 0 points
63
+ */
64
+ export async function scoreCompliance(specId, projectPath) {
65
+ const checkedAt = new Date().toISOString();
66
+ // Locate spec.md
67
+ const specFile = await findSpecFile(specId, projectPath);
68
+ if (specFile === null) {
69
+ return {
70
+ specId,
71
+ score: 0,
72
+ level: 'non-compliant',
73
+ verifiedCriteria: 0,
74
+ partialCriteria: 0,
75
+ unverifiedCriteria: 0,
76
+ totalCriteria: 0,
77
+ criteriaDetails: [],
78
+ checkedAt,
79
+ };
80
+ }
81
+ // Read and parse acceptance criteria
82
+ const content = await readFile(specFile, 'utf-8');
83
+ const criteria = parseCriteria(content);
84
+ if (criteria.length === 0) {
85
+ return {
86
+ specId,
87
+ score: 0,
88
+ level: 'non-compliant',
89
+ verifiedCriteria: 0,
90
+ partialCriteria: 0,
91
+ unverifiedCriteria: 0,
92
+ totalCriteria: 0,
93
+ criteriaDetails: [],
94
+ checkedAt,
95
+ };
96
+ }
97
+ // Match each criterion against the codebase
98
+ const criteriaDetails = await Promise.all(criteria.map((criterion) => matchCriterion(criterion, projectPath)));
99
+ // Compute score
100
+ const N = criteria.length;
101
+ let rawScore = 0;
102
+ let verifiedCriteria = 0;
103
+ let partialCriteria = 0;
104
+ let unverifiedCriteria = 0;
105
+ for (const detail of criteriaDetails) {
106
+ if (detail.status === 'verified') {
107
+ rawScore += 100 / N;
108
+ verifiedCriteria++;
109
+ }
110
+ else if (detail.status === 'partial') {
111
+ rawScore += 50 / N;
112
+ partialCriteria++;
113
+ }
114
+ else {
115
+ unverifiedCriteria++;
116
+ }
117
+ }
118
+ const score = Math.round(rawScore * 10) / 10;
119
+ return {
120
+ specId,
121
+ score,
122
+ level: toLevel(score),
123
+ verifiedCriteria,
124
+ partialCriteria,
125
+ unverifiedCriteria,
126
+ totalCriteria: N,
127
+ criteriaDetails,
128
+ checkedAt,
129
+ };
130
+ }
131
+ //# sourceMappingURL=compliance-scorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compliance-scorer.js","sourceRoot":"","sources":["../../../src/engine/verifier/compliance-scorer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { CriterionMatch } from '../../types/index.js';
2
+ /**
3
+ * Extracts meaningful keywords from a criterion text.
4
+ * Captures: camelCase/PascalCase identifiers, route patterns,
5
+ * quoted strings, and significant technical terms.
6
+ */
7
+ export declare function extractKeywords(criterion: string): string[];
8
+ /**
9
+ * Scans the codebase for evidence matching the criterion.
10
+ * If 2+ keywords found across files → verified
11
+ * If 1 keyword found → partial
12
+ * If 0 keywords found → unverified
13
+ */
14
+ export declare function matchCriterion(criterion: string, projectPath: string): Promise<CriterionMatch>;
15
+ //# sourceMappingURL=criterion-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"criterion-matcher.d.ts","sourceRoot":"","sources":["../../../src/engine/verifier/criterion-matcher.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA+F3D;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAyC3D;AAkBD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CAyDzB"}