sqlew 4.1.2 → 4.3.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 (197) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +25 -165
  3. package/assets/claude-md-snippets/plan-mode-integration.md +48 -24
  4. package/assets/sample-skills/sqlew-decision-format/SKILL.md +73 -0
  5. package/dist/cli/hooks/check-completion.d.ts.map +1 -1
  6. package/dist/cli/hooks/check-completion.js +90 -2
  7. package/dist/cli/hooks/check-completion.js.map +1 -1
  8. package/dist/cli/hooks/init-hooks.d.ts.map +1 -1
  9. package/dist/cli/hooks/init-hooks.js +97 -5
  10. package/dist/cli/hooks/init-hooks.js.map +1 -1
  11. package/dist/cli/hooks/on-enter-plan.d.ts +22 -0
  12. package/dist/cli/hooks/on-enter-plan.d.ts.map +1 -0
  13. package/dist/cli/hooks/on-enter-plan.js +51 -0
  14. package/dist/cli/hooks/on-enter-plan.js.map +1 -0
  15. package/dist/cli/hooks/on-exit-plan.d.ts +20 -0
  16. package/dist/cli/hooks/on-exit-plan.d.ts.map +1 -0
  17. package/dist/cli/hooks/on-exit-plan.js +66 -0
  18. package/dist/cli/hooks/on-exit-plan.js.map +1 -0
  19. package/dist/cli/hooks/on-stop.d.ts +19 -0
  20. package/dist/cli/hooks/on-stop.d.ts.map +1 -0
  21. package/dist/cli/hooks/on-stop.js +152 -0
  22. package/dist/cli/hooks/on-stop.js.map +1 -0
  23. package/dist/cli/hooks/on-subagent-stop.d.ts +20 -0
  24. package/dist/cli/hooks/on-subagent-stop.d.ts.map +1 -0
  25. package/dist/cli/hooks/on-subagent-stop.js +94 -0
  26. package/dist/cli/hooks/on-subagent-stop.js.map +1 -0
  27. package/dist/cli/hooks/plan-pattern-extractor.d.ts +87 -0
  28. package/dist/cli/hooks/plan-pattern-extractor.d.ts.map +1 -0
  29. package/dist/cli/hooks/plan-pattern-extractor.js +218 -0
  30. package/dist/cli/hooks/plan-pattern-extractor.js.map +1 -0
  31. package/dist/cli/hooks/plan-processor.d.ts +43 -0
  32. package/dist/cli/hooks/plan-processor.d.ts.map +1 -0
  33. package/dist/cli/hooks/plan-processor.js +115 -0
  34. package/dist/cli/hooks/plan-processor.js.map +1 -0
  35. package/dist/cli/hooks/plan-toml-parser.d.ts +42 -0
  36. package/dist/cli/hooks/plan-toml-parser.d.ts.map +1 -0
  37. package/dist/cli/hooks/plan-toml-parser.js +178 -0
  38. package/dist/cli/hooks/plan-toml-parser.js.map +1 -0
  39. package/dist/cli/hooks/save.d.ts +7 -9
  40. package/dist/cli/hooks/save.d.ts.map +1 -1
  41. package/dist/cli/hooks/save.js +50 -25
  42. package/dist/cli/hooks/save.js.map +1 -1
  43. package/dist/cli/hooks/stdin-parser.d.ts +66 -2
  44. package/dist/cli/hooks/stdin-parser.d.ts.map +1 -1
  45. package/dist/cli/hooks/stdin-parser.js +57 -2
  46. package/dist/cli/hooks/stdin-parser.js.map +1 -1
  47. package/dist/cli/hooks/suggest.d.ts +8 -4
  48. package/dist/cli/hooks/suggest.d.ts.map +1 -1
  49. package/dist/cli/hooks/suggest.js +21 -123
  50. package/dist/cli/hooks/suggest.js.map +1 -1
  51. package/dist/cli/hooks/track-plan.d.ts +8 -1
  52. package/dist/cli/hooks/track-plan.d.ts.map +1 -1
  53. package/dist/cli/hooks/track-plan.js +64 -66
  54. package/dist/cli/hooks/track-plan.js.map +1 -1
  55. package/dist/cli.d.ts.map +1 -1
  56. package/dist/cli.js +139 -38
  57. package/dist/cli.js.map +1 -1
  58. package/dist/config/global-config.d.ts +90 -0
  59. package/dist/config/global-config.d.ts.map +1 -1
  60. package/dist/config/global-config.js +86 -1
  61. package/dist/config/global-config.js.map +1 -1
  62. package/dist/database/initialization/init.js +3 -3
  63. package/dist/database/initialization/init.js.map +1 -1
  64. package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.d.ts +15 -0
  65. package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.d.ts.map +1 -0
  66. package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.js +74 -0
  67. package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.js.map +1 -0
  68. package/dist/index.js +8 -4
  69. package/dist/index.js.map +1 -1
  70. package/dist/init-skills.d.ts +6 -1
  71. package/dist/init-skills.d.ts.map +1 -1
  72. package/dist/init-skills.js +50 -1
  73. package/dist/init-skills.js.map +1 -1
  74. package/dist/knexfile.d.ts.map +1 -1
  75. package/dist/knexfile.js +16 -12
  76. package/dist/knexfile.js.map +1 -1
  77. package/dist/server/setup.js +5 -5
  78. package/dist/server/setup.js.map +1 -1
  79. package/dist/server/tool-handlers.d.ts.map +1 -1
  80. package/dist/server/tool-handlers.js +7 -1
  81. package/dist/server/tool-handlers.js.map +1 -1
  82. package/dist/server/tool-registry.js +1 -1
  83. package/dist/server/tool-registry.js.map +1 -1
  84. package/dist/tests/feature/decision/truncate.test.d.ts +8 -0
  85. package/dist/tests/feature/decision/truncate.test.d.ts.map +1 -0
  86. package/dist/tests/feature/decision/truncate.test.js +192 -0
  87. package/dist/tests/feature/decision/truncate.test.js.map +1 -0
  88. package/dist/tests/unit/config/plan-toml-cache.test.d.ts +9 -0
  89. package/dist/tests/unit/config/plan-toml-cache.test.d.ts.map +1 -0
  90. package/dist/tests/unit/config/plan-toml-cache.test.js +230 -0
  91. package/dist/tests/unit/config/plan-toml-cache.test.js.map +1 -0
  92. package/dist/tests/unit/hooks/plan-toml-parser.test.d.ts +10 -0
  93. package/dist/tests/unit/hooks/plan-toml-parser.test.d.ts.map +1 -0
  94. package/dist/tests/unit/hooks/plan-toml-parser.test.js +316 -0
  95. package/dist/tests/unit/hooks/plan-toml-parser.test.js.map +1 -0
  96. package/dist/tools/constraints/actions/activate.d.ts +46 -0
  97. package/dist/tools/constraints/actions/activate.d.ts.map +1 -0
  98. package/dist/tools/constraints/actions/activate.js +105 -0
  99. package/dist/tools/constraints/actions/activate.js.map +1 -0
  100. package/dist/tools/constraints/actions/add.d.ts.map +1 -1
  101. package/dist/tools/constraints/actions/add.js +30 -13
  102. package/dist/tools/constraints/actions/add.js.map +1 -1
  103. package/dist/tools/constraints/actions/deactivate.d.ts.map +1 -1
  104. package/dist/tools/constraints/actions/deactivate.js +7 -4
  105. package/dist/tools/constraints/actions/deactivate.js.map +1 -1
  106. package/dist/tools/constraints/actions/get.d.ts.map +1 -1
  107. package/dist/tools/constraints/actions/get.js +10 -7
  108. package/dist/tools/constraints/actions/get.js.map +1 -1
  109. package/dist/tools/constraints/actions/suggest-pending.d.ts +41 -0
  110. package/dist/tools/constraints/actions/suggest-pending.d.ts.map +1 -0
  111. package/dist/tools/constraints/actions/suggest-pending.js +71 -0
  112. package/dist/tools/constraints/actions/suggest-pending.js.map +1 -0
  113. package/dist/tools/constraints/help/example.d.ts.map +1 -1
  114. package/dist/tools/constraints/help/example.js +65 -1
  115. package/dist/tools/constraints/help/example.js.map +1 -1
  116. package/dist/tools/constraints/help/help.d.ts.map +1 -1
  117. package/dist/tools/constraints/help/help.js +10 -5
  118. package/dist/tools/constraints/help/help.js.map +1 -1
  119. package/dist/tools/constraints/index.d.ts +2 -0
  120. package/dist/tools/constraints/index.d.ts.map +1 -1
  121. package/dist/tools/constraints/index.js +2 -0
  122. package/dist/tools/constraints/index.js.map +1 -1
  123. package/dist/tools/context/actions/add-context.d.ts.map +1 -1
  124. package/dist/tools/context/actions/add-context.js +13 -6
  125. package/dist/tools/context/actions/add-context.js.map +1 -1
  126. package/dist/tools/context/actions/list-contexts.d.ts.map +1 -1
  127. package/dist/tools/context/actions/list-contexts.js +12 -7
  128. package/dist/tools/context/actions/list-contexts.js.map +1 -1
  129. package/dist/tools/context/actions/list.d.ts.map +1 -1
  130. package/dist/tools/context/actions/list.js +8 -0
  131. package/dist/tools/context/actions/list.js.map +1 -1
  132. package/dist/tools/context/actions/search-advanced.d.ts.map +1 -1
  133. package/dist/tools/context/actions/search-advanced.js +41 -27
  134. package/dist/tools/context/actions/search-advanced.js.map +1 -1
  135. package/dist/tools/context/actions/search-layer.d.ts.map +1 -1
  136. package/dist/tools/context/actions/search-layer.js +8 -0
  137. package/dist/tools/context/actions/search-layer.js.map +1 -1
  138. package/dist/tools/context/actions/search-tags.d.ts.map +1 -1
  139. package/dist/tools/context/actions/search-tags.js +8 -0
  140. package/dist/tools/context/actions/search-tags.js.map +1 -1
  141. package/dist/tools/files/actions/check-lock.d.ts.map +1 -1
  142. package/dist/tools/files/actions/check-lock.js +9 -3
  143. package/dist/tools/files/actions/check-lock.js.map +1 -1
  144. package/dist/tools/files/actions/get.d.ts.map +1 -1
  145. package/dist/tools/files/actions/get.js +18 -13
  146. package/dist/tools/files/actions/get.js.map +1 -1
  147. package/dist/tools/files/actions/record-batch.d.ts.map +1 -1
  148. package/dist/tools/files/actions/record-batch.js +11 -6
  149. package/dist/tools/files/actions/record-batch.js.map +1 -1
  150. package/dist/tools/files/actions/record.d.ts.map +1 -1
  151. package/dist/tools/files/actions/record.js +8 -2
  152. package/dist/tools/files/actions/record.js.map +1 -1
  153. package/dist/types/actions.d.ts +1 -1
  154. package/dist/types/actions.d.ts.map +1 -1
  155. package/dist/types.d.ts +9 -2
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/utils/action-specs/constraint-specs.d.ts +1 -1
  158. package/dist/utils/action-specs/constraint-specs.d.ts.map +1 -1
  159. package/dist/utils/action-specs/constraint-specs.js +22 -5
  160. package/dist/utils/action-specs/constraint-specs.js.map +1 -1
  161. package/dist/utils/action-specs/decision-specs.d.ts.map +1 -1
  162. package/dist/utils/action-specs/decision-specs.js +11 -10
  163. package/dist/utils/action-specs/decision-specs.js.map +1 -1
  164. package/dist/utils/action-specs/file-specs.js +4 -4
  165. package/dist/utils/action-specs/file-specs.js.map +1 -1
  166. package/dist/utils/hook-queue.d.ts +43 -3
  167. package/dist/utils/hook-queue.d.ts.map +1 -1
  168. package/dist/utils/hook-queue.js +326 -32
  169. package/dist/utils/hook-queue.js.map +1 -1
  170. package/dist/utils/param-normalizer.d.ts +52 -0
  171. package/dist/utils/param-normalizer.d.ts.map +1 -0
  172. package/dist/utils/param-normalizer.js +70 -0
  173. package/dist/utils/param-normalizer.js.map +1 -0
  174. package/dist/utils/parameter-validator.d.ts.map +1 -1
  175. package/dist/utils/parameter-validator.js +2 -0
  176. package/dist/utils/parameter-validator.js.map +1 -1
  177. package/dist/utils/text-truncate.d.ts +13 -0
  178. package/dist/utils/text-truncate.d.ts.map +1 -0
  179. package/dist/utils/text-truncate.js +18 -0
  180. package/dist/utils/text-truncate.js.map +1 -0
  181. package/dist/utils/validators.d.ts +1 -1
  182. package/dist/utils/validators.d.ts.map +1 -1
  183. package/dist/utils/validators.js +1 -1
  184. package/dist/utils/validators.js.map +1 -1
  185. package/dist/watcher/base-watcher.d.ts.map +1 -1
  186. package/dist/watcher/base-watcher.js +4 -3
  187. package/dist/watcher/base-watcher.js.map +1 -1
  188. package/dist/watcher/file-watcher.d.ts.map +1 -1
  189. package/dist/watcher/file-watcher.js +5 -1
  190. package/dist/watcher/file-watcher.js.map +1 -1
  191. package/dist/watcher/queue-watcher.d.ts +12 -1
  192. package/dist/watcher/queue-watcher.d.ts.map +1 -1
  193. package/dist/watcher/queue-watcher.js +92 -12
  194. package/dist/watcher/queue-watcher.js.map +1 -1
  195. package/docs/ADR_CONCEPTS.md +4 -0
  196. package/docs/HOOKS_GUIDE.md +1 -1
  197. package/package.json +1 -1
