@planu/cli 0.72.0 → 0.74.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 (267) hide show
  1. package/README.md +1 -1
  2. package/dist/config/license-plans.json +9 -2
  3. package/dist/config/tool-groups.json +5 -1
  4. package/dist/engine/actuals/git-analyzer.js +1 -1
  5. package/dist/engine/actuals/git-analyzer.js.map +1 -1
  6. package/dist/engine/agent-prompt-generator.d.ts +12 -0
  7. package/dist/engine/agent-prompt-generator.d.ts.map +1 -0
  8. package/dist/engine/agent-prompt-generator.js +171 -0
  9. package/dist/engine/agent-prompt-generator.js.map +1 -0
  10. package/dist/engine/ai-tool-detector/index.d.ts +6 -0
  11. package/dist/engine/ai-tool-detector/index.d.ts.map +1 -0
  12. package/dist/engine/ai-tool-detector/index.js +95 -0
  13. package/dist/engine/ai-tool-detector/index.js.map +1 -0
  14. package/dist/engine/ci-generator/planu-steps.d.ts.map +1 -1
  15. package/dist/engine/ci-generator/planu-steps.js +10 -11
  16. package/dist/engine/ci-generator/planu-steps.js.map +1 -1
  17. package/dist/engine/convention-scanner/codebase-scanner.d.ts +7 -0
  18. package/dist/engine/convention-scanner/codebase-scanner.d.ts.map +1 -0
  19. package/dist/engine/convention-scanner/codebase-scanner.js +258 -0
  20. package/dist/engine/convention-scanner/codebase-scanner.js.map +1 -0
  21. package/dist/engine/convention-scanner/convention-parser.d.ts +7 -0
  22. package/dist/engine/convention-scanner/convention-parser.d.ts.map +1 -0
  23. package/dist/engine/convention-scanner/convention-parser.js +195 -0
  24. package/dist/engine/convention-scanner/convention-parser.js.map +1 -0
  25. package/dist/engine/convention-scanner/index.d.ts +3 -0
  26. package/dist/engine/convention-scanner/index.d.ts.map +1 -0
  27. package/dist/engine/convention-scanner/index.js +5 -0
  28. package/dist/engine/convention-scanner/index.js.map +1 -0
  29. package/dist/engine/convention-sync.d.ts +9 -0
  30. package/dist/engine/convention-sync.d.ts.map +1 -0
  31. package/dist/engine/convention-sync.js +156 -0
  32. package/dist/engine/convention-sync.js.map +1 -0
  33. package/dist/engine/doc-generator/portal/portal-regenerator.d.ts +2 -1
  34. package/dist/engine/doc-generator/portal/portal-regenerator.d.ts.map +1 -1
  35. package/dist/engine/doc-generator/portal/portal-regenerator.js +23 -15
  36. package/dist/engine/doc-generator/portal/portal-regenerator.js.map +1 -1
  37. package/dist/engine/feedback/triage.d.ts +16 -0
  38. package/dist/engine/feedback/triage.d.ts.map +1 -0
  39. package/dist/engine/feedback/triage.js +165 -0
  40. package/dist/engine/feedback/triage.js.map +1 -0
  41. package/dist/engine/hooks-reconciler.d.ts +7 -0
  42. package/dist/engine/hooks-reconciler.d.ts.map +1 -0
  43. package/dist/engine/hooks-reconciler.js +214 -0
  44. package/dist/engine/hooks-reconciler.js.map +1 -0
  45. package/dist/engine/platform-registry.d.ts +17 -0
  46. package/dist/engine/platform-registry.d.ts.map +1 -0
  47. package/dist/engine/platform-registry.js +78 -0
  48. package/dist/engine/platform-registry.js.map +1 -0
  49. package/dist/engine/project-health-checker.d.ts +4 -2
  50. package/dist/engine/project-health-checker.d.ts.map +1 -1
  51. package/dist/engine/project-health-checker.js +96 -7
  52. package/dist/engine/project-health-checker.js.map +1 -1
  53. package/dist/engine/rules-generator/index.d.ts +14 -0
  54. package/dist/engine/rules-generator/index.d.ts.map +1 -0
  55. package/dist/engine/rules-generator/index.js +313 -0
  56. package/dist/engine/rules-generator/index.js.map +1 -0
  57. package/dist/engine/rules-reconciler.d.ts +13 -0
  58. package/dist/engine/rules-reconciler.d.ts.map +1 -0
  59. package/dist/engine/rules-reconciler.js +193 -0
  60. package/dist/engine/rules-reconciler.js.map +1 -0
  61. package/dist/engine/skill-generator/detect.d.ts +1 -0
  62. package/dist/engine/skill-generator/detect.d.ts.map +1 -1
  63. package/dist/engine/skill-generator/detect.js +13 -5
  64. package/dist/engine/skill-generator/detect.js.map +1 -1
  65. package/dist/engine/skills/skills-fetcher.d.ts +4 -0
  66. package/dist/engine/skills/skills-fetcher.d.ts.map +1 -0
  67. package/dist/engine/skills/skills-fetcher.js +102 -0
  68. package/dist/engine/skills/skills-fetcher.js.map +1 -0
  69. package/dist/engine/skills-reconciler.d.ts +15 -0
  70. package/dist/engine/skills-reconciler.d.ts.map +1 -0
  71. package/dist/engine/skills-reconciler.js +98 -0
  72. package/dist/engine/skills-reconciler.js.map +1 -0
  73. package/dist/engine/spec-template-cleaner.d.ts +12 -0
  74. package/dist/engine/spec-template-cleaner.d.ts.map +1 -0
  75. package/dist/engine/spec-template-cleaner.js +119 -0
  76. package/dist/engine/spec-template-cleaner.js.map +1 -0
  77. package/dist/engine/validator/analyzer.d.ts +4 -2
  78. package/dist/engine/validator/analyzer.d.ts.map +1 -1
  79. package/dist/engine/validator/analyzer.js +5 -2
  80. package/dist/engine/validator/analyzer.js.map +1 -1
  81. package/dist/engine/validator/deep-code-checker.d.ts +4 -2
  82. package/dist/engine/validator/deep-code-checker.d.ts.map +1 -1
  83. package/dist/engine/validator/deep-code-checker.js +44 -1
  84. package/dist/engine/validator/deep-code-checker.js.map +1 -1
  85. package/dist/engine/validator/extractors.d.ts +8 -1
  86. package/dist/engine/validator/extractors.d.ts.map +1 -1
  87. package/dist/engine/validator/extractors.js +33 -0
  88. package/dist/engine/validator/extractors.js.map +1 -1
  89. package/dist/engine/validator.d.ts.map +1 -1
  90. package/dist/engine/validator.js +13 -2
  91. package/dist/engine/validator.js.map +1 -1
  92. package/dist/engine/workers/schema.d.ts +58 -0
  93. package/dist/engine/workers/schema.d.ts.map +1 -0
  94. package/dist/engine/workers/schema.js +41 -0
  95. package/dist/engine/workers/schema.js.map +1 -0
  96. package/dist/engine/workers/worker-engine.js +1 -1
  97. package/dist/engine/workers/worker-engine.js.map +1 -1
  98. package/dist/index.js +10 -0
  99. package/dist/index.js.map +1 -1
  100. package/dist/storage/convention-baseline.d.ts +20 -0
  101. package/dist/storage/convention-baseline.d.ts.map +1 -0
  102. package/dist/storage/convention-baseline.js +57 -0
  103. package/dist/storage/convention-baseline.js.map +1 -0
  104. package/dist/storage/feedback-remote.d.ts +8 -0
  105. package/dist/storage/feedback-remote.d.ts.map +1 -0
  106. package/dist/storage/feedback-remote.js +27 -0
  107. package/dist/storage/feedback-remote.js.map +1 -0
  108. package/dist/storage/feedback-store.d.ts +27 -0
  109. package/dist/storage/feedback-store.d.ts.map +1 -0
  110. package/dist/storage/feedback-store.js +272 -0
  111. package/dist/storage/feedback-store.js.map +1 -0
  112. package/dist/storage/index.d.ts +1 -0
  113. package/dist/storage/index.d.ts.map +1 -1
  114. package/dist/storage/index.js +1 -0
  115. package/dist/storage/index.js.map +1 -1
  116. package/dist/tools/convention-sync.d.ts +8 -0
  117. package/dist/tools/convention-sync.d.ts.map +1 -0
  118. package/dist/tools/convention-sync.js +77 -0
  119. package/dist/tools/convention-sync.js.map +1 -0
  120. package/dist/tools/create-spec/post-creation.js +1 -1
  121. package/dist/tools/create-spec/post-creation.js.map +1 -1
  122. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.d.ts +9 -0
  123. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.d.ts.map +1 -0
  124. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.js +68 -0
  125. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.js.map +1 -0
  126. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.d.ts +14 -0
  127. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.d.ts.map +1 -0
  128. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.js +60 -0
  129. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.js.map +1 -0
  130. package/dist/tools/create-spec-hu/ac-adapters/index.d.ts +4 -0
  131. package/dist/tools/create-spec-hu/ac-adapters/index.d.ts.map +1 -1
  132. package/dist/tools/create-spec-hu/ac-adapters/index.js +9 -1
  133. package/dist/tools/create-spec-hu/ac-adapters/index.js.map +1 -1
  134. package/dist/tools/create-spec-hu/serverless-hu-adapter.d.ts +8 -0
  135. package/dist/tools/create-spec-hu/serverless-hu-adapter.d.ts.map +1 -0
  136. package/dist/tools/create-spec-hu/serverless-hu-adapter.js +46 -0
  137. package/dist/tools/create-spec-hu/serverless-hu-adapter.js.map +1 -0
  138. package/dist/tools/create-spec-hu.d.ts.map +1 -1
  139. package/dist/tools/create-spec-hu.js +4 -0
  140. package/dist/tools/create-spec-hu.js.map +1 -1
  141. package/dist/tools/create-spec.d.ts.map +1 -1
  142. package/dist/tools/create-spec.js +3 -2
  143. package/dist/tools/create-spec.js.map +1 -1
  144. package/dist/tools/delete-decision.d.ts.map +1 -1
  145. package/dist/tools/delete-decision.js +2 -0
  146. package/dist/tools/delete-decision.js.map +1 -1
  147. package/dist/tools/delete-project.d.ts.map +1 -1
  148. package/dist/tools/delete-project.js +11 -14
  149. package/dist/tools/delete-project.js.map +1 -1
  150. package/dist/tools/delete-spec.d.ts.map +1 -1
  151. package/dist/tools/delete-spec.js +11 -9
  152. package/dist/tools/delete-spec.js.map +1 -1
  153. package/dist/tools/estimate.d.ts.map +1 -1
  154. package/dist/tools/estimate.js +6 -5
  155. package/dist/tools/estimate.js.map +1 -1
  156. package/dist/tools/export-session.d.ts.map +1 -1
  157. package/dist/tools/export-session.js +13 -10
  158. package/dist/tools/export-session.js.map +1 -1
  159. package/dist/tools/feedback-handler.d.ts +5 -0
  160. package/dist/tools/feedback-handler.d.ts.map +1 -0
  161. package/dist/tools/feedback-handler.js +106 -0
  162. package/dist/tools/feedback-handler.js.map +1 -0
  163. package/dist/tools/generate-teammate-prompt.d.ts +8 -0
  164. package/dist/tools/generate-teammate-prompt.d.ts.map +1 -1
  165. package/dist/tools/generate-teammate-prompt.js +33 -0
  166. package/dist/tools/generate-teammate-prompt.js.map +1 -1
  167. package/dist/tools/init-project/handler.d.ts.map +1 -1
  168. package/dist/tools/init-project/handler.js +42 -7
  169. package/dist/tools/init-project/handler.js.map +1 -1
  170. package/dist/tools/init-project/helpers.d.ts.map +1 -1
  171. package/dist/tools/init-project/helpers.js +1 -2
  172. package/dist/tools/init-project/helpers.js.map +1 -1
  173. package/dist/tools/init-project/result-builder.d.ts.map +1 -1
  174. package/dist/tools/init-project/result-builder.js +12 -1
  175. package/dist/tools/init-project/result-builder.js.map +1 -1
  176. package/dist/tools/log-decision.d.ts.map +1 -1
  177. package/dist/tools/log-decision.js +15 -4
  178. package/dist/tools/log-decision.js.map +1 -1
  179. package/dist/tools/manage-trash.d.ts.map +1 -1
  180. package/dist/tools/manage-trash.js +13 -27
  181. package/dist/tools/manage-trash.js.map +1 -1
  182. package/dist/tools/reconcile-hooks.d.ts +7 -0
  183. package/dist/tools/reconcile-hooks.d.ts.map +1 -0
  184. package/dist/tools/reconcile-hooks.js +78 -0
  185. package/dist/tools/reconcile-hooks.js.map +1 -0
  186. package/dist/tools/reconcile-rules.d.ts +7 -0
  187. package/dist/tools/reconcile-rules.d.ts.map +1 -0
  188. package/dist/tools/reconcile-rules.js +86 -0
  189. package/dist/tools/reconcile-rules.js.map +1 -0
  190. package/dist/tools/reconcile-skills.d.ts +8 -0
  191. package/dist/tools/reconcile-skills.d.ts.map +1 -0
  192. package/dist/tools/reconcile-skills.js +70 -0
  193. package/dist/tools/reconcile-skills.js.map +1 -0
  194. package/dist/tools/register-feedback-tools.d.ts +3 -0
  195. package/dist/tools/register-feedback-tools.d.ts.map +1 -0
  196. package/dist/tools/register-feedback-tools.js +65 -0
  197. package/dist/tools/register-feedback-tools.js.map +1 -0
  198. package/dist/tools/register-spec-tools/core-spec-tools.d.ts.map +1 -1
  199. package/dist/tools/register-spec-tools/core-spec-tools.js +10 -4
  200. package/dist/tools/register-spec-tools/core-spec-tools.js.map +1 -1
  201. package/dist/tools/register-team-tools.d.ts.map +1 -1
  202. package/dist/tools/register-team-tools.js +35 -8
  203. package/dist/tools/register-team-tools.js.map +1 -1
  204. package/dist/tools/safe-handler.d.ts.map +1 -1
  205. package/dist/tools/safe-handler.js +20 -2
  206. package/dist/tools/safe-handler.js.map +1 -1
  207. package/dist/tools/schemas/index.d.ts +1 -0
  208. package/dist/tools/schemas/index.d.ts.map +1 -1
  209. package/dist/tools/schemas/index.js +1 -0
  210. package/dist/tools/schemas/index.js.map +1 -1
  211. package/dist/tools/schemas/reconcile-skills-schemas.d.ts +7 -0
  212. package/dist/tools/schemas/reconcile-skills-schemas.d.ts.map +1 -0
  213. package/dist/tools/schemas/reconcile-skills-schemas.js +18 -0
  214. package/dist/tools/schemas/reconcile-skills-schemas.js.map +1 -0
  215. package/dist/tools/schemas/workers-schema.d.ts +1 -56
  216. package/dist/tools/schemas/workers-schema.d.ts.map +1 -1
  217. package/dist/tools/schemas/workers-schema.js +6 -42
  218. package/dist/tools/schemas/workers-schema.js.map +1 -1
  219. package/dist/tools/skill-registry/search.d.ts.map +1 -1
  220. package/dist/tools/skill-registry/search.js +29 -3
  221. package/dist/tools/skill-registry/search.js.map +1 -1
  222. package/dist/tools/suggest-tooling/skills-fetcher.d.ts +1 -3
  223. package/dist/tools/suggest-tooling/skills-fetcher.d.ts.map +1 -1
  224. package/dist/tools/suggest-tooling/skills-fetcher.js +3 -101
  225. package/dist/tools/suggest-tooling/skills-fetcher.js.map +1 -1
  226. package/dist/tools/token-recording.d.ts +16 -0
  227. package/dist/tools/token-recording.d.ts.map +1 -0
  228. package/dist/tools/token-recording.js +47 -0
  229. package/dist/tools/token-recording.js.map +1 -0
  230. package/dist/tools/update-status-actions.d.ts.map +1 -1
  231. package/dist/tools/update-status-actions.js +1 -2
  232. package/dist/tools/update-status-actions.js.map +1 -1
  233. package/dist/tools/update-status-convention-gate.d.ts +12 -0
  234. package/dist/tools/update-status-convention-gate.d.ts.map +1 -0
  235. package/dist/tools/update-status-convention-gate.js +159 -0
  236. package/dist/tools/update-status-convention-gate.js.map +1 -0
  237. package/dist/tools/update-status-reconcile.d.ts +7 -0
  238. package/dist/tools/update-status-reconcile.d.ts.map +1 -0
  239. package/dist/tools/update-status-reconcile.js +47 -0
  240. package/dist/tools/update-status-reconcile.js.map +1 -0
  241. package/dist/tools/update-status.d.ts.map +1 -1
  242. package/dist/tools/update-status.js +113 -67
  243. package/dist/tools/update-status.js.map +1 -1
  244. package/dist/tools/validate.d.ts.map +1 -1
  245. package/dist/tools/validate.js +93 -3
  246. package/dist/tools/validate.js.map +1 -1
  247. package/dist/types/ai-tool-rules.d.ts +42 -0
  248. package/dist/types/ai-tool-rules.d.ts.map +1 -0
  249. package/dist/types/ai-tool-rules.js +3 -0
  250. package/dist/types/ai-tool-rules.js.map +1 -0
  251. package/dist/types/conventions.d.ts +155 -0
  252. package/dist/types/conventions.d.ts.map +1 -0
  253. package/dist/types/conventions.js +3 -0
  254. package/dist/types/conventions.js.map +1 -0
  255. package/dist/types/feedback.d.ts +76 -0
  256. package/dist/types/feedback.d.ts.map +1 -0
  257. package/dist/types/feedback.js +3 -0
  258. package/dist/types/feedback.js.map +1 -0
  259. package/dist/types/index.d.ts +3 -0
  260. package/dist/types/index.d.ts.map +1 -1
  261. package/dist/types/index.js +1 -0
  262. package/dist/types/index.js.map +1 -1
  263. package/dist/types/project/planu-config.d.ts +4 -0
  264. package/dist/types/project/planu-config.d.ts.map +1 -1
  265. package/package.json +1 -1
  266. package/src/config/license-plans.json +9 -2
  267. package/src/config/tool-groups.json +5 -1
