@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.
Files changed (156) hide show
  1. package/dist/commands/activate.d.ts.map +1 -1
  2. package/dist/commands/activate.js +94 -26
  3. package/dist/commands/activate.js.map +1 -1
  4. package/dist/commands/ci.d.ts +16 -0
  5. package/dist/commands/ci.d.ts.map +1 -0
  6. package/dist/commands/ci.js +323 -0
  7. package/dist/commands/ci.js.map +1 -0
  8. package/dist/commands/commit-msg.d.ts +58 -0
  9. package/dist/commands/commit-msg.d.ts.map +1 -0
  10. package/dist/commands/commit-msg.js +461 -0
  11. package/dist/commands/commit-msg.js.map +1 -0
  12. package/dist/commands/compare.d.ts.map +1 -1
  13. package/dist/commands/compare.js +8 -0
  14. package/dist/commands/compare.js.map +1 -1
  15. package/dist/commands/context.d.ts +17 -0
  16. package/dist/commands/context.d.ts.map +1 -0
  17. package/dist/commands/context.js +687 -0
  18. package/dist/commands/context.js.map +1 -0
  19. package/dist/commands/doctor.d.ts.map +1 -1
  20. package/dist/commands/doctor.js +65 -0
  21. package/dist/commands/doctor.js.map +1 -1
  22. package/dist/commands/enable.d.ts +7 -0
  23. package/dist/commands/enable.d.ts.map +1 -0
  24. package/dist/commands/enable.js +75 -0
  25. package/dist/commands/enable.js.map +1 -0
  26. package/dist/commands/features.d.ts +2 -0
  27. package/dist/commands/features.d.ts.map +1 -0
  28. package/dist/commands/features.js +182 -0
  29. package/dist/commands/features.js.map +1 -0
  30. package/dist/commands/init.d.ts.map +1 -1
  31. package/dist/commands/init.js +22 -1
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/commands/intent.d.ts +5 -3
  34. package/dist/commands/intent.d.ts.map +1 -1
  35. package/dist/commands/intent.js +135 -4
  36. package/dist/commands/intent.js.map +1 -1
  37. package/dist/commands/ledger.d.ts +14 -0
  38. package/dist/commands/ledger.d.ts.map +1 -0
  39. package/dist/commands/ledger.js +128 -0
  40. package/dist/commands/ledger.js.map +1 -0
  41. package/dist/commands/license.d.ts +45 -0
  42. package/dist/commands/license.d.ts.map +1 -0
  43. package/dist/commands/license.js +240 -0
  44. package/dist/commands/license.js.map +1 -0
  45. package/dist/commands/orchestrate.d.ts +12 -0
  46. package/dist/commands/orchestrate.d.ts.map +1 -0
  47. package/dist/commands/orchestrate.js +119 -0
  48. package/dist/commands/orchestrate.js.map +1 -0
  49. package/dist/commands/policy-simulate.d.ts +9 -0
  50. package/dist/commands/policy-simulate.d.ts.map +1 -0
  51. package/dist/commands/policy-simulate.js +46 -0
  52. package/dist/commands/policy-simulate.js.map +1 -0
  53. package/dist/commands/pr-summary.d.ts +59 -0
  54. package/dist/commands/pr-summary.d.ts.map +1 -0
  55. package/dist/commands/pr-summary.js +524 -0
  56. package/dist/commands/pr-summary.js.map +1 -0
  57. package/dist/commands/provenance.d.ts +10 -0
  58. package/dist/commands/provenance.d.ts.map +1 -0
  59. package/dist/commands/provenance.js +87 -0
  60. package/dist/commands/provenance.js.map +1 -0
  61. package/dist/commands/replay.d.ts +2 -0
  62. package/dist/commands/replay.d.ts.map +1 -0
  63. package/dist/commands/replay.js +181 -0
  64. package/dist/commands/replay.js.map +1 -0
  65. package/dist/commands/serve.d.ts +3 -0
  66. package/dist/commands/serve.d.ts.map +1 -1
  67. package/dist/commands/serve.js +73 -1
  68. package/dist/commands/serve.js.map +1 -1
  69. package/dist/commands/session-cleanup.js +1 -0
  70. package/dist/commands/session-cleanup.js.map +1 -1
  71. package/dist/commands/session-summary.d.ts.map +1 -1
  72. package/dist/commands/session-summary.js +180 -3
  73. package/dist/commands/session-summary.js.map +1 -1
  74. package/dist/commands/setup-ci.d.ts +17 -1
  75. package/dist/commands/setup-ci.d.ts.map +1 -1
  76. package/dist/commands/setup-ci.js +202 -51
  77. package/dist/commands/setup-ci.js.map +1 -1
  78. package/dist/commands/share.js +1 -1
  79. package/dist/commands/share.js.map +1 -1
  80. package/dist/commands/stats.d.ts +8 -0
  81. package/dist/commands/stats.d.ts.map +1 -0
  82. package/dist/commands/stats.js +164 -0
  83. package/dist/commands/stats.js.map +1 -0
  84. package/dist/commands/team-ledger.d.ts +11 -0
  85. package/dist/commands/team-ledger.d.ts.map +1 -0
  86. package/dist/commands/team-ledger.js +74 -0
  87. package/dist/commands/team-ledger.js.map +1 -0
  88. package/dist/commands/team-metrics.d.ts +8 -0
  89. package/dist/commands/team-metrics.d.ts.map +1 -0
  90. package/dist/commands/team-metrics.js +57 -0
  91. package/dist/commands/team-metrics.js.map +1 -0
  92. package/dist/commands/upgrade.d.ts +6 -0
  93. package/dist/commands/upgrade.d.ts.map +1 -0
  94. package/dist/commands/upgrade.js +39 -0
  95. package/dist/commands/upgrade.js.map +1 -0
  96. package/dist/commands/verify.d.ts.map +1 -1
  97. package/dist/commands/verify.js +35 -3
  98. package/dist/commands/verify.js.map +1 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +256 -36
  101. package/dist/index.js.map +1 -1
  102. package/dist/intent/extractor.d.ts +15 -0
  103. package/dist/intent/extractor.d.ts.map +1 -0
  104. package/dist/intent/extractor.js +149 -0
  105. package/dist/intent/extractor.js.map +1 -0
  106. package/dist/intent/fetcher.d.ts +33 -0
  107. package/dist/intent/fetcher.d.ts.map +1 -0
  108. package/dist/intent/fetcher.js +364 -0
  109. package/dist/intent/fetcher.js.map +1 -0
  110. package/dist/intent/loader.d.ts +26 -0
  111. package/dist/intent/loader.d.ts.map +1 -0
  112. package/dist/intent/loader.js +80 -0
  113. package/dist/intent/loader.js.map +1 -0
  114. package/dist/intent/types.d.ts +33 -0
  115. package/dist/intent/types.d.ts.map +1 -0
  116. package/dist/intent/types.js +9 -0
  117. package/dist/intent/types.js.map +1 -0
  118. package/dist/project-config.d.ts +38 -0
  119. package/dist/project-config.d.ts.map +1 -0
  120. package/dist/project-config.js +206 -0
  121. package/dist/project-config.js.map +1 -0
  122. package/dist/review-intelligence/detectors/architecture-graph.d.ts +18 -0
  123. package/dist/review-intelligence/detectors/architecture-graph.d.ts.map +1 -0
  124. package/dist/review-intelligence/detectors/architecture-graph.js +73 -0
  125. package/dist/review-intelligence/detectors/architecture-graph.js.map +1 -0
  126. package/dist/review-intelligence/detectors/pack-rules.d.ts +16 -0
  127. package/dist/review-intelligence/detectors/pack-rules.d.ts.map +1 -0
  128. package/dist/review-intelligence/detectors/pack-rules.js +107 -0
  129. package/dist/review-intelligence/detectors/pack-rules.js.map +1 -0
  130. package/dist/review-intelligence/fixes/index.d.ts +18 -0
  131. package/dist/review-intelligence/fixes/index.d.ts.map +1 -1
  132. package/dist/review-intelligence/fixes/index.js +198 -9
  133. package/dist/review-intelligence/fixes/index.js.map +1 -1
  134. package/dist/review-intelligence/index.d.ts +4 -1
  135. package/dist/review-intelligence/index.d.ts.map +1 -1
  136. package/dist/review-intelligence/index.js +20 -3
  137. package/dist/review-intelligence/index.js.map +1 -1
  138. package/dist/review-intelligence/invariants.d.ts +15 -0
  139. package/dist/review-intelligence/invariants.d.ts.map +1 -1
  140. package/dist/review-intelligence/invariants.js +36 -5
  141. package/dist/review-intelligence/invariants.js.map +1 -1
  142. package/dist/review-intelligence/types.d.ts +16 -12
  143. package/dist/review-intelligence/types.d.ts.map +1 -1
  144. package/dist/review-intelligence/types.js +9 -1
  145. package/dist/review-intelligence/types.js.map +1 -1
  146. package/dist/templates/claude-md.d.ts.map +1 -1
  147. package/dist/templates/claude-md.js +32 -127
  148. package/dist/templates/claude-md.js.map +1 -1
  149. package/dist/templates/config.js +4 -4
  150. package/dist/templates/config.js.map +1 -1
  151. package/dist/templates/hooks.d.ts +3 -1
  152. package/dist/templates/hooks.d.ts.map +1 -1
  153. package/dist/templates/hooks.js +101 -2
  154. package/dist/templates/hooks.js.map +1 -1
  155. package/package.json +11 -10
  156. 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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"}