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,94 @@
1
+ /**
2
+ * On-Subagent-Stop Hook Command
3
+ *
4
+ * SubagentStop hook - fires when any subagent (Plan, Explore, etc.) completes.
5
+ * Delegates pattern extraction to plan-processor.ts for DRY.
6
+ *
7
+ * Usage:
8
+ * echo '{"hook_event_name": "SubagentStop"}' | sqlew on-subagent-stop
9
+ *
10
+ * @since v4.2.0
11
+ * @modified v4.2.5 - Refactored to use plan-processor.ts (DRY)
12
+ */
13
+ import { readStdinJson, sendContinue, sendPostToolUseContext, getProjectPath } from './stdin-parser.js';
14
+ import { loadCurrentPlan } from '../../config/global-config.js';
15
+ import { processPlanPatterns } from './plan-processor.js';
16
+ // ============================================================================
17
+ // Constants
18
+ // ============================================================================
19
+ /** Maximum age for plan cache to be considered valid (30 minutes in ms) */
20
+ const MAX_PLAN_CACHE_AGE_MS = 30 * 60 * 1000;
21
+ // ============================================================================
22
+ // Main Entry Point
23
+ // ============================================================================
24
+ /**
25
+ * Main on-subagent-stop command entry point
26
+ *
27
+ * Called as SubagentStop hook when any subagent completes.
28
+ * Delegates pattern extraction to processPlanPatterns.
29
+ */
30
+ export async function onSubagentStopCommand() {
31
+ try {
32
+ const input = await readStdinJson();
33
+ // Check stop_hook_active to prevent infinite loops
34
+ if (isStopHookActive(input)) {
35
+ sendContinue();
36
+ return;
37
+ }
38
+ const projectPath = getProjectPath(input);
39
+ if (!projectPath) {
40
+ sendContinue();
41
+ return;
42
+ }
43
+ // Check if there's a current plan with pending decision
44
+ const planInfo = loadCurrentPlan(projectPath);
45
+ if (!planInfo || !planInfo.decision_pending) {
46
+ sendContinue();
47
+ return;
48
+ }
49
+ // Check if plan cache is stale (older than 30 minutes)
50
+ if (isPlanCacheStale(planInfo)) {
51
+ sendContinue();
52
+ return;
53
+ }
54
+ // Delegate to shared processor (handles recorded check internally)
55
+ const result = processPlanPatterns(projectPath);
56
+ if (result.processed && result.confirmationMessage) {
57
+ sendPostToolUseContext(result.confirmationMessage);
58
+ }
59
+ else {
60
+ sendContinue();
61
+ }
62
+ }
63
+ catch (error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ console.error(`[sqlew on-subagent-stop] Error: ${message}`);
66
+ sendContinue();
67
+ }
68
+ }
69
+ // ============================================================================
70
+ // Helpers
71
+ // ============================================================================
72
+ /**
73
+ * Check if stop hook is already active (infinite loop prevention)
74
+ */
75
+ function isStopHookActive(input) {
76
+ return input.stop_hook_active === true;
77
+ }
78
+ /**
79
+ * Check if plan cache is stale (older than MAX_PLAN_CACHE_AGE_MS)
80
+ */
81
+ function isPlanCacheStale(planInfo) {
82
+ if (!planInfo.plan_updated_at) {
83
+ return true;
84
+ }
85
+ try {
86
+ const updatedAt = new Date(planInfo.plan_updated_at).getTime();
87
+ const age = Date.now() - updatedAt;
88
+ return age > MAX_PLAN_CACHE_AGE_MS;
89
+ }
90
+ catch {
91
+ return true;
92
+ }
93
+ }
94
+ //# sourceMappingURL=on-subagent-stop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"on-subagent-stop.js","sourceRoot":"","sources":["../../../src/cli/hooks/on-subagent-stop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EAAE,cAAc,EAAkB,MAAM,mBAAmB,CAAC;AACxH,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,2EAA2E;AAC3E,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE7C,+EAA+E;AAC/E,mBAAmB;AACnB,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB;IACzC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,aAAa,EAAE,CAAC;QAEpC,mDAAmD;QACnD,IAAI,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC5B,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,wDAAwD;QACxD,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC5C,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,uDAAuD;QACvD,IAAI,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,MAAM,MAAM,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAEhD,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,mBAAmB,EAAE,CAAC;YACnD,sBAAsB,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,mCAAmC,OAAO,EAAE,CAAC,CAAC;QAC5D,YAAY,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E;;GAEG;AACH,SAAS,gBAAgB,CAAC,KAAgB;IACxC,OAAO,KAAK,CAAC,gBAAgB,KAAK,IAAI,CAAC;AACzC,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAsC;IAC9D,IAAI,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACnC,OAAO,GAAG,GAAG,qBAAqB,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Plan Pattern Extractor
3
+ *
4
+ * Extracts decisions and constraints from plan markdown using regex patterns.
5
+ * Looks for specific markers: 📌 Decision and 🚫 Constraint
6
+ *
7
+ * Expected format in plan files:
8
+ *
9
+ * ## 📌 Decision: [hierarchical/key]
10
+ * - **Value**: Decision description
11
+ * - **Layer**: presentation | business | data | infrastructure | cross-cutting
12
+ * - **Tags**: Why this decision was made
13
+ *
14
+ * ## 🚫 Constraint: [category]
15
+ * - **Rule**: Constraint description
16
+ * - **Priority**: critical | high | medium | low
17
+ * - **Tags**: Why this constraint exists
18
+ *
19
+ * @since v4.2.2
20
+ * @modified v4.2.3 - Added resolvePlanPath and buildConfirmationMessage
21
+ */
22
+ /**
23
+ * Extracted decision from plan
24
+ */
25
+ export interface ExtractedDecision {
26
+ /** Hierarchical key (e.g., "auth/jwt-strategy") */
27
+ key: string;
28
+ /** Decision description */
29
+ value: string;
30
+ /** Layer (presentation, business, data, infrastructure, cross-cutting) */
31
+ layer?: string;
32
+ /** Tags for the decision (comma-separated) */
33
+ tags?: string;
34
+ }
35
+ /**
36
+ * Extracted constraint from plan
37
+ */
38
+ export interface ExtractedConstraint {
39
+ /** Category (architecture, security, code-style, performance) */
40
+ category: string;
41
+ /** Constraint rule text */
42
+ rule: string;
43
+ /** Priority (critical, high, medium, low) */
44
+ priority?: string;
45
+ /** Tags for the constraint (comma-separated) */
46
+ tags?: string;
47
+ }
48
+ /**
49
+ * Result of pattern extraction
50
+ */
51
+ export interface ExtractionResult {
52
+ /** Extracted decisions */
53
+ decisions: ExtractedDecision[];
54
+ /** Extracted constraints */
55
+ constraints: ExtractedConstraint[];
56
+ }
57
+ /**
58
+ * Extract decisions and constraints from plan content using regex patterns
59
+ *
60
+ * @param content - Plan markdown content
61
+ * @returns Extraction result with decisions and constraints
62
+ */
63
+ export declare function extractPatternsFromPlan(content: string): ExtractionResult;
64
+ /**
65
+ * Check if content contains any decision/constraint patterns
66
+ *
67
+ * @param content - Plan content
68
+ * @returns true if patterns detected
69
+ */
70
+ export declare function hasPatterns(content: string): boolean;
71
+ /**
72
+ * Resolve plan file path
73
+ * Plans are stored in user's global ~/.claude/plans/ directory
74
+ *
75
+ * @param planFileName - Plan file name (e.g., "my-plan.md")
76
+ * @returns Full path to plan file, or null if not found
77
+ */
78
+ export declare function resolvePlanPath(planFileName: string): string | null;
79
+ /**
80
+ * Build confirmation message for user after pattern extraction
81
+ *
82
+ * @param extracted - Extraction result
83
+ * @param planFile - Plan file name
84
+ * @returns Formatted confirmation message
85
+ */
86
+ export declare function buildConfirmationMessage(extracted: ExtractionResult, planFile: string): string;
87
+ //# sourceMappingURL=plan-pattern-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-pattern-extractor.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/plan-pattern-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAUH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0BAA0B;IAC1B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,4BAA4B;IAC5B,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACpC;AAsBD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAgDzE;AA8ED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEpD;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMnE;AAMD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CA6B9F"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Plan Pattern Extractor
3
+ *
4
+ * Extracts decisions and constraints from plan markdown using regex patterns.
5
+ * Looks for specific markers: 📌 Decision and 🚫 Constraint
6
+ *
7
+ * Expected format in plan files:
8
+ *
9
+ * ## 📌 Decision: [hierarchical/key]
10
+ * - **Value**: Decision description
11
+ * - **Layer**: presentation | business | data | infrastructure | cross-cutting
12
+ * - **Tags**: Why this decision was made
13
+ *
14
+ * ## 🚫 Constraint: [category]
15
+ * - **Rule**: Constraint description
16
+ * - **Priority**: critical | high | medium | low
17
+ * - **Tags**: Why this constraint exists
18
+ *
19
+ * @since v4.2.2
20
+ * @modified v4.2.3 - Added resolvePlanPath and buildConfirmationMessage
21
+ */
22
+ import { existsSync } from 'fs';
23
+ import { join } from 'path';
24
+ import { homedir } from 'os';
25
+ // ============================================================================
26
+ // Constants
27
+ // ============================================================================
28
+ /** Valid layer values */
29
+ const VALID_LAYERS = ['presentation', 'business', 'data', 'infrastructure', 'cross-cutting'];
30
+ /** Valid constraint categories */
31
+ const VALID_CATEGORIES = ['architecture', 'security', 'code-style', 'performance'];
32
+ /** Valid priority values */
33
+ const VALID_PRIORITIES = ['critical', 'high', 'medium', 'low'];
34
+ /** User's global plans directory */
35
+ const GLOBAL_PLANS_DIR = join(homedir(), '.claude', 'plans');
36
+ // ============================================================================
37
+ // Main Extraction Function
38
+ // ============================================================================
39
+ /**
40
+ * Extract decisions and constraints from plan content using regex patterns
41
+ *
42
+ * @param content - Plan markdown content
43
+ * @returns Extraction result with decisions and constraints
44
+ */
45
+ export function extractPatternsFromPlan(content) {
46
+ const decisions = [];
47
+ const constraints = [];
48
+ // Decision pattern: ## or ### 📌 Decision: [key]
49
+ // Supports both h2 (##) and h3 (###) headings for flexibility
50
+ // Captures: key, then body until next ## or ### or end
51
+ const decisionRegex = /#{2,3}\s*📌\s*Decision:\s*(.+?)\n([\s\S]*?)(?=#{2,3}\s|$)/gi;
52
+ // Constraint pattern: ## or ### 🚫 Constraint: [category]
53
+ // Supports both h2 (##) and h3 (###) headings for flexibility
54
+ // Captures: category, then body until next ## or ### or end
55
+ const constraintRegex = /#{2,3}\s*🚫\s*Constraint:\s*(.+?)\n([\s\S]*?)(?=#{2,3}\s|$)/gi;
56
+ // Parse decisions
57
+ let match;
58
+ while ((match = decisionRegex.exec(content)) !== null) {
59
+ const key = match[1].trim();
60
+ const body = match[2];
61
+ const value = extractField(body, 'Value');
62
+ if (!value)
63
+ continue; // Skip if no value
64
+ decisions.push({
65
+ key: normalizeKey(key),
66
+ value,
67
+ layer: normalizeLayer(extractField(body, 'Layer')),
68
+ tags: extractField(body, 'Tags'),
69
+ });
70
+ }
71
+ // Parse constraints
72
+ while ((match = constraintRegex.exec(content)) !== null) {
73
+ const category = match[1].trim();
74
+ const body = match[2];
75
+ const rule = extractField(body, 'Rule');
76
+ if (!rule)
77
+ continue; // Skip if no rule
78
+ constraints.push({
79
+ category: normalizeCategory(category),
80
+ rule,
81
+ priority: normalizePriority(extractField(body, 'Priority')),
82
+ tags: extractField(body, 'Tags'),
83
+ });
84
+ }
85
+ return { decisions, constraints };
86
+ }
87
+ // ============================================================================
88
+ // Field Extraction
89
+ // ============================================================================
90
+ /**
91
+ * Extract a field value from the body text
92
+ *
93
+ * Matches patterns like:
94
+ * - **Field**: Value
95
+ * - **Field**: Value (with more text)
96
+ *
97
+ * @param body - Body text containing fields
98
+ * @param fieldName - Name of the field to extract
99
+ * @returns Field value or empty string
100
+ */
101
+ function extractField(body, fieldName) {
102
+ // Match: - **FieldName**: value (until newline or end)
103
+ // Double backslashes needed in template literals for regex escapes
104
+ const regex = new RegExp(`-\\s*\\*\\*${fieldName}\\*\\*:\\s*(.+?)(?=\\n-\\s*\\*\\*|\\n\\n|$)`, 'is');
105
+ const match = body.match(regex);
106
+ return match ? match[1].trim() : '';
107
+ }
108
+ // ============================================================================
109
+ // Normalization
110
+ // ============================================================================
111
+ /**
112
+ * Normalize decision key
113
+ * Removes extra whitespace, converts to lowercase path format
114
+ */
115
+ function normalizeKey(key) {
116
+ return key
117
+ .trim()
118
+ .toLowerCase()
119
+ .replace(/\s+/g, '-')
120
+ .replace(/[^a-z0-9\-\/]/g, '');
121
+ }
122
+ /**
123
+ * Normalize layer value
124
+ */
125
+ function normalizeLayer(layer) {
126
+ if (!layer)
127
+ return 'cross-cutting';
128
+ const normalized = layer.toLowerCase().trim();
129
+ return VALID_LAYERS.includes(normalized) ? normalized : 'cross-cutting';
130
+ }
131
+ /**
132
+ * Normalize category value
133
+ * Handles bracket notation: [code-style] → code-style
134
+ */
135
+ function normalizeCategory(category) {
136
+ if (!category)
137
+ return 'architecture';
138
+ // Strip brackets: [code-style] → code-style
139
+ const stripped = category.replace(/^\[|\]$/g, '');
140
+ const normalized = stripped.toLowerCase().trim();
141
+ return VALID_CATEGORIES.includes(normalized) ? normalized : 'architecture';
142
+ }
143
+ /**
144
+ * Normalize priority value
145
+ */
146
+ function normalizePriority(priority) {
147
+ if (!priority)
148
+ return 'medium';
149
+ const normalized = priority.toLowerCase().trim();
150
+ return VALID_PRIORITIES.includes(normalized) ? normalized : 'medium';
151
+ }
152
+ // ============================================================================
153
+ // Utility Functions
154
+ // ============================================================================
155
+ /**
156
+ * Check if content contains any decision/constraint patterns
157
+ *
158
+ * @param content - Plan content
159
+ * @returns true if patterns detected
160
+ */
161
+ export function hasPatterns(content) {
162
+ return /#{2,3}\s*📌\s*Decision:/i.test(content) || /#{2,3}\s*🚫\s*Constraint:/i.test(content);
163
+ }
164
+ // ============================================================================
165
+ // Path Resolution
166
+ // ============================================================================
167
+ /**
168
+ * Resolve plan file path
169
+ * Plans are stored in user's global ~/.claude/plans/ directory
170
+ *
171
+ * @param planFileName - Plan file name (e.g., "my-plan.md")
172
+ * @returns Full path to plan file, or null if not found
173
+ */
174
+ export function resolvePlanPath(planFileName) {
175
+ const globalPath = join(GLOBAL_PLANS_DIR, planFileName);
176
+ if (existsSync(globalPath)) {
177
+ return globalPath;
178
+ }
179
+ return null;
180
+ }
181
+ // ============================================================================
182
+ // Message Formatting
183
+ // ============================================================================
184
+ /**
185
+ * Build confirmation message for user after pattern extraction
186
+ *
187
+ * @param extracted - Extraction result
188
+ * @param planFile - Plan file name
189
+ * @returns Formatted confirmation message
190
+ */
191
+ export function buildConfirmationMessage(extracted, planFile) {
192
+ const lines = [
193
+ '',
194
+ `📋 **Extracted from plan "${planFile}"**`,
195
+ '',
196
+ ];
197
+ if (extracted.decisions.length > 0) {
198
+ lines.push(`### ✅ Decisions (${extracted.decisions.length}) → auto-registered as draft`);
199
+ for (const d of extracted.decisions) {
200
+ lines.push(`- **${d.key}**: ${d.value}`);
201
+ if (d.layer)
202
+ lines.push(` - Layer: ${d.layer}`);
203
+ }
204
+ lines.push('');
205
+ }
206
+ if (extracted.constraints.length > 0) {
207
+ lines.push(`### ✅ Constraints (${extracted.constraints.length}) → auto-registered as active`);
208
+ for (const c of extracted.constraints) {
209
+ lines.push(`- **[${c.category}]** ${c.rule} (${c.priority || 'medium'})`);
210
+ }
211
+ lines.push('');
212
+ }
213
+ lines.push('---');
214
+ lines.push('💡 Decisions will be promoted to active when implementation files are edited.');
215
+ lines.push('Check manually: `mcp__sqlew__decision({ action: "list", status: "draft" })`');
216
+ return lines.join('\n');
217
+ }
218
+ //# sourceMappingURL=plan-pattern-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-pattern-extractor.js","sourceRoot":"","sources":["../../../src/cli/hooks/plan-pattern-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Plan Processor - Shared logic for plan pattern extraction and queue registration
3
+ *
4
+ * Consolidates duplicate logic from on-exit-plan.ts and on-subagent-stop.ts.
5
+ * Single source of truth for:
6
+ * - Pattern extraction from plan files
7
+ * - Queue registration of decisions/constraints
8
+ * - Plan state management (recorded flag)
9
+ *
10
+ * @since v4.2.5
11
+ */
12
+ import { type ExtractionResult } from './plan-pattern-extractor.js';
13
+ /** Result of processing plan patterns */
14
+ export interface ProcessPlanResult {
15
+ /** Whether processing was performed */
16
+ processed: boolean;
17
+ /** Reason for skipping (if not processed) */
18
+ skipReason?: string;
19
+ /** Extracted patterns (if processed) */
20
+ extracted?: ExtractionResult;
21
+ /** Confirmation message for user (if processed) */
22
+ confirmationMessage?: string;
23
+ }
24
+ /**
25
+ * Process plan patterns and enqueue decisions/constraints
26
+ *
27
+ * This is the single entry point for plan pattern processing.
28
+ * Both on-exit-plan and on-subagent-stop should call this function.
29
+ *
30
+ * Flow:
31
+ * 1. Load current plan info
32
+ * 2. Check if already recorded (skip if true)
33
+ * 3. Read plan file content
34
+ * 4. Extract patterns (decisions/constraints)
35
+ * 5. Enqueue items for registration
36
+ * 6. Mark plan as recorded
37
+ * 7. Return confirmation message
38
+ *
39
+ * @param projectPath - Project root path
40
+ * @returns Processing result with status and message
41
+ */
42
+ export declare function processPlanPatterns(projectPath: string): ProcessPlanResult;
43
+ //# sourceMappingURL=plan-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-processor.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/plan-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,6BAA6B,CAAC;AAMrC,yCAAyC;AACzC,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,SAAS,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,mDAAmD;IACnD,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,iBAAiB,CA0F1E"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Plan Processor - Shared logic for plan pattern extraction and queue registration
3
+ *
4
+ * Consolidates duplicate logic from on-exit-plan.ts and on-subagent-stop.ts.
5
+ * Single source of truth for:
6
+ * - Pattern extraction from plan files
7
+ * - Queue registration of decisions/constraints
8
+ * - Plan state management (recorded flag)
9
+ *
10
+ * @since v4.2.5
11
+ */
12
+ import { readFileSync } from 'fs';
13
+ import { loadCurrentPlan, saveCurrentPlan } from '../../config/global-config.js';
14
+ import { enqueueDecisionCreate, enqueueConstraintCreate } from '../../utils/hook-queue.js';
15
+ import { extractPatternsFromPlan, hasPatterns, resolvePlanPath, buildConfirmationMessage, } from './plan-pattern-extractor.js';
16
+ // ============================================================================
17
+ // Main Processing Function
18
+ // ============================================================================
19
+ /**
20
+ * Process plan patterns and enqueue decisions/constraints
21
+ *
22
+ * This is the single entry point for plan pattern processing.
23
+ * Both on-exit-plan and on-subagent-stop should call this function.
24
+ *
25
+ * Flow:
26
+ * 1. Load current plan info
27
+ * 2. Check if already recorded (skip if true)
28
+ * 3. Read plan file content
29
+ * 4. Extract patterns (decisions/constraints)
30
+ * 5. Enqueue items for registration
31
+ * 6. Mark plan as recorded
32
+ * 7. Return confirmation message
33
+ *
34
+ * @param projectPath - Project root path
35
+ * @returns Processing result with status and message
36
+ */
37
+ export function processPlanPatterns(projectPath) {
38
+ // Load current plan info
39
+ const planInfo = loadCurrentPlan(projectPath);
40
+ if (!planInfo?.plan_file) {
41
+ return { processed: false, skipReason: 'no_active_plan' };
42
+ }
43
+ // DUPLICATE PREVENTION: Skip if already processed
44
+ if (planInfo.recorded) {
45
+ return { processed: false, skipReason: 'already_recorded' };
46
+ }
47
+ // Resolve plan file path
48
+ const planPath = resolvePlanPath(planInfo.plan_file);
49
+ if (!planPath) {
50
+ return { processed: false, skipReason: 'plan_file_not_found' };
51
+ }
52
+ // Read plan content
53
+ let content;
54
+ try {
55
+ content = readFileSync(planPath, 'utf-8');
56
+ }
57
+ catch {
58
+ return { processed: false, skipReason: 'read_error' };
59
+ }
60
+ // Check for patterns (quick check)
61
+ if (!hasPatterns(content)) {
62
+ return { processed: false, skipReason: 'no_patterns' };
63
+ }
64
+ // Extract patterns
65
+ const extracted = extractPatternsFromPlan(content);
66
+ if (extracted.decisions.length === 0 && extracted.constraints.length === 0) {
67
+ return { processed: false, skipReason: 'no_valid_patterns' };
68
+ }
69
+ // Enqueue items
70
+ const planIdTag = planInfo.plan_id.slice(0, 8);
71
+ for (const decision of extracted.decisions) {
72
+ const extractedTags = decision.tags
73
+ ? decision.tags.split(',').map(t => t.trim()).filter(t => t)
74
+ : [];
75
+ const allTags = ['plan', 'auto-extracted', planIdTag, ...extractedTags];
76
+ enqueueDecisionCreate(projectPath, {
77
+ key: decision.key,
78
+ value: decision.value,
79
+ status: 'draft',
80
+ layer: decision.layer || 'cross-cutting',
81
+ tags: allTags,
82
+ });
83
+ }
84
+ for (const constraint of extracted.constraints) {
85
+ const extractedTags = constraint.tags
86
+ ? constraint.tags.split(',').map(t => t.trim()).filter(t => t)
87
+ : [];
88
+ const allTags = ['plan', 'auto-extracted', planIdTag, ...extractedTags];
89
+ enqueueConstraintCreate(projectPath, {
90
+ text: constraint.rule,
91
+ category: constraint.category,
92
+ priority: constraint.priority || 'medium',
93
+ layer: 'cross-cutting',
94
+ tags: allTags,
95
+ active: true,
96
+ plan_id: planInfo.plan_id,
97
+ });
98
+ }
99
+ // Mark plan as recorded (CRITICAL: prevents duplicate processing)
100
+ const updatedInfo = {
101
+ ...planInfo,
102
+ recorded: true,
103
+ decision_pending: false,
104
+ plan_updated_at: new Date().toISOString(),
105
+ };
106
+ saveCurrentPlan(projectPath, updatedInfo);
107
+ // Build confirmation message
108
+ const confirmationMessage = buildConfirmationMessage(extracted, planInfo.plan_file);
109
+ return {
110
+ processed: true,
111
+ extracted,
112
+ confirmationMessage,
113
+ };
114
+ }
115
+ //# sourceMappingURL=plan-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-processor.js","sourceRoot":"","sources":["../../../src/cli/hooks/plan-processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Plan TOML Parser
3
+ *
4
+ * Parses ```toml blocks from plan markdown files to extract
5
+ * [[decision]] and [[constraint]] entries.
6
+ *
7
+ * Uses smol-toml (already a project dependency) for parsing.
8
+ *
9
+ * @since v4.2.0
10
+ */
11
+ import type { DecisionCandidate, ConstraintCandidate } from '../../config/global-config.js';
12
+ /**
13
+ * Result of parsing plan TOML content
14
+ */
15
+ export interface ParsedPlanToml {
16
+ /** Extracted decision candidates */
17
+ decisions: DecisionCandidate[];
18
+ /** Extracted constraint candidates */
19
+ constraints: ConstraintCandidate[];
20
+ }
21
+ /**
22
+ * Extract all ```toml blocks from markdown content
23
+ *
24
+ * @param content - Full markdown content
25
+ * @returns Array of TOML block contents (without fences)
26
+ */
27
+ export declare function extractTomlBlocks(content: string): string[];
28
+ /**
29
+ * Parse a single TOML block and extract decisions/constraints
30
+ *
31
+ * @param tomlContent - TOML content (without fences)
32
+ * @returns Parsed decisions and constraints
33
+ */
34
+ export declare function parseTomlBlock(tomlContent: string): ParsedPlanToml;
35
+ /**
36
+ * Parse plan content and extract all decisions/constraints from TOML blocks
37
+ *
38
+ * @param content - Full markdown content of plan file
39
+ * @returns Merged decisions and constraints from all TOML blocks
40
+ */
41
+ export declare function parsePlanToml(content: string): ParsedPlanToml;
42
+ //# sourceMappingURL=plan-toml-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-toml-parser.d.ts","sourceRoot":"","sources":["../../../src/cli/hooks/plan-toml-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAM5F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,sCAAsC;IACtC,WAAW,EAAE,mBAAmB,EAAE,CAAC;CACpC;AAcD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAe3D;AAoGD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CAoClE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAiB7D"}