@@ -0,0 +1,313 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { detectAiTools, getPrimaryAiTool } from '../ai-tool-detector/index.js';
4
+ // Stack-specific architecture rules catalog
5
+ export const ARCHITECTURE_RULES = {
6
+ nextjs: {
7
+ title: 'Next.js API Architecture',
8
+ description: 'Clean separation for Next.js API routes',
9
+ layers: [
10
+ {
11
+ name: 'Route Handler',
12
+ path: 'app/api/',
13
+ responsibility: 'Parse request, validate input, call service, format response',
14
+ },
15
+ {
16
+ name: 'Service',
17
+ path: 'lib/services/',
18
+ responsibility: 'Business logic, orchestration, transaction boundaries',
19
+ },
20
+ {
21
+ name: 'Repository',
22
+ path: 'lib/repositories/',
23
+ responsibility: 'Data access (DB queries, external APIs)',
24
+ },
25
+ ],
26
+ conventions: [
27
+ 'Never put business logic in route handlers',
28
+ 'Route handlers should be under 30 lines',
29
+ 'Services are framework-agnostic (no NextRequest/NextResponse)',
30
+ 'Repositories return plain objects, never ORM entities',
31
+ ],
32
+ maxLinesPerHandler: 30,
33
+ },
34
+ express: {
35
+ title: 'Express Architecture',
36
+ description: 'Clean separation for Express.js APIs',
37
+ layers: [
38
+ {
39
+ name: 'Controller',
40
+ path: 'src/controllers/',
41
+ responsibility: 'Parse request, validate, respond',
42
+ },
43
+ {
44
+ name: 'Service',
45
+ path: 'src/services/',
46
+ responsibility: 'Business logic and orchestration',
47
+ },
48
+ {
49
+ name: 'Repository',
50
+ path: 'src/repositories/',
51
+ responsibility: 'Data access layer',
52
+ },
53
+ ],
54
+ conventions: [
55
+ 'Controllers call services, never repositories directly',
56
+ 'Services are stateless',
57
+ 'One file per resource',
58
+ ],
59
+ maxLinesPerHandler: 40,
60
+ },
61
+ fastapi: {
62
+ title: 'FastAPI Architecture',
63
+ description: 'Clean separation for Python FastAPI',
64
+ layers: [
65
+ {
66
+ name: 'Router',
67
+ path: 'app/routers/',
68
+ responsibility: 'Endpoint definitions, input validation',
69
+ },
70
+ {
71
+ name: 'Service',
72
+ path: 'app/services/',
73
+ responsibility: 'Business logic',
74
+ },
75
+ {
76
+ name: 'Repository',
77
+ path: 'app/repositories/',
78
+ responsibility: 'Database access (SQLAlchemy/Prisma)',
79
+ },
80
+ ],
81
+ conventions: [
82
+ 'Use dependency injection via Depends()',
83
+ 'Pydantic models for all I/O',
84
+ 'Async by default',
85
+ ],
86
+ maxLinesPerHandler: 30,
87
+ },
88
+ default: {
89
+ title: 'Clean Architecture',
90
+ description: 'Generic clean architecture rules',
91
+ layers: [
92
+ {
93
+ name: 'Handler',
94
+ path: 'src/handlers/',
95
+ responsibility: 'Input/output boundary',
96
+ },
97
+ {
98
+ name: 'Service',
99
+ path: 'src/services/',
100
+ responsibility: 'Business logic',
101
+ },
102
+ {
103
+ name: 'Repository',
104
+ path: 'src/repositories/',
105
+ responsibility: 'Data access',
106
+ },
107
+ ],
108
+ conventions: [
109
+ 'Separate concerns by layer',
110
+ 'Dependencies point inward',
111
+ 'No framework code in business logic',
112
+ ],
113
+ maxLinesPerHandler: 50,
114
+ },
115
+ };
116
+ /** Detect stack from project files. Returns a key into ARCHITECTURE_RULES. */
117
+ export function detectArchitectureStack(projectPath) {
118
+ // Next.js detection
119
+ if (existsSync(join(projectPath, 'next.config.js')) ||
120
+ existsSync(join(projectPath, 'next.config.ts')) ||
121
+ existsSync(join(projectPath, 'next.config.mjs'))) {
122
+ return 'nextjs';
123
+ }
124
+ // FastAPI detection
125
+ const requirementsTxt = join(projectPath, 'requirements.txt');
126
+ if (existsSync(requirementsTxt)) {
127
+ try {
128
+ const content = readFileSync(requirementsTxt, 'utf-8');
129
+ if (content.toLowerCase().includes('fastapi')) {
130
+ return 'fastapi';
131
+ }
132
+ }
133
+ catch {
134
+ // best-effort
135
+ }
136
+ }
137
+ // Express detection via package.json
138
+ const packageJsonPath = join(projectPath, 'package.json');
139
+ if (existsSync(packageJsonPath)) {
140
+ try {
141
+ const raw = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
142
+ if (typeof raw === 'object' && raw !== null) {
143
+ const pkg = raw;
144
+ const deps = {
145
+ ...(typeof pkg.dependencies === 'object'
146
+ ? pkg.dependencies
147
+ : {}),
148
+ ...(typeof pkg.devDependencies === 'object'
149
+ ? pkg.devDependencies
150
+ : {}),
151
+ };
152
+ if ('express' in deps) {
153
+ return 'express';
154
+ }
155
+ }
156
+ }
157
+ catch {
158
+ // best-effort
159
+ }
160
+ }
161
+ return 'default';
162
+ }
163
+ /** Format layers table as markdown. */
164
+ function formatLayersTable(layers) {
165
+ const rows = layers.map((l) => `| ${l.name} | \`${l.path}\` | ${l.responsibility} |`);
166
+ return ['| Layer | Path | Responsibility |', '|-------|------|----------------|', ...rows].join('\n');
167
+ }
168
+ /** Generate rules content formatted for a specific AI tool. */
169
+ export function generateRulesContent(rule, tool) {
170
+ const conventions = rule.conventions.map((c) => `- ${c}`).join('\n');
171
+ const layersTable = formatLayersTable(rule.layers);
172
+ // All tools use markdown; formatting varies slightly per tool
173
+ switch (tool.toolId) {
174
+ case 'cursor':
175
+ case 'windsurf': {
176
+ // Flat markdown without deep nesting — cursor/windsurf prefer concise rules
177
+ return [
178
+ `# ${rule.title}`,
179
+ '',
180
+ rule.description,
181
+ '',
182
+ '## Layers',
183
+ layersTable,
184
+ '',
185
+ '## Conventions',
186
+ conventions,
187
+ '',
188
+ `## Handler Size Limit`,
189
+ `Max ${rule.maxLinesPerHandler} lines per handler/controller.`,
190
+ '',
191
+ ].join('\n');
192
+ }
193
+ case 'copilot': {
194
+ // GitHub Copilot instructions format
195
+ return [
196
+ `# Architecture Rules: ${rule.title}`,
197
+ '',
198
+ `> ${rule.description}`,
199
+ '',
200
+ '## Layer Structure',
201
+ layersTable,
202
+ '',
203
+ '## Coding Conventions',
204
+ conventions,
205
+ '',
206
+ `## Size Constraints`,
207
+ `- Max ${rule.maxLinesPerHandler} lines per handler`,
208
+ '',
209
+ ].join('\n');
210
+ }
211
+ case 'aider': {
212
+ // Aider CONVENTIONS.md style
213
+ return [
214
+ `# ${rule.title}`,
215
+ '',
216
+ rule.description,
217
+ '',
218
+ '## Architecture Layers',
219
+ layersTable,
220
+ '',
221
+ '## Conventions',
222
+ conventions,
223
+ '',
224
+ `## Constraints`,
225
+ `- Handlers/controllers: max ${rule.maxLinesPerHandler} lines`,
226
+ '',
227
+ ].join('\n');
228
+ }
229
+ case 'claude':
230
+ default: {
231
+ // Standard markdown with full headers — Claude Code format
232
+ return [
233
+ `# ${rule.title}`,
234
+ '',
235
+ `> ${rule.description}`,
236
+ '',
237
+ '## Layer Separation (MANDATORY)',
238
+ '',
239
+ layersTable,
240
+ '',
241
+ '## Conventions (MANDATORY)',
242
+ '',
243
+ conventions,
244
+ '',
245
+ '## Size Budget',
246
+ '',
247
+ `- Max **${rule.maxLinesPerHandler} lines** per handler/controller`,
248
+ '- Extract helpers when exceeding this limit',
249
+ '',
250
+ ].join('\n');
251
+ }
252
+ }
253
+ }
254
+ /** Resolve the file path where rules should be written for a given tool. */
255
+ function resolveRulesFilePath(projectPath, tool, stackKey) {
256
+ switch (tool.toolId) {
257
+ case 'claude':
258
+ return join(projectPath, tool.rulesPath, `architecture-${stackKey}.md`);
259
+ case 'cursor':
260
+ return join(projectPath, '.cursorrules');
261
+ case 'copilot':
262
+ return join(projectPath, '.github', 'copilot-instructions.md');
263
+ case 'windsurf':
264
+ return join(projectPath, '.windsurfrules');
265
+ case 'aider':
266
+ return join(projectPath, 'CONVENTIONS.md');
267
+ default:
268
+ return join(projectPath, tool.rulesPath, `architecture-${stackKey}.md`);
269
+ }
270
+ }
271
+ /** Main entry: detect stack + tools, generate all rules objects. */
272
+ export function generateProjectRules(projectPath) {
273
+ const stackKey = detectArchitectureStack(projectPath);
274
+ const defaultRule = ARCHITECTURE_RULES.default;
275
+ const rule = ARCHITECTURE_RULES[stackKey] ?? defaultRule;
276
+ if (!rule) {
277
+ return [];
278
+ }
279
+ const tools = detectAiTools(projectPath);
280
+ // If no tools detected, generate for claude (default)
281
+ const effectiveTools = tools.length > 0 ? tools : [getPrimaryAiTool(projectPath)];
282
+ return effectiveTools.map((tool) => {
283
+ const filePath = resolveRulesFilePath(projectPath, tool, stackKey);
284
+ const alreadyExists = existsSync(filePath);
285
+ const content = generateRulesContent(rule, tool);
286
+ return { tool, content, filePath, alreadyExists };
287
+ });
288
+ }
289
+ /** Write rules to disk, skipping files that already exist. */
290
+ export function writeRules(rules) {
291
+ const written = [];
292
+ const skipped = [];
293
+ for (const rule of rules) {
294
+ if (rule.alreadyExists) {
295
+ skipped.push(rule.filePath);
296
+ continue;
297
+ }
298
+ try {
299
+ const dir = rule.filePath.substring(0, rule.filePath.lastIndexOf('/'));
300
+ if (dir) {
301
+ mkdirSync(dir, { recursive: true });
302
+ }
303
+ writeFileSync(rule.filePath, rule.content, 'utf-8');
304
+ written.push(rule.filePath);
305
+ }
306
+ catch {
307
+ // best-effort — skip on error
308
+ skipped.push(rule.filePath);
309
+ }
310
+ }
311
+ return { written, skipped };
312
+ }
313
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/rules-generator/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { RulesReconciliation } from '../types/index.js';
2
+ export type { RulesReconciliation };
3
+ declare function readFileSafe(path: string): string;
4
+ /**
5
+ * Compare CLAUDE.md conventions against existing .claude/rules/ files.
6
+ * Auto-patches missing convention categories by generating new rules files.
7
+ * Never overwrites existing rules files.
8
+ *
9
+ * Never throws — returns a zero-score reconciliation on unexpected errors.
10
+ */
11
+ export declare function reconcileRules(projectPath: string): RulesReconciliation;
12
+ export { readFileSafe };
13
+ //# sourceMappingURL=rules-reconciler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules-reconciler.d.ts","sourceRoot":"","sources":["../../src/engine/rules-reconciler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAepC,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1C;AA6HD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,CA6DvE;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,193 @@
1
+ // engine/rules-reconciler.ts — Compare CLAUDE.md conventions against .claude/rules/ and auto-patch drift (SPEC-189)
2
+ import { readFileSync, readdirSync, writeFileSync, mkdirSync } from 'node:fs';
3
+ import { join, basename } from 'node:path';
4
+ import { parseConventions } from './convention-scanner/convention-parser.js';
5
+ // ── Helpers ───────────────────────────────────────────────────────────────────
6
+ function listRulesFiles(projectPath) {
7
+ const rulesDir = join(projectPath, '.claude', 'rules');
8
+ try {
9
+ return readdirSync(rulesDir)
10
+ .filter((f) => f.endsWith('.md'))
11
+ .map((f) => join(rulesDir, f));
12
+ }
13
+ catch {
14
+ return [];
15
+ }
16
+ }
17
+ function readFileSafe(path) {
18
+ try {
19
+ return readFileSync(path, 'utf-8');
20
+ }
21
+ catch {
22
+ return '';
23
+ }
24
+ }
25
+ /** Unique convention categories detected in CLAUDE.md (source: 'claude-md' only). */
26
+ function categoriesInClaudeMd(rules) {
27
+ const categories = new Set();
28
+ for (const r of rules) {
29
+ if (r.source === 'claude-md') {
30
+ categories.add(r.category);
31
+ }
32
+ }
33
+ return categories;
34
+ }
35
+ /**
36
+ * Build a map: category → rules files that mention it (via keyword matching).
37
+ * A rules file "covers" a category if it contains any line that would parse
38
+ * as that category using the same keywords as convention-parser.
39
+ */
40
+ function buildCoverageMap(rulesFiles, allRules) {
41
+ const coverageMap = new Map();
42
+ // Build per-file category sets from already-parsed rules
43
+ for (const r of allRules) {
44
+ if (r.source !== 'rules-file') {
45
+ continue;
46
+ }
47
+ const existing = coverageMap.get(r.category) ?? [];
48
+ if (!existing.includes(r.sourceFile)) {
49
+ existing.push(r.sourceFile);
50
+ }
51
+ coverageMap.set(r.category, existing);
52
+ }
53
+ // Ensure every rules file appears in the map even with no matches
54
+ for (const filePath of rulesFiles) {
55
+ for (const [, files] of coverageMap) {
56
+ if (!files.includes(filePath)) {
57
+ // already handled above; this loop is a no-op but makes intent clear
58
+ }
59
+ }
60
+ }
61
+ return coverageMap;
62
+ }
63
+ /**
64
+ * Find rules files whose content does NOT match any category still present
65
+ * in CLAUDE.md — meaning they may be stale.
66
+ *
67
+ * A file is "stale" when it has NO categories in common with CLAUDE.md categories.
68
+ */
69
+ function detectStaleRules(rulesFiles, allRules, claudeCategories) {
70
+ // Build per-file category sets
71
+ const fileCategories = new Map();
72
+ for (const r of allRules) {
73
+ if (r.source !== 'rules-file') {
74
+ continue;
75
+ }
76
+ const cats = fileCategories.get(r.sourceFile) ?? new Set();
77
+ cats.add(r.category);
78
+ fileCategories.set(r.sourceFile, cats);
79
+ }
80
+ const stale = [];
81
+ for (const filePath of rulesFiles) {
82
+ const cats = fileCategories.get(filePath);
83
+ if (!cats || cats.size === 0) {
84
+ // No parseable conventions found — candidate for stale
85
+ stale.push(basename(filePath));
86
+ continue;
87
+ }
88
+ // Stale if none of its categories overlap with CLAUDE.md categories
89
+ const hasOverlap = [...cats].some((c) => claudeCategories.has(c));
90
+ if (!hasOverlap) {
91
+ stale.push(basename(filePath));
92
+ }
93
+ }
94
+ return stale;
95
+ }
96
+ /** Generate minimal markdown content for a new rules file covering a category. */
97
+ function generateRuleFileContent(category, conventions) {
98
+ const relevant = conventions.filter((r) => r.source === 'claude-md' && r.category === category);
99
+ const lines = [
100
+ `# ${category.charAt(0).toUpperCase() + category.slice(1)} Conventions (auto-generated by reconcile_rules)`,
101
+ '',
102
+ `Rules for the **${category}** category extracted from CLAUDE.md.`,
103
+ '',
104
+ '## Conventions',
105
+ '',
106
+ ];
107
+ for (const r of relevant) {
108
+ const prefix = r.severity === 'critical'
109
+ ? '**[MANDATORY]**'
110
+ : r.severity === 'warning'
111
+ ? '**[SHOULD]**'
112
+ : '';
113
+ lines.push(`- ${prefix} ${r.description}`);
114
+ }
115
+ lines.push('');
116
+ return lines.join('\n');
117
+ }
118
+ /** Write a new rules file to .claude/rules/ for the given category. */
119
+ function writeNewRulesFile(projectPath, category, conventions) {
120
+ const rulesDir = join(projectPath, '.claude', 'rules');
121
+ mkdirSync(rulesDir, { recursive: true });
122
+ const fileName = `${category}.md`;
123
+ const filePath = join(rulesDir, fileName);
124
+ const content = generateRuleFileContent(category, conventions);
125
+ writeFileSync(filePath, content, 'utf-8');
126
+ return fileName;
127
+ }
128
+ // ── Public API ────────────────────────────────────────────────────────────────
129
+ /**
130
+ * Compare CLAUDE.md conventions against existing .claude/rules/ files.
131
+ * Auto-patches missing convention categories by generating new rules files.
132
+ * Never overwrites existing rules files.
133
+ *
134
+ * Never throws — returns a zero-score reconciliation on unexpected errors.
135
+ */
136
+ export function reconcileRules(projectPath) {
137
+ try {
138
+ // 1. Parse all conventions (CLAUDE.md + rules files)
139
+ const allRules = parseConventions(projectPath);
140
+ const rulesFiles = listRulesFiles(projectPath);
141
+ // 2. Determine which categories are defined in CLAUDE.md
142
+ const claudeCategories = categoriesInClaudeMd(allRules);
143
+ if (claudeCategories.size === 0) {
144
+ return {
145
+ rulesInSync: rulesFiles.length === 0,
146
+ newRulesNeeded: [],
147
+ staleRules: rulesFiles.map((f) => basename(f)),
148
+ updatedRules: [],
149
+ healthScore: rulesFiles.length === 0 ? 100 : 0,
150
+ };
151
+ }
152
+ // 3. Build coverage map: which categories are covered by rules files
153
+ const coverageMap = buildCoverageMap(rulesFiles, allRules);
154
+ // 4. Find categories in CLAUDE.md with no rules file coverage
155
+ const newRulesNeeded = [];
156
+ for (const category of claudeCategories) {
157
+ const coveredBy = coverageMap.get(category) ?? [];
158
+ if (coveredBy.length === 0) {
159
+ newRulesNeeded.push(category);
160
+ }
161
+ }
162
+ // 5. Detect stale rules files
163
+ const staleRules = detectStaleRules(rulesFiles, allRules, claudeCategories);
164
+ // 6. Auto-patch: generate new rules files for uncovered categories
165
+ const updatedRules = [];
166
+ for (const category of newRulesNeeded) {
167
+ const fileName = writeNewRulesFile(projectPath, category, allRules);
168
+ updatedRules.push(fileName);
169
+ }
170
+ // 7. Calculate health score
171
+ const covered = claudeCategories.size - newRulesNeeded.length + updatedRules.length;
172
+ const healthScore = Math.round((covered / claudeCategories.size) * 100);
173
+ return {
174
+ rulesInSync: newRulesNeeded.length === 0 && staleRules.length === 0,
175
+ newRulesNeeded,
176
+ staleRules,
177
+ updatedRules,
178
+ healthScore,
179
+ };
180
+ }
181
+ catch {
182
+ return {
183
+ rulesInSync: false,
184
+ newRulesNeeded: [],
185
+ staleRules: [],
186
+ updatedRules: [],
187
+ healthScore: 0,
188
+ };
189
+ }
190
+ }
191
+ // Re-export for external use
192
+ export { readFileSafe };
193
+ //# sourceMappingURL=rules-reconciler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules-reconciler.js","sourceRoot":"","sources":["../../src/engine/rules-reconciler.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ export declare function detectAgentPlatform(projectConventions: Record<string, s
15
15
  /**
16
16
  * Detect which AI agent platform is being used by scanning actual config files on disk.
17
17
  * More reliable than convention-based detection.
18
+ * Merges built-in platforms with any custom platforms defined in planu.json.
18
19
  */
