id3-cli 0.9.1
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/README.ja-JP.md +769 -0
- package/README.ko-KR.md +769 -0
- package/README.md +769 -0
- package/README.tr-TR.md +769 -0
- package/README.zh-CN.md +769 -0
- package/dist/bin/cli.d.ts +2 -0
- package/dist/bin/cli.js +40 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/scripts/build-hooks.d.ts +1 -0
- package/dist/scripts/build-hooks.js +58 -0
- package/dist/scripts/build-hooks.js.map +1 -0
- package/dist/src/hooks/auto-audit.d.ts +4 -0
- package/dist/src/hooks/auto-audit.js +47 -0
- package/dist/src/hooks/auto-audit.js.map +1 -0
- package/dist/src/hooks/claude-pretool-entry.d.ts +1 -0
- package/dist/src/hooks/claude-pretool-entry.js +36 -0
- package/dist/src/hooks/claude-pretool-entry.js.map +1 -0
- package/dist/src/hooks/claude-stop-entry.d.ts +1 -0
- package/dist/src/hooks/claude-stop-entry.js +7 -0
- package/dist/src/hooks/claude-stop-entry.js.map +1 -0
- package/dist/src/hooks/post-commit-entry.d.ts +1 -0
- package/dist/src/hooks/post-commit-entry.js +7 -0
- package/dist/src/hooks/post-commit-entry.js.map +1 -0
- package/dist/src/hooks/pre-commit-entry.d.ts +1 -0
- package/dist/src/hooks/pre-commit-entry.js +16 -0
- package/dist/src/hooks/pre-commit-entry.js.map +1 -0
- package/dist/src/hooks/rule-check.d.ts +8 -0
- package/dist/src/hooks/rule-check.js +101 -0
- package/dist/src/hooks/rule-check.js.map +1 -0
- package/dist/src/hooks/schema-drift.d.ts +17 -0
- package/dist/src/hooks/schema-drift.js +151 -0
- package/dist/src/hooks/schema-drift.js.map +1 -0
- package/dist/src/hooks/shared.d.ts +43 -0
- package/dist/src/hooks/shared.js +98 -0
- package/dist/src/hooks/shared.js.map +1 -0
- package/dist/src/init.d.ts +20 -0
- package/dist/src/init.js +193 -0
- package/dist/src/init.js.map +1 -0
- package/dist/src/preview/mockup-generator.d.ts +56 -0
- package/dist/src/preview/mockup-generator.js +402 -0
- package/dist/src/preview/mockup-generator.js.map +1 -0
- package/dist/src/preview/renderer.d.ts +30 -0
- package/dist/src/preview/renderer.js +145 -0
- package/dist/src/preview/renderer.js.map +1 -0
- package/dist/src/preview/server.d.ts +9 -0
- package/dist/src/preview/server.js +55 -0
- package/dist/src/preview/server.js.map +1 -0
- package/dist/src/preview/ui-auditor.d.ts +27 -0
- package/dist/src/preview/ui-auditor.js +141 -0
- package/dist/src/preview/ui-auditor.js.map +1 -0
- package/dist/src/preview/ui-gate.d.ts +66 -0
- package/dist/src/preview/ui-gate.js +210 -0
- package/dist/src/preview/ui-gate.js.map +1 -0
- package/dist/src/utils/ascii.d.ts +7 -0
- package/dist/src/utils/ascii.js +41 -0
- package/dist/src/utils/ascii.js.map +1 -0
- package/dist/src/utils/fs.d.ts +6 -0
- package/dist/src/utils/fs.js +39 -0
- package/dist/src/utils/fs.js.map +1 -0
- package/dist/templates/hooks/iddd-auto-audit.js +121 -0
- package/dist/templates/hooks/iddd-schema-drift.js +279 -0
- package/dist/templates/hooks/post-commit +121 -0
- package/dist/templates/hooks/pre-commit +348 -0
- package/package.json +37 -0
- package/templates/.agents/skills/.gitkeep +0 -0
- package/templates/.claude/hooks/.gitkeep +0 -0
- package/templates/.claude/hooks/hook-config.json +34 -0
- package/templates/.claude/skills/.gitkeep +0 -0
- package/templates/.codex/.gitkeep +0 -0
- package/templates/.codex/hooks.json +40 -0
- package/templates/.iddd/commit-count +1 -0
- package/templates/.iddd/preview/.gitkeep +0 -0
- package/templates/AGENTS.md +204 -0
- package/templates/CLAUDE.md +215 -0
- package/templates/README.md +476 -0
- package/templates/docs/.gitkeep +0 -0
- package/templates/docs/business-rules.md +14 -0
- package/templates/docs/domain-glossary.md +8 -0
- package/templates/docs/info-debt.md +17 -0
- package/templates/docs/model-changelog.md +12 -0
- package/templates/hooks/.gitkeep +0 -0
- package/templates/hooks/iddd-auto-audit.js +121 -0
- package/templates/hooks/iddd-schema-drift.js +279 -0
- package/templates/hooks/post-commit +121 -0
- package/templates/hooks/pre-commit +348 -0
- package/templates/skills/id3-design-information/SKILL.md +170 -0
- package/templates/skills/id3-design-information/references/phase2-procedure.md +241 -0
- package/templates/skills/id3-design-ui/.gitkeep +0 -0
- package/templates/skills/id3-design-ui/SKILL.md +200 -0
- package/templates/skills/id3-design-ui/references/.gitkeep +0 -0
- package/templates/skills/id3-design-ui/references/step1-structure-derivation.md +177 -0
- package/templates/skills/id3-design-ui/references/step2-visual-contract.md +257 -0
- package/templates/skills/id3-design-ui/references/step3-gate-and-mockup.md +177 -0
- package/templates/skills/id3-design-ui/references/step4-implementation.md +244 -0
- package/templates/skills/id3-identify-entities/SKILL.md +239 -0
- package/templates/skills/id3-identify-entities/references/.gitkeep +0 -0
- package/templates/skills/id3-identify-entities/references/phase0-brownfield.md +377 -0
- package/templates/skills/id3-identify-entities/references/phase1-greenfield.md +319 -0
- package/templates/skills/id3-info-audit/.gitkeep +0 -0
- package/templates/skills/id3-info-audit/SKILL.md +191 -0
- package/templates/skills/id3-preview/.gitkeep +0 -0
- package/templates/skills/id3-preview/SKILL.md +168 -0
- package/templates/skills/id3-spawn-team/.gitkeep +0 -0
- package/templates/skills/id3-spawn-team/SKILL.md +213 -0
- package/templates/specs/.gitkeep +0 -0
- package/templates/specs/data-model.md +26 -0
- package/templates/specs/entity-catalog.md +22 -0
- package/templates/specs/ui-design-contract.md +54 -0
- package/templates/specs/ui-inventory.md +24 -0
- package/templates/specs/ui-structure.md +32 -0
- package/templates/src/.gitkeep +0 -0
- package/templates/steering/.gitkeep +0 -0
- package/templates/steering/data-conventions.md +42 -0
- package/templates/steering/product.md +38 -0
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { initProject, printBanner, printSuccess } from '../src/init.js';
|
|
3
|
+
import { createInterface } from 'node:readline';
|
|
4
|
+
const args = process.argv.slice(2);
|
|
5
|
+
const flags = args.filter((a) => a.startsWith('--'));
|
|
6
|
+
const positional = args.filter((a) => !a.startsWith('--'));
|
|
7
|
+
// npx id3@latest [target-dir] — no subcommand needed
|
|
8
|
+
// npx id3@latest init [target-dir] — also works
|
|
9
|
+
const hasInit = positional[0] === 'init';
|
|
10
|
+
const targetDir = hasInit ? (positional[1] ?? '.') : (positional[0] ?? '.');
|
|
11
|
+
const noSymlink = flags.includes('--no-symlink');
|
|
12
|
+
{
|
|
13
|
+
printBanner();
|
|
14
|
+
const result = await initProject(targetDir, { noSymlink });
|
|
15
|
+
if (result.alreadyInstalled) {
|
|
16
|
+
const answer = await prompt('IDDD appears to be already installed. Overwrite? (y/N) ');
|
|
17
|
+
if (answer.toLowerCase() !== 'y') {
|
|
18
|
+
console.log('Aborted.');
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
const retryResult = await initProject(targetDir, {
|
|
22
|
+
overwrite: true,
|
|
23
|
+
noSymlink,
|
|
24
|
+
});
|
|
25
|
+
printSuccess(retryResult);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
printSuccess(result);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function prompt(question) {
|
|
32
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
rl.question(question, (answer) => {
|
|
35
|
+
rl.close();
|
|
36
|
+
resolve(answer);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAE3D,sDAAsD;AACtD,iDAAiD;AACjD,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC;AACzC,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;AAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAEjD,CAAC;IAEC,WAAW,EAAE,CAAC;IAEd,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IAE3D,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,MAAM,MAAM,CACzB,yDAAyD,CAC1D,CAAC;QACF,IAAI,MAAM,CAAC,WAAW,EAAE,KAAK,GAAG,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE;YAC/C,SAAS,EAAE,IAAI;YACf,SAAS;SACV,CAAC,CAAC;QACH,YAAY,CAAC,WAAW,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,QAAgB;IAC9B,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { build } from 'esbuild';
|
|
2
|
+
import { chmod } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
// When compiled, this runs from dist/scripts/, so go up 2 levels to project root
|
|
5
|
+
const outDir = join(import.meta.dirname, '..', '..', 'templates', 'hooks');
|
|
6
|
+
async function buildHooks() {
|
|
7
|
+
// Git Hook: Pre-commit (schema-drift + rule-check)
|
|
8
|
+
await build({
|
|
9
|
+
entryPoints: ['src/hooks/pre-commit-entry.ts'],
|
|
10
|
+
bundle: true,
|
|
11
|
+
platform: 'node',
|
|
12
|
+
target: 'node18',
|
|
13
|
+
format: 'esm',
|
|
14
|
+
outfile: join(outDir, 'pre-commit'),
|
|
15
|
+
banner: { js: '#!/usr/bin/env node' },
|
|
16
|
+
});
|
|
17
|
+
// Git Hook: Post-commit (auto-audit)
|
|
18
|
+
await build({
|
|
19
|
+
entryPoints: ['src/hooks/post-commit-entry.ts'],
|
|
20
|
+
bundle: true,
|
|
21
|
+
platform: 'node',
|
|
22
|
+
target: 'node18',
|
|
23
|
+
format: 'esm',
|
|
24
|
+
outfile: join(outDir, 'post-commit'),
|
|
25
|
+
banner: { js: '#!/usr/bin/env node' },
|
|
26
|
+
});
|
|
27
|
+
// Claude Code Hook: PreToolUse (schema-drift + rule-check)
|
|
28
|
+
await build({
|
|
29
|
+
entryPoints: ['src/hooks/claude-pretool-entry.ts'],
|
|
30
|
+
bundle: true,
|
|
31
|
+
platform: 'node',
|
|
32
|
+
target: 'node18',
|
|
33
|
+
format: 'esm',
|
|
34
|
+
outfile: join(outDir, 'iddd-schema-drift.js'),
|
|
35
|
+
banner: { js: '#!/usr/bin/env node' },
|
|
36
|
+
});
|
|
37
|
+
// Claude Code Hook: Stop (auto-audit)
|
|
38
|
+
await build({
|
|
39
|
+
entryPoints: ['src/hooks/claude-stop-entry.ts'],
|
|
40
|
+
bundle: true,
|
|
41
|
+
platform: 'node',
|
|
42
|
+
target: 'node18',
|
|
43
|
+
format: 'esm',
|
|
44
|
+
outfile: join(outDir, 'iddd-auto-audit.js'),
|
|
45
|
+
banner: { js: '#!/usr/bin/env node' },
|
|
46
|
+
});
|
|
47
|
+
// Make all bundles executable
|
|
48
|
+
await chmod(join(outDir, 'pre-commit'), 0o755);
|
|
49
|
+
await chmod(join(outDir, 'post-commit'), 0o755);
|
|
50
|
+
await chmod(join(outDir, 'iddd-schema-drift.js'), 0o755);
|
|
51
|
+
await chmod(join(outDir, 'iddd-auto-audit.js'), 0o755);
|
|
52
|
+
console.log('✓ Hooks built successfully (Git + Claude Code)');
|
|
53
|
+
}
|
|
54
|
+
buildHooks().catch((err) => {
|
|
55
|
+
console.error('Hook build failed:', err);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=build-hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-hooks.js","sourceRoot":"","sources":["../../scripts/build-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,iFAAiF;AACjF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;AAE3E,KAAK,UAAU,UAAU;IACvB,mDAAmD;IACnD,MAAM,KAAK,CAAC;QACV,WAAW,EAAE,CAAC,+BAA+B,CAAC;QAC9C,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC;QACnC,MAAM,EAAE,EAAE,EAAE,EAAE,qBAAqB,EAAE;KACtC,CAAC,CAAC;IAEH,qCAAqC;IACrC,MAAM,KAAK,CAAC;QACV,WAAW,EAAE,CAAC,gCAAgC,CAAC;QAC/C,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC;QACpC,MAAM,EAAE,EAAE,EAAE,EAAE,qBAAqB,EAAE;KACtC,CAAC,CAAC;IAEH,2DAA2D;IAC3D,MAAM,KAAK,CAAC;QACV,WAAW,EAAE,CAAC,mCAAmC,CAAC;QAClD,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,sBAAsB,CAAC;QAC7C,MAAM,EAAE,EAAE,EAAE,EAAE,qBAAqB,EAAE;KACtC,CAAC,CAAC;IAEH,sCAAsC;IACtC,MAAM,KAAK,CAAC;QACV,WAAW,EAAE,CAAC,gCAAgC,CAAC;QAC/C,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC;QAC3C,MAAM,EAAE,EAAE,EAAE,EAAE,qBAAqB,EAAE;KACtC,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,sBAAsB,CAAC,EAAE,KAAK,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,oBAAoB,CAAC,EAAE,KAAK,CAAC,CAAC;IAEvD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;AAChE,CAAC;AAED,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACzB,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function incrementCounter(projectRoot: string): Promise<number>;
|
|
2
|
+
export declare function shouldRunAudit(projectRoot: string, threshold: number): Promise<boolean>;
|
|
3
|
+
export declare function resetCounter(projectRoot: string): Promise<void>;
|
|
4
|
+
export declare function runAutoAudit(projectRoot: string): Promise<void>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isSkipHooks, logSkip, loadHookConfig, printWarn } from './shared.js';
|
|
4
|
+
export async function incrementCounter(projectRoot) {
|
|
5
|
+
const counterPath = join(projectRoot, '.iddd', 'commit-count');
|
|
6
|
+
let count = 0;
|
|
7
|
+
try {
|
|
8
|
+
const content = await readFile(counterPath, 'utf-8');
|
|
9
|
+
count = parseInt(content.trim(), 10) || 0;
|
|
10
|
+
}
|
|
11
|
+
catch { }
|
|
12
|
+
count++;
|
|
13
|
+
await mkdir(join(projectRoot, '.iddd'), { recursive: true });
|
|
14
|
+
await writeFile(counterPath, count.toString());
|
|
15
|
+
return count;
|
|
16
|
+
}
|
|
17
|
+
export async function shouldRunAudit(projectRoot, threshold) {
|
|
18
|
+
const counterPath = join(projectRoot, '.iddd', 'commit-count');
|
|
19
|
+
try {
|
|
20
|
+
const content = await readFile(counterPath, 'utf-8');
|
|
21
|
+
return parseInt(content.trim(), 10) >= threshold;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function resetCounter(projectRoot) {
|
|
28
|
+
const counterPath = join(projectRoot, '.iddd', 'commit-count');
|
|
29
|
+
await writeFile(counterPath, '0');
|
|
30
|
+
}
|
|
31
|
+
export async function runAutoAudit(projectRoot) {
|
|
32
|
+
if (isSkipHooks()) {
|
|
33
|
+
await logSkip(projectRoot);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const config = await loadHookConfig(projectRoot);
|
|
37
|
+
if (!config?.hooks['post-commit']['auto-audit']?.enabled) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const threshold = config.hooks['post-commit']['auto-audit'].interval_commits;
|
|
41
|
+
const count = await incrementCounter(projectRoot);
|
|
42
|
+
if (count >= threshold) {
|
|
43
|
+
printWarn('ℹ️ Auto-Audit Triggered', `${count} commits since last audit.\nRun /id3-info-audit for a full check.\n\nReport saved to .iddd/last-audit-report.md`);
|
|
44
|
+
await resetCounter(projectRoot);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=auto-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-audit.js","sourceRoot":"","sources":["../../../src/hooks/auto-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE9E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAC/D,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACrD,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IACV,KAAK,EAAE,CAAC;IACR,MAAM,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,MAAM,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,WAAmB,EACnB,SAAiB;IAEjB,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAC/D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC;IAC/D,MAAM,SAAS,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB;IACpD,IAAI,WAAW,EAAE,EAAE,CAAC;QAClB,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;QACzD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,YAAY,CAAC,CAAC,gBAAgB,CAAC;IAC7E,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAElD,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;QACvB,SAAS,CACP,yBAAyB,EACzB,GAAG,KAAK,iHAAiH,CAC1H,CAAC;QACF,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { parseHookInput } from './shared.js';
|
|
3
|
+
import { runSchemaDriftFromHookInput } from './schema-drift.js';
|
|
4
|
+
import { runRuleCheck } from './rule-check.js';
|
|
5
|
+
const projectRoot = resolve('.');
|
|
6
|
+
async function main() {
|
|
7
|
+
// Read stdin JSON from Claude Code Hook API
|
|
8
|
+
const chunks = [];
|
|
9
|
+
for await (const chunk of process.stdin) {
|
|
10
|
+
chunks.push(chunk);
|
|
11
|
+
}
|
|
12
|
+
const stdinData = Buffer.concat(chunks).toString('utf-8');
|
|
13
|
+
const hookInput = parseHookInput(stdinData);
|
|
14
|
+
if (!hookInput) {
|
|
15
|
+
// Not a valid hook input — pass through
|
|
16
|
+
process.exit(0);
|
|
17
|
+
}
|
|
18
|
+
// schema-drift check
|
|
19
|
+
const schemaDriftOk = await runSchemaDriftFromHookInput(projectRoot, hookInput);
|
|
20
|
+
if (!schemaDriftOk) {
|
|
21
|
+
// Output error JSON for Claude Code Hook API
|
|
22
|
+
const result = {
|
|
23
|
+
decision: 'block',
|
|
24
|
+
reason: 'Schema drift detected. Update specs/entity-catalog.md first.',
|
|
25
|
+
};
|
|
26
|
+
process.stdout.write(JSON.stringify(result));
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
// rule-check (warning only, does not block)
|
|
30
|
+
await runRuleCheck(projectRoot);
|
|
31
|
+
}
|
|
32
|
+
main().catch((err) => {
|
|
33
|
+
console.error('IDDD claude-pretool hook error:', err);
|
|
34
|
+
process.exit(0); // don't block on errors
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=claude-pretool-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-pretool-entry.js","sourceRoot":"","sources":["../../../src/hooks/claude-pretool-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,2BAA2B,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEjC,KAAK,UAAU,IAAI;IACjB,4CAA4C;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAE1D,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,wCAAwC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qBAAqB;IACrB,MAAM,aAAa,GAAG,MAAM,2BAA2B,CACrD,WAAW,EACX,SAAS,CACV,CAAC;IACF,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,6CAA6C;QAC7C,MAAM,MAAM,GAAG;YACb,QAAQ,EAAE,OAAO;YACjB,MAAM,EAAE,8DAA8D;SACvE,CAAC;QACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,4CAA4C;IAC5C,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;AAC3C,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { runAutoAudit } from './auto-audit.js';
|
|
3
|
+
const projectRoot = resolve('.');
|
|
4
|
+
runAutoAudit(projectRoot).catch((err) => {
|
|
5
|
+
console.error('IDDD claude-stop hook error:', err);
|
|
6
|
+
});
|
|
7
|
+
//# sourceMappingURL=claude-stop-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-stop-entry.js","sourceRoot":"","sources":["../../../src/hooks/claude-stop-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEjC,YAAY,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { runAutoAudit } from './auto-audit.js';
|
|
3
|
+
const projectRoot = resolve('.');
|
|
4
|
+
runAutoAudit(projectRoot).catch((err) => {
|
|
5
|
+
console.error('IDDD post-commit hook error:', err);
|
|
6
|
+
});
|
|
7
|
+
//# sourceMappingURL=post-commit-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-commit-entry.js","sourceRoot":"","sources":["../../../src/hooks/post-commit-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEjC,YAAY,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACtC,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { runSchemaDrift } from './schema-drift.js';
|
|
3
|
+
import { runRuleCheck } from './rule-check.js';
|
|
4
|
+
const projectRoot = resolve('.');
|
|
5
|
+
async function main() {
|
|
6
|
+
const schemaDriftOk = await runSchemaDrift(projectRoot);
|
|
7
|
+
if (!schemaDriftOk) {
|
|
8
|
+
process.exit(1);
|
|
9
|
+
}
|
|
10
|
+
await runRuleCheck(projectRoot);
|
|
11
|
+
}
|
|
12
|
+
main().catch((err) => {
|
|
13
|
+
console.error('IDDD pre-commit hook error:', err);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=pre-commit-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pre-commit-entry.js","sourceRoot":"","sources":["../../../src/hooks/pre-commit-entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAEjC,KAAK,UAAU,IAAI;IACjB,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,WAAW,CAAC,CAAC;IACxD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC;AAClC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface ValidationDetection {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
content: string;
|
|
5
|
+
pattern: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectValidationPatterns(content: string, filePath: string): ValidationDetection[];
|
|
8
|
+
export declare function runRuleCheck(projectRoot: string): Promise<boolean>;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { getCachedDiff, getCachedFileContent, isValidationFile, isSkipHooks, logSkip, loadHookConfig, printWarn, } from './shared.js';
|
|
4
|
+
const VALIDATION_PATTERNS = [
|
|
5
|
+
{
|
|
6
|
+
regex: /z\.\s*(?:object|string|number|boolean|array|enum)\s*\(/g,
|
|
7
|
+
label: 'zod',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
regex: /yup\.\s*(?:object|string|number|boolean|array)\s*\(/g,
|
|
11
|
+
label: 'yup',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
regex: /Joi\.\s*(?:object|string|number|boolean|array)\s*\(/g,
|
|
15
|
+
label: 'joi',
|
|
16
|
+
},
|
|
17
|
+
{ regex: /CHECK\s*\(/gi, label: 'SQL CHECK' },
|
|
18
|
+
{ regex: /NOT\s+NULL/gi, label: 'SQL NOT NULL' },
|
|
19
|
+
{ regex: /ADD\s+.*UNIQUE/gi, label: 'SQL UNIQUE' },
|
|
20
|
+
{ regex: /@validator\s*\(/g, label: 'pydantic' },
|
|
21
|
+
{ regex: /@field_validator\s*\(/g, label: 'pydantic-v2' },
|
|
22
|
+
{ regex: /@Valid/g, label: 'java-valid' },
|
|
23
|
+
{ regex: /@NotNull/g, label: 'java-notnull' },
|
|
24
|
+
{
|
|
25
|
+
regex: /@Column\s*\(\s*.*nullable\s*[:=]\s*false/g,
|
|
26
|
+
label: 'orm-notnull',
|
|
27
|
+
},
|
|
28
|
+
{ regex: /@IsNotEmpty\s*\(/g, label: 'class-validator' },
|
|
29
|
+
{
|
|
30
|
+
regex: /body\s*\(\s*['"].*['"]\s*\)\s*\.(?:not|is)/g,
|
|
31
|
+
label: 'express-validator',
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
export function detectValidationPatterns(content, filePath) {
|
|
35
|
+
const detections = [];
|
|
36
|
+
const lines = content.split('\n');
|
|
37
|
+
for (let i = 0; i < lines.length; i++) {
|
|
38
|
+
const line = lines[i];
|
|
39
|
+
if (!line.startsWith('+') && content.includes('\n+')) {
|
|
40
|
+
// only check added lines if it looks like a diff
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const cleanLine = line.replace(/^\+/, '');
|
|
44
|
+
for (const { regex, label } of VALIDATION_PATTERNS) {
|
|
45
|
+
regex.lastIndex = 0;
|
|
46
|
+
if (regex.test(cleanLine)) {
|
|
47
|
+
detections.push({
|
|
48
|
+
file: filePath,
|
|
49
|
+
line: i + 1,
|
|
50
|
+
content: cleanLine.trim(),
|
|
51
|
+
pattern: label,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return detections;
|
|
57
|
+
}
|
|
58
|
+
async function hasMatchingRule(projectRoot, detection) {
|
|
59
|
+
try {
|
|
60
|
+
const rulesPath = join(projectRoot, 'docs', 'business-rules.md');
|
|
61
|
+
const rules = await readFile(rulesPath, 'utf-8');
|
|
62
|
+
// Simple check: look for BR-xxx entries that reference the same file/pattern
|
|
63
|
+
return rules.includes('BR-') && rules.length > 200;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function runRuleCheck(projectRoot) {
|
|
70
|
+
if (isSkipHooks()) {
|
|
71
|
+
await logSkip(projectRoot);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
const config = await loadHookConfig(projectRoot);
|
|
75
|
+
if (!config?.hooks['pre-commit']['rule-check']?.enabled) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
const { validation_patterns } = config.hooks['pre-commit']['rule-check'];
|
|
79
|
+
const diff = getCachedDiff();
|
|
80
|
+
const validationFiles = diff.filter((e) => isValidationFile(e.path, validation_patterns));
|
|
81
|
+
if (validationFiles.length === 0)
|
|
82
|
+
return true;
|
|
83
|
+
const allDetections = [];
|
|
84
|
+
for (const file of validationFiles) {
|
|
85
|
+
const content = getCachedFileContent(file.path);
|
|
86
|
+
if (content) {
|
|
87
|
+
allDetections.push(...detectValidationPatterns(content, file.path));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (allDetections.length === 0)
|
|
91
|
+
return true;
|
|
92
|
+
// Check if rules exist
|
|
93
|
+
for (const detection of allDetections) {
|
|
94
|
+
const matched = await hasMatchingRule(projectRoot, detection);
|
|
95
|
+
if (!matched) {
|
|
96
|
+
printWarn('⚠️ New Validation Detected', `File: ${detection.file}:${detection.line}\nPattern: ${detection.pattern}\nContent: ${detection.content}\n\nNo matching BR-xxx in business-rules.md\nConsider registering this rule.`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return true; // never blocks, warning only
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=rule-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-check.js","sourceRoot":"","sources":["../../../src/hooks/rule-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HookInput } from './shared.js';
|
|
2
|
+
export interface SchemaChange {
|
|
3
|
+
type: 'add' | 'modify' | 'drop';
|
|
4
|
+
table: string;
|
|
5
|
+
column?: string;
|
|
6
|
+
trivial: boolean;
|
|
7
|
+
description: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function analyzeSchemaChanges(diffContent: string, filePath: string): SchemaChange[];
|
|
10
|
+
/**
|
|
11
|
+
* Git Hook mode: extract file list from git diff --cached
|
|
12
|
+
*/
|
|
13
|
+
export declare function runSchemaDrift(projectRoot: string): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* Claude Code Hook mode: receive { tool_name, tool_input: { file_path } } JSON from stdin
|
|
16
|
+
*/
|
|
17
|
+
export declare function runSchemaDriftFromHookInput(projectRoot: string, hookInput: HookInput): Promise<boolean>;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { getCachedDiff, getCachedFileContent, isSchemaFile, isSkipHooks, logSkip, loadHookConfig, printBlock, printWarn, } from './shared.js';
|
|
2
|
+
export function analyzeSchemaChanges(diffContent, filePath) {
|
|
3
|
+
const changes = [];
|
|
4
|
+
const addedLines = diffContent
|
|
5
|
+
.split('\n')
|
|
6
|
+
.filter((l) => l.startsWith('+') && !l.startsWith('+++'))
|
|
7
|
+
.map((l) => l.slice(1).trim());
|
|
8
|
+
for (const line of addedLines) {
|
|
9
|
+
// SQL: CREATE TABLE
|
|
10
|
+
const createMatch = line.match(/CREATE\s+TABLE\s+(\w+)/i);
|
|
11
|
+
if (createMatch) {
|
|
12
|
+
changes.push({
|
|
13
|
+
type: 'add',
|
|
14
|
+
table: createMatch[1],
|
|
15
|
+
trivial: false,
|
|
16
|
+
description: `Table ${createMatch[1]} created`,
|
|
17
|
+
});
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
// SQL: ALTER TABLE ... ADD COLUMN
|
|
21
|
+
const alterAddMatch = line.match(/ALTER\s+TABLE\s+(\w+)\s+ADD\s+(?:COLUMN\s+)?(\w+)/i);
|
|
22
|
+
if (alterAddMatch) {
|
|
23
|
+
changes.push({
|
|
24
|
+
type: 'add',
|
|
25
|
+
table: alterAddMatch[1],
|
|
26
|
+
column: alterAddMatch[2],
|
|
27
|
+
trivial: false,
|
|
28
|
+
description: `Column ${alterAddMatch[1]}.${alterAddMatch[2]} added`,
|
|
29
|
+
});
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
// SQL: DROP TABLE
|
|
33
|
+
const dropMatch = line.match(/DROP\s+TABLE\s+(\w+)/i);
|
|
34
|
+
if (dropMatch) {
|
|
35
|
+
changes.push({
|
|
36
|
+
type: 'drop',
|
|
37
|
+
table: dropMatch[1],
|
|
38
|
+
trivial: false,
|
|
39
|
+
description: `Table ${dropMatch[1]} dropped`,
|
|
40
|
+
});
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// SQL: CREATE INDEX (trivial)
|
|
44
|
+
const indexMatch = line.match(/CREATE\s+(?:UNIQUE\s+)?INDEX\s+/i);
|
|
45
|
+
if (indexMatch) {
|
|
46
|
+
const tableMatch = line.match(/ON\s+(\w+)/i);
|
|
47
|
+
changes.push({
|
|
48
|
+
type: 'modify',
|
|
49
|
+
table: tableMatch?.[1] ?? 'unknown',
|
|
50
|
+
trivial: true,
|
|
51
|
+
description: `Index added`,
|
|
52
|
+
});
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Prisma: model definition
|
|
56
|
+
const prismaModel = line.match(/^model\s+(\w+)\s*\{/);
|
|
57
|
+
if (prismaModel) {
|
|
58
|
+
changes.push({
|
|
59
|
+
type: 'add',
|
|
60
|
+
table: prismaModel[1],
|
|
61
|
+
trivial: false,
|
|
62
|
+
description: `Model ${prismaModel[1]} added`,
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// Django: class Model(models.Model)
|
|
67
|
+
const djangoModel = line.match(/^class\s+(\w+)\(.*Model.*\)/);
|
|
68
|
+
if (djangoModel) {
|
|
69
|
+
changes.push({
|
|
70
|
+
type: 'add',
|
|
71
|
+
table: djangoModel[1],
|
|
72
|
+
trivial: false,
|
|
73
|
+
description: `Model ${djangoModel[1]} added`,
|
|
74
|
+
});
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return changes;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Git Hook mode: extract file list from git diff --cached
|
|
82
|
+
*/
|
|
83
|
+
export async function runSchemaDrift(projectRoot) {
|
|
84
|
+
if (isSkipHooks()) {
|
|
85
|
+
await logSkip(projectRoot);
|
|
86
|
+
return true; // allow
|
|
87
|
+
}
|
|
88
|
+
const config = await loadHookConfig(projectRoot);
|
|
89
|
+
if (!config?.hooks['pre-commit']['schema-drift']?.enabled) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const { monitored_patterns } = config.hooks['pre-commit']['schema-drift'];
|
|
93
|
+
const diff = getCachedDiff();
|
|
94
|
+
const schemaFiles = diff.filter((e) => isSchemaFile(e.path, monitored_patterns));
|
|
95
|
+
if (schemaFiles.length === 0)
|
|
96
|
+
return true;
|
|
97
|
+
// Check if entity-catalog.md is also being committed
|
|
98
|
+
const catalogModified = diff.some((e) => e.path === 'specs/entity-catalog.md');
|
|
99
|
+
// Analyze changes
|
|
100
|
+
const allChanges = [];
|
|
101
|
+
for (const file of schemaFiles) {
|
|
102
|
+
const content = getCachedFileContent(file.path);
|
|
103
|
+
if (content) {
|
|
104
|
+
allChanges.push(...analyzeSchemaChanges(content, file.path));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (allChanges.length === 0)
|
|
108
|
+
return true;
|
|
109
|
+
const hasStructural = allChanges.some((c) => !c.trivial);
|
|
110
|
+
if (catalogModified) {
|
|
111
|
+
return true; // entity-catalog.md updated together — OK
|
|
112
|
+
}
|
|
113
|
+
if (!hasStructural) {
|
|
114
|
+
// Only trivial changes (indexes, etc.)
|
|
115
|
+
printWarn('⚠️ Schema Change Detected', allChanges.map((c) => c.description).join('\n') +
|
|
116
|
+
'\n\nConsider updating specs/entity-catalog.md');
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
// Structural change without entity-catalog.md update — BLOCK
|
|
120
|
+
const changeList = allChanges
|
|
121
|
+
.filter((c) => !c.trivial)
|
|
122
|
+
.map((c) => ` ${c.description}`)
|
|
123
|
+
.join('\n');
|
|
124
|
+
printBlock('❌ Schema Drift Detected', `entity-catalog.md must be updated first.\n\n${changeList}\n\nRun /id3-info-audit or manually update\nspecs/entity-catalog.md`);
|
|
125
|
+
return false; // block commit
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Claude Code Hook mode: receive { tool_name, tool_input: { file_path } } JSON from stdin
|
|
129
|
+
*/
|
|
130
|
+
export async function runSchemaDriftFromHookInput(projectRoot, hookInput) {
|
|
131
|
+
if (isSkipHooks()) {
|
|
132
|
+
await logSkip(projectRoot);
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
const config = await loadHookConfig(projectRoot);
|
|
136
|
+
if (!config?.hooks['pre-commit']['schema-drift']?.enabled) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
const { monitored_patterns } = config.hooks['pre-commit']['schema-drift'];
|
|
140
|
+
// Extract relative path from absolute file_path
|
|
141
|
+
const relativePath = hookInput.filePath.startsWith(projectRoot)
|
|
142
|
+
? hookInput.filePath.slice(projectRoot.length + 1)
|
|
143
|
+
: hookInput.filePath;
|
|
144
|
+
if (!isSchemaFile(relativePath, monitored_patterns)) {
|
|
145
|
+
return true; // not a schema file — allow
|
|
146
|
+
}
|
|
147
|
+
// Schema file is being written/edited — check if entity-catalog.md exists and is recent
|
|
148
|
+
printWarn('⚠️ Schema File Modified', `File: ${relativePath}\n\nEnsure specs/entity-catalog.md is updated\nto reflect this schema change.`);
|
|
149
|
+
return true; // warn only in Claude Code Hook mode (non-blocking)
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=schema-drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-drift.js","sourceRoot":"","sources":["../../../src/hooks/schema-drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface DiffEntry {
|
|
2
|
+
status: string;
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function parseGitDiff(output: string): DiffEntry[];
|
|
6
|
+
export interface HookInput {
|
|
7
|
+
toolName: string;
|
|
8
|
+
filePath: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function parseHookInput(stdinData: string): HookInput | null;
|
|
11
|
+
export declare function getCachedDiff(): DiffEntry[];
|
|
12
|
+
export declare function getCachedFileContent(filePath: string): string | null;
|
|
13
|
+
export declare function isSchemaFile(filePath: string, patterns: string[]): boolean;
|
|
14
|
+
export declare function isValidationFile(filePath: string, patterns: string[]): boolean;
|
|
15
|
+
export declare function matchGlob(filePath: string, pattern: string): boolean;
|
|
16
|
+
export interface HookConfig {
|
|
17
|
+
enabled: boolean;
|
|
18
|
+
hooks: {
|
|
19
|
+
'pre-commit': {
|
|
20
|
+
'schema-drift': {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
severity: 'block' | 'warn';
|
|
23
|
+
monitored_patterns: string[];
|
|
24
|
+
};
|
|
25
|
+
'rule-check': {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
severity: 'block' | 'warn';
|
|
28
|
+
validation_patterns: string[];
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
'post-commit': {
|
|
32
|
+
'auto-audit': {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
interval_commits: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export declare function loadHookConfig(projectRoot: string): Promise<HookConfig | null>;
|
|
40
|
+
export declare function isSkipHooks(): boolean;
|
|
41
|
+
export declare function logSkip(projectRoot: string): Promise<void>;
|
|
42
|
+
export declare function printBlock(title: string, message: string): void;
|
|
43
|
+
export declare function printWarn(title: string, message: string): void;
|