@codeledger/cli 0.6.8 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/activate.d.ts.map +1 -1
- package/dist/commands/activate.js +94 -26
- package/dist/commands/activate.js.map +1 -1
- package/dist/commands/ci.d.ts +16 -0
- package/dist/commands/ci.d.ts.map +1 -0
- package/dist/commands/ci.js +323 -0
- package/dist/commands/ci.js.map +1 -0
- package/dist/commands/commit-msg.d.ts +58 -0
- package/dist/commands/commit-msg.d.ts.map +1 -0
- package/dist/commands/commit-msg.js +461 -0
- package/dist/commands/commit-msg.js.map +1 -0
- package/dist/commands/compare.d.ts.map +1 -1
- package/dist/commands/compare.js +8 -0
- package/dist/commands/compare.js.map +1 -1
- package/dist/commands/context.d.ts +17 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +687 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +65 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/enable.d.ts +7 -0
- package/dist/commands/enable.d.ts.map +1 -0
- package/dist/commands/enable.js +75 -0
- package/dist/commands/enable.js.map +1 -0
- package/dist/commands/features.d.ts +2 -0
- package/dist/commands/features.d.ts.map +1 -0
- package/dist/commands/features.js +182 -0
- package/dist/commands/features.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +22 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/intent.d.ts +5 -3
- package/dist/commands/intent.d.ts.map +1 -1
- package/dist/commands/intent.js +135 -4
- package/dist/commands/intent.js.map +1 -1
- package/dist/commands/ledger.d.ts +14 -0
- package/dist/commands/ledger.d.ts.map +1 -0
- package/dist/commands/ledger.js +128 -0
- package/dist/commands/ledger.js.map +1 -0
- package/dist/commands/license.d.ts +45 -0
- package/dist/commands/license.d.ts.map +1 -0
- package/dist/commands/license.js +240 -0
- package/dist/commands/license.js.map +1 -0
- package/dist/commands/orchestrate.d.ts +12 -0
- package/dist/commands/orchestrate.d.ts.map +1 -0
- package/dist/commands/orchestrate.js +119 -0
- package/dist/commands/orchestrate.js.map +1 -0
- package/dist/commands/policy-simulate.d.ts +9 -0
- package/dist/commands/policy-simulate.d.ts.map +1 -0
- package/dist/commands/policy-simulate.js +46 -0
- package/dist/commands/policy-simulate.js.map +1 -0
- package/dist/commands/pr-summary.d.ts +59 -0
- package/dist/commands/pr-summary.d.ts.map +1 -0
- package/dist/commands/pr-summary.js +524 -0
- package/dist/commands/pr-summary.js.map +1 -0
- package/dist/commands/provenance.d.ts +10 -0
- package/dist/commands/provenance.d.ts.map +1 -0
- package/dist/commands/provenance.js +87 -0
- package/dist/commands/provenance.js.map +1 -0
- package/dist/commands/replay.d.ts +2 -0
- package/dist/commands/replay.d.ts.map +1 -0
- package/dist/commands/replay.js +181 -0
- package/dist/commands/replay.js.map +1 -0
- package/dist/commands/serve.d.ts +3 -0
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +73 -1
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/session-cleanup.js +1 -0
- package/dist/commands/session-cleanup.js.map +1 -1
- package/dist/commands/session-summary.d.ts.map +1 -1
- package/dist/commands/session-summary.js +180 -3
- package/dist/commands/session-summary.js.map +1 -1
- package/dist/commands/setup-ci.d.ts +17 -1
- package/dist/commands/setup-ci.d.ts.map +1 -1
- package/dist/commands/setup-ci.js +202 -51
- package/dist/commands/setup-ci.js.map +1 -1
- package/dist/commands/share.js +1 -1
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/stats.d.ts +8 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +164 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/team-ledger.d.ts +11 -0
- package/dist/commands/team-ledger.d.ts.map +1 -0
- package/dist/commands/team-ledger.js +74 -0
- package/dist/commands/team-ledger.js.map +1 -0
- package/dist/commands/team-metrics.d.ts +8 -0
- package/dist/commands/team-metrics.d.ts.map +1 -0
- package/dist/commands/team-metrics.js +57 -0
- package/dist/commands/team-metrics.js.map +1 -0
- package/dist/commands/upgrade.d.ts +6 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +39 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +35 -3
- package/dist/commands/verify.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +256 -36
- package/dist/index.js.map +1 -1
- package/dist/intent/extractor.d.ts +15 -0
- package/dist/intent/extractor.d.ts.map +1 -0
- package/dist/intent/extractor.js +149 -0
- package/dist/intent/extractor.js.map +1 -0
- package/dist/intent/fetcher.d.ts +33 -0
- package/dist/intent/fetcher.d.ts.map +1 -0
- package/dist/intent/fetcher.js +364 -0
- package/dist/intent/fetcher.js.map +1 -0
- package/dist/intent/loader.d.ts +26 -0
- package/dist/intent/loader.d.ts.map +1 -0
- package/dist/intent/loader.js +80 -0
- package/dist/intent/loader.js.map +1 -0
- package/dist/intent/types.d.ts +33 -0
- package/dist/intent/types.d.ts.map +1 -0
- package/dist/intent/types.js +9 -0
- package/dist/intent/types.js.map +1 -0
- package/dist/project-config.d.ts +38 -0
- package/dist/project-config.d.ts.map +1 -0
- package/dist/project-config.js +206 -0
- package/dist/project-config.js.map +1 -0
- package/dist/review-intelligence/detectors/architecture-graph.d.ts +18 -0
- package/dist/review-intelligence/detectors/architecture-graph.d.ts.map +1 -0
- package/dist/review-intelligence/detectors/architecture-graph.js +73 -0
- package/dist/review-intelligence/detectors/architecture-graph.js.map +1 -0
- package/dist/review-intelligence/detectors/pack-rules.d.ts +16 -0
- package/dist/review-intelligence/detectors/pack-rules.d.ts.map +1 -0
- package/dist/review-intelligence/detectors/pack-rules.js +107 -0
- package/dist/review-intelligence/detectors/pack-rules.js.map +1 -0
- package/dist/review-intelligence/fixes/index.d.ts +18 -0
- package/dist/review-intelligence/fixes/index.d.ts.map +1 -1
- package/dist/review-intelligence/fixes/index.js +198 -9
- package/dist/review-intelligence/fixes/index.js.map +1 -1
- package/dist/review-intelligence/index.d.ts +4 -1
- package/dist/review-intelligence/index.d.ts.map +1 -1
- package/dist/review-intelligence/index.js +20 -3
- package/dist/review-intelligence/index.js.map +1 -1
- package/dist/review-intelligence/invariants.d.ts +15 -0
- package/dist/review-intelligence/invariants.d.ts.map +1 -1
- package/dist/review-intelligence/invariants.js +36 -5
- package/dist/review-intelligence/invariants.js.map +1 -1
- package/dist/review-intelligence/types.d.ts +16 -12
- package/dist/review-intelligence/types.d.ts.map +1 -1
- package/dist/review-intelligence/types.js +9 -1
- package/dist/review-intelligence/types.js.map +1 -1
- package/dist/templates/claude-md.d.ts.map +1 -1
- package/dist/templates/claude-md.js +32 -127
- package/dist/templates/claude-md.js.map +1 -1
- package/dist/templates/config.js +4 -4
- package/dist/templates/config.js.map +1 -1
- package/dist/templates/hooks.d.ts +3 -1
- package/dist/templates/hooks.d.ts.map +1 -1
- package/dist/templates/hooks.js +101 -2
- package/dist/templates/hooks.js.map +1 -1
- package/package.json +11 -10
- package/LICENSE +0 -27
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intent loader — resolves an IssueIntent from:
|
|
3
|
+
* 1. --intent-file <path> (pre-extracted JSON)
|
|
4
|
+
* 2. --issue <ID> (fetch from tracker, extract intent)
|
|
5
|
+
* 3. branch name inference (via tracker_prefix config)
|
|
6
|
+
* 4. (none) (returns null — diff-only inference)
|
|
7
|
+
*/
|
|
8
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import { fetchIssue } from './fetcher.js';
|
|
11
|
+
import { extractIntent } from './extractor.js';
|
|
12
|
+
/**
|
|
13
|
+
* Infer an issue ID from a branch name using a tracker prefix.
|
|
14
|
+
* E.g., branch "feat/LINEAR-123-add-search" with prefix "LINEAR" → "LINEAR-123"
|
|
15
|
+
*
|
|
16
|
+
* When branchName is omitted, reads current branch from git.
|
|
17
|
+
*/
|
|
18
|
+
export function inferIssueFromBranch(trackerPrefix, branchName) {
|
|
19
|
+
if (!trackerPrefix)
|
|
20
|
+
return null;
|
|
21
|
+
let branch = branchName;
|
|
22
|
+
if (!branch) {
|
|
23
|
+
try {
|
|
24
|
+
branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
25
|
+
encoding: 'utf-8',
|
|
26
|
+
timeout: 5000,
|
|
27
|
+
}).trim();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Match PREFIX-123 anywhere in the branch name
|
|
34
|
+
const pattern = new RegExp(`(${trackerPrefix}-\\d+)`, 'i');
|
|
35
|
+
const match = branch.match(pattern);
|
|
36
|
+
return match?.[1] ?? null;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load intent from the best available source.
|
|
40
|
+
* Returns null if no intent source is provided.
|
|
41
|
+
*/
|
|
42
|
+
export async function loadIntent(source) {
|
|
43
|
+
// Priority 1: pre-extracted file
|
|
44
|
+
if (source.intentFile) {
|
|
45
|
+
if (!existsSync(source.intentFile)) {
|
|
46
|
+
console.error(`Intent file not found: ${source.intentFile}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const content = readFileSync(source.intentFile, 'utf-8');
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
console.error(`Failed to parse intent file: ${source.intentFile}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Priority 2: explicit issue ID
|
|
59
|
+
if (source.issue) {
|
|
60
|
+
const raw = await fetchIssue(source.issue);
|
|
61
|
+
if (!raw) {
|
|
62
|
+
console.error(`Could not fetch issue: ${source.issue}`);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return extractIntent(source.issue, raw);
|
|
66
|
+
}
|
|
67
|
+
// Priority 3: infer from branch name using tracker prefix
|
|
68
|
+
if (source.trackerPrefix) {
|
|
69
|
+
const inferred = inferIssueFromBranch(source.trackerPrefix);
|
|
70
|
+
if (inferred) {
|
|
71
|
+
const raw = await fetchIssue(inferred);
|
|
72
|
+
if (raw) {
|
|
73
|
+
return extractIntent(inferred, raw);
|
|
74
|
+
}
|
|
75
|
+
// Inference found a match but fetch failed — not fatal, fall through
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/intent/loader.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQ/C;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,aAAqB,EAAE,UAAmB;IAC7E,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEhC,IAAI,MAAM,GAAG,UAAU,CAAC;IACxB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,GAAG,QAAQ,CAAC,iCAAiC,EAAE;gBACnD,QAAQ,EAAE,OAAO;gBACjB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC,IAAI,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,IAAI,aAAa,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAoB;IACnD,iCAAiC;IACjC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAgB,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,gCAAgC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,0BAA0B,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,0DAA0D;IAC1D,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,GAAG,EAAE,CAAC;gBACR,OAAO,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACtC,CAAC;YACD,qEAAqE;QACvE,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared intent types for issue-driven context.
|
|
3
|
+
*
|
|
4
|
+
* An IssueIntent represents structured data extracted from an external
|
|
5
|
+
* issue tracker (Linear, Jira, GitHub Issues, etc.) that enriches
|
|
6
|
+
* commit messages, PR summaries, and other downstream outputs.
|
|
7
|
+
*/
|
|
8
|
+
export interface IssueIntent {
|
|
9
|
+
/** Issue title */
|
|
10
|
+
title: string;
|
|
11
|
+
/** Inferred high-level goal */
|
|
12
|
+
goal: string;
|
|
13
|
+
/** Constraints extracted from the issue (if detectable) */
|
|
14
|
+
constraints: string[];
|
|
15
|
+
/** Acceptance criteria (if present in the issue body) */
|
|
16
|
+
acceptance_criteria: string[];
|
|
17
|
+
/** Source issue identifier (e.g., LINEAR-123, JIRA-456) */
|
|
18
|
+
source_id: string;
|
|
19
|
+
/** Source system (e.g., 'github', 'linear', 'jira', 'manual') */
|
|
20
|
+
source_system: string;
|
|
21
|
+
/** Raw issue body (for reference) */
|
|
22
|
+
raw: string;
|
|
23
|
+
}
|
|
24
|
+
/** Minimal issue data fetched from a tracker API */
|
|
25
|
+
export interface RawIssueData {
|
|
26
|
+
title: string;
|
|
27
|
+
body: string;
|
|
28
|
+
labels?: string[];
|
|
29
|
+
state?: string;
|
|
30
|
+
assignee?: string;
|
|
31
|
+
url?: string;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,yDAAyD;IACzD,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,oDAAoD;AACpD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared intent types for issue-driven context.
|
|
3
|
+
*
|
|
4
|
+
* An IssueIntent represents structured data extracted from an external
|
|
5
|
+
* issue tracker (Linear, Jira, GitHub Issues, etc.) that enriches
|
|
6
|
+
* commit messages, PR summaries, and other downstream outputs.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/intent/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-level configuration loader for .codeledger.yml
|
|
3
|
+
*
|
|
4
|
+
* Reads optional project config from repo root (.codeledger.yml) that controls
|
|
5
|
+
* commit-msg, pr-summary, and PR review bot defaults. This is separate from
|
|
6
|
+
* the core .codeledger/config.json which handles scoring, selection, and harness.
|
|
7
|
+
*
|
|
8
|
+
* Uses a minimal YAML parser (no dependency) — supports only the flat/nested
|
|
9
|
+
* key-value structure documented in sample.codeledger.yml.
|
|
10
|
+
*/
|
|
11
|
+
export interface ProjectConfig {
|
|
12
|
+
pr: {
|
|
13
|
+
base_branch: string;
|
|
14
|
+
comment_enabled: boolean;
|
|
15
|
+
sections: string[];
|
|
16
|
+
};
|
|
17
|
+
verify: {
|
|
18
|
+
mode: 'observe' | 'warn' | 'block';
|
|
19
|
+
severity_threshold: string;
|
|
20
|
+
review_intelligence: {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
invariants: Record<string, boolean>;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
commit_msg: {
|
|
26
|
+
signature: boolean;
|
|
27
|
+
format: 'full' | 'minimal';
|
|
28
|
+
};
|
|
29
|
+
intent: {
|
|
30
|
+
tracker_prefix: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load project config from .codeledger.yml in the given directory.
|
|
35
|
+
* Returns defaults if the file doesn't exist or fails to parse.
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadProjectConfig(cwd: string): ProjectConfig;
|
|
38
|
+
//# sourceMappingURL=project-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-config.d.ts","sourceRoot":"","sources":["../src/project-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE;QACF,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,OAAO,CAAC;QACzB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;QACnC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,mBAAmB,EAAE;YACnB,OAAO,EAAE,OAAO,CAAC;YACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;SACrC,CAAC;KACH,CAAC;IACF,UAAU,EAAE;QACV,SAAS,EAAE,OAAO,CAAC;QACnB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;KAC5B,CAAC;IACF,MAAM,EAAE;QACN,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAmID;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAe5D"}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-level configuration loader for .codeledger.yml
|
|
3
|
+
*
|
|
4
|
+
* Reads optional project config from repo root (.codeledger.yml) that controls
|
|
5
|
+
* commit-msg, pr-summary, and PR review bot defaults. This is separate from
|
|
6
|
+
* the core .codeledger/config.json which handles scoring, selection, and harness.
|
|
7
|
+
*
|
|
8
|
+
* Uses a minimal YAML parser (no dependency) — supports only the flat/nested
|
|
9
|
+
* key-value structure documented in sample.codeledger.yml.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
pr: {
|
|
15
|
+
base_branch: 'main',
|
|
16
|
+
comment_enabled: true,
|
|
17
|
+
sections: [
|
|
18
|
+
'summary', 'why', 'business_impact', 'key_changes',
|
|
19
|
+
'subsystems_touched', 'risk_signals', 'verify_findings',
|
|
20
|
+
'reviewer_focus', 'testing', 'stats',
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
verify: {
|
|
24
|
+
mode: 'warn',
|
|
25
|
+
severity_threshold: 'P1',
|
|
26
|
+
review_intelligence: {
|
|
27
|
+
enabled: true,
|
|
28
|
+
invariants: {
|
|
29
|
+
runtime_validation: true,
|
|
30
|
+
outbound_io: true,
|
|
31
|
+
platform_helpers: true,
|
|
32
|
+
build_runtime: true,
|
|
33
|
+
test_integrity: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
commit_msg: {
|
|
38
|
+
signature: false,
|
|
39
|
+
format: 'full',
|
|
40
|
+
},
|
|
41
|
+
intent: {
|
|
42
|
+
tracker_prefix: '',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
// ── Minimal YAML parser ──────────────────────────────────────────────────────
|
|
46
|
+
// Handles the subset of YAML used in .codeledger.yml: scalars, simple lists,
|
|
47
|
+
// and nested objects (2-space indent). No anchors, aliases, flow style, or
|
|
48
|
+
// multi-line strings.
|
|
49
|
+
function parseSimpleYaml(text) {
|
|
50
|
+
const result = {};
|
|
51
|
+
const lines = text.split('\n');
|
|
52
|
+
const stack = [
|
|
53
|
+
{ indent: -1, obj: result },
|
|
54
|
+
];
|
|
55
|
+
for (const rawLine of lines) {
|
|
56
|
+
// Skip comments and blank lines
|
|
57
|
+
const commentIdx = rawLine.indexOf('#');
|
|
58
|
+
const line = commentIdx >= 0 ? rawLine.slice(0, commentIdx) : rawLine;
|
|
59
|
+
if (line.trim() === '')
|
|
60
|
+
continue;
|
|
61
|
+
const indent = line.length - line.trimStart().length;
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
// List item: "- value"
|
|
64
|
+
if (trimmed.startsWith('- ')) {
|
|
65
|
+
const value = parseScalar(trimmed.slice(2).trim());
|
|
66
|
+
// Find the parent at this indent level — pop entries at deeper or equal indent
|
|
67
|
+
while (stack.length > 1 && (stack[stack.length - 1]?.indent ?? -1) >= indent) {
|
|
68
|
+
stack.pop();
|
|
69
|
+
}
|
|
70
|
+
let parent = stack[stack.length - 1]?.obj ?? result;
|
|
71
|
+
// If we landed on an empty object created by "key:" syntax, go one level
|
|
72
|
+
// up and convert the key from an empty object to an array.
|
|
73
|
+
if (Object.keys(parent).length === 0 && stack.length > 1) {
|
|
74
|
+
stack.pop();
|
|
75
|
+
const grandparent = stack[stack.length - 1]?.obj ?? result;
|
|
76
|
+
const gpKeys = Object.keys(grandparent);
|
|
77
|
+
const gpLastKey = gpKeys[gpKeys.length - 1];
|
|
78
|
+
if (gpLastKey !== undefined) {
|
|
79
|
+
grandparent[gpLastKey] = [value];
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
// Find the last key in the parent to attach the list item
|
|
84
|
+
const keys = Object.keys(parent);
|
|
85
|
+
const lastKey = keys[keys.length - 1];
|
|
86
|
+
if (lastKey !== undefined) {
|
|
87
|
+
if (!Array.isArray(parent[lastKey])) {
|
|
88
|
+
parent[lastKey] = [];
|
|
89
|
+
}
|
|
90
|
+
parent[lastKey].push(value);
|
|
91
|
+
}
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Key-value pair: "key: value" or "key:" (nested object)
|
|
95
|
+
const colonIdx = trimmed.indexOf(':');
|
|
96
|
+
if (colonIdx < 0)
|
|
97
|
+
continue;
|
|
98
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
99
|
+
const rawValue = trimmed.slice(colonIdx + 1).trim();
|
|
100
|
+
// Pop stack to find the right parent
|
|
101
|
+
while (stack.length > 1 && (stack[stack.length - 1]?.indent ?? -1) >= indent) {
|
|
102
|
+
stack.pop();
|
|
103
|
+
}
|
|
104
|
+
const parent = stack[stack.length - 1]?.obj ?? result;
|
|
105
|
+
if (rawValue === '') {
|
|
106
|
+
// Nested object — key with no value
|
|
107
|
+
const nested = {};
|
|
108
|
+
parent[key] = nested;
|
|
109
|
+
stack.push({ indent, obj: nested });
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
parent[key] = parseScalar(rawValue);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
function parseScalar(value) {
|
|
118
|
+
if (value === 'true')
|
|
119
|
+
return true;
|
|
120
|
+
if (value === 'false')
|
|
121
|
+
return false;
|
|
122
|
+
if (value === 'null' || value === '~')
|
|
123
|
+
return '';
|
|
124
|
+
// Quoted strings
|
|
125
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
126
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
127
|
+
return value.slice(1, -1);
|
|
128
|
+
}
|
|
129
|
+
// Numbers
|
|
130
|
+
const num = Number(value);
|
|
131
|
+
if (!isNaN(num) && value !== '')
|
|
132
|
+
return num;
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
// ── Loader ───────────────────────────────────────────────────────────────────
|
|
136
|
+
/**
|
|
137
|
+
* Load project config from .codeledger.yml in the given directory.
|
|
138
|
+
* Returns defaults if the file doesn't exist or fails to parse.
|
|
139
|
+
*/
|
|
140
|
+
export function loadProjectConfig(cwd) {
|
|
141
|
+
const filePath = join(cwd, '.codeledger.yml');
|
|
142
|
+
if (!existsSync(filePath)) {
|
|
143
|
+
return { ...DEFAULT_CONFIG };
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
147
|
+
const parsed = parseSimpleYaml(raw);
|
|
148
|
+
return mergeConfig(DEFAULT_CONFIG, parsed);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Non-fatal — fall back to defaults
|
|
152
|
+
return { ...DEFAULT_CONFIG };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function mergeConfig(defaults, overrides) {
|
|
156
|
+
const result = structuredClone(defaults);
|
|
157
|
+
// pr section
|
|
158
|
+
const pr = overrides['pr'];
|
|
159
|
+
if (pr) {
|
|
160
|
+
if (typeof pr['base_branch'] === 'string')
|
|
161
|
+
result.pr.base_branch = pr['base_branch'];
|
|
162
|
+
if (typeof pr['comment_enabled'] === 'boolean')
|
|
163
|
+
result.pr.comment_enabled = pr['comment_enabled'];
|
|
164
|
+
if (Array.isArray(pr['sections']))
|
|
165
|
+
result.pr.sections = pr['sections'];
|
|
166
|
+
}
|
|
167
|
+
// verify section
|
|
168
|
+
const verify = overrides['verify'];
|
|
169
|
+
if (verify) {
|
|
170
|
+
if (typeof verify['mode'] === 'string' && ['observe', 'warn', 'block'].includes(verify['mode'])) {
|
|
171
|
+
result.verify.mode = verify['mode'];
|
|
172
|
+
}
|
|
173
|
+
if (typeof verify['severity_threshold'] === 'string') {
|
|
174
|
+
result.verify.severity_threshold = verify['severity_threshold'];
|
|
175
|
+
}
|
|
176
|
+
const ri = verify['review_intelligence'];
|
|
177
|
+
if (ri) {
|
|
178
|
+
if (typeof ri['enabled'] === 'boolean')
|
|
179
|
+
result.verify.review_intelligence.enabled = ri['enabled'];
|
|
180
|
+
const invariants = ri['invariants'];
|
|
181
|
+
if (invariants) {
|
|
182
|
+
for (const [k, v] of Object.entries(invariants)) {
|
|
183
|
+
if (typeof v === 'boolean')
|
|
184
|
+
result.verify.review_intelligence.invariants[k] = v;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// commit_msg section
|
|
190
|
+
const commitMsg = overrides['commit_msg'];
|
|
191
|
+
if (commitMsg) {
|
|
192
|
+
if (typeof commitMsg['signature'] === 'boolean')
|
|
193
|
+
result.commit_msg.signature = commitMsg['signature'];
|
|
194
|
+
if (typeof commitMsg['format'] === 'string' && ['full', 'minimal'].includes(commitMsg['format'])) {
|
|
195
|
+
result.commit_msg.format = commitMsg['format'];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// intent section
|
|
199
|
+
const intent = overrides['intent'];
|
|
200
|
+
if (intent) {
|
|
201
|
+
if (typeof intent['tracker_prefix'] === 'string')
|
|
202
|
+
result.intent.tracker_prefix = intent['tracker_prefix'];
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=project-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-config.js","sourceRoot":"","sources":["../src/project-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InvariantDetector } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* INVARIANT — architecture_graph
|
|
4
|
+
*
|
|
5
|
+
* Runs the architecture graph analysis and converts structural violations
|
|
6
|
+
* (circular dependencies, service boundary violations) into ReviewFindings
|
|
7
|
+
* so they appear in `codeledger verify` and CI gate output.
|
|
8
|
+
*
|
|
9
|
+
* This detector is graph-level (not per-file), so it ignores the files list
|
|
10
|
+
* and analyzes the whole repo structure. It caches the graph result per
|
|
11
|
+
* analysis run.
|
|
12
|
+
*
|
|
13
|
+
* Severity:
|
|
14
|
+
* - Circular dependencies: P1
|
|
15
|
+
* - Service boundary violations: P1 or P2 (from graph analysis)
|
|
16
|
+
*/
|
|
17
|
+
export declare const architectureGraphDetector: InvariantDetector;
|
|
18
|
+
//# sourceMappingURL=architecture-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture-graph.d.ts","sourceRoot":"","sources":["../../../src/review-intelligence/detectors/architecture-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAGlB,MAAM,aAAa,CAAC;AAMrB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,EAAE,iBA4DvC,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { buildArchitectureGraph, } from '../../architecture-graph/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* INVARIANT — architecture_graph
|
|
4
|
+
*
|
|
5
|
+
* Runs the architecture graph analysis and converts structural violations
|
|
6
|
+
* (circular dependencies, service boundary violations) into ReviewFindings
|
|
7
|
+
* so they appear in `codeledger verify` and CI gate output.
|
|
8
|
+
*
|
|
9
|
+
* This detector is graph-level (not per-file), so it ignores the files list
|
|
10
|
+
* and analyzes the whole repo structure. It caches the graph result per
|
|
11
|
+
* analysis run.
|
|
12
|
+
*
|
|
13
|
+
* Severity:
|
|
14
|
+
* - Circular dependencies: P1
|
|
15
|
+
* - Service boundary violations: P1 or P2 (from graph analysis)
|
|
16
|
+
*/
|
|
17
|
+
export const architectureGraphDetector = {
|
|
18
|
+
name: 'architecture_graph',
|
|
19
|
+
analyze(ctx) {
|
|
20
|
+
const findings = [];
|
|
21
|
+
let graph;
|
|
22
|
+
try {
|
|
23
|
+
graph = buildArchitectureGraph(ctx.cwd);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Graph build can fail in repos without package structure — skip silently
|
|
27
|
+
return findings;
|
|
28
|
+
}
|
|
29
|
+
// Convert circular dependencies to findings
|
|
30
|
+
for (const cycle of graph.cycles) {
|
|
31
|
+
if (cycle.length < 2)
|
|
32
|
+
continue;
|
|
33
|
+
const cycleStr = cycle.join(' → ');
|
|
34
|
+
findings.push({
|
|
35
|
+
rule_id: 'RI-AG-001',
|
|
36
|
+
title: 'Circular dependency detected',
|
|
37
|
+
severity: 'P1',
|
|
38
|
+
category: 'architecture_graph',
|
|
39
|
+
file: cycle[0],
|
|
40
|
+
line: 0,
|
|
41
|
+
trigger: cycleStr,
|
|
42
|
+
missing_companions: [
|
|
43
|
+
'Break the cycle by extracting shared types/interfaces into a common package',
|
|
44
|
+
],
|
|
45
|
+
why_it_matters: `Circular dependency: ${cycleStr}. ` +
|
|
46
|
+
'Circular package dependencies cause unpredictable initialization order, ' +
|
|
47
|
+
'make tree-shaking impossible, and often indicate a layering violation.',
|
|
48
|
+
confidence: 'high',
|
|
49
|
+
fixable: false,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Convert boundary violations to findings
|
|
53
|
+
for (const violation of graph.boundaryViolations) {
|
|
54
|
+
findings.push({
|
|
55
|
+
rule_id: 'RI-AG-002',
|
|
56
|
+
title: 'Service boundary violation',
|
|
57
|
+
severity: violation.severity,
|
|
58
|
+
category: 'architecture_graph',
|
|
59
|
+
file: violation.sourceService,
|
|
60
|
+
line: 0,
|
|
61
|
+
trigger: `${violation.sourceService} imports ${violation.importPath}`,
|
|
62
|
+
missing_companions: [
|
|
63
|
+
'Use the public API/events of the target service instead of direct imports',
|
|
64
|
+
],
|
|
65
|
+
why_it_matters: violation.description,
|
|
66
|
+
confidence: 'high',
|
|
67
|
+
fixable: false,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return findings;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=architecture-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture-graph.js","sourceRoot":"","sources":["../../../src/review-intelligence/detectors/architecture-graph.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,sBAAsB,GAEvB,MAAM,mCAAmC,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,IAAI,EAAE,oBAAoB;IAE1B,OAAO,CAAC,GAAoB;QAC1B,MAAM,QAAQ,GAAoB,EAAE,CAAC;QAErC,IAAI,KAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;YAC1E,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,4CAA4C;QAC5C,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YACjC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAE/B,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAE,8BAA8B;gBACrC,QAAQ,EAAE,IAAI;gBACd,QAAQ,EAAE,oBAAoB;gBAC9B,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE;gBACf,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,QAAQ;gBACjB,kBAAkB,EAAE;oBAClB,6EAA6E;iBAC9E;gBACD,cAAc,EACZ,wBAAwB,QAAQ,IAAI;oBACpC,0EAA0E;oBAC1E,wEAAwE;gBAC1E,UAAU,EAAE,MAAM;gBAClB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;QACL,CAAC;QAED,0CAA0C;QAC1C,KAAK,MAAM,SAAS,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;YACjD,QAAQ,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,WAAW;gBACpB,KAAK,EAAE,4BAA4B;gBACnC,QAAQ,EAAE,SAAS,CAAC,QAAQ;gBAC5B,QAAQ,EAAE,oBAAoB;gBAC9B,IAAI,EAAE,SAAS,CAAC,aAAa;gBAC7B,IAAI,EAAE,CAAC;gBACP,OAAO,EAAE,GAAG,SAAS,CAAC,aAAa,YAAY,SAAS,CAAC,UAAU,EAAE;gBACrE,kBAAkB,EAAE;oBAClB,2EAA2E;iBAC5E;gBACD,cAAc,EAAE,SAAS,CAAC,WAAW;gBACrC,UAAU,EAAE,MAAM;gBAClB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InvariantDetector } from '../types.js';
|
|
2
|
+
import type { PackRule } from '../packs/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* INVARIANT — pack_rules (dynamic)
|
|
5
|
+
*
|
|
6
|
+
* Enforces enabled invariant pack rules. Each PackRule has:
|
|
7
|
+
* - trigger_pattern: regex that matches raw callsites
|
|
8
|
+
* - helper: the sanctioned wrapper/helper name that should be used
|
|
9
|
+
* - kind: required_wrapper | required_helper | forbidden_pattern | required_pattern
|
|
10
|
+
*
|
|
11
|
+
* This detector is parameterized at construction time with the active pack
|
|
12
|
+
* rules. It is NOT registered as a static built-in — instead it is created
|
|
13
|
+
* on-the-fly by the engine when enabled packs have rules.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createPackRulesDetector(rules: PackRule[]): InvariantDetector;
|
|
16
|
+
//# sourceMappingURL=pack-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-rules.d.ts","sourceRoot":"","sources":["../../../src/review-intelligence/detectors/pack-rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,iBAAiB,CA6B5E"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* INVARIANT — pack_rules (dynamic)
|
|
3
|
+
*
|
|
4
|
+
* Enforces enabled invariant pack rules. Each PackRule has:
|
|
5
|
+
* - trigger_pattern: regex that matches raw callsites
|
|
6
|
+
* - helper: the sanctioned wrapper/helper name that should be used
|
|
7
|
+
* - kind: required_wrapper | required_helper | forbidden_pattern | required_pattern
|
|
8
|
+
*
|
|
9
|
+
* This detector is parameterized at construction time with the active pack
|
|
10
|
+
* rules. It is NOT registered as a static built-in — instead it is created
|
|
11
|
+
* on-the-fly by the engine when enabled packs have rules.
|
|
12
|
+
*/
|
|
13
|
+
export function createPackRulesDetector(rules) {
|
|
14
|
+
return {
|
|
15
|
+
name: 'pack_rules',
|
|
16
|
+
analyze(ctx) {
|
|
17
|
+
const findings = [];
|
|
18
|
+
if (rules.length === 0)
|
|
19
|
+
return findings;
|
|
20
|
+
for (const filePath of ctx.files) {
|
|
21
|
+
const content = ctx.fileContents.get(filePath);
|
|
22
|
+
if (!content)
|
|
23
|
+
continue;
|
|
24
|
+
if (!isAnalyzableFile(filePath))
|
|
25
|
+
continue;
|
|
26
|
+
const lines = content.split('\n');
|
|
27
|
+
for (const rule of rules) {
|
|
28
|
+
if (rule.kind === 'forbidden_pattern') {
|
|
29
|
+
analyzeForbiddenPattern(rule, filePath, lines, findings);
|
|
30
|
+
}
|
|
31
|
+
else if (rule.kind === 'required_wrapper' || rule.kind === 'required_helper') {
|
|
32
|
+
analyzeRequiredWrapper(rule, filePath, content, lines, findings);
|
|
33
|
+
}
|
|
34
|
+
// required_pattern rules are structural — handled by built-in detectors
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return findings;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function analyzeForbiddenPattern(rule, filePath, lines, findings) {
|
|
42
|
+
if (!rule.trigger_pattern)
|
|
43
|
+
return;
|
|
44
|
+
const triggerRe = new RegExp(rule.trigger_pattern, 'g');
|
|
45
|
+
for (let i = 0; i < lines.length; i++) {
|
|
46
|
+
const line = lines[i];
|
|
47
|
+
const trimmed = line.trim();
|
|
48
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
49
|
+
continue;
|
|
50
|
+
triggerRe.lastIndex = 0;
|
|
51
|
+
if (triggerRe.test(trimmed)) {
|
|
52
|
+
findings.push({
|
|
53
|
+
rule_id: rule.rule_id,
|
|
54
|
+
title: rule.description,
|
|
55
|
+
severity: rule.severity,
|
|
56
|
+
category: 'pack_rules',
|
|
57
|
+
file: filePath,
|
|
58
|
+
line: i + 1,
|
|
59
|
+
trigger: trimmed.slice(0, 80),
|
|
60
|
+
missing_companions: ['Remove or replace the forbidden pattern'],
|
|
61
|
+
why_it_matters: rule.description,
|
|
62
|
+
confidence: 'high',
|
|
63
|
+
fixable: false,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function analyzeRequiredWrapper(rule, filePath, content, lines, findings) {
|
|
69
|
+
if (!rule.trigger_pattern || !rule.helper)
|
|
70
|
+
return;
|
|
71
|
+
// Check if the file uses the sanctioned helper
|
|
72
|
+
const helperUsed = content.includes(rule.helper);
|
|
73
|
+
if (helperUsed)
|
|
74
|
+
return; // File already uses the helper
|
|
75
|
+
const triggerRe = new RegExp(rule.trigger_pattern, 'g');
|
|
76
|
+
for (let i = 0; i < lines.length; i++) {
|
|
77
|
+
const line = lines[i];
|
|
78
|
+
const trimmed = line.trim();
|
|
79
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
80
|
+
continue;
|
|
81
|
+
if (trimmed.startsWith('import '))
|
|
82
|
+
continue;
|
|
83
|
+
triggerRe.lastIndex = 0;
|
|
84
|
+
if (triggerRe.test(trimmed)) {
|
|
85
|
+
findings.push({
|
|
86
|
+
rule_id: rule.rule_id,
|
|
87
|
+
title: rule.description,
|
|
88
|
+
severity: rule.severity,
|
|
89
|
+
category: 'pack_rules',
|
|
90
|
+
file: filePath,
|
|
91
|
+
line: i + 1,
|
|
92
|
+
trigger: trimmed.slice(0, 80),
|
|
93
|
+
missing_companions: [`Use ${rule.helper} instead`],
|
|
94
|
+
why_it_matters: `Repository convention: ${rule.description}. ` +
|
|
95
|
+
`The sanctioned helper \`${rule.helper}\` should be used instead of raw calls.`,
|
|
96
|
+
confidence: 'high',
|
|
97
|
+
fixable: true,
|
|
98
|
+
});
|
|
99
|
+
// Only report first violation per file per rule to avoid noise
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function isAnalyzableFile(filePath) {
|
|
105
|
+
return /\.(?:ts|tsx|js|jsx|mts|mjs)$/.test(filePath);
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=pack-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack-rules.js","sourceRoot":"","sources":["../../../src/review-intelligence/detectors/pack-rules.ts"],"names":[],"mappings":"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"}
|