@promptci/core 0.0.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.
Files changed (179) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +30 -0
  3. package/dist/agent-practices.d.ts +22 -0
  4. package/dist/agent-practices.d.ts.map +1 -0
  5. package/dist/agent-practices.js +582 -0
  6. package/dist/agent-practices.js.map +1 -0
  7. package/dist/baseline.d.ts +40 -0
  8. package/dist/baseline.d.ts.map +1 -0
  9. package/dist/baseline.js +172 -0
  10. package/dist/baseline.js.map +1 -0
  11. package/dist/canonical-owner.d.ts +3 -0
  12. package/dist/canonical-owner.d.ts.map +1 -0
  13. package/dist/canonical-owner.js +131 -0
  14. package/dist/canonical-owner.js.map +1 -0
  15. package/dist/cheap-model-routing.d.ts +4 -0
  16. package/dist/cheap-model-routing.d.ts.map +1 -0
  17. package/dist/cheap-model-routing.js +43 -0
  18. package/dist/cheap-model-routing.js.map +1 -0
  19. package/dist/ci-alignment.d.ts +10 -0
  20. package/dist/ci-alignment.d.ts.map +1 -0
  21. package/dist/ci-alignment.js +343 -0
  22. package/dist/ci-alignment.js.map +1 -0
  23. package/dist/cli-output-filter.d.ts +16 -0
  24. package/dist/cli-output-filter.d.ts.map +1 -0
  25. package/dist/cli-output-filter.js +88 -0
  26. package/dist/cli-output-filter.js.map +1 -0
  27. package/dist/command-validity.d.ts +12 -0
  28. package/dist/command-validity.d.ts.map +1 -0
  29. package/dist/command-validity.js +543 -0
  30. package/dist/command-validity.js.map +1 -0
  31. package/dist/conflicts.d.ts +49 -0
  32. package/dist/conflicts.d.ts.map +1 -0
  33. package/dist/conflicts.js +1065 -0
  34. package/dist/conflicts.js.map +1 -0
  35. package/dist/context-analysis.d.ts +15 -0
  36. package/dist/context-analysis.d.ts.map +1 -0
  37. package/dist/context-analysis.js +24 -0
  38. package/dist/context-analysis.js.map +1 -0
  39. package/dist/context-bloat.d.ts +17 -0
  40. package/dist/context-bloat.d.ts.map +1 -0
  41. package/dist/context-bloat.js +148 -0
  42. package/dist/context-bloat.js.map +1 -0
  43. package/dist/context-cost.d.ts +4 -0
  44. package/dist/context-cost.d.ts.map +1 -0
  45. package/dist/context-cost.js +70 -0
  46. package/dist/context-cost.js.map +1 -0
  47. package/dist/context-optimizer.d.ts +14 -0
  48. package/dist/context-optimizer.d.ts.map +1 -0
  49. package/dist/context-optimizer.js +219 -0
  50. package/dist/context-optimizer.js.map +1 -0
  51. package/dist/context-recommender.d.ts +3 -0
  52. package/dist/context-recommender.d.ts.map +1 -0
  53. package/dist/context-recommender.js +329 -0
  54. package/dist/context-recommender.js.map +1 -0
  55. package/dist/dead-references.d.ts +33 -0
  56. package/dist/dead-references.d.ts.map +1 -0
  57. package/dist/dead-references.js +607 -0
  58. package/dist/dead-references.js.map +1 -0
  59. package/dist/detectors.d.ts +11 -0
  60. package/dist/detectors.d.ts.map +1 -0
  61. package/dist/detectors.js +160 -0
  62. package/dist/detectors.js.map +1 -0
  63. package/dist/duplicates.d.ts +36 -0
  64. package/dist/duplicates.d.ts.map +1 -0
  65. package/dist/duplicates.js +436 -0
  66. package/dist/duplicates.js.map +1 -0
  67. package/dist/fix-engine.d.ts +16 -0
  68. package/dist/fix-engine.d.ts.map +1 -0
  69. package/dist/fix-engine.js +179 -0
  70. package/dist/fix-engine.js.map +1 -0
  71. package/dist/framework-packs.d.ts +8 -0
  72. package/dist/framework-packs.d.ts.map +1 -0
  73. package/dist/framework-packs.js +22 -0
  74. package/dist/framework-packs.js.map +1 -0
  75. package/dist/frameworks/dotnet.d.ts +4 -0
  76. package/dist/frameworks/dotnet.d.ts.map +1 -0
  77. package/dist/frameworks/dotnet.js +77 -0
  78. package/dist/frameworks/dotnet.js.map +1 -0
  79. package/dist/frameworks/go.d.ts +4 -0
  80. package/dist/frameworks/go.d.ts.map +1 -0
  81. package/dist/frameworks/go.js +39 -0
  82. package/dist/frameworks/go.js.map +1 -0
  83. package/dist/frameworks/nextjs.d.ts +4 -0
  84. package/dist/frameworks/nextjs.d.ts.map +1 -0
  85. package/dist/frameworks/nextjs.js +66 -0
  86. package/dist/frameworks/nextjs.js.map +1 -0
  87. package/dist/frameworks/python.d.ts +4 -0
  88. package/dist/frameworks/python.d.ts.map +1 -0
  89. package/dist/frameworks/python.js +66 -0
  90. package/dist/frameworks/python.js.map +1 -0
  91. package/dist/frameworks/rust.d.ts +4 -0
  92. package/dist/frameworks/rust.d.ts.map +1 -0
  93. package/dist/frameworks/rust.js +72 -0
  94. package/dist/frameworks/rust.js.map +1 -0
  95. package/dist/frameworks/unity.d.ts +4 -0
  96. package/dist/frameworks/unity.d.ts.map +1 -0
  97. package/dist/frameworks/unity.js +74 -0
  98. package/dist/frameworks/unity.js.map +1 -0
  99. package/dist/health-score.d.ts +37 -0
  100. package/dist/health-score.d.ts.map +1 -0
  101. package/dist/health-score.js +164 -0
  102. package/dist/health-score.js.map +1 -0
  103. package/dist/index.d.ts +31 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +23 -0
  106. package/dist/index.js.map +1 -0
  107. package/dist/llm.d.ts +6 -0
  108. package/dist/llm.d.ts.map +1 -0
  109. package/dist/llm.js +67 -0
  110. package/dist/llm.js.map +1 -0
  111. package/dist/manifest-consistency.d.ts +37 -0
  112. package/dist/manifest-consistency.d.ts.map +1 -0
  113. package/dist/manifest-consistency.js +659 -0
  114. package/dist/manifest-consistency.js.map +1 -0
  115. package/dist/mcp-detector.d.ts +4 -0
  116. package/dist/mcp-detector.d.ts.map +1 -0
  117. package/dist/mcp-detector.js +131 -0
  118. package/dist/mcp-detector.js.map +1 -0
  119. package/dist/missing-context.d.ts +15 -0
  120. package/dist/missing-context.d.ts.map +1 -0
  121. package/dist/missing-context.js +517 -0
  122. package/dist/missing-context.js.map +1 -0
  123. package/dist/native-tool-preference.d.ts +20 -0
  124. package/dist/native-tool-preference.d.ts.map +1 -0
  125. package/dist/native-tool-preference.js +94 -0
  126. package/dist/native-tool-preference.js.map +1 -0
  127. package/dist/output-verbosity.d.ts +3 -0
  128. package/dist/output-verbosity.d.ts.map +1 -0
  129. package/dist/output-verbosity.js +83 -0
  130. package/dist/output-verbosity.js.map +1 -0
  131. package/dist/product-boundary.d.ts +11 -0
  132. package/dist/product-boundary.d.ts.map +1 -0
  133. package/dist/product-boundary.js +301 -0
  134. package/dist/product-boundary.js.map +1 -0
  135. package/dist/project-type.d.ts +15 -0
  136. package/dist/project-type.d.ts.map +1 -0
  137. package/dist/project-type.js +116 -0
  138. package/dist/project-type.js.map +1 -0
  139. package/dist/prompt-cache.d.ts +3 -0
  140. package/dist/prompt-cache.d.ts.map +1 -0
  141. package/dist/prompt-cache.js +151 -0
  142. package/dist/prompt-cache.js.map +1 -0
  143. package/dist/repo-context.d.ts +37 -0
  144. package/dist/repo-context.d.ts.map +1 -0
  145. package/dist/repo-context.js +221 -0
  146. package/dist/repo-context.js.map +1 -0
  147. package/dist/report.d.ts +87 -0
  148. package/dist/report.d.ts.map +1 -0
  149. package/dist/report.js +558 -0
  150. package/dist/report.js.map +1 -0
  151. package/dist/scan.d.ts +7 -0
  152. package/dist/scan.d.ts.map +1 -0
  153. package/dist/scan.js +43 -0
  154. package/dist/scan.js.map +1 -0
  155. package/dist/scanner.d.ts +3 -0
  156. package/dist/scanner.d.ts.map +1 -0
  157. package/dist/scanner.js +216 -0
  158. package/dist/scanner.js.map +1 -0
  159. package/dist/security-pack.d.ts +4 -0
  160. package/dist/security-pack.d.ts.map +1 -0
  161. package/dist/security-pack.js +403 -0
  162. package/dist/security-pack.js.map +1 -0
  163. package/dist/stale-instructions.d.ts +20 -0
  164. package/dist/stale-instructions.d.ts.map +1 -0
  165. package/dist/stale-instructions.js +269 -0
  166. package/dist/stale-instructions.js.map +1 -0
  167. package/dist/suppression.d.ts +64 -0
  168. package/dist/suppression.d.ts.map +1 -0
  169. package/dist/suppression.js +338 -0
  170. package/dist/suppression.js.map +1 -0
  171. package/dist/types.d.ts +128 -0
  172. package/dist/types.d.ts.map +1 -0
  173. package/dist/types.js +3 -0
  174. package/dist/types.js.map +1 -0
  175. package/dist/vague-guidance.d.ts +12 -0
  176. package/dist/vague-guidance.d.ts.map +1 -0
  177. package/dist/vague-guidance.js +235 -0
  178. package/dist/vague-guidance.js.map +1 -0
  179. package/package.json +54 -0