@@ -0,0 +1,316 @@
1
+ /**
2
+ * Plan TOML Parser Unit Tests
3
+ *
4
+ * Tests for extracting and parsing [[decision]] and [[constraint]]
5
+ * from ```toml blocks in plan markdown files.
6
+ *
7
+ * @since v4.2.0
8
+ */
9
+ import { describe, it } from 'node:test';
10
+ import assert from 'node:assert';
11
+ import { extractTomlBlocks, parseTomlBlock, parsePlanToml, } from '../../../cli/hooks/plan-toml-parser.js';
12
+ describe('plan-toml-parser', () => {
13
+ describe('extractTomlBlocks', () => {
14
+ it('should extract single toml block', () => {
15
+ const content = `
16
+ # Plan
17
+
18
+ Some text here.
19
+
20
+ \`\`\`toml
21
+ [[decision]]
22
+ key = "test"
23
+ value = "value"
24
+ \`\`\`
25
+
26
+ More text.
27
+ `;
28
+ const blocks = extractTomlBlocks(content);
29
+ assert.strictEqual(blocks.length, 1);
30
+ assert.ok(blocks[0].includes('[[decision]]'));
31
+ });
32
+ it('should extract multiple toml blocks', () => {
33
+ const content = `
34
+ \`\`\`toml
35
+ [[decision]]
36
+ key = "first"
37
+ value = "one"
38
+ \`\`\`
39
+
40
+ Some text between.
41
+
42
+ \`\`\`toml
43
+ [[decision]]
44
+ key = "second"
45
+ value = "two"
46
+ \`\`\`
47
+ `;
48
+ const blocks = extractTomlBlocks(content);
49
+ assert.strictEqual(blocks.length, 2);
50
+ });
51
+ it('should handle empty content', () => {
52
+ const blocks = extractTomlBlocks('');
53
+ assert.strictEqual(blocks.length, 0);
54
+ });
55
+ it('should ignore non-toml code blocks', () => {
56
+ const content = `
57
+ \`\`\`javascript
58
+ const x = 1;
59
+ \`\`\`
60
+
61
+ \`\`\`toml
62
+ [[decision]]
63
+ key = "test"
64
+ value = "value"
65
+ \`\`\`
66
+
67
+ \`\`\`python
68
+ print("hello")
69
+ \`\`\`
70
+ `;
71
+ const blocks = extractTomlBlocks(content);
72
+ assert.strictEqual(blocks.length, 1);
73
+ });
74
+ it('should be case-insensitive for toml tag', () => {
75
+ const content = `
76
+ \`\`\`TOML
77
+ [[decision]]
78
+ key = "upper"
79
+ value = "case"
80
+ \`\`\`
81
+ `;
82
+ const blocks = extractTomlBlocks(content);
83
+ assert.strictEqual(blocks.length, 1);
84
+ });
85
+ });
86
+ describe('parseTomlBlock - decisions', () => {
87
+ it('should parse decision with required fields only', () => {
88
+ const toml = `
89
+ [[decision]]
90
+ key = "api/auth"
91
+ value = "Use JWT tokens"
92
+ `;
93
+ const result = parseTomlBlock(toml);
94
+ assert.strictEqual(result.decisions.length, 1);
95
+ assert.strictEqual(result.decisions[0].key, 'api/auth');
96
+ assert.strictEqual(result.decisions[0].value, 'Use JWT tokens');
97
+ });
98
+ it('should parse decision with all optional fields', () => {
99
+ const toml = `
100
+ [[decision]]
101
+ key = "database/orm"
102
+ value = "Knex query builder"
103
+ status = "active"
104
+ layer = "data"
105
+ tags = ["database", "architecture"]
106
+ rationale = "Explicit SQL control"
107
+ alternatives = ["TypeORM", "Prisma"]
108
+ tradeoffs = "Learning curve vs flexibility"
109
+ `;
110
+ const result = parseTomlBlock(toml);
111
+ assert.strictEqual(result.decisions.length, 1);
112
+ const d = result.decisions[0];
113
+ assert.strictEqual(d.key, 'database/orm');
114
+ assert.strictEqual(d.value, 'Knex query builder');
115
+ assert.strictEqual(d.status, 'active');
116
+ assert.strictEqual(d.layer, 'data');
117
+ assert.deepStrictEqual(d.tags, ['database', 'architecture']);
118
+ assert.strictEqual(d.rationale, 'Explicit SQL control');
119
+ assert.deepStrictEqual(d.alternatives, ['TypeORM', 'Prisma']);
120
+ assert.strictEqual(d.tradeoffs, 'Learning curve vs flexibility');
121
+ });
122
+ it('should parse multiple decisions', () => {
123
+ const toml = `
124
+ [[decision]]
125
+ key = "first"
126
+ value = "First decision"
127
+
128
+ [[decision]]
129
+ key = "second"
130
+ value = "Second decision"
131
+
132
+ [[decision]]
133
+ key = "third"
134
+ value = "Third decision"
135
+ `;
136
+ const result = parseTomlBlock(toml);
137
+ assert.strictEqual(result.decisions.length, 3);
138
+ });
139
+ it('should skip invalid decisions (missing required fields)', () => {
140
+ const toml = `
141
+ [[decision]]
142
+ key = "valid"
143
+ value = "This is valid"
144
+
145
+ [[decision]]
146
+ key = "missing-value"
147
+
148
+ [[decision]]
149
+ value = "missing-key"
150
+ `;
151
+ const result = parseTomlBlock(toml);
152
+ assert.strictEqual(result.decisions.length, 1);
153
+ assert.strictEqual(result.decisions[0].key, 'valid');
154
+ });
155
+ });
156
+ describe('parseTomlBlock - constraints', () => {
157
+ it('should parse constraint with required fields only', () => {
158
+ const toml = `
159
+ [[constraint]]
160
+ text = "All API endpoints must validate JWT"
161
+ category = "security"
162
+ `;
163
+ const result = parseTomlBlock(toml);
164
+ assert.strictEqual(result.constraints.length, 1);
165
+ assert.strictEqual(result.constraints[0].text, 'All API endpoints must validate JWT');
166
+ assert.strictEqual(result.constraints[0].category, 'security');
167
+ });
168
+ it('should parse constraint with all optional fields', () => {
169
+ const toml = `
170
+ [[constraint]]
171
+ text = "No raw SQL strings"
172
+ category = "code-style"
173
+ priority = "high"
174
+ layer = "data"
175
+ tags = ["database", "security"]
176
+ rationale = "Prevent SQL injection"
177
+ `;
178
+ const result = parseTomlBlock(toml);
179
+ assert.strictEqual(result.constraints.length, 1);
180
+ const c = result.constraints[0];
181
+ assert.strictEqual(c.text, 'No raw SQL strings');
182
+ assert.strictEqual(c.category, 'code-style');
183
+ assert.strictEqual(c.priority, 'high');
184
+ assert.strictEqual(c.layer, 'data');
185
+ assert.deepStrictEqual(c.tags, ['database', 'security']);
186
+ assert.strictEqual(c.rationale, 'Prevent SQL injection');
187
+ });
188
+ it('should parse multiple constraints', () => {
189
+ const toml = `
190
+ [[constraint]]
191
+ text = "First rule"
192
+ category = "security"
193
+
194
+ [[constraint]]
195
+ text = "Second rule"
196
+ category = "performance"
197
+ `;
198
+ const result = parseTomlBlock(toml);
199
+ assert.strictEqual(result.constraints.length, 2);
200
+ });
201
+ it('should skip invalid constraints (missing required fields)', () => {
202
+ const toml = `
203
+ [[constraint]]
204
+ text = "Valid constraint"
205
+ category = "security"
206
+
207
+ [[constraint]]
208
+ text = "Missing category"
209
+
210
+ [[constraint]]
211
+ category = "missing-text"
212
+ `;
213
+ const result = parseTomlBlock(toml);
214
+ assert.strictEqual(result.constraints.length, 1);
215
+ assert.strictEqual(result.constraints[0].text, 'Valid constraint');
216
+ });
217
+ });
218
+ describe('parseTomlBlock - mixed decisions and constraints', () => {
219
+ it('should parse both decisions and constraints from same block', () => {
220
+ const toml = `
221
+ [[decision]]
222
+ key = "auth/method"
223
+ value = "JWT with refresh tokens"
224
+ layer = "business"
225
+
226
+ [[constraint]]
227
+ text = "All endpoints must validate JWT"
228
+ category = "security"
229
+ priority = "critical"
230
+
231
+ [[decision]]
232
+ key = "database/engine"
233
+ value = "PostgreSQL 15"
234
+ layer = "data"
235
+
236
+ [[constraint]]
237
+ text = "Use parameterized queries only"
238
+ category = "security"
239
+ `;
240
+ const result = parseTomlBlock(toml);
241
+ assert.strictEqual(result.decisions.length, 2);
242
+ assert.strictEqual(result.constraints.length, 2);
243
+ });
244
+ });
245
+ describe('parsePlanToml - end-to-end', () => {
246
+ it('should parse complete plan markdown with toml blocks', () => {
247
+ const content = `
248
+ # Implementation Plan
249
+
250
+ ## Overview
251
+ This is a plan for implementing authentication.
252
+
253
+ ## Architectural Decisions & Constraints
254
+
255
+ \`\`\`toml
256
+ [[decision]]
257
+ key = "auth/provider"
258
+ value = "Custom JWT implementation"
259
+ status = "active"
260
+ layer = "business"
261
+ tags = ["auth", "security"]
262
+ rationale = "Full control over token lifecycle"
263
+
264
+ [[constraint]]
265
+ text = "JWT tokens must expire within 15 minutes"
266
+ category = "security"
267
+ priority = "critical"
268
+ layer = "business"
269
+ \`\`\`
270
+
271
+ ## Implementation Steps
272
+
273
+ 1. Create token service
274
+ 2. Add middleware
275
+
276
+ ## Additional Constraints
277
+
278
+ \`\`\`toml
279
+ [[constraint]]
280
+ text = "Store refresh tokens in HTTP-only cookies"
281
+ category = "security"
282
+ priority = "high"
283
+ \`\`\`
284
+ `;
285
+ const result = parsePlanToml(content);
286
+ assert.strictEqual(result.decisions.length, 1);
287
+ assert.strictEqual(result.constraints.length, 2);
288
+ assert.strictEqual(result.decisions[0].key, 'auth/provider');
289
+ assert.strictEqual(result.constraints[0].text, 'JWT tokens must expire within 15 minutes');
290
+ assert.strictEqual(result.constraints[1].text, 'Store refresh tokens in HTTP-only cookies');
291
+ });
292
+ it('should handle plan with no toml blocks', () => {
293
+ const content = `
294
+ # Simple Plan
295
+
296
+ Just some text without any TOML.
297
+ `;
298
+ const result = parsePlanToml(content);
299
+ assert.strictEqual(result.decisions.length, 0);
300
+ assert.strictEqual(result.constraints.length, 0);
301
+ });
302
+ it('should handle malformed toml gracefully', () => {
303
+ const content = `
304
+ \`\`\`toml
305
+ this is not valid toml
306
+ { broken json
307
+ \`\`\`
308
+ `;
309
+ // Should not throw, just return empty
310
+ const result = parsePlanToml(content);
311
+ assert.strictEqual(result.decisions.length, 0);
312
+ assert.strictEqual(result.constraints.length, 0);
313
+ });
314
+ });
315
+ });
316
+ //# sourceMappingURL=plan-toml-parser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-toml-parser.test.js","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/plan-toml-parser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Activate constraints (by tag or by ID)
3
+ *
4
+ * - activateConstraintsByTag: Bulk activate by tag (for plan-based workflow)
5
+ * - activateConstraint: Single constraint by ID (MCP action)
6
+ *
7
+ * @since v4.2.1
8
+ */
9
+ import { DatabaseAdapter } from '../../../adapters/index.js';
10
+ /**
11
+ * Activate constraints by tag response
12
+ */
13
+ export interface ActivateConstraintsResponse {
14
+ success: boolean;
15
+ activated_count: number;
16
+ }
17
+ /**
18
+ * Activate constraint by ID response
19
+ */
20
+ export interface ActivateConstraintByIdResponse {
21
+ success: boolean;
22
+ constraint_id: number;
23
+ message: string;
24
+ }
25
+ /**
26
+ * Activate all constraints matching a specific tag
27
+ *
28
+ * Used by queue-watcher to activate constraints when implementation starts.
29
+ * The tag typically contains the plan_id short form (8 chars).
30
+ *
31
+ * @param tag - Tag to match (e.g., plan_id short form)
32
+ * @param adapter - Optional database adapter (for testing)
33
+ * @returns Number of constraints activated
34
+ */
35
+ export declare function activateConstraintsByTag(tag: string, adapter?: DatabaseAdapter): Promise<ActivateConstraintsResponse>;
36
+ /**
37
+ * Activate a single constraint by ID
38
+ *
39
+ * @param params - Parameters containing constraint_id
40
+ * @param adapter - Optional database adapter (for testing)
41
+ * @returns Success response with constraint ID
42
+ */
43
+ export declare function activateConstraint(params: {
44
+ constraint_id: number;
45
+ }, adapter?: DatabaseAdapter): Promise<ActivateConstraintByIdResponse>;
46
+ //# sourceMappingURL=activate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activate.d.ts","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/activate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAO7D;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,2BAA2B,CAAC,CAqCtC;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,EACjC,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,8BAA8B,CAAC,CA6CzC"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Activate constraints (by tag or by ID)
3
+ *
4
+ * - activateConstraintsByTag: Bulk activate by tag (for plan-based workflow)
5
+ * - activateConstraint: Single constraint by ID (MCP action)
6
+ *
7
+ * @since v4.2.1
8
+ */
9
+ import { getAdapter } from '../../../database.js';
10
+ import { getProjectContext } from '../../../utils/project-context.js';
11
+ import { normalizeParams, CONSTRAINT_ALIASES } from '../../../utils/param-normalizer.js';
12
+ import connectionManager from '../../../utils/connection-manager.js';
13
+ import { SQLITE_TRUE } from '../../../constants.js';
14
+ /**
15
+ * Activate all constraints matching a specific tag
16
+ *
17
+ * Used by queue-watcher to activate constraints when implementation starts.
18
+ * The tag typically contains the plan_id short form (8 chars).
19
+ *
20
+ * @param tag - Tag to match (e.g., plan_id short form)
21
+ * @param adapter - Optional database adapter (for testing)
22
+ * @returns Number of constraints activated
23
+ */
24
+ export async function activateConstraintsByTag(tag, adapter) {
25
+ const actualAdapter = adapter ?? getAdapter();
26
+ const knex = actualAdapter.getKnex();
27
+ try {
28
+ return await connectionManager.executeWithRetry(async () => {
29
+ const projectId = getProjectContext().getProjectId();
30
+ // Find constraints with matching tag that are inactive
31
+ const constraintIds = await knex('v4_constraints as c')
32
+ .join('v4_constraint_tags as ct', 'c.id', 'ct.constraint_id')
33
+ .join('v4_tags as t', 'ct.tag_id', 't.id')
34
+ .where('c.project_id', projectId)
35
+ .where('c.active', 0)
36
+ .where('t.name', tag)
37
+ .select('c.id')
38
+ .then(rows => rows.map(r => r.id));
39
+ if (constraintIds.length === 0) {
40
+ return { success: true, activated_count: 0 };
41
+ }
42
+ // Activate all matching constraints
43
+ await knex('v4_constraints')
44
+ .whereIn('id', constraintIds)
45
+ .where('project_id', projectId)
46
+ .update({ active: SQLITE_TRUE });
47
+ return {
48
+ success: true,
49
+ activated_count: constraintIds.length,
50
+ };
51
+ });
52
+ }
53
+ catch (error) {
54
+ const message = error instanceof Error ? error.message : String(error);
55
+ throw new Error(`Failed to activate constraints: ${message}`);
56
+ }
57
+ }
58
+ /**
59
+ * Activate a single constraint by ID
60
+ *
61
+ * @param params - Parameters containing constraint_id
62
+ * @param adapter - Optional database adapter (for testing)
63
+ * @returns Success response with constraint ID
64
+ */
65
+ export async function activateConstraint(params, adapter) {
66
+ const actualAdapter = adapter ?? getAdapter();
67
+ const knex = actualAdapter.getKnex();
68
+ // Normalize aliases: id → constraint_id
69
+ const normalizedParams = normalizeParams(params, CONSTRAINT_ALIASES);
70
+ try {
71
+ return await connectionManager.executeWithRetry(async () => {
72
+ const projectId = getProjectContext().getProjectId();
73
+ // Check if constraint exists
74
+ const constraint = await knex('v4_constraints')
75
+ .where('id', normalizedParams.constraint_id)
76
+ .where('project_id', projectId)
77
+ .first();
78
+ if (!constraint) {
79
+ throw new Error(`Constraint not found: ${normalizedParams.constraint_id}`);
80
+ }
81
+ if (constraint.active === 1) {
82
+ return {
83
+ success: true,
84
+ constraint_id: normalizedParams.constraint_id,
85
+ message: 'Constraint already active',
86
+ };
87
+ }
88
+ // Activate the constraint
89
+ await knex('v4_constraints')
90
+ .where('id', normalizedParams.constraint_id)
91
+ .where('project_id', projectId)
92
+ .update({ active: SQLITE_TRUE });
93
+ return {
94
+ success: true,
95
+ constraint_id: normalizedParams.constraint_id,
96
+ message: 'Constraint activated',
97
+ };
98
+ });
99
+ }
100
+ catch (error) {
101
+ const message = error instanceof Error ? error.message : String(error);
102
+ throw new Error(`Failed to activate constraint: ${message}`);
103
+ }
104
+ }
105
+ //# sourceMappingURL=activate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activate.js","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/activate.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/add.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAkB7D,OAAO,KAAK,EACV,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,qBAAqB,CAAC,CA6EhC"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/add.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAmB7D,OAAO,KAAK,EACV,mBAAmB,EACnB,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAErB;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,qBAAqB,CAAC,CA+FhC"}
@@ -6,6 +6,7 @@ import { getAdapter, getLayerId, getOrCreateTag, getOrCreateCategoryId } from '.
6
6
  import { STRING_TO_PRIORITY, DEFAULT_PRIORITY, SQLITE_TRUE, STANDARD_LAYERS } from '../../../constants.js';
