sqlew 5.2.0 → 5.2.2

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 (109) hide show
  1. package/CHANGELOG.md +2169 -2110
  2. package/LICENSE +190 -190
  3. package/NOTICE +24 -24
  4. package/README.md +204 -199
  5. package/dist/adapters/mysql-adapter.js +3 -3
  6. package/dist/adapters/postgresql-adapter.js +3 -3
  7. package/dist/cli/db-export.js +32 -32
  8. package/dist/cli/db-import.js +30 -30
  9. package/dist/cli/hooks/codex-transcript.d.ts +23 -0
  10. package/dist/cli/hooks/codex-transcript.d.ts.map +1 -0
  11. package/dist/cli/hooks/codex-transcript.js +134 -0
  12. package/dist/cli/hooks/codex-transcript.js.map +1 -0
  13. package/dist/cli/hooks/on-exit-plan.d.ts.map +1 -1
  14. package/dist/cli/hooks/on-exit-plan.js +30 -3
  15. package/dist/cli/hooks/on-exit-plan.js.map +1 -1
  16. package/dist/cli/hooks/on-prompt.d.ts +2 -2
  17. package/dist/cli/hooks/on-prompt.d.ts.map +1 -1
  18. package/dist/cli/hooks/on-prompt.js +33 -16
  19. package/dist/cli/hooks/on-prompt.js.map +1 -1
  20. package/dist/cli/hooks/plan-pattern-extractor.d.ts +2 -0
  21. package/dist/cli/hooks/plan-pattern-extractor.d.ts.map +1 -1
  22. package/dist/cli/hooks/plan-pattern-extractor.js +1 -0
  23. package/dist/cli/hooks/plan-pattern-extractor.js.map +1 -1
  24. package/dist/cli/hooks/plan-processor.d.ts.map +1 -1
  25. package/dist/cli/hooks/plan-processor.js +1 -0
  26. package/dist/cli/hooks/plan-processor.js.map +1 -1
  27. package/dist/cli/hooks/pr-adr.js +5 -5
  28. package/dist/cli/hooks/stdin-parser.d.ts +4 -2
  29. package/dist/cli/hooks/stdin-parser.d.ts.map +1 -1
  30. package/dist/cli/hooks/stdin-parser.js +79 -9
  31. package/dist/cli/hooks/stdin-parser.js.map +1 -1
  32. package/dist/cli/hooks/track-plan.js +15 -15
  33. package/dist/cli.js +48 -48
  34. package/dist/config/global-config.js +19 -19
  35. package/dist/database/migrations/v4/20251126000000_v4_bootstrap.js +32 -32
  36. package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.js +3 -3
  37. package/dist/database/migrations/v4/20260613000000_add_constraint_reason.d.ts +9 -0
  38. package/dist/database/migrations/v4/20260613000000_add_constraint_reason.d.ts.map +1 -0
  39. package/dist/database/migrations/v4/20260613000000_add_constraint_reason.js +31 -0
  40. package/dist/database/migrations/v4/20260613000000_add_constraint_reason.js.map +1 -0
  41. package/dist/help-data/constraint.toml +265 -259
  42. package/dist/help-data/decision.toml +845 -845
  43. package/dist/help-data/queue.toml +134 -134
  44. package/dist/schema.d.ts.map +1 -1
  45. package/dist/schema.js +4 -5
  46. package/dist/schema.js.map +1 -1
  47. package/dist/server/tool-schemas.js +30 -30
  48. package/dist/tests/docker/native/constraint-operations.test.js +38 -0
  49. package/dist/tests/docker/native/constraint-operations.test.js.map +1 -1
  50. package/dist/tests/docker/native/db-init.js +9 -9
  51. package/dist/tests/feature/constraint/reason.test.d.ts +7 -0
  52. package/dist/tests/feature/constraint/reason.test.d.ts.map +1 -0
  53. package/dist/tests/feature/constraint/reason.test.js +68 -0
  54. package/dist/tests/feature/constraint/reason.test.js.map +1 -0
  55. package/dist/tests/unit/hooks/codex-hook-normalization.test.d.ts +7 -0
  56. package/dist/tests/unit/hooks/codex-hook-normalization.test.d.ts.map +1 -0
  57. package/dist/tests/unit/hooks/codex-hook-normalization.test.js +112 -0
  58. package/dist/tests/unit/hooks/codex-hook-normalization.test.js.map +1 -0
  59. package/dist/tests/unit/hooks/grok-hook-normalization.test.js +45 -7
  60. package/dist/tests/unit/hooks/grok-hook-normalization.test.js.map +1 -1
  61. package/dist/tests/unit/hooks/plan-pattern-extractor.test.d.ts +8 -0
  62. package/dist/tests/unit/hooks/plan-pattern-extractor.test.d.ts.map +1 -0
  63. package/dist/tests/unit/hooks/plan-pattern-extractor.test.js +110 -0
  64. package/dist/tests/unit/hooks/plan-pattern-extractor.test.js.map +1 -0
  65. package/dist/tests/utils/db-schema.js +48 -48
  66. package/dist/tests/utils/test-helpers.js +48 -48
  67. package/dist/tools/constraints/actions/add.d.ts.map +1 -1
  68. package/dist/tools/constraints/actions/add.js +1 -0
  69. package/dist/tools/constraints/actions/add.js.map +1 -1
  70. package/dist/tools/constraints/actions/get.d.ts.map +1 -1
  71. package/dist/tools/constraints/actions/get.js +9 -7
  72. package/dist/tools/constraints/actions/get.js.map +1 -1
  73. package/dist/tools/constraints/help/example.js +1 -1
  74. package/dist/tools/constraints/help/example.js.map +1 -1
  75. package/dist/types/constraint/params.d.ts +2 -0
  76. package/dist/types/constraint/params.d.ts.map +1 -1
  77. package/dist/types/view-entities.d.ts +1 -0
  78. package/dist/types/view-entities.d.ts.map +1 -1
  79. package/dist/utils/action-specs/constraint-specs.d.ts.map +1 -1
  80. package/dist/utils/action-specs/constraint-specs.js +4 -3
  81. package/dist/utils/action-specs/constraint-specs.js.map +1 -1
  82. package/dist/utils/hook-queue.d.ts +2 -0
  83. package/dist/utils/hook-queue.d.ts.map +1 -1
  84. package/dist/utils/hook-queue.js.map +1 -1
  85. package/dist/utils/project-root.d.ts +1 -0
  86. package/dist/utils/project-root.d.ts.map +1 -1
  87. package/dist/utils/project-root.js +6 -0
  88. package/dist/utils/project-root.js.map +1 -1
  89. package/dist/utils/view-queries.d.ts.map +1 -1
  90. package/dist/utils/view-queries.js +1 -0
  91. package/dist/utils/view-queries.js.map +1 -1
  92. package/dist/watcher/queue-watcher.d.ts.map +1 -1
  93. package/dist/watcher/queue-watcher.js +1 -0
  94. package/dist/watcher/queue-watcher.js.map +1 -1
  95. package/docs/ADR_CONCEPTS.md +152 -152
  96. package/docs/CLI_USAGE.md +392 -392
  97. package/docs/CONFIGURATION.md +157 -157
  98. package/docs/CROSS_DATABASE.md +66 -66
  99. package/docs/DATABASE_AUTH.md +135 -135
  100. package/docs/HOOKS_GUIDE.md +116 -101
  101. package/docs/MIGRATION_TO_SAAS.md +176 -176
  102. package/docs/SHARED_DATABASE.md +108 -108
  103. package/package.json +88 -88
  104. package/scripts/copy-help-data.js +19 -19
  105. package/scripts/filter-test-output.js +78 -78
  106. package/dist/tests/docker/native/help-system.test.d.ts +0 -8
  107. package/dist/tests/docker/native/help-system.test.d.ts.map +0 -1
  108. package/dist/tests/docker/native/help-system.test.js +0 -508
  109. package/dist/tests/docker/native/help-system.test.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reason.test.js","sourceRoot":"","sources":["../../../../src/tests/feature/constraint/reason.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Codex Hook Normalization Unit Tests