19
20
  export declare function detectAgentPlatformFromFiles(projectPath: string): Promise<{
20
21
  platform: AgentPlatform;
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-generator/detect.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAMxF,wBAAsB,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC,CAa9D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBlF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAgClF;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,CAChD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAsClF"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/engine/skill-generator/detect.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAOxF,wBAAsB,aAAa,IAAI,OAAO,CAAC,eAAe,CAAC,CAa9D;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBlF;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAgClF;AAED;;;;GAIG;AACH,wBAAsB,4BAA4B,CAChD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,QAAQ,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA6ClF"}
@@ -1,6 +1,7 @@
1
1
  // Agent platform detection functions
2
2
  import { readFile, access } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
+ import { loadPlatforms as loadExtendedPlatforms } from '../platform-registry.js';
4
5
  // === Agent Platform Config ===
5
6
  let platformsCache = null;
6
7
  export async function loadPlatforms() {
@@ -75,16 +76,22 @@ export async function detectAgentPlatform(projectConventions) {
75
76
  /**
76
77
  * Detect which AI agent platform is being used by scanning actual config files on disk.
77
78
  * More reliable than convention-based detection.
79
+ * Merges built-in platforms with any custom platforms defined in planu.json.
78
80
  */
79
81
  export async function detectAgentPlatformFromFiles(projectPath) {
80
- const platforms = await loadPlatforms();
82
+ // Use extended registry so custom platforms defined in planu.json are included
83
+ const allPlatforms = await loadExtendedPlatforms(projectPath);
81
84
  const detectedFrom = [];
82
85
  let bestPlatform = 'claude-code';
83
86
  let bestScore = 0;
84
- for (const [key, config] of Object.entries(platforms.platforms)) {
87
+ for (const platformDef of allPlatforms) {
85
88
  let score = 0;
86
89
  const foundFiles = [];
87
- const configFiles = config.configFiles ?? [config.rulesFile];
90
+ const configFiles = platformDef.configFiles.length > 0
91
+ ? platformDef.configFiles
92
+ : platformDef.rulesFile
93
+ ? [platformDef.rulesFile]
94
+ : [];
88
95
  for (const cfgFile of configFiles) {
89
96
  if (!cfgFile) {
90
97
  continue;
@@ -100,11 +107,12 @@ export async function detectAgentPlatformFromFiles(projectPath) {
100
107
  }
101
108
  }
102
109
  if (foundFiles.length > 0) {
103
- detectedFrom.push(...foundFiles.map((f) => `${key}: ${f}`));
110
+ detectedFrom.push(...foundFiles.map((f) => `${platformDef.id}: ${f}`));
104
111
  }
105
112
  if (score > bestScore) {
106
113
  bestScore = score;
107
- bestPlatform = key;
114
+ // Custom platform ids fall back to 'custom' if not in the AgentPlatform union
115
+ bestPlatform = platformDef.id;
108
116
  }
109
117
  }
110
118
  const confidence = bestScore > 0 ? Math.min(1, bestScore / 6) : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../src/engine/skill-generator/detect.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,gCAAgC;AAEhC,IAAI,cAAc,GAA2B,IAAI,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,mCAAmC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjF,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACpD,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAoB,CAAC;QACxD,OAAO,cAAc,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAuB;IAC1D,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAE7C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,QAAQ;YACR,SAAS,EAAE,EAAE;YACb,MAAM,EAAE,UAAU;YAClB,YAAY,EAAE,EAAE;YAChB,UAAU,EAAE,KAAK;SAClB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ;QACR,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,SAAS;QACxC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,kBAA0C;IAE1C,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;IACxC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,YAAY,GAAkB,aAAa,CAAC;IAChD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAChE,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,4CAA4C;QAC5C,IAAI,MAAM,CAAC,SAAS,IAAI,kBAAkB,CAAC,UAAU,CAAC,KAAK,MAAM,CAAC,SAAS,EAAE,CAAC;YAC5E,KAAK,IAAI,CAAC,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,8CAA8C;QAC9C,qEAAqE;QACrE,MAAM,aAAa,GAAG,GAAG,KAAK,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC;QAC1E,IAAI,kBAAkB,CAAC,aAAa,CAAC,EAAE,CAAC;YACtC,KAAK,IAAI,CAAC,CAAC;YACX,YAAY,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAC;YAClB,YAAY,GAAG,GAAoB,CAAC;QACtC,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;IAE9C,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAC9D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,WAAmB;IAEnB,MAAM,SAAS,GAAG,MAAM,aAAa,EAAE,CAAC;IACxC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,IAAI,YAAY,GAAkB,aAAa,CAAC;IAChD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;QAChE,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,MAAM,UAAU,GAAa,EAAE,CAAC;QAEhC,MAAM,WAAW,GAAa,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAEvE,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,SAAS;YACX,CAAC;YACD,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YAC5C,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACvB,KAAK,IAAI,CAAC,CAAC;gBACX,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,CAAC;YAAC,MAAM,CAAC;gBACP,qCAAqC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,YAAY,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,SAAS,GAAG,KAAK,CAAC;YAClB,YAAY,GAAG,GAAoB,CAAC;QACtC,CAAC;IACH,CAAC;IAED,MAAM,UAAU,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../src/engine/skill-generator/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ProjectKnowledge, RecommendedSkill } from '../../types/index.js';
2
+ export declare function isMcpServer(knowledge: ProjectKnowledge): boolean;
3
+ export declare function fetchRecommendedSkills(knowledge: ProjectKnowledge): Promise<RecommendedSkill[]>;
4
+ //# sourceMappingURL=skills-fetcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-fetcher.d.ts","sourceRoot":"","sources":["../../../src/engine/skills/skills-fetcher.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG/E,wBAAgB,WAAW,CAAC,SAAS,EAAE,gBAAgB,GAAG,OAAO,CAQhE;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,gBAAgB,GAC1B,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAgC7B"}