7
7
  import { validateCategory, validatePriority } from '../../../utils/validators.js';
8
8
  import { validateActionParams } from '../../../utils/parameter-validator.js';
9
+ import { normalizeParams, CONSTRAINT_ALIASES } from '../../../utils/param-normalizer.js';
9
10
  import { parseStringArray } from '../../../utils/param-parser.js';
10
11
  import { getProjectContext } from '../../../utils/project-context.js';
11
12
  import connectionManager from '../../../utils/connection-manager.js';
@@ -18,50 +19,65 @@ import connectionManager from '../../../utils/connection-manager.js';
18
19
  */
19
20
  export async function addConstraint(params, adapter) {
20
21
  const actualAdapter = adapter ?? getAdapter();
22
+ // Normalize aliases: text → constraint_text
23
+ const normalizedParams = normalizeParams(params, CONSTRAINT_ALIASES);
21
24
  try {
22
25
  return await connectionManager.executeWithRetry(async () => {
23
26
  // Fail-fast project_id validation (Constraint #29)
24
27
  const projectId = getProjectContext().getProjectId();
25
28
  // Validate parameters
26
- validateActionParams('constraint', 'add', params);
29
+ validateActionParams('constraint', 'add', normalizedParams);
27
30
  // Validate category
28
- validateCategory(params.category);
31
+ validateCategory(normalizedParams.category);
29
32
  // Validate priority if provided
30
- const priorityStr = params.priority || 'medium';
33
+ const priorityStr = normalizedParams.priority || 'medium';
31
34
  validatePriority(priorityStr);
32
35
  const priority = STRING_TO_PRIORITY[priorityStr] || DEFAULT_PRIORITY;
33
36
  // Validate and get layer ID if provided
34
37
  let layerId = null;
35
- if (params.layer) {
36
- if (!STANDARD_LAYERS.includes(params.layer)) {
38
+ if (normalizedParams.layer) {
39
+ if (!STANDARD_LAYERS.includes(normalizedParams.layer)) {
37
40
  throw new Error(`Invalid layer. Must be one of: ${STANDARD_LAYERS.join(', ')}`);
38
41
  }
39
- layerId = await getLayerId(actualAdapter, params.layer);
42
+ layerId = await getLayerId(actualAdapter, normalizedParams.layer);
40
43
  if (!layerId) {
41
- throw new Error(`Layer not found: ${params.layer}`);
44
+ throw new Error(`Layer not found: ${normalizedParams.layer}`);
42
45
  }
43
46
  }
44
47
  // Use transaction for multi-table insert
45
48
  const result = await actualAdapter.transaction(async (trx) => {
46
49
  // Get or create category
47
- const categoryId = await getOrCreateCategoryId(actualAdapter, params.category, trx);
50
+ const categoryId = await getOrCreateCategoryId(actualAdapter, normalizedParams.category, trx);
51
+ // Duplicate check: skip if same text + category already exists
52
+ const existing = await trx('v4_constraints')
53
+ .where({
54
+ constraint_text: normalizedParams.constraint_text,
55
+ category_id: categoryId,
56
+ project_id: projectId
57
+ })
58
+ .first();
59
+ if (existing) {
60
+ return { constraintId: existing.id, alreadyExists: true };
61
+ }
48
62
  // Note: Agent tracking removed in v4.0 (created_by param kept for API compatibility but not stored)
49
63
  // Calculate timestamp
50
64
  const ts = Math.floor(Date.now() / 1000);
51
65
  // Insert constraint with project_id (agent_id removed in v4.0)
66
+ // v4.2.1: Support active parameter for plan-based workflow
67
+ const activeValue = normalizedParams.active === false ? 0 : SQLITE_TRUE;
52
68
  const [constraintId] = await trx('v4_constraints').insert({
53
69
  category_id: categoryId,
54
70
  layer_id: layerId,
55
- constraint_text: params.constraint_text,
71
+ constraint_text: normalizedParams.constraint_text,
56
72
  priority: priority,
57
- active: SQLITE_TRUE,
73
+ active: activeValue,
58
74
  ts: ts,
59
75
  project_id: projectId
60
76
  });
61
77
  // Insert m_tags if provided
62
- if (params.tags && params.tags.length > 0) {
78
+ if (normalizedParams.tags && normalizedParams.tags.length > 0) {
63
79
  // Parse tags (handles both arrays and JSON strings from MCP)
64
- const tags = parseStringArray(params.tags);
80
+ const tags = parseStringArray(normalizedParams.tags);
65
81
  for (const tagName of tags) {
66
82
  const tagId = await getOrCreateTag(actualAdapter, projectId, tagName, trx); // v3.7.3: pass projectId
67
83
  await trx('v4_constraint_tags').insert({
@@ -70,11 +86,12 @@ export async function addConstraint(params, adapter) {
70
86
  });
71
87
  }
72
88
  }
73
- return { constraintId: Number(constraintId) };
89
+ return { constraintId: Number(constraintId), alreadyExists: false };
74
90
  });
75
91
  return {
76
92
  success: true,
77
93
  constraint_id: result.constraintId,
94
+ already_exists: result.alreadyExists,
78
95
  };
79
96
  });
80
97
  }
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/add.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/add.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"deactivate.d.ts","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/deactivate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAM7D,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,MAAM,aAAa,CAAC;AAErB;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,EAClC,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,4BAA4B,CAAC,CAmCvC"}
1
+ {"version":3,"file":"deactivate.d.ts","sourceRoot":"","sources":["../../../../src/tools/constraints/actions/deactivate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAO7D,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC7B,MAAM,aAAa,CAAC;AAErB;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,EAClC,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,4BAA4B,CAAC,CAsCvC"}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { getAdapter } from '../../../database.js';
6
6
  import { validateActionParams } from '../../../utils/parameter-validator.js';
7
+ import { normalizeParams, CONSTRAINT_ALIASES } from '../../../utils/param-normalizer.js';
7
8
  import { getProjectContext } from '../../../utils/project-context.js';
8
9
  import connectionManager from '../../../utils/connection-manager.js';
9
10
  import { SQLITE_FALSE } from '../../../constants.js';
@@ -18,23 +19,25 @@ import { SQLITE_FALSE } from '../../../constants.js';
18
19
  export async function deactivateConstraint(params, adapter) {
19
20
  const actualAdapter = adapter ?? getAdapter();
20
21
  const knex = actualAdapter.getKnex();
22
+ // Normalize aliases: id → constraint_id
23
+ const normalizedParams = normalizeParams(params, CONSTRAINT_ALIASES);
21
24
  try {
22
25
  return await connectionManager.executeWithRetry(async () => {
23
26
  // Fail-fast project_id validation (Constraint #29)
24
27
  const projectId = getProjectContext().getProjectId();
25
28
  // Validate parameters
26
- validateActionParams('constraint', 'deactivate', params);
29
+ validateActionParams('constraint', 'deactivate', normalizedParams);
27
30
  // Check if constraint exists in current project
28
31
  const constraint = await knex('v4_constraints')
29
- .where({ id: params.constraint_id, project_id: projectId })
32
+ .where({ id: normalizedParams.constraint_id, project_id: projectId })
30
33
  .select('id', 'active')
31
34
  .first();
32
35
  if (!constraint) {
33
- throw new Error(`Constraint not found: ${params.constraint_id}`);
36
+ throw new Error(`Constraint not found: ${normalizedParams.constraint_id}`);
34
37
  }
35
38
  // Update constraint to inactive (idempotent) with project_id filter
36
39
  await knex('v4_constraints')
37
- .where({ id: params.constraint_id, project_id: projectId })
40
+ .where({ id: normalizedParams.constraint_id, project_id: projectId })
38
41
  .update({ active: SQLITE_FALSE });
39
42
  return {
40
43
  success: true,