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.
- package/CHANGELOG.md +2169 -2110
- package/LICENSE +190 -190
- package/NOTICE +24 -24
- package/README.md +204 -199
- package/dist/adapters/mysql-adapter.js +3 -3
- package/dist/adapters/postgresql-adapter.js +3 -3
- package/dist/cli/db-export.js +32 -32
- package/dist/cli/db-import.js +30 -30
- package/dist/cli/hooks/codex-transcript.d.ts +23 -0
- package/dist/cli/hooks/codex-transcript.d.ts.map +1 -0
- package/dist/cli/hooks/codex-transcript.js +134 -0
- package/dist/cli/hooks/codex-transcript.js.map +1 -0
- package/dist/cli/hooks/on-exit-plan.d.ts.map +1 -1
- package/dist/cli/hooks/on-exit-plan.js +30 -3
- package/dist/cli/hooks/on-exit-plan.js.map +1 -1
- package/dist/cli/hooks/on-prompt.d.ts +2 -2
- package/dist/cli/hooks/on-prompt.d.ts.map +1 -1
- package/dist/cli/hooks/on-prompt.js +33 -16
- package/dist/cli/hooks/on-prompt.js.map +1 -1
- package/dist/cli/hooks/plan-pattern-extractor.d.ts +2 -0
- package/dist/cli/hooks/plan-pattern-extractor.d.ts.map +1 -1
- package/dist/cli/hooks/plan-pattern-extractor.js +1 -0
- package/dist/cli/hooks/plan-pattern-extractor.js.map +1 -1
- package/dist/cli/hooks/plan-processor.d.ts.map +1 -1
- package/dist/cli/hooks/plan-processor.js +1 -0
- package/dist/cli/hooks/plan-processor.js.map +1 -1
- package/dist/cli/hooks/pr-adr.js +5 -5
- package/dist/cli/hooks/stdin-parser.d.ts +4 -2
- package/dist/cli/hooks/stdin-parser.d.ts.map +1 -1
- package/dist/cli/hooks/stdin-parser.js +79 -9
- package/dist/cli/hooks/stdin-parser.js.map +1 -1
- package/dist/cli/hooks/track-plan.js +15 -15
- package/dist/cli.js +48 -48
- package/dist/config/global-config.js +19 -19
- package/dist/database/migrations/v4/20251126000000_v4_bootstrap.js +32 -32
- package/dist/database/migrations/v4/20260102204000_v4_fix_decision_set_example.js +3 -3
- package/dist/database/migrations/v4/20260613000000_add_constraint_reason.d.ts +9 -0
- package/dist/database/migrations/v4/20260613000000_add_constraint_reason.d.ts.map +1 -0
- package/dist/database/migrations/v4/20260613000000_add_constraint_reason.js +31 -0
- package/dist/database/migrations/v4/20260613000000_add_constraint_reason.js.map +1 -0
- package/dist/help-data/constraint.toml +265 -259
- package/dist/help-data/decision.toml +845 -845
- package/dist/help-data/queue.toml +134 -134
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +4 -5
- package/dist/schema.js.map +1 -1
- package/dist/server/tool-schemas.js +30 -30
- package/dist/tests/docker/native/constraint-operations.test.js +38 -0
- package/dist/tests/docker/native/constraint-operations.test.js.map +1 -1
- package/dist/tests/docker/native/db-init.js +9 -9
- package/dist/tests/feature/constraint/reason.test.d.ts +7 -0
- package/dist/tests/feature/constraint/reason.test.d.ts.map +1 -0
- package/dist/tests/feature/constraint/reason.test.js +68 -0
- package/dist/tests/feature/constraint/reason.test.js.map +1 -0
- package/dist/tests/unit/hooks/codex-hook-normalization.test.d.ts +7 -0
- package/dist/tests/unit/hooks/codex-hook-normalization.test.d.ts.map +1 -0
- package/dist/tests/unit/hooks/codex-hook-normalization.test.js +112 -0
- package/dist/tests/unit/hooks/codex-hook-normalization.test.js.map +1 -0
- package/dist/tests/unit/hooks/grok-hook-normalization.test.js +45 -7
- package/dist/tests/unit/hooks/grok-hook-normalization.test.js.map +1 -1
- package/dist/tests/unit/hooks/plan-pattern-extractor.test.d.ts +8 -0
- package/dist/tests/unit/hooks/plan-pattern-extractor.test.d.ts.map +1 -0
- package/dist/tests/unit/hooks/plan-pattern-extractor.test.js +110 -0
- package/dist/tests/unit/hooks/plan-pattern-extractor.test.js.map +1 -0
- package/dist/tests/utils/db-schema.js +48 -48
- package/dist/tests/utils/test-helpers.js +48 -48
- package/dist/tools/constraints/actions/add.d.ts.map +1 -1
- package/dist/tools/constraints/actions/add.js +1 -0
- package/dist/tools/constraints/actions/add.js.map +1 -1
- package/dist/tools/constraints/actions/get.d.ts.map +1 -1
- package/dist/tools/constraints/actions/get.js +9 -7
- package/dist/tools/constraints/actions/get.js.map +1 -1
- package/dist/tools/constraints/help/example.js +1 -1
- package/dist/tools/constraints/help/example.js.map +1 -1
- package/dist/types/constraint/params.d.ts +2 -0
- package/dist/types/constraint/params.d.ts.map +1 -1
- package/dist/types/view-entities.d.ts +1 -0
- package/dist/types/view-entities.d.ts.map +1 -1
- package/dist/utils/action-specs/constraint-specs.d.ts.map +1 -1
- package/dist/utils/action-specs/constraint-specs.js +4 -3
- package/dist/utils/action-specs/constraint-specs.js.map +1 -1
- package/dist/utils/hook-queue.d.ts +2 -0
- package/dist/utils/hook-queue.d.ts.map +1 -1
- package/dist/utils/hook-queue.js.map +1 -1
- package/dist/utils/project-root.d.ts +1 -0
- package/dist/utils/project-root.d.ts.map +1 -1
- package/dist/utils/project-root.js +6 -0
- package/dist/utils/project-root.js.map +1 -1
- package/dist/utils/view-queries.d.ts.map +1 -1
- package/dist/utils/view-queries.js +1 -0
- package/dist/utils/view-queries.js.map +1 -1
- package/dist/watcher/queue-watcher.d.ts.map +1 -1
- package/dist/watcher/queue-watcher.js +1 -0
- package/dist/watcher/queue-watcher.js.map +1 -1
- package/docs/ADR_CONCEPTS.md +152 -152
- package/docs/CLI_USAGE.md +392 -392
- package/docs/CONFIGURATION.md +157 -157
- package/docs/CROSS_DATABASE.md +66 -66
- package/docs/DATABASE_AUTH.md +135 -135
- package/docs/HOOKS_GUIDE.md +116 -101
- package/docs/MIGRATION_TO_SAAS.md +176 -176
- package/docs/SHARED_DATABASE.md +108 -108
- package/package.json +88 -88
- package/scripts/copy-help-data.js +19 -19
- package/scripts/filter-test-output.js +78 -78
- package/dist/tests/docker/native/help-system.test.d.ts +0 -8
- package/dist/tests/docker/native/help-system.test.d.ts.map +0 -1
- package/dist/tests/docker/native/help-system.test.js +0 -508
- 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 @@
|
|
|
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
|
-
|
|
88
|
-
process.env.
|
|
89
|
-
|
|
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
|
-
|
|
93
|
-
process.env.
|
|
94
|
-
|
|
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":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,kBAAkB,EAClB,mBAAmB,
|
|
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 @@
|
|
|
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({
|