@planu/cli 0.72.0 → 0.73.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 (255) 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 +78 -5
  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-hu/ac-adapters/convention-adapter.d.ts +9 -0
  121. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.d.ts.map +1 -0
  122. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.js +68 -0
  123. package/dist/tools/create-spec-hu/ac-adapters/convention-adapter.js.map +1 -0
  124. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.d.ts +14 -0
  125. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.d.ts.map +1 -0
  126. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.js +60 -0
  127. package/dist/tools/create-spec-hu/ac-adapters/custom-template-adapter.js.map +1 -0
  128. package/dist/tools/create-spec-hu/ac-adapters/index.d.ts +4 -0
  129. package/dist/tools/create-spec-hu/ac-adapters/index.d.ts.map +1 -1
  130. package/dist/tools/create-spec-hu/ac-adapters/index.js +9 -1
  131. package/dist/tools/create-spec-hu/ac-adapters/index.js.map +1 -1
  132. package/dist/tools/create-spec.d.ts.map +1 -1
  133. package/dist/tools/create-spec.js +3 -2
  134. package/dist/tools/create-spec.js.map +1 -1
  135. package/dist/tools/delete-decision.d.ts.map +1 -1
  136. package/dist/tools/delete-decision.js +2 -0
  137. package/dist/tools/delete-decision.js.map +1 -1
  138. package/dist/tools/delete-project.d.ts.map +1 -1
  139. package/dist/tools/delete-project.js +11 -14
  140. package/dist/tools/delete-project.js.map +1 -1
  141. package/dist/tools/delete-spec.d.ts.map +1 -1
  142. package/dist/tools/delete-spec.js +11 -9
  143. package/dist/tools/delete-spec.js.map +1 -1
  144. package/dist/tools/estimate.d.ts.map +1 -1
  145. package/dist/tools/estimate.js +6 -5
  146. package/dist/tools/estimate.js.map +1 -1
  147. package/dist/tools/export-session.d.ts.map +1 -1
  148. package/dist/tools/export-session.js +7 -9
  149. package/dist/tools/export-session.js.map +1 -1
  150. package/dist/tools/feedback-handler.d.ts +5 -0
  151. package/dist/tools/feedback-handler.d.ts.map +1 -0
  152. package/dist/tools/feedback-handler.js +106 -0
  153. package/dist/tools/feedback-handler.js.map +1 -0
  154. package/dist/tools/generate-teammate-prompt.d.ts +8 -0
  155. package/dist/tools/generate-teammate-prompt.d.ts.map +1 -1
  156. package/dist/tools/generate-teammate-prompt.js +33 -0
  157. package/dist/tools/generate-teammate-prompt.js.map +1 -1
  158. package/dist/tools/init-project/handler.d.ts.map +1 -1
  159. package/dist/tools/init-project/handler.js +42 -7
  160. package/dist/tools/init-project/handler.js.map +1 -1
  161. package/dist/tools/init-project/helpers.d.ts.map +1 -1
  162. package/dist/tools/init-project/helpers.js +1 -2
  163. package/dist/tools/init-project/helpers.js.map +1 -1
  164. package/dist/tools/init-project/result-builder.d.ts.map +1 -1
  165. package/dist/tools/init-project/result-builder.js +12 -1
  166. package/dist/tools/init-project/result-builder.js.map +1 -1
  167. package/dist/tools/log-decision.d.ts.map +1 -1
  168. package/dist/tools/log-decision.js +15 -4
  169. package/dist/tools/log-decision.js.map +1 -1
  170. package/dist/tools/manage-trash.d.ts.map +1 -1
  171. package/dist/tools/manage-trash.js +13 -27
  172. package/dist/tools/manage-trash.js.map +1 -1
  173. package/dist/tools/reconcile-hooks.d.ts +7 -0
  174. package/dist/tools/reconcile-hooks.d.ts.map +1 -0
  175. package/dist/tools/reconcile-hooks.js +78 -0
  176. package/dist/tools/reconcile-hooks.js.map +1 -0
  177. package/dist/tools/reconcile-rules.d.ts +7 -0
  178. package/dist/tools/reconcile-rules.d.ts.map +1 -0
  179. package/dist/tools/reconcile-rules.js +86 -0
  180. package/dist/tools/reconcile-rules.js.map +1 -0
  181. package/dist/tools/reconcile-skills.d.ts +8 -0
  182. package/dist/tools/reconcile-skills.d.ts.map +1 -0
  183. package/dist/tools/reconcile-skills.js +70 -0
  184. package/dist/tools/reconcile-skills.js.map +1 -0
  185. package/dist/tools/register-feedback-tools.d.ts +3 -0
  186. package/dist/tools/register-feedback-tools.d.ts.map +1 -0
  187. package/dist/tools/register-feedback-tools.js +65 -0
  188. package/dist/tools/register-feedback-tools.js.map +1 -0
  189. package/dist/tools/register-spec-tools/core-spec-tools.d.ts.map +1 -1
  190. package/dist/tools/register-spec-tools/core-spec-tools.js +10 -4
  191. package/dist/tools/register-spec-tools/core-spec-tools.js.map +1 -1
  192. package/dist/tools/register-team-tools.d.ts.map +1 -1
  193. package/dist/tools/register-team-tools.js +35 -8
  194. package/dist/tools/register-team-tools.js.map +1 -1
  195. package/dist/tools/safe-handler.d.ts.map +1 -1
  196. package/dist/tools/safe-handler.js +20 -2
  197. package/dist/tools/safe-handler.js.map +1 -1
  198. package/dist/tools/schemas/index.d.ts +1 -0
  199. package/dist/tools/schemas/index.d.ts.map +1 -1
  200. package/dist/tools/schemas/index.js +1 -0
  201. package/dist/tools/schemas/index.js.map +1 -1
  202. package/dist/tools/schemas/reconcile-skills-schemas.d.ts +7 -0
  203. package/dist/tools/schemas/reconcile-skills-schemas.d.ts.map +1 -0
  204. package/dist/tools/schemas/reconcile-skills-schemas.js +18 -0
  205. package/dist/tools/schemas/reconcile-skills-schemas.js.map +1 -0
  206. package/dist/tools/schemas/workers-schema.d.ts +1 -56
  207. package/dist/tools/schemas/workers-schema.d.ts.map +1 -1
  208. package/dist/tools/schemas/workers-schema.js +6 -42
  209. package/dist/tools/schemas/workers-schema.js.map +1 -1
  210. package/dist/tools/skill-registry/search.d.ts.map +1 -1
  211. package/dist/tools/skill-registry/search.js +29 -3
  212. package/dist/tools/skill-registry/search.js.map +1 -1
  213. package/dist/tools/suggest-tooling/skills-fetcher.d.ts +1 -3
  214. package/dist/tools/suggest-tooling/skills-fetcher.d.ts.map +1 -1
  215. package/dist/tools/suggest-tooling/skills-fetcher.js +3 -101
  216. package/dist/tools/suggest-tooling/skills-fetcher.js.map +1 -1
  217. package/dist/tools/token-recording.d.ts +16 -0
  218. package/dist/tools/token-recording.d.ts.map +1 -0
  219. package/dist/tools/token-recording.js +47 -0
  220. package/dist/tools/token-recording.js.map +1 -0
  221. package/dist/tools/update-status-convention-gate.d.ts +12 -0
  222. package/dist/tools/update-status-convention-gate.d.ts.map +1 -0
  223. package/dist/tools/update-status-convention-gate.js +159 -0
  224. package/dist/tools/update-status-convention-gate.js.map +1 -0
  225. package/dist/tools/update-status-reconcile.d.ts +7 -0
  226. package/dist/tools/update-status-reconcile.d.ts.map +1 -0
  227. package/dist/tools/update-status-reconcile.js +47 -0
  228. package/dist/tools/update-status-reconcile.js.map +1 -0
  229. package/dist/tools/update-status.d.ts.map +1 -1
  230. package/dist/tools/update-status.js +113 -67
  231. package/dist/tools/update-status.js.map +1 -1
  232. package/dist/tools/validate.d.ts.map +1 -1
  233. package/dist/tools/validate.js +92 -2
  234. package/dist/tools/validate.js.map +1 -1
  235. package/dist/types/ai-tool-rules.d.ts +42 -0
  236. package/dist/types/ai-tool-rules.d.ts.map +1 -0
  237. package/dist/types/ai-tool-rules.js +3 -0
  238. package/dist/types/ai-tool-rules.js.map +1 -0
  239. package/dist/types/conventions.d.ts +155 -0
  240. package/dist/types/conventions.d.ts.map +1 -0
  241. package/dist/types/conventions.js +3 -0
  242. package/dist/types/conventions.js.map +1 -0
  243. package/dist/types/feedback.d.ts +76 -0
  244. package/dist/types/feedback.d.ts.map +1 -0
  245. package/dist/types/feedback.js +3 -0
  246. package/dist/types/feedback.js.map +1 -0
  247. package/dist/types/index.d.ts +3 -0
  248. package/dist/types/index.d.ts.map +1 -1
  249. package/dist/types/index.js +1 -0
  250. package/dist/types/index.js.map +1 -1
  251. package/dist/types/project/planu-config.d.ts +4 -0
  252. package/dist/types/project/planu-config.d.ts.map +1 -1
  253. package/package.json +1 -1
  254. package/src/config/license-plans.json +9 -2
  255. package/src/config/tool-groups.json +5 -1
