@mycodemap/mycodemap 0.4.2 → 0.5.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/CHANGELOG.md +105 -3
- package/README.md +192 -53
- package/dist/ai/claude.d.ts +38 -0
- package/dist/ai/claude.d.ts.map +1 -0
- package/dist/ai/claude.js +169 -0
- package/dist/ai/claude.js.map +1 -0
- package/dist/ai/codex.d.ts +38 -0
- package/dist/ai/codex.d.ts.map +1 -0
- package/dist/ai/codex.js +169 -0
- package/dist/ai/codex.js.map +1 -0
- package/dist/ai/factory.d.ts +48 -0
- package/dist/ai/factory.d.ts.map +1 -0
- package/dist/ai/factory.js +95 -0
- package/dist/ai/factory.js.map +1 -0
- package/dist/ai/index.d.ts +12 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +29 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/provider.d.ts +70 -0
- package/dist/ai/provider.d.ts.map +1 -0
- package/dist/ai/provider.js +31 -0
- package/dist/ai/provider.js.map +1 -0
- package/dist/ai/subagent-caller.d.ts +90 -0
- package/dist/ai/subagent-caller.d.ts.map +1 -0
- package/dist/ai/subagent-caller.js +280 -0
- package/dist/ai/subagent-caller.js.map +1 -0
- package/dist/ai/types.d.ts +70 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +5 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/cli/commands/analyze.d.ts +18 -0
- package/dist/cli/commands/analyze.d.ts.map +1 -1
- package/dist/cli/commands/analyze.js +239 -6
- package/dist/cli/commands/analyze.js.map +1 -1
- package/dist/cli/commands/check.d.ts +22 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +168 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/ci.d.ts +25 -0
- package/dist/cli/commands/ci.d.ts.map +1 -1
- package/dist/cli/commands/ci.js +139 -36
- package/dist/cli/commands/ci.js.map +1 -1
- package/dist/cli/commands/complexity.d.ts.map +1 -1
- package/dist/cli/commands/complexity.js +6 -0
- package/dist/cli/commands/complexity.js.map +1 -1
- package/dist/cli/commands/design.d.ts +52 -0
- package/dist/cli/commands/design.d.ts.map +1 -0
- package/dist/cli/commands/design.js +274 -0
- package/dist/cli/commands/design.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +121 -8
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/history.d.ts +26 -0
- package/dist/cli/commands/history.d.ts.map +1 -0
- package/dist/cli/commands/history.js +92 -0
- package/dist/cli/commands/history.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +13 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +108 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/server.d.ts +9 -0
- package/dist/cli/commands/server.d.ts.map +1 -0
- package/dist/cli/commands/server.js +65 -0
- package/dist/cli/commands/server.js.map +1 -0
- package/dist/cli/commands/ship/pipeline.d.ts.map +1 -1
- package/dist/cli/commands/ship/pipeline.js +8 -1
- package/dist/cli/commands/ship/pipeline.js.map +1 -1
- package/dist/cli/commands/ship/publisher.d.ts +9 -1
- package/dist/cli/commands/ship/publisher.d.ts.map +1 -1
- package/dist/cli/commands/ship/publisher.js +149 -6
- package/dist/cli/commands/ship/publisher.js.map +1 -1
- package/dist/cli/commands/workflow.d.ts.map +1 -1
- package/dist/cli/commands/workflow.js +22 -2
- package/dist/cli/commands/workflow.js.map +1 -1
- package/dist/cli/config-loader.d.ts.map +1 -1
- package/dist/cli/config-loader.js +3 -2
- package/dist/cli/config-loader.js.map +1 -1
- package/dist/cli/contract-checker.d.ts +33 -0
- package/dist/cli/contract-checker.d.ts.map +1 -0
- package/dist/cli/contract-checker.js +719 -0
- package/dist/cli/contract-checker.js.map +1 -0
- package/dist/cli/contract-diff-scope.d.ts +14 -0
- package/dist/cli/contract-diff-scope.d.ts.map +1 -0
- package/dist/cli/contract-diff-scope.js +127 -0
- package/dist/cli/contract-diff-scope.js.map +1 -0
- package/dist/cli/contract-gate-thresholds.d.ts +14 -0
- package/dist/cli/contract-gate-thresholds.d.ts.map +1 -0
- package/dist/cli/contract-gate-thresholds.js +19 -0
- package/dist/cli/contract-gate-thresholds.js.map +1 -0
- package/dist/cli/design-contract-loader.d.ts +15 -0
- package/dist/cli/design-contract-loader.d.ts.map +1 -0
- package/dist/cli/design-contract-loader.js +527 -0
- package/dist/cli/design-contract-loader.js.map +1 -0
- package/dist/cli/design-contract-schema.d.ts +11 -0
- package/dist/cli/design-contract-schema.d.ts.map +1 -0
- package/dist/cli/design-contract-schema.js +75 -0
- package/dist/cli/design-contract-schema.js.map +1 -0
- package/dist/cli/design-handoff-builder.d.ts +15 -0
- package/dist/cli/design-handoff-builder.d.ts.map +1 -0
- package/dist/cli/design-handoff-builder.js +345 -0
- package/dist/cli/design-handoff-builder.js.map +1 -0
- package/dist/cli/design-scope-resolver.d.ts +8 -0
- package/dist/cli/design-scope-resolver.d.ts.map +1 -0
- package/dist/cli/design-scope-resolver.js +760 -0
- package/dist/cli/design-scope-resolver.js.map +1 -0
- package/dist/cli/design-verification-builder.d.ts +8 -0
- package/dist/cli/design-verification-builder.d.ts.map +1 -0
- package/dist/cli/design-verification-builder.js +369 -0
- package/dist/cli/design-verification-builder.js.map +1 -0
- package/dist/cli/index.js +20 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/paths.d.ts.map +1 -1
- package/dist/cli/paths.js +30 -7
- package/dist/cli/paths.js.map +1 -1
- package/dist/cli-new/commands/server.d.ts +13 -0
- package/dist/cli-new/commands/server.d.ts.map +1 -0
- package/dist/cli-new/commands/server.js +90 -0
- package/dist/cli-new/commands/server.js.map +1 -0
- package/dist/core/analyzer.d.ts.map +1 -1
- package/dist/core/analyzer.js +16 -0
- package/dist/core/analyzer.js.map +1 -1
- package/dist/domain/entities/CodeGraph.d.ts +5 -1
- package/dist/domain/entities/CodeGraph.d.ts.map +1 -1
- package/dist/domain/entities/CodeGraph.js +29 -12
- package/dist/domain/entities/CodeGraph.js.map +1 -1
- package/dist/domain/entities/Dependency.d.ts +8 -1
- package/dist/domain/entities/Dependency.d.ts.map +1 -1
- package/dist/domain/entities/Dependency.js +19 -4
- package/dist/domain/entities/Dependency.js.map +1 -1
- package/dist/domain/entities/Symbol.d.ts +2 -1
- package/dist/domain/entities/Symbol.d.ts.map +1 -1
- package/dist/domain/entities/Symbol.js +6 -3
- package/dist/domain/entities/Symbol.js.map +1 -1
- package/dist/generator/ai-overview.d.ts +51 -0
- package/dist/generator/ai-overview.d.ts.map +1 -0
- package/dist/generator/ai-overview.js +160 -0
- package/dist/generator/ai-overview.js.map +1 -0
- package/dist/infrastructure/storage/StorageFactory.d.ts +13 -5
- package/dist/infrastructure/storage/StorageFactory.d.ts.map +1 -1
- package/dist/infrastructure/storage/StorageFactory.js +62 -16
- package/dist/infrastructure/storage/StorageFactory.js.map +1 -1
- package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts +3 -1
- package/dist/infrastructure/storage/adapters/FileSystemStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js +10 -2
- package/dist/infrastructure/storage/adapters/FileSystemStorage.js.map +1 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts +3 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js +9 -1
- package/dist/infrastructure/storage/adapters/KuzuDBStorage.js.map +1 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts +3 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.d.ts.map +1 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.js +9 -1
- package/dist/infrastructure/storage/adapters/MemoryStorage.js.map +1 -1
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts +41 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js +162 -0
- package/dist/infrastructure/storage/adapters/Neo4jStorage.js.map +1 -0
- package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts +53 -0
- package/dist/infrastructure/storage/adapters/SQLiteStorage.d.ts.map +1 -0
- package/dist/infrastructure/storage/adapters/SQLiteStorage.js +879 -0
- package/dist/infrastructure/storage/adapters/SQLiteStorage.js.map +1 -0
- package/dist/infrastructure/storage/graph-helpers.d.ts +3 -1
- package/dist/infrastructure/storage/graph-helpers.d.ts.map +1 -1
- package/dist/infrastructure/storage/graph-helpers.js +90 -0
- package/dist/infrastructure/storage/graph-helpers.js.map +1 -1
- package/dist/infrastructure/storage/index.d.ts +1 -1
- package/dist/infrastructure/storage/index.d.ts.map +1 -1
- package/dist/infrastructure/storage/interfaces/StorageBase.d.ts +3 -1
- package/dist/infrastructure/storage/interfaces/StorageBase.d.ts.map +1 -1
- package/dist/infrastructure/storage/interfaces/StorageBase.js.map +1 -1
- package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts +27 -0
- package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.d.ts.map +1 -0
- package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js +246 -0
- package/dist/infrastructure/storage/sqlite/GovernanceGraphCache.js.map +1 -0
- package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts +25 -0
- package/dist/infrastructure/storage/sqlite/perf-thresholds.d.ts.map +1 -0
- package/dist/infrastructure/storage/sqlite/perf-thresholds.js +25 -0
- package/dist/infrastructure/storage/sqlite/perf-thresholds.js.map +1 -0
- package/dist/infrastructure/storage/sqlite/schema.d.ts +4 -0
- package/dist/infrastructure/storage/sqlite/schema.d.ts.map +1 -0
- package/dist/infrastructure/storage/sqlite/schema.js +111 -0
- package/dist/infrastructure/storage/sqlite/schema.js.map +1 -0
- package/dist/interface/types/design-check.d.ts +73 -0
- package/dist/interface/types/design-check.d.ts.map +1 -0
- package/dist/interface/types/design-check.js +4 -0
- package/dist/interface/types/design-check.js.map +1 -0
- package/dist/interface/types/design-contract.d.ts +123 -0
- package/dist/interface/types/design-contract.d.ts.map +1 -0
- package/dist/interface/types/design-contract.js +7 -0
- package/dist/interface/types/design-contract.js.map +1 -0
- package/dist/interface/types/design-handoff.d.ts +68 -0
- package/dist/interface/types/design-handoff.d.ts.map +1 -0
- package/dist/interface/types/design-handoff.js +4 -0
- package/dist/interface/types/design-handoff.js.map +1 -0
- package/dist/interface/types/design-mapping.d.ts +51 -0
- package/dist/interface/types/design-mapping.d.ts.map +1 -0
- package/dist/interface/types/design-mapping.js +4 -0
- package/dist/interface/types/design-mapping.js.map +1 -0
- package/dist/interface/types/design-verification.d.ts +49 -0
- package/dist/interface/types/design-verification.d.ts.map +1 -0
- package/dist/interface/types/design-verification.js +4 -0
- package/dist/interface/types/design-verification.js.map +1 -0
- package/dist/interface/types/history-risk.d.ts +90 -0
- package/dist/interface/types/history-risk.d.ts.map +1 -0
- package/dist/interface/types/history-risk.js +4 -0
- package/dist/interface/types/history-risk.js.map +1 -0
- package/dist/interface/types/index.d.ts +20 -1
- package/dist/interface/types/index.d.ts.map +1 -1
- package/dist/interface/types/storage.d.ts +28 -1
- package/dist/interface/types/storage.d.ts.map +1 -1
- package/dist/orchestrator/adapters/ast-grep-adapter.d.ts +10 -0
- package/dist/orchestrator/adapters/ast-grep-adapter.d.ts.map +1 -1
- package/dist/orchestrator/adapters/ast-grep-adapter.js +46 -17
- package/dist/orchestrator/adapters/ast-grep-adapter.js.map +1 -1
- package/dist/orchestrator/adapters/codemap-adapter.d.ts.map +1 -1
- package/dist/orchestrator/adapters/codemap-adapter.js +2 -22
- package/dist/orchestrator/adapters/codemap-adapter.js.map +1 -1
- package/dist/orchestrator/ai-feed-generator.d.ts +210 -0
- package/dist/orchestrator/ai-feed-generator.d.ts.map +1 -0
- package/dist/orchestrator/ai-feed-generator.js +377 -0
- package/dist/orchestrator/ai-feed-generator.js.map +1 -0
- package/dist/orchestrator/history-risk-service.d.ts +55 -0
- package/dist/orchestrator/history-risk-service.d.ts.map +1 -0
- package/dist/orchestrator/history-risk-service.js +680 -0
- package/dist/orchestrator/history-risk-service.js.map +1 -0
- package/dist/orchestrator/types.d.ts +19 -1
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/orchestrator/types.js +19 -0
- package/dist/orchestrator/types.js.map +1 -1
- package/dist/server/mcp/index.d.ts +4 -0
- package/dist/server/mcp/index.d.ts.map +1 -0
- package/dist/server/mcp/index.js +5 -0
- package/dist/server/mcp/index.js.map +1 -0
- package/dist/server/mcp/server.d.ts +17 -0
- package/dist/server/mcp/server.d.ts.map +1 -0
- package/dist/server/mcp/server.js +84 -0
- package/dist/server/mcp/server.js.map +1 -0
- package/dist/server/mcp/service.d.ts +22 -0
- package/dist/server/mcp/service.d.ts.map +1 -0
- package/dist/server/mcp/service.js +177 -0
- package/dist/server/mcp/service.js.map +1 -0
- package/dist/server/mcp/types.d.ts +56 -0
- package/dist/server/mcp/types.d.ts.map +1 -0
- package/dist/server/mcp/types.js +4 -0
- package/dist/server/mcp/types.js.map +1 -0
- package/docs/AI_ASSISTANT_SETUP.md +1 -1
- package/docs/SETUP_GUIDE.md +6 -6
- package/docs/ai-guide/COMMANDS.md +171 -4
- package/docs/ai-guide/INTEGRATION.md +137 -433
- package/docs/ai-guide/OUTPUT.md +890 -5
- package/docs/ai-guide/PATTERNS.md +54 -14
- package/docs/ai-guide/PROMPTS.md +17 -6
- package/docs/archive/test-report-symbol-search.md +384 -0
- package/docs/archive/test-scenario-4-complexity-analysis.md +460 -0
- package/docs/archive/test_report_scenario5.md +615 -0
- package/docs/archive/test_scenario_3_impact_analysis_report.md +520 -0
- package/docs/backlog.md +177 -0
- package/docs/eatdogfood-reports/2026-04-17-eatdogfood-agent-experience.md +231 -0
- package/docs/exec-plans/completed/2026-04-17-eatdogfood-codemap-cli.md +103 -0
- package/docs/ideation/2026-04-15-executable-architecture-constitution-ideation.md +102 -0
- package/docs/product-specs/DESIGN_CONTRACT_TEMPLATE.md +126 -0
- package/docs/product-specs/MVP3-ARCHITECTURE-COMPARISON.md +11 -10
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-PRD.md +10 -10
- package/docs/product-specs/MVP3-ARCHITECTURE-REDESIGN-TECH-PRD.md +17 -12
- package/docs/product-specs/README.md +2 -1
- package/docs/rules/README.md +16 -11
- package/docs/rules/architecture-guardrails.md +24 -336
- package/docs/rules/code-quality-redlines.md +25 -311
- package/docs/rules/engineering-with-codex-openai.md +20 -3
- package/docs/rules/validation.md +90 -37
- package/mycodemap.config.schema.json +3 -3
- package/package.json +7 -2
- package/scripts/benchmark-governance-graph.mjs +132 -0
- package/scripts/calibrate-contract-gate.mjs +221 -0
- package/scripts/capability-report.py +255 -0
- package/scripts/experiments/arcadedb-http-smoke.mjs +90 -0
- package/scripts/qa-rule-control.sh +254 -0
- package/scripts/report-high-risk-files.mjs +395 -0
- package/scripts/rule-context.mjs +155 -0
- package/scripts/smoke-sqlite-impact.mjs +85 -0
- package/scripts/sync-analyze-docs.js +1 -0
- package/scripts/tests/test_capability_report.py +89 -0
- package/scripts/tests/test_rule_control_workflow.py +51 -0
- package/scripts/tests/test_validate_rules.py +81 -0
- package/scripts/validate-ai-docs.js +283 -1
- package/scripts/validate-docs.js +479 -25
- package/scripts/validate-rules.py +254 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const USAGE = 'Usage: node scripts/rule-context.mjs --files <path> [<path>...] --format json|prompt';
|
|
6
|
+
const DEFAULT_VERIFY_COMMANDS = ['python3 scripts/validate-rules.py code --report-only'];
|
|
7
|
+
|
|
8
|
+
const ROUTES = [
|
|
9
|
+
{
|
|
10
|
+
matches: filePath => filePath.endsWith('.test.ts'),
|
|
11
|
+
rules: ['docs/rules/testing.md'],
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
matches: filePath => /^src\/interface\//.test(filePath),
|
|
15
|
+
rules: ['docs/rules/architecture-guardrails.md'],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
matches: filePath => /^src\/(?:cli|domain|server|infrastructure)\//.test(filePath),
|
|
19
|
+
rules: [
|
|
20
|
+
'docs/rules/code-quality-redlines.md',
|
|
21
|
+
'docs/rules/architecture-guardrails.md',
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
matches: filePath =>
|
|
26
|
+
/^(?:docs\/|\.githooks\/|\.github\/workflows\/)/.test(filePath),
|
|
27
|
+
rules: [
|
|
28
|
+
'docs/rules/validation.md',
|
|
29
|
+
'docs/rules/engineering-with-codex-openai.md',
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
function normalizeFilePath(filePath) {
|
|
35
|
+
const resolved = path.isAbsolute(filePath)
|
|
36
|
+
? path.relative(process.cwd(), filePath)
|
|
37
|
+
: filePath;
|
|
38
|
+
|
|
39
|
+
return resolved.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseArgs(argv) {
|
|
43
|
+
const files = [];
|
|
44
|
+
let format = 'json';
|
|
45
|
+
|
|
46
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
47
|
+
const current = argv[index];
|
|
48
|
+
|
|
49
|
+
if (current === '--files') {
|
|
50
|
+
index += 1;
|
|
51
|
+
while (index < argv.length && !argv[index].startsWith('--')) {
|
|
52
|
+
files.push(argv[index]);
|
|
53
|
+
index += 1;
|
|
54
|
+
}
|
|
55
|
+
index -= 1;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (current === '--format') {
|
|
60
|
+
format = argv[index + 1] ?? '';
|
|
61
|
+
index += 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (current === '--help' || current === '-h') {
|
|
66
|
+
console.log(USAGE);
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (files.length === 0 || (format !== 'json' && format !== 'prompt')) {
|
|
72
|
+
console.error(USAGE);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
files: files.map(normalizeFilePath),
|
|
78
|
+
format,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function inferScopedRules(files) {
|
|
83
|
+
const matchedRules = [];
|
|
84
|
+
const matchedFiles = [];
|
|
85
|
+
|
|
86
|
+
for (const filePath of files) {
|
|
87
|
+
const route = ROUTES.find(candidate => candidate.matches(filePath));
|
|
88
|
+
if (!route) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
matchedFiles.push(filePath);
|
|
93
|
+
|
|
94
|
+
for (const rulePath of route.rules) {
|
|
95
|
+
if (!matchedRules.includes(rulePath)) {
|
|
96
|
+
matchedRules.push(rulePath);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (matchedRules.length === 2) {
|
|
100
|
+
return matchedRules.length === 0
|
|
101
|
+
? { files, matchedFiles: [], matchedRules: [], verifyCommands: [] }
|
|
102
|
+
: {
|
|
103
|
+
files,
|
|
104
|
+
matchedFiles,
|
|
105
|
+
matchedRules,
|
|
106
|
+
verifyCommands: DEFAULT_VERIFY_COMMANDS,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return matchedRules.length === 0
|
|
113
|
+
? { files, matchedFiles: [], matchedRules: [], verifyCommands: [] }
|
|
114
|
+
: {
|
|
115
|
+
files,
|
|
116
|
+
matchedFiles,
|
|
117
|
+
matchedRules,
|
|
118
|
+
verifyCommands: DEFAULT_VERIFY_COMMANDS,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function formatPrompt(result) {
|
|
123
|
+
if (result.matchedRules.length === 0) {
|
|
124
|
+
return 'No scoped rules inferred';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return [
|
|
128
|
+
'Only inject matched rules:',
|
|
129
|
+
...result.matchedRules.map(rulePath => `- ${rulePath}`),
|
|
130
|
+
'',
|
|
131
|
+
'Verify after edits:',
|
|
132
|
+
...result.verifyCommands.map(command => `- ${command}`),
|
|
133
|
+
].join('\n');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const args = parseArgs(process.argv.slice(2));
|
|
137
|
+
const result = inferScopedRules(args.files);
|
|
138
|
+
|
|
139
|
+
if (args.format === 'prompt') {
|
|
140
|
+
console.log(formatPrompt(result));
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
console.log(
|
|
145
|
+
JSON.stringify(
|
|
146
|
+
{
|
|
147
|
+
files: result.files,
|
|
148
|
+
matchedFiles: result.matchedFiles,
|
|
149
|
+
matchedRules: result.matchedRules,
|
|
150
|
+
verifyCommands: result.verifyCommands,
|
|
151
|
+
},
|
|
152
|
+
null,
|
|
153
|
+
2,
|
|
154
|
+
),
|
|
155
|
+
);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
7
|
+
const loadModule = async (relativePath) => import(pathToFileURL(path.join(repoRoot, relativePath)).href);
|
|
8
|
+
const { SQLiteStorage } = await loadModule('dist/infrastructure/storage/adapters/SQLiteStorage.js');
|
|
9
|
+
const { QueryHandler } = await loadModule('dist/server/handlers/QueryHandler.js');
|
|
10
|
+
|
|
11
|
+
function createImpactFixture() {
|
|
12
|
+
return {
|
|
13
|
+
project: {
|
|
14
|
+
id: 'proj-smoke',
|
|
15
|
+
name: 'sqlite-impact-smoke',
|
|
16
|
+
rootPath: '/fixture',
|
|
17
|
+
createdAt: new Date('2026-04-15T00:00:00Z'),
|
|
18
|
+
updatedAt: new Date('2026-04-15T00:00:00Z'),
|
|
19
|
+
},
|
|
20
|
+
modules: [
|
|
21
|
+
{
|
|
22
|
+
id: 'core',
|
|
23
|
+
projectId: 'proj-smoke',
|
|
24
|
+
path: 'src/core.ts',
|
|
25
|
+
language: 'ts',
|
|
26
|
+
stats: { lines: 10, codeLines: 8, commentLines: 1, blankLines: 1 },
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'service',
|
|
30
|
+
projectId: 'proj-smoke',
|
|
31
|
+
path: 'src/service.ts',
|
|
32
|
+
language: 'ts',
|
|
33
|
+
stats: { lines: 10, codeLines: 8, commentLines: 1, blankLines: 1 },
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'api',
|
|
37
|
+
projectId: 'proj-smoke',
|
|
38
|
+
path: 'src/api.ts',
|
|
39
|
+
language: 'ts',
|
|
40
|
+
stats: { lines: 10, codeLines: 8, commentLines: 1, blankLines: 1 },
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
symbols: [],
|
|
44
|
+
dependencies: [
|
|
45
|
+
{ id: 'dep-1', sourceId: 'service', targetId: 'core', type: 'import' },
|
|
46
|
+
{ id: 'dep-2', sourceId: 'api', targetId: 'service', type: 'import' },
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const rootDir = mkdtempSync(path.join(tmpdir(), 'codemap-sqlite-impact-smoke-'));
|
|
52
|
+
const storage = new SQLiteStorage({ type: 'sqlite', databasePath: '.codemap/governance.sqlite' });
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await storage.initialize(rootDir);
|
|
56
|
+
await storage.saveCodeGraph(createImpactFixture());
|
|
57
|
+
const handler = new QueryHandler(storage);
|
|
58
|
+
const result = await handler.analyzeImpact({ moduleId: 'core', depth: 3 });
|
|
59
|
+
const stats = storage.getGovernanceGraphRuntimeStats();
|
|
60
|
+
|
|
61
|
+
if (result.rootModule !== 'core') {
|
|
62
|
+
throw new Error(`unexpected root module: ${result.rootModule}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (result.totalAffected !== 2 || result.maxDepth !== 2) {
|
|
66
|
+
throw new Error(`unexpected impact result: ${JSON.stringify(result)}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (stats.cacheMode !== 'memory-eager') {
|
|
70
|
+
throw new Error(`expected memory-eager smoke path, got ${stats.cacheMode} (${stats.warning ?? 'no warning'})`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
console.log(JSON.stringify({
|
|
74
|
+
ok: true,
|
|
75
|
+
smoke: 'sqlite-impact',
|
|
76
|
+
cacheMode: stats.cacheMode,
|
|
77
|
+
rootModule: result.rootModule,
|
|
78
|
+
affectedModules: result.affectedModules,
|
|
79
|
+
loadMs: stats.loadMs,
|
|
80
|
+
rssDeltaMb: stats.rssDeltaMb,
|
|
81
|
+
}, null, 2));
|
|
82
|
+
} finally {
|
|
83
|
+
await storage.close();
|
|
84
|
+
rmSync(rootDir, { recursive: true, force: true });
|
|
85
|
+
}
|
|
@@ -92,6 +92,7 @@ function renderCommandsAnalyzeIntentExamples() {
|
|
|
92
92
|
title: '1. find - 查找符号 / 文本',
|
|
93
93
|
commands: [
|
|
94
94
|
'mycodemap analyze -i find -k "UnifiedResult"',
|
|
95
|
+
'mycodemap analyze -i find -k "SourceLocation" --json --structured',
|
|
95
96
|
'mycodemap analyze -i find -t "src/orchestrator" -k "IntentRouter" --topK 20',
|
|
96
97
|
],
|
|
97
98
|
},
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import io
|
|
3
|
+
import importlib.util
|
|
4
|
+
import json
|
|
5
|
+
import tempfile
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def load_capability_report_module():
|
|
11
|
+
module_path = Path(__file__).resolve().parents[1] / "capability-report.py"
|
|
12
|
+
spec = importlib.util.spec_from_file_location("capability_report", module_path)
|
|
13
|
+
if spec is None or spec.loader is None:
|
|
14
|
+
raise RuntimeError(f"Unable to load module from {module_path}")
|
|
15
|
+
module = importlib.util.module_from_spec(spec)
|
|
16
|
+
spec.loader.exec_module(module)
|
|
17
|
+
return module
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CapabilityReportTests(unittest.TestCase):
|
|
21
|
+
@classmethod
|
|
22
|
+
def setUpClass(cls):
|
|
23
|
+
cls.module = load_capability_report_module()
|
|
24
|
+
|
|
25
|
+
def test_required_fail_status(self):
|
|
26
|
+
def failing_runner(command, cwd, timeout):
|
|
27
|
+
return {
|
|
28
|
+
"available": True,
|
|
29
|
+
"returncode": 1,
|
|
30
|
+
"stdout": "",
|
|
31
|
+
"stderr": "failed",
|
|
32
|
+
"duration_ms": 8,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
item = self.module.build_item(
|
|
36
|
+
"python3",
|
|
37
|
+
"required",
|
|
38
|
+
["python3", "--version"],
|
|
39
|
+
cwd=Path("."),
|
|
40
|
+
timeout=10,
|
|
41
|
+
runner=failing_runner,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
self.assertEqual(item["status"], "REQUIRED_FAIL")
|
|
45
|
+
|
|
46
|
+
def test_optional_disabled_status(self):
|
|
47
|
+
def missing_runner(command, cwd, timeout):
|
|
48
|
+
return {
|
|
49
|
+
"available": False,
|
|
50
|
+
"returncode": None,
|
|
51
|
+
"stdout": "",
|
|
52
|
+
"stderr": "missing",
|
|
53
|
+
"duration_ms": 5,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
item = self.module.build_item(
|
|
57
|
+
"validate_rules",
|
|
58
|
+
"optional",
|
|
59
|
+
["python3", "scripts/validate-rules.py", "code", "--report-only"],
|
|
60
|
+
cwd=Path("."),
|
|
61
|
+
timeout=10,
|
|
62
|
+
runner=missing_runner,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
self.assertEqual(item["status"], "OPTIONAL_DISABLED")
|
|
66
|
+
|
|
67
|
+
def test_output_file_written(self):
|
|
68
|
+
fake_report = {
|
|
69
|
+
"version": 1,
|
|
70
|
+
"generated_at": "2026-04-19T00:00:00Z",
|
|
71
|
+
"summary": {"required": {"passed": 1, "failed": 0, "total": 1}},
|
|
72
|
+
"items": [{"name": "python3", "kind": "required", "status": "PASS"}],
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
76
|
+
output_path = Path(temp_dir) / "capability-report.json"
|
|
77
|
+
with contextlib.redirect_stdout(io.StringIO()):
|
|
78
|
+
exit_code = self.module.main(["--output", str(output_path)], report_builder=lambda: fake_report)
|
|
79
|
+
|
|
80
|
+
self.assertEqual(exit_code, 0)
|
|
81
|
+
self.assertTrue(output_path.exists())
|
|
82
|
+
|
|
83
|
+
payload = json.loads(output_path.read_text(encoding="utf-8"))
|
|
84
|
+
self.assertIn("summary", payload)
|
|
85
|
+
self.assertIn("items", payload)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
unittest.main()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
import unittest
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RuleControlWorkflowTests(unittest.TestCase):
|
|
13
|
+
def test_rule_context_is_scoped(self):
|
|
14
|
+
result = subprocess.run(
|
|
15
|
+
[
|
|
16
|
+
"node",
|
|
17
|
+
"scripts/rule-context.mjs",
|
|
18
|
+
"--files",
|
|
19
|
+
"src/cli/index.ts",
|
|
20
|
+
"--format",
|
|
21
|
+
"json",
|
|
22
|
+
],
|
|
23
|
+
cwd=ROOT,
|
|
24
|
+
check=True,
|
|
25
|
+
capture_output=True,
|
|
26
|
+
text=True,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
payload = json.loads(result.stdout)
|
|
30
|
+
self.assertIn("docs/rules/code-quality-redlines.md", payload["matchedRules"])
|
|
31
|
+
self.assertNotIn("docs/rules/testing.md", payload["matchedRules"])
|
|
32
|
+
|
|
33
|
+
def test_execute_workflows_include_rule_context(self):
|
|
34
|
+
workflow_paths = [
|
|
35
|
+
ROOT / ".codex/get-shit-done/workflows/execute-phase.md",
|
|
36
|
+
ROOT / ".claude/get-shit-done/workflows/execute-phase.md",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
for workflow_path in workflow_paths:
|
|
40
|
+
content = workflow_path.read_text(encoding="utf-8")
|
|
41
|
+
self.assertIn("rule-context.mjs --files", content)
|
|
42
|
+
self.assertIn("<rule_context>", content)
|
|
43
|
+
|
|
44
|
+
def test_ci_contains_rule_backstop(self):
|
|
45
|
+
content = (ROOT / ".github/workflows/ci-gateway.yml").read_text(encoding="utf-8")
|
|
46
|
+
self.assertIn("Rule validation backstop", content)
|
|
47
|
+
self.assertIn("python3 scripts/validate-rules.py code", content)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
unittest.main()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib.util
|
|
4
|
+
import sys
|
|
5
|
+
import unittest
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load_validate_rules_module():
|
|
10
|
+
module_path = Path(__file__).resolve().parents[1] / "validate-rules.py"
|
|
11
|
+
spec = importlib.util.spec_from_file_location("validate_rules", module_path)
|
|
12
|
+
if spec is None or spec.loader is None:
|
|
13
|
+
raise RuntimeError(f"Failed to load module from {module_path}")
|
|
14
|
+
|
|
15
|
+
module = importlib.util.module_from_spec(spec)
|
|
16
|
+
sys.modules[spec.name] = module
|
|
17
|
+
spec.loader.exec_module(module)
|
|
18
|
+
return module
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
validate_rules = load_validate_rules_module()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def make_check(level: str, status: str):
|
|
25
|
+
return validate_rules.make_check(
|
|
26
|
+
name=f"{level.lower()}-{status}",
|
|
27
|
+
level=level,
|
|
28
|
+
command=["echo", status],
|
|
29
|
+
status=status,
|
|
30
|
+
output=status,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ValidateRulesExitCodeTests(unittest.TestCase):
|
|
35
|
+
def test_exit_code_for_no_findings(self):
|
|
36
|
+
checks = [make_check("P0", "passed"), make_check("P1", "passed")]
|
|
37
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=False), 0)
|
|
38
|
+
|
|
39
|
+
def test_exit_code_for_p0(self):
|
|
40
|
+
checks = [make_check("P0", "failed"), make_check("P1", "passed")]
|
|
41
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=False), 1)
|
|
42
|
+
|
|
43
|
+
def test_exit_code_for_p1(self):
|
|
44
|
+
checks = [make_check("P0", "passed"), make_check("P1", "failed")]
|
|
45
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=False), 2)
|
|
46
|
+
|
|
47
|
+
def test_exit_code_for_p2(self):
|
|
48
|
+
checks = [make_check("P0", "passed"), make_check("P2", "failed")]
|
|
49
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=False), 3)
|
|
50
|
+
|
|
51
|
+
def test_exit_code_for_unavailable(self):
|
|
52
|
+
checks = [make_check("P0", "failed"), make_check("P1", "unavailable")]
|
|
53
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=False), 4)
|
|
54
|
+
|
|
55
|
+
def test_report_only_exits_zero(self):
|
|
56
|
+
checks = [make_check("P0", "failed"), make_check("P1", "unavailable")]
|
|
57
|
+
self.assertEqual(validate_rules.resolve_exit_code(checks, report_only=True), 0)
|
|
58
|
+
|
|
59
|
+
def test_report_status_values_are_runtime_only(self):
|
|
60
|
+
checks = [
|
|
61
|
+
make_check("P0", "passed"),
|
|
62
|
+
make_check("P1", "failed"),
|
|
63
|
+
make_check("P2", "unavailable"),
|
|
64
|
+
]
|
|
65
|
+
report = validate_rules.build_report("all", checks, report_only=False)
|
|
66
|
+
self.assertEqual([check["level"] for check in report["checks"]], ["P0", "P1", "P2"])
|
|
67
|
+
self.assertSetEqual(
|
|
68
|
+
{check["status"] for check in report["checks"]},
|
|
69
|
+
{"passed", "failed", "unavailable"},
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def test_arch_check_marks_missing_dist_as_unavailable(self):
|
|
73
|
+
missing_dist = Path("/tmp/validate-rules-missing-dist.js")
|
|
74
|
+
checks = validate_rules.execute_checks("arch", dist_cli_path=missing_dist)
|
|
75
|
+
self.assertEqual(len(checks), 1)
|
|
76
|
+
self.assertEqual(checks[0]["level"], "P0")
|
|
77
|
+
self.assertEqual(checks[0]["status"], "unavailable")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
unittest.main()
|