@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,309 @@
1
+ // Planu — project-dna/stack-detector.ts
2
+ // Detects project stack by reading manifest files.
3
+ import { readFile, access } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ // ---------------------------------------------------------------------------
6
+ // Helpers
7
+ // ---------------------------------------------------------------------------
8
+ async function fileExists(filePath) {
9
+ try {
10
+ await access(filePath);
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ async function readFileIfExists(filePath) {
18
+ try {
19
+ return await readFile(filePath, 'utf-8');
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ // ---------------------------------------------------------------------------
26
+ // Stack detection
27
+ // ---------------------------------------------------------------------------
28
+ /**
29
+ * Detects the technology stack by reading common manifest files.
30
+ * Returns normalized stack tokens (e.g. 'nextjs', 'supabase', 'vitest').
31
+ */
32
+ export async function detectStack(projectPath) {
33
+ const tokens = new Set();
34
+ await detectFromPackageJson(projectPath, tokens);
35
+ await detectFromRequirements(projectPath, tokens);
36
+ await detectFromCargo(projectPath, tokens);
37
+ await detectFromGoMod(projectPath, tokens);
38
+ await detectFromTsConfig(projectPath, tokens);
39
+ await detectFromCiCd(projectPath, tokens);
40
+ return Array.from(tokens);
41
+ }
42
+ async function detectFromPackageJson(projectPath, tokens) {
43
+ const content = await readFileIfExists(join(projectPath, 'package.json'));
44
+ if (content === null) {
45
+ return;
46
+ }
47
+ let pkg;
48
+ try {
49
+ pkg = JSON.parse(content);
50
+ }
51
+ catch {
52
+ return;
53
+ }
54
+ if (typeof pkg !== 'object' || pkg === null) {
55
+ return;
56
+ }
57
+ const record = pkg;
58
+ const deps = {
59
+ ...(typeof record.dependencies === 'object' && record.dependencies !== null
60
+ ? record.dependencies
61
+ : {}),
62
+ ...(typeof record.devDependencies === 'object' && record.devDependencies !== null
63
+ ? record.devDependencies
64
+ : {}),
65
+ };
66
+ const mappings = [
67
+ ['next', 'nextjs'],
68
+ ['react', 'react'],
69
+ ['@supabase/supabase-js', 'supabase'],
70
+ ['@supabase/ssr', 'supabase'],
71
+ ['vitest', 'vitest'],
72
+ ['jest', 'jest'],
73
+ ['@prisma/client', 'prisma'],
74
+ ['prisma', 'prisma'],
75
+ ['stripe', 'stripe'],
76
+ ['zod', 'zod'],
77
+ ['typescript', 'typescript'],
78
+ ['vue', 'vue'],
79
+ ['svelte', 'svelte'],
80
+ ['express', 'express'],
81
+ ['fastify', 'fastify'],
82
+ ['drizzle-orm', 'drizzle'],
83
+ ['tailwindcss', 'tailwind'],
84
+ ['@trpc/server', 'trpc'],
85
+ ['graphql', 'graphql'],
86
+ ['mongoose', 'mongoose'],
87
+ ['sequelize', 'sequelize'],
88
+ ['redis', 'redis'],
89
+ ['ioredis', 'redis'],
90
+ ['@nestjs/core', 'nestjs'],
91
+ ['electron', 'electron'],
92
+ ];
93
+ for (const [dep, token] of mappings) {
94
+ if (dep in deps) {
95
+ tokens.add(token);
96
+ }
97
+ }
98
+ }
99
+ async function detectFromRequirements(projectPath, tokens) {
100
+ const content = await readFileIfExists(join(projectPath, 'requirements.txt'));
101
+ if (content === null) {
102
+ return;
103
+ }
104
+ const lines = content.toLowerCase();
105
+ const mappings = [
106
+ ['fastapi', 'fastapi'],
107
+ ['django', 'django'],
108
+ ['flask', 'flask'],
109
+ ['pydantic', 'pydantic'],
110
+ ['sqlalchemy', 'sqlalchemy'],
111
+ ['alembic', 'alembic'],
112
+ ['pytest', 'pytest'],
113
+ ['celery', 'celery'],
114
+ ['uvicorn', 'uvicorn'],
115
+ ];
116
+ for (const [keyword, token] of mappings) {
117
+ if (lines.includes(keyword)) {
118
+ tokens.add(token);
119
+ }
120
+ }
121
+ }
122
+ async function detectFromCargo(projectPath, tokens) {
123
+ const content = await readFileIfExists(join(projectPath, 'Cargo.toml'));
124
+ if (content === null) {
125
+ return;
126
+ }
127
+ const text = content.toLowerCase();
128
+ const mappings = [
129
+ ['actix', 'actix'],
130
+ ['axum', 'axum'],
131
+ ['tokio', 'tokio'],
132
+ ['serde', 'serde'],
133
+ ['diesel', 'diesel'],
134
+ ['sqlx', 'sqlx'],
135
+ ];
136
+ for (const [keyword, token] of mappings) {
137
+ if (text.includes(keyword)) {
138
+ tokens.add(token);
139
+ }
140
+ }
141
+ }
142
+ async function detectFromGoMod(projectPath, tokens) {
143
+ const content = await readFileIfExists(join(projectPath, 'go.mod'));
144
+ if (content === null) {
145
+ return;
146
+ }
147
+ const text = content.toLowerCase();
148
+ const mappings = [
149
+ ['gin-gonic/gin', 'gin'],
150
+ ['labstack/echo', 'echo'],
151
+ ['gofiber/fiber', 'fiber'],
152
+ ['gorm.io', 'gorm'],
153
+ ];
154
+ for (const [keyword, token] of mappings) {
155
+ if (text.includes(keyword)) {
156
+ tokens.add(token);
157
+ }
158
+ }
159
+ }
160
+ async function detectFromTsConfig(projectPath, tokens) {
161
+ const content = await readFileIfExists(join(projectPath, 'tsconfig.json'));
162
+ if (content === null) {
163
+ return;
164
+ }
165
+ try {
166
+ const parsed = JSON.parse(content);
167
+ if (typeof parsed !== 'object' || parsed === null) {
168
+ return;
169
+ }
170
+ const record = parsed;
171
+ const compilerOptions = record.compilerOptions;
172
+ if (typeof compilerOptions === 'object' && compilerOptions !== null) {
173
+ const opts = compilerOptions;
174
+ if (opts.strict === true) {
175
+ tokens.add('typescript-strict');
176
+ }
177
+ }
178
+ }
179
+ catch {
180
+ // malformed tsconfig, skip
181
+ }
182
+ }
183
+ async function detectFromCiCd(projectPath, tokens) {
184
+ const githubWorkflows = join(projectPath, '.github', 'workflows');
185
+ if (await fileExists(githubWorkflows)) {
186
+ tokens.add('github-actions');
187
+ }
188
+ if (await fileExists(join(projectPath, '.gitlab-ci.yml'))) {
189
+ tokens.add('gitlab-ci');
190
+ }
191
+ }
192
+ /**
193
+ * Detects the package manager by checking lock files and manifests.
194
+ */
195
+ export async function detectPackageManager(projectPath) {
196
+ const checks = [
197
+ ['pnpm-lock.yaml', 'pnpm'],
198
+ ['yarn.lock', 'yarn'],
199
+ ['bun.lockb', 'bun'],
200
+ ['bun.lock', 'bun'],
201
+ ['package-lock.json', 'npm'],
202
+ ['Cargo.lock', 'cargo'],
203
+ ['go.sum', 'go'],
204
+ ['requirements.txt', 'pip'],
205
+ ['Pipfile.lock', 'pip'],
206
+ ['poetry.lock', 'pip'],
207
+ ];
208
+ for (const [file, pm] of checks) {
209
+ if (await fileExists(join(projectPath, file))) {
210
+ return pm;
211
+ }
212
+ }
213
+ if (await fileExists(join(projectPath, 'package.json'))) {
214
+ return 'npm';
215
+ }
216
+ return 'unknown';
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // Testing framework detection
220
+ // ---------------------------------------------------------------------------
221
+ /**
222
+ * Detects the primary testing framework based on stack tokens and config files.
223
+ */
224
+ export async function detectTestingFramework(projectPath, stack) {
225
+ if (stack.includes('vitest')) {
226
+ return 'vitest';
227
+ }
228
+ if (stack.includes('jest')) {
229
+ return 'jest';
230
+ }
231
+ if (stack.includes('pytest')) {
232
+ return 'pytest';
233
+ }
234
+ // Go test is always available if go.mod exists
235
+ if (await fileExists(join(projectPath, 'go.mod'))) {
236
+ return 'go-test';
237
+ }
238
+ return undefined;
239
+ }
240
+ // ---------------------------------------------------------------------------
241
+ // Linter detection
242
+ // ---------------------------------------------------------------------------
243
+ /**
244
+ * Detects the primary linter based on config files and stack tokens.
245
+ */
246
+ export async function detectLinter(projectPath, stack) {
247
+ const eslintFiles = [
248
+ 'eslint.config.js',
249
+ 'eslint.config.mjs',
250
+ 'eslint.config.ts',
251
+ '.eslintrc.js',
252
+ '.eslintrc.json',
253
+ '.eslintrc.yml',
254
+ '.eslintrc.yaml',
255
+ ];
256
+ for (const f of eslintFiles) {
257
+ if (await fileExists(join(projectPath, f))) {
258
+ return 'eslint';
259
+ }
260
+ }
261
+ if (stack.includes('fastapi') || stack.includes('django') || stack.includes('flask')) {
262
+ if (await fileExists(join(projectPath, 'pyproject.toml'))) {
263
+ const content = await readFileIfExists(join(projectPath, 'pyproject.toml'));
264
+ if (content?.includes('ruff') === true) {
265
+ return 'ruff';
266
+ }
267
+ }
268
+ return 'ruff';
269
+ }
270
+ if (await fileExists(join(projectPath, '.golangci.yml'))) {
271
+ return 'golangci-lint';
272
+ }
273
+ if (await fileExists(join(projectPath, 'Cargo.toml'))) {
274
+ return 'clippy';
275
+ }
276
+ return undefined;
277
+ }
278
+ // ---------------------------------------------------------------------------
279
+ // Formatter detection
280
+ // ---------------------------------------------------------------------------
281
+ /**
282
+ * Detects the primary code formatter based on config files and stack tokens.
283
+ */
284
+ export async function detectFormatter(projectPath, stack) {
285
+ const prettierFiles = [
286
+ 'prettier.config.js',
287
+ 'prettier.config.mjs',
288
+ '.prettierrc',
289
+ '.prettierrc.json',
290
+ '.prettierrc.yml',
291
+ '.prettierrc.yaml',
292
+ ];
293
+ for (const f of prettierFiles) {
294
+ if (await fileExists(join(projectPath, f))) {
295
+ return 'prettier';
296
+ }
297
+ }
298
+ if (stack.includes('fastapi') || stack.includes('django') || stack.includes('flask')) {
299
+ return 'black';
300
+ }
301
+ if (await fileExists(join(projectPath, 'go.mod'))) {
302
+ return 'gofmt';
303
+ }
304
+ if (await fileExists(join(projectPath, 'Cargo.toml'))) {
305
+ return 'rustfmt';
306
+ }
307
+ return undefined;
308
+ }
309
+ //# sourceMappingURL=stack-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-detector.js","sourceRoot":"","sources":["../../../src/engine/project-dna/stack-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SimilarProblemsResult } from '../../types/index.js';
2
+ export declare function findSimilarProblems(query: string, projectPath: string, specId?: string): Promise<SimilarProblemsResult>;
3
+ //# sourceMappingURL=similarity-finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity-finder.d.ts","sourceRoot":"","sources":["../../../src/engine/similar-problems/similarity-finder.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,qBAAqB,EAEtB,MAAM,sBAAsB,CAAC;AAyG9B,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,CAAC,CAiDhC"}
@@ -0,0 +1,144 @@
1
+ // engine/similar-problems/similarity-finder.ts — SPEC-405
2
+ // Find specs similar to a given description across all registered projects.
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { glob } from 'glob';
6
+ import { getProjects } from '../../storage/global-projects-store.js';
7
+ import { parseFrontmatter } from '../frontmatter-parser.js';
8
+ // ---------------------------------------------------------------------------
9
+ // Tokenization + Jaccard similarity
10
+ // ---------------------------------------------------------------------------
11
+ const STOP_WORDS = new Set([
12
+ 'a',
13
+ 'an',
14
+ 'the',
15
+ 'and',
16
+ 'or',
17
+ 'but',
18
+ 'in',
19
+ 'on',
20
+ 'at',
21
+ 'to',
22
+ 'for',
23
+ 'of',
24
+ 'with',
25
+ 'by',
26
+ 'from',
27
+ 'is',
28
+ 'are',
29
+ 'was',
30
+ 'were',
31
+ 'be',
32
+ 'been',
33
+ 'as',
34
+ 'that',
35
+ 'this',
36
+ 'it',
37
+ 'its',
38
+ 'we',
39
+ 'i',
40
+ 'you',
41
+ 'he',
42
+ 'she',
43
+ 'they',
44
+ ]);
45
+ function tokenize(text) {
46
+ return text
47
+ .toLowerCase()
48
+ .replace(/[^a-z0-9\s]/g, ' ')
49
+ .split(/\s+/)
50
+ .filter((w) => w.length > 2 && !STOP_WORDS.has(w));
51
+ }
52
+ function jaccardSimilarity(a, b) {
53
+ const setA = new Set(a);
54
+ const setB = new Set(b);
55
+ let intersection = 0;
56
+ for (const word of setA) {
57
+ if (setB.has(word)) {
58
+ intersection++;
59
+ }
60
+ }
61
+ const union = setA.size + setB.size - intersection;
62
+ return union === 0 ? 0 : intersection / union;
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Spec loading from a project path
66
+ // ---------------------------------------------------------------------------
67
+ async function loadSpecsFromProject(projectPath) {
68
+ let files;
69
+ try {
70
+ const pattern = join(projectPath, 'planu', 'specs', '*', 'spec.md');
71
+ files = await glob(pattern, { nodir: true });
72
+ }
73
+ catch {
74
+ return [];
75
+ }
76
+ const entries = [];
77
+ await Promise.all(files.map(async (filePath) => {
78
+ try {
79
+ const content = await readFile(filePath, 'utf-8');
80
+ const { metadata } = parseFrontmatter(content);
81
+ const specId = typeof metadata.id === 'string' ? metadata.id : '';
82
+ const title = typeof metadata.title === 'string' ? metadata.title : '';
83
+ if (!specId || !title) {
84
+ return;
85
+ }
86
+ const rawTags = metadata.tags;
87
+ const tags = Array.isArray(rawTags)
88
+ ? rawTags.filter((t) => typeof t === 'string')
89
+ : [];
90
+ const tokens = tokenize(`${title} ${tags.join(' ')}`);
91
+ entries.push({ specId, title, tags, projectPath, tokens });
92
+ }
93
+ catch {
94
+ // skip unreadable files
95
+ }
96
+ }));
97
+ return entries;
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Public function
101
+ // ---------------------------------------------------------------------------
102
+ export async function findSimilarProblems(query, projectPath, specId) {
103
+ // Gather registered projects plus the current one
104
+ const registered = await getProjects();
105
+ const paths = new Set([projectPath, ...registered.map((p) => p.path)]);
106
+ // Load all specs across all projects
107
+ const allSpecs = [];
108
+ await Promise.all([...paths].map(async (p) => {
109
+ const specs = await loadSpecsFromProject(p);
110
+ allSpecs.push(...specs);
111
+ }));
112
+ // Build query tokens
113
+ const queryTokens = tokenize(specId ? `${specId} ${query}` : query);
114
+ const scored = [];
115
+ for (const entry of allSpecs) {
116
+ // Skip exact match by specId
117
+ if (specId && entry.specId === specId && entry.projectPath === projectPath) {
118
+ continue;
119
+ }
120
+ const score = jaccardSimilarity(queryTokens, entry.tokens);
121
+ if (score === 0) {
122
+ continue;
123
+ }
124
+ const keyMatches = queryTokens.filter((t) => entry.tokens.includes(t));
125
+ scored.push({
126
+ specId: entry.specId,
127
+ title: entry.title,
128
+ projectPath: entry.projectPath,
129
+ similarityScore: score,
130
+ keyMatches,
131
+ _score: score,
132
+ });
133
+ }
134
+ const results = scored
135
+ .sort((a, b) => b._score - a._score)
136
+ .slice(0, 5)
137
+ .map(({ _score: _, ...rest }) => rest);
138
+ return {
139
+ query,
140
+ results,
141
+ totalSearched: allSpecs.length,
142
+ };
143
+ }
144
+ //# sourceMappingURL=similarity-finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"similarity-finder.js","sourceRoot":"","sources":["../../../src/engine/similar-problems/similarity-finder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { PmPullSyncResult, PmConflictStrategy } from '../../types/index.js';
2
+ /**
3
+ * Pull updates from Asana into Planu.
4
+ *
5
+ * Compares current Planu spec status against Asana task completion state,
6
+ * detecting divergence and resolving conflicts per the chosen strategy.
7
+ */
8
+ export declare function pullFromAsana(projectPath: string, conflictStrategy: PmConflictStrategy): Promise<PmPullSyncResult>;
9
+ //# sourceMappingURL=asana-puller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asana-puller.d.ts","sourceRoot":"","sources":["../../../src/engine/sync/asana-puller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAM9B;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,kBAAkB,GACnC,OAAO,CAAC,gBAAgB,CAAC,CA8D3B"}
@@ -0,0 +1,91 @@
1
+ import { getAsanaConfig, getAsanaSyncMap } from '../../storage/asana-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 Asana into Planu.
7
+ *
8
+ * Compares current Planu spec status against Asana task completion state,
9
+ * detecting divergence and resolving conflicts per the chosen strategy.
10
+ */
11
+ export async function pullFromAsana(projectPath, conflictStrategy) {
12
+ const config = await getAsanaConfig(projectPath);
13
+ if (config === null) {
14
+ throw new Error('Asana not configured. Run configure_asana first.');
15
+ }
16
+ const projectId = hashProjectPath(projectPath);
17
+ const syncMap = await getAsanaSyncMap(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
+ const liveStatus = await fetchAsanaTaskStatus(config.token, entry.taskGid);
28
+ if (liveStatus === null) {
29
+ continue;
30
+ }
31
+ if (liveStatus === spec.status) {
32
+ continue;
33
+ }
34
+ rawConflicts.push({
35
+ specId: spec.id,
36
+ field: 'status',
37
+ planuValue: spec.status,
38
+ externalValue: liveStatus,
39
+ strategy: conflictStrategy,
40
+ });
41
+ }
42
+ const conflicts = resolveConflicts(rawConflicts, conflictStrategy);
43
+ for (const conflict of conflicts) {
44
+ if (conflict.resolution === 'external-applied') {
45
+ pulled.push({
46
+ externalId: syncMap[conflict.specId]?.taskGid ?? '',
47
+ externalTitle: conflict.specId,
48
+ specId: conflict.specId,
49
+ field: conflict.field,
50
+ oldValue: conflict.planuValue,
51
+ newValue: conflict.externalValue,
52
+ appliedAt: now,
53
+ });
54
+ }
55
+ }
56
+ return {
57
+ integration: 'asana',
58
+ pulled,
59
+ conflicts,
60
+ newSpecsCreated: [],
61
+ executedAt: now,
62
+ };
63
+ }
64
+ /**
65
+ * Fetch the current status of an Asana task via the Asana API.
66
+ * Returns a Planu-normalized status string or null on failure.
67
+ */
68
+ async function fetchAsanaTaskStatus(token, taskGid) {
69
+ try {
70
+ const response = await fetch(`https://app.asana.com/api/1.0/tasks/${taskGid}?opt_fields=completed,name`, {
71
+ headers: {
72
+ Authorization: `Bearer ${token}`,
73
+ Accept: 'application/json',
74
+ },
75
+ });
76
+ if (!response.ok) {
77
+ return null;
78
+ }
79
+ const data = (await response.json());
80
+ const completed = data.data?.completed;
81
+ if (completed === undefined) {
82
+ return null;
83
+ }
84
+ // Map Asana task completion to Planu status
85
+ return completed ? 'done' : 'in-progress';
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }
91
+ //# sourceMappingURL=asana-puller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asana-puller.js","sourceRoot":"","sources":["../../../src/engine/sync/asana-puller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { PmSyncConflict, PmConflictStrategy } from '../../types/index.js';
2
+ /**
3
+ * Resolve a single conflict using the given strategy.
4
+ *
5
+ * Strategies:
6
+ * - spec-wins → Planu value is authoritative; external change is discarded.
7
+ * - external-wins → External PM value is authoritative; applied to Planu.
8
+ * - newest-wins → The most recently updated side wins. Falls back to spec-wins
9
+ * when timestamps are equal or unparseable.
10
+ * - manual → Conflict is flagged for human review; no automatic resolution.
11
+ */
12
+ export declare function resolveConflict(conflict: Omit<PmSyncConflict, 'resolution'>, strategy: PmConflictStrategy): PmSyncConflict;
13
+ /**
14
+ * Resolve a list of conflicts using the given strategy.
15
+ */
16
+ export declare function resolveConflicts(conflicts: Omit<PmSyncConflict, 'resolution'>[], strategy: PmConflictStrategy): PmSyncConflict[];
17
+ //# sourceMappingURL=conflict-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conflict-resolver.d.ts","sourceRoot":"","sources":["../../../src/engine/sync/conflict-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/E;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,EAC5C,QAAQ,EAAE,kBAAkB,GAC3B,cAAc,CAGhB;AAqDD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,EAAE,EAC/C,QAAQ,EAAE,kBAAkB,GAC3B,cAAc,EAAE,CAElB"}