@@ -0,0 +1,272 @@
1
+ // storage/feedback-store.ts — Feedback Hub persistence (SPEC-188)
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join, dirname } from 'node:path';
4
+ import { withFileLock } from './file-mutex.js';
5
+ import { sendFeedbackRemote } from './feedback-remote.js';
6
+ // ---------------------------------------------------------------------------
7
+ // Path helpers
8
+ // ---------------------------------------------------------------------------
9
+ function getFeedbackPath(dataDir) {
10
+ return join(dataDir, 'global', 'feedback', 'feedback-ledger.json');
11
+ }
12
+ function ensureDir(dirPath) {
13
+ if (!existsSync(dirPath)) {
14
+ mkdirSync(dirPath, { recursive: true });
15
+ }
16
+ }
17
+ // ---------------------------------------------------------------------------
18
+ // Low-level I/O
19
+ // ---------------------------------------------------------------------------
20
+ function readLedger(filePath) {
21
+ if (!existsSync(filePath)) {
22
+ return [];
23
+ }
24
+ try {
25
+ const raw = readFileSync(filePath, 'utf-8');
26
+ const parsed = JSON.parse(raw);
27
+ if (!Array.isArray(parsed)) {
28
+ return [];
29
+ }
30
+ return parsed;
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ }
36
+ function writeLedger(filePath, entries) {
37
+ ensureDir(dirname(filePath));
38
+ writeFileSync(filePath, JSON.stringify(entries, null, 2), 'utf-8');
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // ID generation
42
+ // ---------------------------------------------------------------------------
43
+ function generateId(entries) {
44
+ if (entries.length === 0) {
45
+ return 'FB-001';
46
+ }
47
+ const nums = entries
48
+ .map((e) => {
49
+ const m = /^FB-(\d+)$/.exec(e.id);
50
+ return m?.[1] !== undefined ? parseInt(m[1], 10) : 0;
51
+ })
52
+ .filter((n) => n > 0);
53
+ const maxNum = nums.length > 0 ? Math.max(...nums) : 0;
54
+ return `FB-${String(maxNum + 1).padStart(3, '0')}`;
55
+ }
56
+ // ---------------------------------------------------------------------------
57
+ // Version helper
58
+ // ---------------------------------------------------------------------------
59
+ function readPlanuVersion(dataDir) {
60
+ // Walk up from dataDir to find package.json
61
+ const projectRoot = dirname(dataDir.endsWith('/data') ? dataDir : dataDir);
62
+ const candidates = [
63
+ join(dataDir, '..', 'package.json'),
64
+ join(dataDir, '../../package.json'),
65
+ join(process.cwd(), 'package.json'),
66
+ ];
67
+ for (const candidate of candidates) {
68
+ if (existsSync(candidate)) {
69
+ try {
70
+ const raw = readFileSync(candidate, 'utf-8');
71
+ const pkg = JSON.parse(raw);
72
+ if (typeof pkg.version === 'string') {
73
+ return pkg.version;
74
+ }
75
+ }
76
+ catch {
77
+ // continue
78
+ }
79
+ }
80
+ }
81
+ void projectRoot;
82
+ return 'unknown';
83
+ }
84
+ // ---------------------------------------------------------------------------
85
+ // Similarity helper (word overlap)
86
+ // ---------------------------------------------------------------------------
87
+ const STOP_WORDS = new Set([
88
+ 'the',
89
+ 'a',
90
+ 'an',
91
+ 'is',
92
+ 'are',
93
+ 'was',
94
+ 'were',
95
+ 'it',
96
+ 'its',
97
+ 'in',
98
+ 'on',
99
+ 'at',
100
+ 'to',
101
+ 'for',
102
+ 'of',
103
+ 'and',
104
+ 'or',
105
+ 'but',
106
+ 'not',
107
+ 'with',
108
+ 'this',
109
+ 'that',
110
+ 'i',
111
+ 'we',
112
+ 'my',
113
+ 'our',
114
+ ]);
115
+ function tokenize(text) {
116
+ return new Set(text
117
+ .toLowerCase()
118
+ .replace(/[^a-z0-9\s]/g, ' ')
119
+ .split(/\s+/)
120
+ .filter((w) => w.length > 1 && !STOP_WORDS.has(w)));
121
+ }
122
+ function jaccardScore(a, b) {
123
+ if (a.size === 0 && b.size === 0) {
124
+ return 1;
125
+ }
126
+ const intersection = [...a].filter((w) => b.has(w)).length;
127
+ const union = new Set([...a, ...b]).size;
128
+ return union === 0 ? 0 : intersection / union;
129
+ }
130
+ // ---------------------------------------------------------------------------
131
+ // Public API
132
+ // ---------------------------------------------------------------------------
133
+ /**
134
+ * Submit a new feedback entry. Auto-generates ID, timestamp, and version.
135
+ */
136
+ export async function submitFeedback(dataDir, entry) {
137
+ const filePath = getFeedbackPath(dataDir);
138
+ const version = readPlanuVersion(dataDir);
139
+ return withFileLock(filePath, () => {
140
+ const entries = readLedger(filePath);
141
+ const id = generateId(entries);
142
+ const newEntry = {
143
+ ...entry,
144
+ id,
145
+ createdAt: new Date().toISOString(),
146
+ planuVersion: version,
147
+ };
148
+ entries.push(newEntry);
149
+ writeLedger(filePath, entries);
150
+ void sendFeedbackRemote({
151
+ type: newEntry.type,
152
+ title: newEntry.title,
153
+ description: newEntry.description,
154
+ planuVersion: newEntry.planuVersion,
155
+ stack: newEntry.context?.stack,
156
+ tags: newEntry.tags,
157
+ });
158
+ return Promise.resolve(newEntry);
159
+ });
160
+ }
161
+ /**
162
+ * Load and filter feedback entries.
163
+ */
164
+ export function getFeedback(dataDir, filter) {
165
+ const filePath = getFeedbackPath(dataDir);
166
+ let entries = readLedger(filePath);
167
+ if (filter?.type !== undefined) {
168
+ entries = entries.filter((e) => e.type === filter.type);
169
+ }
170
+ if (filter?.status !== undefined) {
171
+ entries = entries.filter((e) => e.status === filter.status);
172
+ }
173
+ if (filter?.specId !== undefined) {
174
+ entries = entries.filter((e) => e.specId === filter.specId);
175
+ }
176
+ return entries;
177
+ }
178
+ /**
179
+ * Update an existing feedback entry by ID.
180
+ */
181
+ export async function updateFeedback(dataDir, id, update) {
182
+ const filePath = getFeedbackPath(dataDir);
183
+ return withFileLock(filePath, () => {
184
+ const entries = readLedger(filePath);
185
+ const idx = entries.findIndex((e) => e.id === id);
186
+ if (idx === -1) {
187
+ return Promise.resolve(null);
188
+ }
189
+ const existing = entries[idx];
190
+ if (existing === undefined) {
191
+ return Promise.resolve(null);
192
+ }
193
+ const merged = { ...existing, ...update, id };
194
+ entries[idx] = merged;
195
+ writeLedger(filePath, entries);
196
+ return Promise.resolve(merged);
197
+ });
198
+ }
199
+ /**
200
+ * Mark feedback as resolved, optionally linking spec and PR.
201
+ */
202
+ export async function resolveFeedback(dataDir, id, specId, prUrl, notes) {
203
+ return updateFeedback(dataDir, id, {
204
+ status: 'resolved',
205
+ resolvedAt: new Date().toISOString(),
206
+ ...(specId !== undefined ? { specId } : {}),
207
+ ...(prUrl !== undefined ? { prUrl } : {}),
208
+ ...(notes !== undefined ? { resolvedNotes: notes } : {}),
209
+ });
210
+ }
211
+ /**
212
+ * Compute summary statistics across all feedback.
213
+ */
214
+ export function getSummary(dataDir) {
215
+ const entries = readLedger(getFeedbackPath(dataDir));
216
+ const byType = {
217
+ bug: 0,
218
+ feature: 0,
219
+ suggestion: 0,
220
+ dx: 0,
221
+ };
222
+ const byStatus = {
223
+ pending: 0,
224
+ triaged: 0,
225
+ spec_created: 0,
226
+ implementing: 0,
227
+ resolved: 0,
228
+ dismissed: 0,
229
+ };
230
+ let totalResolutionMs = 0;
231
+ let resolvedCount = 0;
232
+ for (const e of entries) {
233
+ byType[e.type] = byType[e.type] + 1;
234
+ byStatus[e.status] = byStatus[e.status] + 1;
235
+ if (e.status === 'resolved' && e.resolvedAt) {
236
+ const created = new Date(e.createdAt).getTime();
237
+ const resolved = new Date(e.resolvedAt).getTime();
238
+ if (!isNaN(created) && !isNaN(resolved)) {
239
+ totalResolutionMs += resolved - created;
240
+ resolvedCount++;
241
+ }
242
+ }
243
+ }
244
+ const avgResolutionDays = resolvedCount > 0 ? totalResolutionMs / resolvedCount / (1000 * 60 * 60 * 24) : 0;
245
+ const topRequests = [...entries]
246
+ .filter((e) => (e.votes ?? 0) > 0)
247
+ .sort((a, b) => (b.votes ?? 0) - (a.votes ?? 0))
248
+ .slice(0, 5)
249
+ .map((e) => ({ title: e.title, votes: e.votes ?? 0, id: e.id }));
250
+ return {
251
+ total: entries.length,
252
+ byType,
253
+ byStatus,
254
+ pending: byStatus.pending,
255
+ resolved: byStatus.resolved,
256
+ avgResolutionDays,
257
+ topRequests,
258
+ };
259
+ }
260
+ /**
261
+ * Find feedback entries with title similar to the given string.
262
+ * Uses Jaccard word overlap. Threshold defaults to 0.3.
263
+ */
264
+ export function findSimilar(dataDir, title, threshold = 0.3) {
265
+ const entries = readLedger(getFeedbackPath(dataDir));
266
+ const queryTokens = tokenize(title);
267
+ return entries.filter((e) => {
268
+ const entryTokens = tokenize(e.title);
269
+ return jaccardScore(queryTokens, entryTokens) >= threshold;
270
+ });
271
+ }
272
+ //# sourceMappingURL=feedback-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback-store.js","sourceRoot":"","sources":["../../src/storage/feedback-store.ts"],"names":[],"mappings":"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"}
@@ -16,4 +16,5 @@ export * as errorTelemetryStore from './error-telemetry-store.js';
16
16
  export * as specObservabilityStore from './spec-observability-store.js';
17
17
  export * as federationStore from './federation-store.js';
18
18
  export * as rbacStore from './rbac-store.js';
19
+ export * as conventionBaselineStore from './convention-baseline.js';
19
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,mBAAmB,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,sBAAsB,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,mBAAmB,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,sBAAsB,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,uBAAuB,MAAM,0BAA0B,CAAC"}
@@ -17,4 +17,5 @@ export * as errorTelemetryStore from './error-telemetry-store.js';
17
17
  export * as specObservabilityStore from './spec-observability-store.js';
18
18
  export * as federationStore from './federation-store.js';
19
19
  export * as rbacStore from './rbac-store.js';
20
+ export * as conventionBaselineStore from './convention-baseline.js';
20
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EACL,eAAe,EACf,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,mBAAmB,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,sBAAsB,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EACL,eAAe,EACf,QAAQ,EACR,SAAS,EACT,cAAc,EACd,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,cAAc,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,aAAa,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,iBAAiB,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,oBAAoB,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,mBAAmB,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,sBAAsB,MAAM,+BAA+B,CAAC;AACxE,OAAO,KAAK,eAAe,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,SAAS,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,uBAAuB,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ToolResult } from '../types/index.js';
3
+ export declare function handleConfigHealth(args: {
4
+ projectId: string;
5
+ projectPath: string;
6
+ }): Promise<ToolResult>;
7
+ export declare function registerConfigHealthTool(server: McpServer): void;
8
+ //# sourceMappingURL=convention-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-sync.d.ts","sourceRoot":"","sources":["../../src/tools/convention-sync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAwEpD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,UAAU,CAAC,CAMtB;AAMD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAehE"}
@@ -0,0 +1,77 @@
1
+ // tools/convention-sync.ts — MCP tool: config_health
2
+ // Shows overall sync percentage between project conventions and their enforcement.
3
+ // READ-ONLY: never modifies files.
4
+ import { z } from 'zod';
5
+ import { calculateConventionSync } from '../engine/convention-sync.js';
6
+ import { getKnowledge } from '../storage/knowledge-store.js';
7
+ import { safeTracked } from './safe-handler.js';
8
+ // ---------------------------------------------------------------------------
9
+ // Zod schema
10
+ // ---------------------------------------------------------------------------
11
+ const configHealthSchema = {
12
+ projectId: z
13
+ .string()
14
+ .max(64)
15
+ .describe('Project identifier (hash) used to load project knowledge for skills analysis'),
16
+ projectPath: z.string().max(4096).describe('Absolute path to the project root to analyse'),
17
+ };
18
+ // ---------------------------------------------------------------------------
19
+ // Formatter
20
+ // ---------------------------------------------------------------------------
21
+ function scoreBar(score) {
22
+ const filled = Math.round(score / 10);
23
+ return '[' + '█'.repeat(filled) + '░'.repeat(10 - filled) + ']';
24
+ }
25
+ function formatReport(report) {
26
+ const { overallScore, rulesHealth, skillsHealth, hooksHealth, conventionHealth } = report;
27
+ const lines = [];
28
+ lines.push('# Convention Sync Health Report');
29
+ lines.push('');
30
+ lines.push(`## Overall Score: ${overallScore}/100 ${scoreBar(overallScore)}`);
31
+ lines.push('');
32
+ lines.push(`**${report.summary}**`);
33
+ lines.push('');
34
+ lines.push('## Dimension Breakdown');
35
+ lines.push('');
36
+ lines.push(`| Dimension | Score | Bar |`);
37
+ lines.push(`|-----------------|-------|----------------------------|`);
38
+ lines.push(`| Rules files | ${String(rulesHealth).padStart(3)}/100 | ${scoreBar(rulesHealth)} |`);
39
+ lines.push(`| Skills | ${String(skillsHealth).padStart(3)}/100 | ${scoreBar(skillsHealth)} |`);
40
+ lines.push(`| Git hooks | ${String(hooksHealth).padStart(3)}/100 | ${scoreBar(hooksHealth)} |`);
41
+ lines.push(`| Conventions | ${String(conventionHealth).padStart(3)}/100 | ${scoreBar(conventionHealth)} |`);
42
+ lines.push('');
43
+ if (report.recommendations.length > 0) {
44
+ lines.push('## Recommendations');
45
+ lines.push('');
46
+ for (const rec of report.recommendations) {
47
+ lines.push(`- ${rec}`);
48
+ }
49
+ lines.push('');
50
+ }
51
+ return lines.join('\n');
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Handler
55
+ // ---------------------------------------------------------------------------
56
+ export async function handleConfigHealth(args) {
57
+ const knowledge = await getKnowledge(args.projectId);
58
+ const report = await calculateConventionSync(args.projectPath, knowledge);
59
+ const text = formatReport(report);
60
+ const isError = report.overallScore === 0;
61
+ return { content: [{ type: 'text', text }], isError };
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Registration
65
+ // ---------------------------------------------------------------------------
66
+ export function registerConfigHealthTool(server) {
67
+ server.registerTool('config_health', {
68
+ description: "Calculate the overall sync percentage between the project's conventions and its enforcement mechanisms (rules files, skills, git hooks, convention violations). Returns a 0–100 weighted score with per-dimension breakdown and prioritised recommendations. READ-ONLY — never modifies files.",
69
+ inputSchema: configHealthSchema,
70
+ annotations: {
71
+ readOnlyHint: true,
72
+ destructiveHint: false,
73
+ title: 'Config Health',
74
+ },
75
+ }, safeTracked('config_health', async (args) => handleConfigHealth(args)));
76
+ }
77
+ //# sourceMappingURL=convention-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-sync.js","sourceRoot":"","sources":["../../src/tools/convention-sync.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,mFAAmF;AACnF,mCAAmC;AAGnC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,kBAAkB,GAAG;IACzB,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,CAAC,8EAA8E,CAAC;IAC3F,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,8CAA8C,CAAC;CAClF,CAAC;AAEX,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,SAAS,QAAQ,CAAC,KAAa;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACtC,OAAO,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,MAA4B;IAChD,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAAC;IAC1F,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,qBAAqB,YAAY,SAAS,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACrC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IACvE,KAAK,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;IACvE,KAAK,CAAC,IAAI,CACR,uBAAuB,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,WAAW,CAAC,IAAI,CAC1F,CAAC;IACF,KAAK,CAAC,IAAI,CACR,uBAAuB,MAAM,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,YAAY,CAAC,IAAI,CAC5F,CAAC;IACF,KAAK,CAAC,IAAI,CACR,uBAAuB,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,WAAW,CAAC,IAAI,CAC1F,CAAC;IACF,KAAK,CAAC,IAAI,CACR,uBAAuB,MAAM,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CACpG,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,MAAM,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YACzC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAGxC;IACC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1E,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC;IAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;AACxD,CAAC;AAED,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,MAAM,UAAU,wBAAwB,CAAC,MAAiB;IACxD,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,WAAW,EACT,gSAAgS;QAClS,WAAW,EAAE,kBAAkB;QAC/B,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,KAAK,EAAE,eAAe;SACvB;KACF,EACD,WAAW,CAAC,eAAe,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ProjectKnowledge } from '../../../types/index.js';
2
+ /**
3
+ * Reads CLAUDE.md and .claude/rules/*.md conventions, then generates
4
+ * project-specific acceptance criteria that every spec should include.
5
+ *
6
+ * Returns `- [ ] ...` lines that enforce the project's own conventions.
7
+ */
8
+ export declare function generateConventionAcs(knowledge: ProjectKnowledge): string[];
9
+ //# sourceMappingURL=convention-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-adapter.d.ts","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/convention-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,EAAE,CA0E3E"}
@@ -0,0 +1,68 @@
1
+ // tools/create-spec-hu/ac-adapters/convention-adapter.ts — SPEC-191
2
+ // Generates acceptance criteria from project conventions (CLAUDE.md + .claude/rules/)
3
+ import { parseConventions } from '../../../engine/convention-scanner/index.js';
4
+ /**
5
+ * Reads CLAUDE.md and .claude/rules/*.md conventions, then generates
6
+ * project-specific acceptance criteria that every spec should include.
7
+ *
8
+ * Returns `- [ ] ...` lines that enforce the project's own conventions.
9
+ */
10
+ export function generateConventionAcs(knowledge) {
11
+ const projectPath = knowledge.projectPath;
12
+ if (!projectPath) {
13
+ return [];
14
+ }
15
+ const rules = parseConventions(projectPath);
16
+ if (rules.length === 0) {
17
+ return [];
18
+ }
19
+ const acs = [];
20
+ // Group rules by category and generate one AC per category
21
+ const byCategory = new Map();
22
+ for (const rule of rules) {
23
+ const existing = byCategory.get(rule.category) ?? [];
24
+ existing.push(rule.description);
25
+ byCategory.set(rule.category, existing);
26
+ }
27
+ // Naming conventions
28
+ const naming = byCategory.get('naming');
29
+ if (naming) {
30
+ acs.push('- [ ] All new identifiers follow project naming conventions: ' +
31
+ naming.slice(0, 3).join('; '));
32
+ }
33
+ // i18n conventions
34
+ const i18n = byCategory.get('i18n');
35
+ if (i18n) {
36
+ acs.push('- [ ] No hardcoded user-facing strings — all text uses i18n/translation system');
37
+ }
38
+ // Architecture conventions
39
+ const arch = byCategory.get('architecture');
40
+ if (arch) {
41
+ acs.push('- [ ] Import patterns comply with project architecture rules: ' +
42
+ arch.slice(0, 2).join('; '));
43
+ }
44
+ // File limit conventions
45
+ const fileLimits = byCategory.get('file-limits');
46
+ if (fileLimits) {
47
+ acs.push('- [ ] File and function sizes within project limits: ' + fileLimits.slice(0, 2).join('; '));
48
+ }
49
+ // Code quality conventions
50
+ const codeQuality = byCategory.get('code-quality');
51
+ if (codeQuality) {
52
+ acs.push('- [ ] Code quality rules enforced: ' + codeQuality.slice(0, 3).join('; '));
53
+ }
54
+ // Testing conventions
55
+ const testing = byCategory.get('testing');
56
+ if (testing) {
57
+ acs.push('- [ ] Testing conventions followed: ' + testing.slice(0, 2).join('; '));
58
+ }
59
+ // Custom conventions
60
+ const custom = byCategory.get('custom');
61
+ if (custom) {
62
+ for (const desc of custom.slice(0, 3)) {
63
+ acs.push(`- [ ] ${desc}`);
64
+ }
65
+ }
66
+ return acs;
67
+ }
68
+ //# sourceMappingURL=convention-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-adapter.js","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/convention-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ProjectKnowledge } from '../../../types/index.js';
2
+ /**
3
+ * Reads `specTemplate` from the project's planu.json and converts each entry
4
+ * into a `- [ ] ...` acceptance criteria line.
5
+ *
6
+ * Supported keys inside `specTemplate`:
7
+ * - `acceptanceCriteria` — array of strings, one AC per item
8
+ * - `qualityGates` — array of strings, appended after acceptanceCriteria
9
+ *
10
+ * Returns an empty array when planu.json is absent, unreadable, or has no
11
+ * `specTemplate` section.
12
+ */
13
+ export declare function generateCustomTemplateAcs(knowledge: ProjectKnowledge): string[];
14
+ //# sourceMappingURL=custom-template-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-template-adapter.d.ts","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/custom-template-adapter.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,yBAAyB,CAAC;AAkBjF;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAkC/E"}
@@ -0,0 +1,60 @@
1
+ // tools/create-spec-hu/ac-adapters/custom-template-adapter.ts
2
+ // Generates acceptance criteria from project-defined specTemplate in planu.json
3
+ import { readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ function isStringArray(value) {
6
+ return Array.isArray(value) && value.every((item) => typeof item === 'string');
7
+ }
8
+ function readPlanuJsonConfig(projectPath) {
9
+ try {
10
+ const raw = JSON.parse(readFileSync(join(projectPath, 'planu.json'), 'utf-8'));
11
+ if (typeof raw !== 'object' || raw === null) {
12
+ return null;
13
+ }
14
+ return raw;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ }
20
+ /**
21
+ * Reads `specTemplate` from the project's planu.json and converts each entry
22
+ * into a `- [ ] ...` acceptance criteria line.
23
+ *
24
+ * Supported keys inside `specTemplate`:
25
+ * - `acceptanceCriteria` — array of strings, one AC per item
26
+ * - `qualityGates` — array of strings, appended after acceptanceCriteria
27
+ *
28
+ * Returns an empty array when planu.json is absent, unreadable, or has no
29
+ * `specTemplate` section.
30
+ */
31
+ export function generateCustomTemplateAcs(knowledge) {
32
+ const projectPath = knowledge.projectPath;
33
+ if (!projectPath) {
34
+ return [];
35
+ }
36
+ const config = readPlanuJsonConfig(projectPath);
37
+ if (!config?.specTemplate) {
38
+ return [];
39
+ }
40
+ const { acceptanceCriteria, qualityGates } = config.specTemplate;
41
+ const acs = [];
42
+ if (isStringArray(acceptanceCriteria)) {
43
+ for (const criterion of acceptanceCriteria) {
44
+ const trimmed = criterion.trim();
45
+ if (trimmed) {
46
+ acs.push(`- [ ] ${trimmed}`);
47
+ }
48
+ }
49
+ }
50
+ if (isStringArray(qualityGates)) {
51
+ for (const gate of qualityGates) {
52
+ const trimmed = gate.trim();
53
+ if (trimmed) {
54
+ acs.push(`- [ ] ${trimmed}`);
55
+ }
56
+ }
57
+ }
58
+ return acs;
59
+ }
60
+ //# sourceMappingURL=custom-template-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-template-adapter.js","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/custom-template-adapter.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gFAAgF;AAEhF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,mBAAmB,CAAC,WAAmB;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QACxF,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,GAAsB,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAA2B;IACnE,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;IAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;QAC1B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC;IAEjE,MAAM,GAAG,GAAa,EAAE,CAAC;IAEzB,IAAI,aAAa,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACtC,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;YAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;YACjC,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,CAAC,IAAI,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,OAAO,EAAE,CAAC;gBACZ,GAAG,CAAC,IAAI,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -3,8 +3,12 @@ export { generateArchitectureAcs } from './architecture-adapter.js';
3
3
  export { generateStackAcs } from './stack-adapter.js';
4
4
  export { generateDatabaseAcs } from './database-adapter.js';
5
5
  export { generateTestingAcs } from './testing-adapter.js';
6
+ export { generateConventionAcs } from './convention-adapter.js';
7
+ export { generateCustomTemplateAcs } from './custom-template-adapter.js';
6
8
  /**
7
9
  * Aggregates ACs from all specialized adapters, deduplicates, and returns the final list.
10
+ * SPEC-191: Now includes project-specific convention criteria from CLAUDE.md + .claude/rules/.
11
+ * Custom template ACs (from planu.json specTemplate) are prepended so they appear first.
8
12
  *
9
13
  * @param knowledge - Detected project knowledge (architecture, stack, DB, testing).
10
14
  * @param _specType - Spec type (reserved for future per-type filtering).
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAMhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAU/F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/create-spec-hu/ac-adapters/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAQhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAEzE;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/F"}
@@ -1,15 +1,21 @@
1
- // tools/create-spec-hu/ac-adapters/index.ts
1
+ // tools/create-spec-hu/ac-adapters/index.ts — SPEC-191: convention injection
2
2
  // Barrel: aggregates all specialized AC adapters into a single entry point.
3
3
  import { generateArchitectureAcs } from './architecture-adapter.js';
4
4
  import { generateStackAcs } from './stack-adapter.js';
5
5
  import { generateDatabaseAcs } from './database-adapter.js';
6
6
  import { generateTestingAcs } from './testing-adapter.js';
7
+ import { generateConventionAcs } from './convention-adapter.js';
8
+ import { generateCustomTemplateAcs } from './custom-template-adapter.js';
7
9
  export { generateArchitectureAcs } from './architecture-adapter.js';
8
10
  export { generateStackAcs } from './stack-adapter.js';
9
11
  export { generateDatabaseAcs } from './database-adapter.js';
10
12
  export { generateTestingAcs } from './testing-adapter.js';
13
+ export { generateConventionAcs } from './convention-adapter.js';
14
+ export { generateCustomTemplateAcs } from './custom-template-adapter.js';
11
15
  /**
12
16
  * Aggregates ACs from all specialized adapters, deduplicates, and returns the final list.
17
+ * SPEC-191: Now includes project-specific convention criteria from CLAUDE.md + .claude/rules/.
18
+ * Custom template ACs (from planu.json specTemplate) are prepended so they appear first.
13
19
  *
14
20
  * @param knowledge - Detected project knowledge (architecture, stack, DB, testing).
15
21
  * @param _specType - Spec type (reserved for future per-type filtering).
@@ -17,6 +23,8 @@ export { generateTestingAcs } from './testing-adapter.js';
17
23
  */
18
24
  export function generateSpecializedAcs(knowledge, _specType) {
19
25
  const all = [
26
+ ...generateCustomTemplateAcs(knowledge),
27
+ ...generateConventionAcs(knowledge),
20
28
  ...generateArchitectureAcs(knowledge),
21
29
  ...generateStackAcs(knowledge),
22
30
  ...generateDatabaseAcs(knowledge),