3
+ *
4
+ * @since v5.2.1
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=codex-hook-normalization.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-hook-normalization.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/codex-hook-normalization.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Codex Hook Normalization Unit Tests
3
+ *
4
+ * @since v5.2.1
5
+ */
6
+ import { describe, it, beforeEach, afterEach } from 'node:test';
7
+ import assert from 'node:assert';
8
+ import { homedir } from 'os';
9
+ import { join } from 'path';
10
+ import { normalizeHookInput, isPlanMode, } from '../../../cli/hooks/stdin-parser.js';
11
+ import { findCodexTranscriptPath, extractPlanMarkdownFromCodexTranscript, } from '../../../cli/hooks/codex-transcript.js';
12
+ import { determineProjectRoot } from '../../../utils/project-root.js';
13
+ describe('codex-hook-normalization', () => {
14
+ const originalEnv = { ...process.env };
15
+ beforeEach(() => {
16
+ delete process.env.CODEX_SESSION_ID;
17
+ delete process.env.CODEX_CWD;
18
+ delete process.env.CODEX_HOME;
19
+ delete process.env.GROK_HOOK_EVENT;
20
+ delete process.env.GROK_WORKSPACE_ROOT;
21
+ delete process.env.CLAUDE_PROJECT_DIR;
22
+ delete process.env.SQLEW_PROJECT_ROOT;
23
+ });
24
+ afterEach(() => {
25
+ process.env = { ...originalEnv };
26
+ });
27
+ describe('normalizeHookInput', () => {
28
+ it('should normalize Codex shell_command to Bash', () => {
29
+ const result = normalizeHookInput({
30
+ hook_event_name: 'PreToolUse',
31
+ tool_name: 'shell_command',
32
+ cwd: 'C:/project',
33
+ });
34
+ assert.strictEqual(result.client, 'codex');
35
+ assert.strictEqual(result.tool_name, 'Bash');
36
+ assert.strictEqual(result.cwd, 'C:/project');
37
+ });
38
+ it('should normalize Codex apply_patch to Edit', () => {
39
+ const result = normalizeHookInput({
40
+ hook_event_name: 'PostToolUse',
41
+ tool_name: 'apply_patch',
42
+ cwd: 'C:/project',
43
+ });
44
+ assert.strictEqual(result.client, 'codex');
45
+ assert.strictEqual(result.tool_name, 'Edit');
46
+ });
47
+ it('should map collaboration_mode plan to permission_mode plan', () => {
48
+ const result = normalizeHookInput({
49
+ hook_event_name: 'UserPromptSubmit',
50
+ collaboration_mode: { mode: 'plan' },
51
+ cwd: 'C:/project',
52
+ session_id: 'sess-codex-1',
53
+ });
54
+ assert.strictEqual(result.client, 'codex');
55
+ assert.strictEqual(result.collaboration_mode, 'plan');
56
+ assert.strictEqual(result.permission_mode, 'plan');
57
+ });
58
+ it('should use CODEX env vars when stdin is empty', () => {
59
+ process.env.CODEX_SESSION_ID = 'sess-1';
60
+ process.env.CODEX_CWD = 'C:/project';
61
+ const result = normalizeHookInput({});
62
+ assert.strictEqual(result.client, 'codex');
63
+ assert.strictEqual(result.session_id, 'sess-1');
64
+ assert.strictEqual(result.cwd, 'C:/project');
65
+ });
66
+ });
67
+ describe('isPlanMode', () => {
68
+ it('should detect Codex plan mode via collaboration_mode', () => {
69
+ assert.strictEqual(isPlanMode({ client: 'codex', collaboration_mode: 'plan' }), true);
70
+ });
71
+ it('should detect Codex after normalization', () => {
72
+ const normalized = normalizeHookInput({
73
+ hook_event_name: 'UserPromptSubmit',
74
+ collaboration_mode_kind: 'plan',
75
+ cwd: 'C:/project',
76
+ });
77
+ assert.strictEqual(isPlanMode(normalized), true);
78
+ });
79
+ });
80
+ describe('findCodexTranscriptPath', () => {
81
+ it('should reject invalid session ids', () => {
82
+ assert.strictEqual(findCodexTranscriptPath('../escape'), null);
83
+ assert.strictEqual(findCodexTranscriptPath(''), null);
84
+ });
85
+ it('should find an existing local rollout transcript when present', () => {
86
+ const sessionId = '019e85cb-a131-7760-9a30-f164fcf83073';
87
+ const expected = join(homedir(), '.codex', 'sessions', '2026', '06', '02', `rollout-2026-06-02T09-46-15-${sessionId}.jsonl`);
88
+ const found = findCodexTranscriptPath(sessionId);
89
+ if (found) {
90
+ assert.strictEqual(found, expected);
91
+ }
92
+ });
93
+ });
94
+ describe('extractPlanMarkdownFromCodexTranscript', () => {
95
+ it('should return null for missing files', () => {
96
+ assert.strictEqual(extractPlanMarkdownFromCodexTranscript('C:/missing/transcript.jsonl'), null);
97
+ });
98
+ });
99
+ describe('determineProjectRoot', () => {
100
+ // determineProjectRoot uses path.isAbsolute(), which is platform-specific:
101
+ // 'C:/...' is absolute only on win32. Build paths that are absolute on the
102
+ // current platform so the precedence assertions hold on Linux CI too.
103
+ const absRoot = (p) => (process.platform === 'win32' ? `C:${p}` : p);
104
+ it('should prefer CODEX_CWD over SQLEW_PROJECT_ROOT', () => {
105
+ const codexRoot = absRoot('/codex-workspace');
106
+ process.env.CODEX_CWD = codexRoot;
107
+ process.env.SQLEW_PROJECT_ROOT = absRoot('/other');
108
+ assert.strictEqual(determineProjectRoot({}), codexRoot);
109
+ });
110
+ });
111
+ });
112
+ //# sourceMappingURL=codex-hook-normalization.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-hook-normalization.test.js","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/codex-hook-normalization.test.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ import { describe, it, beforeEach, afterEach } from 'node:test';
9
9
  import assert from 'node:assert';