@@ -0,0 +1,72 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ export function detectRust(context) {
4
+ const issues = [];
5
+ const { repoRoot, files } = context;
6
+ const hasCargoToml = fs.existsSync(path.join(repoRoot, 'Cargo.toml'));
7
+ const combinedContent = files.map(f => f.content).join('\n');
8
+ const hasRustMentions = /\bcargo\.toml\b|\bcargo\s+(build|test|run|clippy|fmt)\b/i.test(combinedContent);
9
+ if (!hasCargoToml && !hasRustMentions) {
10
+ return [];
11
+ }
12
+ const allFilePaths = files.map(f => f.path);
13
+ // 1. Missing cargo verification commands
14
+ const hasCargoCommands = /cargo\s+(test|clippy|fmt)/i.test(combinedContent);
15
+ if (!hasCargoCommands) {
16
+ issues.push({
17
+ id: 'rust-missing-verification-commands',
18
+ severity: 'warning',
19
+ category: 'structure',
20
+ title: 'Missing Rust Verification Commands',
21
+ summary: 'Rust project detected, but instructions do not mention Cargo verification commands like "cargo test" or "cargo clippy".',
22
+ filePaths: allFilePaths,
23
+ locations: [],
24
+ evidence: ['Rust detected, but no cargo test/clippy/fmt commands found in instructions.'],
25
+ recommendation: 'Add instructions telling the agent to run cargo test, cargo clippy, and cargo fmt to verify changes.',
26
+ fixRecipe: 'Before saying work is complete, verify changes by running cargo fmt, cargo clippy, and cargo test.',
27
+ confidence: 0.85,
28
+ });
29
+ }
30
+ // 2. MSRV check against Cargo.toml
31
+ let rustVersion;
32
+ if (hasCargoToml) {
33
+ try {
34
+ const cargoContent = fs.readFileSync(path.join(repoRoot, 'Cargo.toml'), 'utf-8');
35
+ const match = /^rust-version\s*=\s*["'](.*?)["']/m.exec(cargoContent);
36
+ if (match) {
37
+ rustVersion = match[1]?.trim();
38
+ }
39
+ }
40
+ catch {
41
+ // ignore
42
+ }
43
+ }
44
+ if (rustVersion) {
45
+ const majorMinor = (version) => {
46
+ const match = /^(\d+)\.(\d+)/.exec(version);
47
+ return match ? `${match[1]}.${match[2]}` : undefined;
48
+ };
49
+ const rustVersionRe = /\bRust\s+(\d+\.\d+(?:\.\d+)?)\b/i;
50
+ const match = rustVersionRe.exec(combinedContent);
51
+ if (match) {
52
+ const instrVersion = match[1];
53
+ if (majorMinor(instrVersion) !== majorMinor(rustVersion)) {
54
+ issues.push({
55
+ id: 'rust-version-mismatch',
56
+ severity: 'warning',
57
+ category: 'stale_instruction',
58
+ title: 'Rust Version Mismatch',
59
+ summary: `Instructions mention Rust version ${instrVersion}, but Cargo.toml specifies rust-version = "${rustVersion}".`,
60
+ filePaths: allFilePaths,
61
+ locations: [],
62
+ evidence: [`Cargo.toml requires rust-version = ${rustVersion}; instructions mention Rust ${instrVersion}`],
63
+ recommendation: `Update instructions to match the Rust version specified in Cargo.toml (${rustVersion}).`,
64
+ fixRecipe: `Target Rust ${rustVersion} as the Minimum Supported Rust Version (MSRV) for this project.`,
65
+ confidence: 0.8,
66
+ });
67
+ }
68
+ }
69
+ }
70
+ return issues;
71
+ }
72
+ //# sourceMappingURL=rust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rust.js","sourceRoot":"","sources":["../../src/frameworks/rust.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { RepoContext } from '../repo-context.js';
2
+ import type { PromptCiIssue } from '../types.js';
3
+ export declare function detectUnity(context: RepoContext): PromptCiIssue[];
4
+ //# sourceMappingURL=unity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unity.d.ts","sourceRoot":"","sources":["../../src/frameworks/unity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CA+EjE"}
@@ -0,0 +1,74 @@
1
+ import * as path from 'node:path';
2
+ import * as fs from 'node:fs';
3
+ export function detectUnity(context) {
4
+ const issues = [];
5
+ const { repoRoot, files } = context;
6
+ const hasAssets = fs.existsSync(path.join(repoRoot, 'Assets'));
7
+ const hasProjectVersion = fs.existsSync(path.join(repoRoot, 'ProjectSettings', 'ProjectVersion.txt'));
8
+ const combinedContent = files.map(f => f.content).join('\n');
9
+ const hasUnityMentions = /\bunity\b.*\b(lts|editor|hub|engine)\b|\bmonobehaviour\b|\bunityengine\b|\bgameobject\b|\bprefab\b|\bscriptableobject\b/i.test(combinedContent);
10
+ if (!(hasAssets && hasProjectVersion) && !hasUnityMentions) {
11
+ return [];
12
+ }
13
+ const allFilePaths = files.map(f => f.path);
14
+ // 1. MonoBehaviour lifecycle guidance
15
+ const hasMonoBehaviourGuidance = /monobehaviour\s+(?:lifecycle|guidance|rules?)|\blifecycle\s+(?:method|methods|guidance|rules?)|instantiate\b.*monobehaviour|avoid\b.*update|new\s+monobehaviour|awake\(\)|start\(\)|update\(\)/i.test(combinedContent);
16
+ if (!hasMonoBehaviourGuidance) {
17
+ issues.push({
18
+ id: 'unity-missing-monobehaviour-guidance',
19
+ severity: 'warning',
20
+ category: 'structure',
21
+ title: 'Missing Unity MonoBehaviour Lifecycle Guidance',
22
+ summary: 'Unity project detected, but instructions lack guidelines on MonoBehaviour lifecycle (e.g. not calling "new" on MonoBehaviours, avoiding empty Update methods).',
23
+ filePaths: allFilePaths,
24
+ locations: [],
25
+ evidence: ['Unity detected, but no MonoBehaviour lifecycle rules found in instructions.'],
26
+ recommendation: 'Add guidance warning never to use "new" to instantiate MonoBehaviours, and advising on efficient Update() / Awake() / Start() usage.',
27
+ fixRecipe: 'Do not instantiate MonoBehaviours using the "new" keyword; always use GameObject.AddComponent or Object.Instantiate. Avoid leaving empty Awake, Start, or Update methods in scripts as they still incur Unity lifecycle overhead.',
28
+ confidence: 0.8,
29
+ });
30
+ }
31
+ // 2. Serialization & Prefab Safety guidance
32
+ // FW2: bare 'prefab' also satisfies hasUnityMentions above — a file whose
33
+ // ONLY Unity signal is a passing mention of "prefab" (e.g. "we use prefabs
34
+ // for reusable components") would enable the pack AND simultaneously
35
+ // satisfy this guidance check with the exact same word, so the
36
+ // serialization/prefab-safety warning could never fire for that file. The
37
+ // bare word is removed here; "prefab" only counts as real GUIDANCE (not
38
+ // just a mention) when paired with a guidance-indicating term.
39
+ const hasSerializationGuidance = /\[serializefield\]|serializefield\b|prefab\s+(?:safety|workflow|guidance|rules?)|meta\s+file/i.test(combinedContent);
40
+ if (!hasSerializationGuidance) {
41
+ issues.push({
42
+ id: 'unity-missing-serialization-guidance',
43
+ severity: 'warning',
44
+ category: 'structure',
45
+ title: 'Missing Unity Serialization and Prefab Safety Guidance',
46
+ summary: 'Unity project detected, but instructions lack safety rules for Prefabs and [SerializeField] parameters.',
47
+ filePaths: allFilePaths,
48
+ locations: [],
49
+ evidence: ['Unity detected, but no SerializeField or prefab rules found in instructions.'],
50
+ recommendation: 'Add rules for using [SerializeField] for private variables to expose them in the inspector, and avoiding editing .meta files manually.',
51
+ fixRecipe: 'Use [SerializeField] to expose private fields in the Unity Inspector instead of making them public. Never manually edit or delete .meta files; let the Unity Editor manage them to prevent serialization breakages.',
52
+ confidence: 0.8,
53
+ });
54
+ }
55
+ // 3. Play Mode & Test Runner verification guidance
56
+ const hasTestRunnerGuidance = /play\s+mode|test\s+runner|unity\s+test/i.test(combinedContent);
57
+ if (!hasTestRunnerGuidance) {
58
+ issues.push({
59
+ id: 'unity-missing-test-guidance',
60
+ severity: 'info',
61
+ category: 'structure',
62
+ title: 'Missing Unity Play Mode and Test Runner Guidance',
63
+ summary: 'Unity project detected, but instructions do not guide agents to test changes in Play Mode or Unity Test Runner.',
64
+ filePaths: allFilePaths,
65
+ locations: [],
66
+ evidence: ['Unity detected, but no Play Mode/Test Runner verification found in instructions.'],
67
+ recommendation: 'Add instructions telling agents to run tests using Unity Test Runner or test changes in Play Mode.',
68
+ fixRecipe: 'Verify gameplay and UI changes by testing in the Unity Editor Play Mode or running Unity Test Runner (Window > General > Test Runner).',
69
+ confidence: 0.75,
70
+ });
71
+ }
72
+ return issues;
73
+ }
74
+ //# sourceMappingURL=unity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unity.js","sourceRoot":"","sources":["../../src/frameworks/unity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Health score computation and top-fix selection for PromptCI.
3
+ *
4
+ * Both functions are pure and deterministic — no randomness, same output
5
+ * for the same input regardless of call order.
6
+ */
7
+ import type { PromptCiIssue, TopFix } from './types.js';
8
+ /**
9
+ * Compute a health score from 0–100 based on issue severity and confidence.
10
+ *
11
+ * Starts at 100. Each issue subtracts (severityWeight × confidence), subject to
12
+ * per-category caps so a single noisy detector cannot drive the score to zero on
13
+ * its own.
14
+ *
15
+ * Result is clamped to [0, 100] and rounded to the nearest integer.
16
+ */
17
+ export declare function computeHealthScore(issues: PromptCiIssue[]): number;
18
+ /**
19
+ * Classify the likely blast-radius impact of an issue.
20
+ */
21
+ export declare function getIssueImpact(issue: PromptCiIssue): 'high' | 'medium' | 'low';
22
+ /**
23
+ * Select up to 3 top fixes from the issue list.
24
+ *
25
+ * Priority order (descending):
26
+ * 1. Severity weight (critical → high → warning → info)
27
+ * 2. Confidence (higher first)
28
+ * 3. Blast-radius impact (high → medium → low)
29
+ * 4. Number of files affected (more files = higher priority)
30
+ * 5. Category string (alphabetical, for stable tie-breaking)
31
+ * 6. Issue id (alphabetical, final stable tie-breaker)
32
+ *
33
+ * At most one fix per category is included to keep top-fixes diverse and
34
+ * actionable — the highest-priority issue per category wins.
35
+ */
36
+ export declare function selectTopFixes(issues: PromptCiIssue[]): TopFix[];
37
+ //# sourceMappingURL=health-score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-score.d.ts","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAwBtF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAoBlE;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAiE9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAuChE"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Health score computation and top-fix selection for PromptCI.
3
+ *
4
+ * Both functions are pure and deterministic — no randomness, same output
5
+ * for the same input regardless of call order.
6
+ */
7
+ const SEVERITY_WEIGHT = {
8
+ critical: 18,
9
+ high: 10,
10
+ warning: 4,
11
+ info: 1,
12
+ };
13
+ /**
14
+ * BUG-D1: Per-category maximum deduction caps.
15
+ *
16
+ * Without these, a repo with 30+ dead-reference warnings (structure category)
17
+ * accumulates >100 points of penalty and bottoms out at 0 even when all other
18
+ * detectors are clean. Caps prevent a single noisy category from dominating the
19
+ * score while still penalising repos that genuinely have many issues.
20
+ */
21
+ const CATEGORY_DEDUCTION_CAP = {
22
+ structure: 30, // dead references
23
+ stale_instruction: 15,
24
+ duplicate: 20,
25
+ vague_guidance: 10,
26
+ };
27
+ /**
28
+ * Compute a health score from 0–100 based on issue severity and confidence.
29
+ *
30
+ * Starts at 100. Each issue subtracts (severityWeight × confidence), subject to
31
+ * per-category caps so a single noisy detector cannot drive the score to zero on
32
+ * its own.
33
+ *
34
+ * Result is clamped to [0, 100] and rounded to the nearest integer.
35
+ */
36
+ export function computeHealthScore(issues) {
37
+ let score = 100;
38
+ const categoryDeductions = new Map();
39
+ for (const issue of issues) {
40
+ const deduction = (SEVERITY_WEIGHT[issue.severity] ?? 0) * issue.confidence;
41
+ const cap = CATEGORY_DEDUCTION_CAP[issue.category];
42
+ if (cap !== undefined) {
43
+ const soFar = categoryDeductions.get(issue.category) ?? 0;
44
+ const allowed = Math.max(0, cap - soFar);
45
+ const actual = Math.min(deduction, allowed);
46
+ categoryDeductions.set(issue.category, soFar + actual);
47
+ score -= actual;
48
+ }
49
+ else {
50
+ score -= deduction;
51
+ }
52
+ }
53
+ return Math.round(Math.max(0, Math.min(100, score)));
54
+ }
55
+ const IMPACT_WEIGHT = {
56
+ high: 3,
57
+ medium: 2,
58
+ low: 1,
59
+ };
60
+ /**
61
+ * Classify the likely blast-radius impact of an issue.
62
+ */
63
+ export function getIssueImpact(issue) {
64
+ if (issue.impact)
65
+ return issue.impact;
66
+ const cat = issue.category;
67
+ const title = issue.title.toLowerCase();
68
+ // 1. Security & Privacy -> High
69
+ if (cat === 'security' ||
70
+ title.includes('secret') ||
71
+ title.includes('auth') ||
72
+ title.includes('supabase') ||
73
+ title.includes('service role') ||
74
+ title.includes('upload')) {
75
+ return 'high';
76
+ }
77
+ // 2. Build Validation & Commands -> High
78
+ if (cat === 'command_validity' ||
79
+ title.includes('build') ||
80
+ title.includes('test') ||
81
+ title.includes('lint') ||
82
+ title.includes('run script') ||
83
+ title.includes('package manager') ||
84
+ title.includes('workflow')) {
85
+ return 'high';
86
+ }
87
+ // 3. Deployment -> High
88
+ if (title.includes('deploy') || title.includes('vercel') || title.includes('ci/cd') || title.includes('release')) {
89
+ return 'high';
90
+ }
91
+ // 4. Architecture & Framework choices -> High
92
+ if (title.includes('framework') ||
93
+ title.includes('router') ||
94
+ title.includes('database') ||
95
+ title.includes('version conflict') ||
96
+ title.includes('package manager mismatch')) {
97
+ return 'high';
98
+ }
99
+ // 5. Tool Behavior / Agent Practices -> High
100
+ if (cat === 'agent_practices' ||
101
+ title.includes('verification') ||
102
+ title.includes('scope') ||
103
+ title.includes('read-before-edit') ||
104
+ title.includes('honesty') ||
105
+ title.includes('plan-first')) {
106
+ return 'high';
107
+ }
108
+ // 6. Style & Low-Risk Duplication -> Low
109
+ if (cat === 'vague_guidance' || cat === 'duplicate' || title.includes('duplicate') || title.includes('vague')) {
110
+ return 'low';
111
+ }
112
+ return 'medium';
113
+ }
114
+ /**
115
+ * Select up to 3 top fixes from the issue list.
116
+ *
117
+ * Priority order (descending):
118
+ * 1. Severity weight (critical → high → warning → info)
119
+ * 2. Confidence (higher first)
120
+ * 3. Blast-radius impact (high → medium → low)
121
+ * 4. Number of files affected (more files = higher priority)
122
+ * 5. Category string (alphabetical, for stable tie-breaking)
123
+ * 6. Issue id (alphabetical, final stable tie-breaker)
124
+ *
125
+ * At most one fix per category is included to keep top-fixes diverse and
126
+ * actionable — the highest-priority issue per category wins.
127
+ */
128
+ export function selectTopFixes(issues) {
129
+ const sorted = [...issues].sort((a, b) => {
130
+ const weightDiff = (SEVERITY_WEIGHT[b.severity] ?? 0) - (SEVERITY_WEIGHT[a.severity] ?? 0);
131
+ if (weightDiff !== 0)
132
+ return weightDiff;
133
+ const confDiff = b.confidence - a.confidence;
134
+ if (confDiff !== 0)
135
+ return confDiff;
136
+ const impactDiff = IMPACT_WEIGHT[getIssueImpact(b)] - IMPACT_WEIGHT[getIssueImpact(a)];
137
+ if (impactDiff !== 0)
138
+ return impactDiff;
139
+ const filesDiff = b.filePaths.length - a.filePaths.length;
140
+ if (filesDiff !== 0)
141
+ return filesDiff;
142
+ const catDiff = a.category.localeCompare(b.category);
143
+ if (catDiff !== 0)
144
+ return catDiff;
145
+ return a.id.localeCompare(b.id);
146
+ });
147
+ const fixes = [];
148
+ const seenCategories = new Set();
149
+ for (const issue of sorted) {
150
+ if (fixes.length >= 3)
151
+ break;
152
+ // One fix per category — avoids flooding top-fixes with e.g. 3 duplicate issues
153
+ if (seenCategories.has(issue.category))
154
+ continue;
155
+ seenCategories.add(issue.category);
156
+ fixes.push({
157
+ title: issue.title,
158
+ reason: issue.summary,
159
+ suggestedAction: issue.recommendation,
160
+ });
161
+ }
162
+ return fixes;
163
+ }
164
+ //# sourceMappingURL=health-score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-score.js","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /** Root export for @promptci/core */
2
+ export * from './types.js';
3
+ export { scanFiles } from './scanner.js';
4
+ export { detectProjectType, detectProjectTypeFromContent } from './project-type.js';
5
+ export { detectDuplicates, detectDuplicateHeadings, normalizeSection } from './duplicates.js';
6
+ export { detectConflicts, detectVersionConflicts, detectCompetingTechConflicts } from './conflicts.js';
7
+ export { detectDeadReferences } from './dead-references.js';
8
+ export { detectAgentPractices } from './agent-practices.js';
9
+ export { parseSuppressions, buildValidationIssues, applySuppressions } from './suppression.js';
10
+ export type { SuppressionAnnotation } from './suppression.js';
11
+ export { computeHealthScore, selectTopFixes } from './health-score.js';
12
+ export { generateMarkdownReport, generateJsonReport, writeReport, readHistoryIndex, archiveExistingReport, historyIndexPath } from './report.js';
13
+ export type { WriteReportOptions, HistoryEntry } from './report.js';
14
+ export { detectManifestConsistency } from './manifest-consistency.js';
15
+ export type { ManifestData } from './manifest-consistency.js';
16
+ export { buildRepoContext, parsePackageJsonFacts } from './repo-context.js';
17
+ export type { RepoContext, PackageJsonFacts, WorkflowFacts, WorkflowCommand } from './repo-context.js';
18
+ export { runDetectors } from './detectors.js';
19
+ export type { DetectorDefinition, DetectorGroup } from './detectors.js';
20
+ export { analyzeContext } from './context-analysis.js';
21
+ export type { ContextAnalysis } from './context-analysis.js';
22
+ export { scan } from './scan.js';
23
+ export { computeFingerprint, createBaseline, filterNewIssues, assertValidBaseline } from './baseline.js';
24
+ export { applyFixRecipe, resolveSafePath } from './fix-engine.js';
25
+ export { detectCliOutputFilter } from './cli-output-filter.js';
26
+ export { detectNativeToolPreference } from './native-tool-preference.js';
27
+ export type { FileChange } from './fix-engine.js';
28
+ export { callLlm } from './llm.js';
29
+ export { optimizeContext } from './context-optimizer.js';
30
+ export type { OptimizeOptions, OptimizeResult } from './context-optimizer.js';
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC/F,YAAY,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjJ,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AACtE,YAAY,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvG,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,23 @@
1
+ /** Root export for @promptci/core */
2
+ export * from './types.js';
3
+ export { scanFiles } from './scanner.js';
4
+ export { detectProjectType, detectProjectTypeFromContent } from './project-type.js';
5
+ export { detectDuplicates, detectDuplicateHeadings, normalizeSection } from './duplicates.js';
6
+ export { detectConflicts, detectVersionConflicts, detectCompetingTechConflicts } from './conflicts.js';
7
+ export { detectDeadReferences } from './dead-references.js';
8
+ export { detectAgentPractices } from './agent-practices.js';
9
+ export { parseSuppressions, buildValidationIssues, applySuppressions } from './suppression.js';
10
+ export { computeHealthScore, selectTopFixes } from './health-score.js';
11
+ export { generateMarkdownReport, generateJsonReport, writeReport, readHistoryIndex, archiveExistingReport, historyIndexPath } from './report.js';
12
+ export { detectManifestConsistency } from './manifest-consistency.js';
13
+ export { buildRepoContext, parsePackageJsonFacts } from './repo-context.js';
14
+ export { runDetectors } from './detectors.js';
15
+ export { analyzeContext } from './context-analysis.js';
16
+ export { scan } from './scan.js';
17
+ export { computeFingerprint, createBaseline, filterNewIssues, assertValidBaseline } from './baseline.js';
18
+ export { applyFixRecipe, resolveSafePath } from './fix-engine.js';
19
+ export { detectCliOutputFilter } from './cli-output-filter.js';
20
+ export { detectNativeToolPreference } from './native-tool-preference.js';
21
+ export { callLlm } from './llm.js';
22
+ export { optimizeContext } from './context-optimizer.js';
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AACvG,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE/F,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,WAAW,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEjJ,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAEtE,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/llm.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Lightweight LLM Client wrapper using Node's native fetch.
3
+ * Gated by OPENAI_API_KEY and ANTHROPIC_API_KEY.
4
+ */
5
+ export declare function callLlm(systemPrompt: string, userPrompt: string, responseFormatJson?: boolean): Promise<string>;
6
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAsB,OAAO,CAC3B,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAClB,kBAAkB,GAAE,OAAe,GAClC,OAAO,CAAC,MAAM,CAAC,CAgFjB"}
package/dist/llm.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Lightweight LLM Client wrapper using Node's native fetch.
3
+ * Gated by OPENAI_API_KEY and ANTHROPIC_API_KEY.
4
+ */
5
+ export async function callLlm(systemPrompt, userPrompt, responseFormatJson = false) {
6
+ const openaiKey = process.env.OPENAI_API_KEY;
7
+ const anthropicKey = process.env.ANTHROPIC_API_KEY;
8
+ if (!openaiKey && !anthropicKey) {
9
+ throw new Error('Please set OPENAI_API_KEY or ANTHROPIC_API_KEY to use this feature.');
10
+ }
11
+ const modelOverride = process.env.PROMPTCI_LLM_MODEL;
12
+ if (openaiKey) {
13
+ const model = modelOverride ?? 'gpt-4o';
14
+ const body = {
15
+ model,
16
+ messages: [
17
+ { role: 'system', content: systemPrompt },
18
+ { role: 'user', content: userPrompt }
19
+ ],
20
+ };
21
+ if (responseFormatJson) {
22
+ body.response_format = { type: 'json_object' };
23
+ }
24
+ const res = await globalThis.fetch('https://api.openai.com/v1/chat/completions', {
25
+ method: 'POST',
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ 'Authorization': `Bearer ${openaiKey}`,
29
+ },
30
+ body: JSON.stringify(body),
31
+ });
32
+ if (!res.ok) {
33
+ const errText = await res.text();
34
+ throw new Error(`OpenAI API request failed (${res.status}): ${errText}`);
35
+ }
36
+ const json = await res.json();
37
+ return json.choices?.[0]?.message?.content || '';
38
+ }
39
+ else {
40
+ // Anthropic
41
+ const model = modelOverride ?? 'claude-3-5-sonnet-latest';
42
+ const body = {
43
+ model,
44
+ max_tokens: 4096,
45
+ system: systemPrompt,
46
+ messages: [
47
+ { role: 'user', content: userPrompt }
48
+ ],
49
+ };
50
+ const res = await globalThis.fetch('https://api.anthropic.com/v1/messages', {
51
+ method: 'POST',
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ 'x-api-key': anthropicKey,
55
+ 'anthropic-version': '2023-06-01',
56
+ },
57
+ body: JSON.stringify(body),
58
+ });
59
+ if (!res.ok) {
60
+ const errText = await res.text();
61
+ throw new Error(`Anthropic API request failed (${res.status}): ${errText}`);
62
+ }
63
+ const json = await res.json();
64
+ return json.content?.[0]?.text || '';
65
+ }
66
+ }
67
+ //# sourceMappingURL=llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,YAAoB,EACpB,UAAkB,EAClB,qBAA8B,KAAK;IAEnC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAEnD,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAErD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,KAAK,GAAG,aAAa,IAAI,QAAQ,CAAC;QACxC,MAAM,IAAI,GAA4B;YACpC,KAAK;YACL,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;gBACzC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;aACtC;SACF,CAAC;QACF,IAAI,kBAAkB,EAAE,CAAC;YACvB,IAAI,CAAC,eAAe,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QACjD,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,4CAA4C,EAAE;YAC/E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,SAAS,EAAE;aACvC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,MAAM,MAAM,OAAO,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAM1B,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,YAAY;QACZ,MAAM,KAAK,GAAG,aAAa,IAAI,0BAA0B,CAAC;QAC1D,MAAM,IAAI,GAA4B;YACpC,KAAK;YACL,UAAU,EAAE,IAAI;YAChB,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE;gBACR,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE;aACtC;SACF,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,KAAK,CAAC,uCAAuC,EAAE;YAC1E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,YAAa;gBAC1B,mBAAmB,EAAE,YAAY;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,iCAAiC,GAAG,CAAC,MAAM,MAAM,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAK1B,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;IACvC,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Manifest-consistency detector for PromptCI.
3
+ *
4
+ * Cross-references instruction file content against project manifest files
5
+ * (pyproject.toml, package.json) and flags mismatches that would cause an
6
+ * agent to follow an instruction that conflicts with the actual build setup.
7
+ *
8
+ * BUG-001: Tooling mismatch — instruction says `pip install -r requirements.txt`
9
+ * but pyproject.toml declares Poetry as the build backend and there is
10
+ * no requirements.txt in the repo.
11
+ *
12
+ * BUG-002: Python version mismatch — instruction file claims an older Python
13
+ * version than the one pinned in pyproject.toml's `python` constraint.
14
+ *
15
+ * BUG-003: Library version mismatch — instruction file claims compatibility
16
+ * with an older major library version than the one pinned in pyproject.toml.
17
+ *
18
+ * Findings are heuristic — wording is intentionally cautious.
19
+ */
20
+ import type { PromptCiIssue } from './types.js';
21
+ import type { RepoContext } from './repo-context.js';
22
+ export type ManifestData = {
23
+ /** Raw text content of package.json, if present. */
24
+ packageJson?: string;
25
+ /** Raw text content of pyproject.toml, if present. */
26
+ pyproject?: string;
27
+ };
28
+ /**
29
+ * Cross-reference instruction files against project manifests and flag
30
+ * inconsistencies that would mislead an agent about the build setup.
31
+ *
32
+ * @param files Scanned instruction files.
33
+ * @param manifests Raw text of any manifest files that were read by the scanner.
34
+ * @param repoRoot Absolute path to the repo root (used for file existence checks).
35
+ */
36
+ export declare function detectManifestConsistency(context: RepoContext): PromptCiIssue[];
37
+ //# sourceMappingURL=manifest-consistency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest-consistency.d.ts","sourceRoot":"","sources":["../src/manifest-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD,MAAM,MAAM,YAAY,GAAG;IACzB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAgsBF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAuB/E"}