10
10
  import { homedir } from 'os';
11
11
  import { join } from 'path';
12
- import { normalizeHookInput, computeGrokPlanPath, } from '../../../cli/hooks/stdin-parser.js';
12
+ import { normalizeHookInput, computeGrokPlanPath, isPlanMode, } from '../../../cli/hooks/stdin-parser.js';
13
13
  import { determineProjectRoot } from '../../../utils/project-root.js';
14
14
  describe('grok-hook-normalization', () => {
15
15
  const originalEnv = { ...process.env };
@@ -69,6 +69,38 @@ describe('grok-hook-normalization', () => {
69
69
  assert.strictEqual(result.session_id, 'sess-1');
70
70
  });
71
71
  });
72
+ describe('isPlanMode', () => {
73
+ it('should detect Claude plan mode via permission_mode', () => {
74
+ assert.strictEqual(isPlanMode({ hook_event_name: 'UserPromptSubmit', permission_mode: 'plan' }), true);
75
+ });
76
+ it('should return false for Claude non-plan prompts', () => {
77
+ assert.strictEqual(isPlanMode({ hook_event_name: 'UserPromptSubmit', permission_mode: 'default' }), false);
78
+ });
79
+ it('should detect Grok plan mode after normalization (enter_plan_mode)', () => {
80
+ // Regression: normalizeHookInput maps enter_plan_mode -> EnterPlanMode,
81
+ // so isPlanMode must match the normalized PascalCase name.
82
+ const normalized = normalizeHookInput({
83
+ hookEventName: 'pre_tool_use',
84
+ toolName: 'enter_plan_mode',
85
+ workspaceRoot: 'C:/project',
86
+ });
87
+ assert.strictEqual(isPlanMode(normalized), true);
88
+ });
89
+ it('should detect Grok plan mode after normalization (exit_plan_mode)', () => {
90
+ const normalized = normalizeHookInput({
91
+ hookEventName: 'post_tool_use',
92
+ toolName: 'exit_plan_mode',
93
+ workspaceRoot: 'C:/project',
94
+ });
95
+ assert.strictEqual(isPlanMode(normalized), true);
96
+ });
97
+ it('should accept raw snake_case tool names defensively', () => {
98
+ assert.strictEqual(isPlanMode({ tool_name: 'enter_plan_mode' }), true);
99
+ });
100
+ it('should return false for unrelated tools', () => {
101
+ assert.strictEqual(isPlanMode({ tool_name: 'Bash' }), false);
102
+ });
103
+ });
72
104
  describe('computeGrokPlanPath', () => {
73
105
  it('should encode Windows workspace path for session directory', () => {
74
106
  const workspace = 'C:\\Users\\kitayama\\RustroverProjects\\mcp-sqlew';
@@ -83,15 +115,21 @@ describe('grok-hook-normalization', () => {
83
115
  });
84
116
  });
85
117
  describe('determineProjectRoot', () => {
118
+ // determineProjectRoot uses path.isAbsolute(), which is platform-specific:
119
+ // 'C:/...' is absolute only on win32. Build paths that are absolute on the
120
+ // current platform so the precedence assertions hold on Linux CI too.
121
+ const absRoot = (p) => (process.platform === 'win32' ? `C:${p}` : p);
86
122
  it('should prefer GROK_WORKSPACE_ROOT over SQLEW_PROJECT_ROOT', () => {
87
- process.env.GROK_WORKSPACE_ROOT = 'C:/grok-workspace';
88
- process.env.SQLEW_PROJECT_ROOT = 'C:/other';
89
- assert.strictEqual(determineProjectRoot({}), 'C:/grok-workspace');
123
+ const grokRoot = absRoot('/grok-workspace');
124
+ process.env.GROK_WORKSPACE_ROOT = grokRoot;
125
+ process.env.SQLEW_PROJECT_ROOT = absRoot('/other');
126
+ assert.strictEqual(determineProjectRoot({}), grokRoot);
90
127
  });
91
128
  it('should prefer CLAUDE_PROJECT_DIR over GROK_WORKSPACE_ROOT', () => {
92
- process.env.CLAUDE_PROJECT_DIR = 'C:/claude-project';
93
- process.env.GROK_WORKSPACE_ROOT = 'C:/grok-workspace';
94
- assert.strictEqual(determineProjectRoot({}), 'C:/claude-project');
129
+ const claudeRoot = absRoot('/claude-project');
130
+ process.env.CLAUDE_PROJECT_DIR = claudeRoot;
131
+ process.env.GROK_WORKSPACE_ROOT = absRoot('/grok-workspace');
132
+ assert.strictEqual(determineProjectRoot({}), claudeRoot);
95
133
  });
96
134
  });
97
135
  });
@@ -1 +1 @@
1
- {"version":3,"file":"grok-hook-normalization.test.js","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/grok-hook-normalization.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"grok-hook-normalization.test.js","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/grok-hook-normalization.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Plan Pattern Extractor Unit Tests
3
+ *
4
+ * Tests for extracting 📌 Decision and 🚫 Constraint blocks
5
+ * from plan markdown using regex patterns.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=plan-pattern-extractor.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-pattern-extractor.test.d.ts","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/plan-pattern-extractor.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Plan Pattern Extractor Unit Tests
3
+ *
4
+ * Tests for extracting 📌 Decision and 🚫 Constraint blocks
5
+ * from plan markdown using regex patterns.
6
+ */
7
+ import { describe, it } from 'node:test';
8
+ import assert from 'node:assert';
9
+ import { extractPatternsFromPlan } from '../../../cli/hooks/plan-pattern-extractor.js';
10
+ describe('plan-pattern-extractor', () => {
11
+ describe('extractPatternsFromPlan - constraint reason', () => {
12
+ it('should extract reason from constraint block with Reason field', () => {
13
+ const content = `
14
+ ### 🚫 Constraint: security
15
+ - **Rule**: No hardcoded API keys
16
+ - **Priority**: critical
17
+ - **Reason**: Keys committed to git cannot be rotated
18
+ - **Tags**: security, env
19
+ `;
20
+ const result = extractPatternsFromPlan(content);
21
+ assert.strictEqual(result.constraints.length, 1);
22
+ assert.strictEqual(result.constraints[0].category, 'security');
23
+ assert.strictEqual(result.constraints[0].rule, 'No hardcoded API keys');
24
+ assert.strictEqual(result.constraints[0].priority, 'critical');
25
+ assert.strictEqual(result.constraints[0].reason, 'Keys committed to git cannot be rotated');
26
+ assert.strictEqual(result.constraints[0].tags, 'security, env');
27
+ });
28
+ it('should leave reason undefined when Reason field is absent', () => {
29
+ const content = `
30
+ ### 🚫 Constraint: architecture
31
+ - **Rule**: Use dependency injection for services
32
+ - **Priority**: high
33
+ - **Tags**: architecture, design
34
+ `;
35
+ const result = extractPatternsFromPlan(content);
36
+ assert.strictEqual(result.constraints.length, 1);
37
+ assert.strictEqual(result.constraints[0].rule, 'Use dependency injection for services');
38
+ assert.strictEqual(result.constraints[0].priority, 'high');
39
+ assert.strictEqual(result.constraints[0].tags, 'architecture, design');
40
+ assert.strictEqual(result.constraints[0].reason, undefined);
41
+ });
42
+ it('should extract all fields correctly when Reason is mixed with other fields', () => {
43
+ const content = `
44
+ ### 🚫 Constraint: code-style
45
+ - **Rule**: No console.log in production code
46
+ - **Reason**: Logs leak sensitive data to browser consoles
47
+ - **Priority**: medium
48
+ - **Tags**: logging, quality
49
+ `;
50
+ const result = extractPatternsFromPlan(content);
51
+ assert.strictEqual(result.constraints.length, 1);
52
+ const c = result.constraints[0];
53
+ assert.strictEqual(c.category, 'code-style');
54
+ assert.strictEqual(c.rule, 'No console.log in production code');
55
+ assert.strictEqual(c.reason, 'Logs leak sensitive data to browser consoles');
56
+ assert.strictEqual(c.priority, 'medium');
57
+ assert.strictEqual(c.tags, 'logging, quality');
58
+ });
59
+ it('should process multiple constraint blocks with and without reason individually', () => {
60
+ const content = `
61
+ ### 🚫 Constraint: security
62
+ - **Rule**: No hardcoded API keys
63
+ - **Priority**: critical
64
+ - **Reason**: Keys committed to git cannot be rotated
65
+
66
+ ### 🚫 Constraint: performance
67
+ - **Rule**: Cache API responses for 5 minutes
68
+ - **Priority**: low
69
+ - **Tags**: caching
70
+ `;
71
+ const result = extractPatternsFromPlan(content);
72
+ assert.strictEqual(result.constraints.length, 2);
73
+ assert.strictEqual(result.constraints[0].category, 'security');
74
+ assert.strictEqual(result.constraints[0].rule, 'No hardcoded API keys');
75
+ assert.strictEqual(result.constraints[0].reason, 'Keys committed to git cannot be rotated');
76
+ assert.strictEqual(result.constraints[1].category, 'performance');
77
+ assert.strictEqual(result.constraints[1].rule, 'Cache API responses for 5 minutes');
78
+ assert.strictEqual(result.constraints[1].priority, 'low');
79
+ assert.strictEqual(result.constraints[1].tags, 'caching');
80
+ assert.strictEqual(result.constraints[1].reason, undefined);
81
+ });
82
+ it('should not affect decision extraction when constraints include Reason field', () => {
83
+ const content = `
84
+ ### 📌 Decision: auth/jwt-strategy
85
+ - **Value**: Use JWT with refresh tokens
86
+ - **Layer**: business
87
+ - **Tags**: auth, security
88
+ - **Rationale**: Stateless sessions scale better
89
+
90
+ ### 🚫 Constraint: security
91
+ - **Rule**: No hardcoded API keys
92
+ - **Priority**: critical
93
+ - **Reason**: Keys committed to git cannot be rotated
94
+ `;
95
+ const result = extractPatternsFromPlan(content);
96
+ assert.strictEqual(result.decisions.length, 1);
97
+ const d = result.decisions[0];
98
+ assert.strictEqual(d.key, 'auth/jwt-strategy');
99
+ assert.strictEqual(d.value, 'Use JWT with refresh tokens');
100
+ assert.strictEqual(d.layer, 'business');
101
+ assert.strictEqual(d.tags, 'auth, security');
102
+ assert.strictEqual(d.rationale, 'Stateless sessions scale better');
103
+ assert.strictEqual(d.alternatives, undefined);
104
+ assert.strictEqual(d.tradeoffs, undefined);
105
+ assert.strictEqual(result.constraints.length, 1);
106
+ assert.strictEqual(result.constraints[0].reason, 'Keys committed to git cannot be rotated');
107
+ });
108
+ });
109
+ });
110
+ //# sourceMappingURL=plan-pattern-extractor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-pattern-extractor.test.js","sourceRoot":"","sources":["../../../../src/tests/unit/hooks/plan-pattern-extractor.test.ts"],"names":[],"mappings":"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"}
@@ -36,9 +36,9 @@ export async function disconnectDb(db) {
36
36
  export async function dropAllTables(db, type) {
37
37
  if (type === 'sqlite') {
38
38
  // SQLite: Get all tables and views, then drop them
39
- const objects = await db.raw(`
40
- SELECT name, type FROM sqlite_master
41
- WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
39
+ const objects = await db.raw(`
40
+ SELECT name, type FROM sqlite_master
41
+ WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
42
42
  `);
43
43
  await db.raw('PRAGMA foreign_keys = OFF');
44
44
  for (const row of objects) {
@@ -55,19 +55,19 @@ export async function dropAllTables(db, type) {
55
55
  // MySQL/MariaDB: Drop all views first, then tables
56
56
  await db.raw('SET FOREIGN_KEY_CHECKS=0');
57
57
  // Drop views
58
- const views = await db.raw(`
59
- SELECT TABLE_NAME
60
- FROM INFORMATION_SCHEMA.TABLES
61
- WHERE TABLE_SCHEMA = 'mcp_test' AND TABLE_TYPE = 'VIEW'
58
+ const views = await db.raw(`
59
+ SELECT TABLE_NAME
60
+ FROM INFORMATION_SCHEMA.TABLES
61
+ WHERE TABLE_SCHEMA = 'mcp_test' AND TABLE_TYPE = 'VIEW'
62
62
  `);
63
63
  for (const row of views[0]) {
64
64
  await db.raw(`DROP VIEW IF EXISTS ??`, [row.TABLE_NAME]);
65
65
  }
66
66
  // Drop tables
67
- const tables = await db.raw(`
68
- SELECT TABLE_NAME
69
- FROM INFORMATION_SCHEMA.TABLES
70
- WHERE TABLE_SCHEMA = 'mcp_test' AND TABLE_TYPE = 'BASE TABLE'
67
+ const tables = await db.raw(`
68
+ SELECT TABLE_NAME
69
+ FROM INFORMATION_SCHEMA.TABLES
70
+ WHERE TABLE_SCHEMA = 'mcp_test' AND TABLE_TYPE = 'BASE TABLE'
71
71
  `);
72
72
  for (const row of tables[0]) {
73
73
  await db.raw(`DROP TABLE IF EXISTS ??`, [row.TABLE_NAME]);
@@ -85,30 +85,30 @@ export async function dropAllTables(db, type) {
85
85
  */
86
86
  export async function getTables(db, type) {
87
87
  if (type === 'sqlite') {
88
- const result = await db.raw(`
89
- SELECT name FROM sqlite_master
90
- WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'knex_migrations'
91
- ORDER BY name
88
+ const result = await db.raw(`
89
+ SELECT name FROM sqlite_master
90
+ WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'knex_migrations'
91
+ ORDER BY name
92
92
  `);
93
93
  return result.map((r) => r.name);
94
94
  }
95
95
  else if (type === 'mysql' || type === 'mariadb') {
96
- const result = await db.raw(`
97
- SELECT TABLE_NAME
98
- FROM INFORMATION_SCHEMA.TABLES
99
- WHERE TABLE_SCHEMA = 'mcp_test'
100
- AND TABLE_TYPE = 'BASE TABLE'
101
- AND TABLE_NAME != 'knex_migrations'
102
- ORDER BY TABLE_NAME
96
+ const result = await db.raw(`
97
+ SELECT TABLE_NAME
98
+ FROM INFORMATION_SCHEMA.TABLES
99
+ WHERE TABLE_SCHEMA = 'mcp_test'
100
+ AND TABLE_TYPE = 'BASE TABLE'
101
+ AND TABLE_NAME != 'knex_migrations'
102
+ ORDER BY TABLE_NAME
103
103
  `);
104
104
  return result[0].map((r) => r.TABLE_NAME);
105
105
  }
106
106
  else if (type === 'postgresql') {
107
- const result = await db.raw(`
108
- SELECT tablename
109
- FROM pg_tables
110
- WHERE schemaname = 'public' AND tablename != 'knex_migrations'
111
- ORDER BY tablename
107
+ const result = await db.raw(`
108
+ SELECT tablename
109
+ FROM pg_tables
110
+ WHERE schemaname = 'public' AND tablename != 'knex_migrations'
111
+ ORDER BY tablename
112
112
  `);
113
113
  return result.rows.map((r) => r.tablename);
114
114
  }
@@ -161,15 +161,15 @@ export async function getFKConstraints(db, type, tableName) {
161
161
  }
162
162
  }
163
163
  else if (type === 'mysql' || type === 'mariadb') {
164
- const result = await db.raw(`
165
- SELECT
166
- COLUMN_NAME,
167
- REFERENCED_TABLE_NAME,
168
- REFERENCED_COLUMN_NAME
169
- FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
170
- WHERE TABLE_SCHEMA = 'mcp_test'
171
- AND TABLE_NAME = ?
172
- AND REFERENCED_TABLE_NAME IS NOT NULL
164
+ const result = await db.raw(`
165
+ SELECT
166
+ COLUMN_NAME,
167
+ REFERENCED_TABLE_NAME,
168
+ REFERENCED_COLUMN_NAME
169
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
170
+ WHERE TABLE_SCHEMA = 'mcp_test'
171
+ AND TABLE_NAME = ?
172
+ AND REFERENCED_TABLE_NAME IS NOT NULL
173
173
  `, [tableName]);
174
174
  for (const fk of result[0]) {
175
175
  constraints.push({
@@ -181,18 +181,18 @@ export async function getFKConstraints(db, type, tableName) {
181
181
  }
182
182
  }
183
183
  else if (type === 'postgresql') {
184
- const result = await db.raw(`
185
- SELECT
186
- kcu.column_name,
187
- ccu.table_name AS referenced_table,
188
- ccu.column_name AS referenced_column
189
- FROM information_schema.table_constraints AS tc
190
- JOIN information_schema.key_column_usage AS kcu
191
- ON tc.constraint_name = kcu.constraint_name
192
- JOIN information_schema.constraint_column_usage AS ccu
193
- ON ccu.constraint_name = tc.constraint_name
194
- WHERE tc.constraint_type = 'FOREIGN KEY'
195
- AND tc.table_name = ?
184
+ const result = await db.raw(`
185
+ SELECT
186
+ kcu.column_name,
187
+ ccu.table_name AS referenced_table,
188
+ ccu.column_name AS referenced_column
189
+ FROM information_schema.table_constraints AS tc
190
+ JOIN information_schema.key_column_usage AS kcu
191
+ ON tc.constraint_name = kcu.constraint_name
192
+ JOIN information_schema.constraint_column_usage AS ccu
193
+ ON ccu.constraint_name = tc.constraint_name
194
+ WHERE tc.constraint_type = 'FOREIGN KEY'
195
+ AND tc.table_name = ?
196
196
  `, [tableName]);
197
197
  for (const fk of result.rows) {
198
198
  constraints.push({