@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.
- package/LICENSE +201 -0
- package/README.md +30 -0
- package/dist/agent-practices.d.ts +22 -0
- package/dist/agent-practices.d.ts.map +1 -0
- package/dist/agent-practices.js +582 -0
- package/dist/agent-practices.js.map +1 -0
- package/dist/baseline.d.ts +40 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +172 -0
- package/dist/baseline.js.map +1 -0
- package/dist/canonical-owner.d.ts +3 -0
- package/dist/canonical-owner.d.ts.map +1 -0
- package/dist/canonical-owner.js +131 -0
- package/dist/canonical-owner.js.map +1 -0
- package/dist/cheap-model-routing.d.ts +4 -0
- package/dist/cheap-model-routing.d.ts.map +1 -0
- package/dist/cheap-model-routing.js +43 -0
- package/dist/cheap-model-routing.js.map +1 -0
- package/dist/ci-alignment.d.ts +10 -0
- package/dist/ci-alignment.d.ts.map +1 -0
- package/dist/ci-alignment.js +343 -0
- package/dist/ci-alignment.js.map +1 -0
- package/dist/cli-output-filter.d.ts +16 -0
- package/dist/cli-output-filter.d.ts.map +1 -0
- package/dist/cli-output-filter.js +88 -0
- package/dist/cli-output-filter.js.map +1 -0
- package/dist/command-validity.d.ts +12 -0
- package/dist/command-validity.d.ts.map +1 -0
- package/dist/command-validity.js +543 -0
- package/dist/command-validity.js.map +1 -0
- package/dist/conflicts.d.ts +49 -0
- package/dist/conflicts.d.ts.map +1 -0
- package/dist/conflicts.js +1065 -0
- package/dist/conflicts.js.map +1 -0
- package/dist/context-analysis.d.ts +15 -0
- package/dist/context-analysis.d.ts.map +1 -0
- package/dist/context-analysis.js +24 -0
- package/dist/context-analysis.js.map +1 -0
- package/dist/context-bloat.d.ts +17 -0
- package/dist/context-bloat.d.ts.map +1 -0
- package/dist/context-bloat.js +148 -0
- package/dist/context-bloat.js.map +1 -0
- package/dist/context-cost.d.ts +4 -0
- package/dist/context-cost.d.ts.map +1 -0
- package/dist/context-cost.js +70 -0
- package/dist/context-cost.js.map +1 -0
- package/dist/context-optimizer.d.ts +14 -0
- package/dist/context-optimizer.d.ts.map +1 -0
- package/dist/context-optimizer.js +219 -0
- package/dist/context-optimizer.js.map +1 -0
- package/dist/context-recommender.d.ts +3 -0
- package/dist/context-recommender.d.ts.map +1 -0
- package/dist/context-recommender.js +329 -0
- package/dist/context-recommender.js.map +1 -0
- package/dist/dead-references.d.ts +33 -0
- package/dist/dead-references.d.ts.map +1 -0
- package/dist/dead-references.js +607 -0
- package/dist/dead-references.js.map +1 -0
- package/dist/detectors.d.ts +11 -0
- package/dist/detectors.d.ts.map +1 -0
- package/dist/detectors.js +160 -0
- package/dist/detectors.js.map +1 -0
- package/dist/duplicates.d.ts +36 -0
- package/dist/duplicates.d.ts.map +1 -0
- package/dist/duplicates.js +436 -0
- package/dist/duplicates.js.map +1 -0
- package/dist/fix-engine.d.ts +16 -0
- package/dist/fix-engine.d.ts.map +1 -0
- package/dist/fix-engine.js +179 -0
- package/dist/fix-engine.js.map +1 -0
- package/dist/framework-packs.d.ts +8 -0
- package/dist/framework-packs.d.ts.map +1 -0
- package/dist/framework-packs.js +22 -0
- package/dist/framework-packs.js.map +1 -0
- package/dist/frameworks/dotnet.d.ts +4 -0
- package/dist/frameworks/dotnet.d.ts.map +1 -0
- package/dist/frameworks/dotnet.js +77 -0
- package/dist/frameworks/dotnet.js.map +1 -0
- package/dist/frameworks/go.d.ts +4 -0
- package/dist/frameworks/go.d.ts.map +1 -0
- package/dist/frameworks/go.js +39 -0
- package/dist/frameworks/go.js.map +1 -0
- package/dist/frameworks/nextjs.d.ts +4 -0
- package/dist/frameworks/nextjs.d.ts.map +1 -0
- package/dist/frameworks/nextjs.js +66 -0
- package/dist/frameworks/nextjs.js.map +1 -0
- package/dist/frameworks/python.d.ts +4 -0
- package/dist/frameworks/python.d.ts.map +1 -0
- package/dist/frameworks/python.js +66 -0
- package/dist/frameworks/python.js.map +1 -0
- package/dist/frameworks/rust.d.ts +4 -0
- package/dist/frameworks/rust.d.ts.map +1 -0
- package/dist/frameworks/rust.js +72 -0
- package/dist/frameworks/rust.js.map +1 -0
- package/dist/frameworks/unity.d.ts +4 -0
- package/dist/frameworks/unity.d.ts.map +1 -0
- package/dist/frameworks/unity.js +74 -0
- package/dist/frameworks/unity.js.map +1 -0
- package/dist/health-score.d.ts +37 -0
- package/dist/health-score.d.ts.map +1 -0
- package/dist/health-score.js +164 -0
- package/dist/health-score.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +6 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +67 -0
- package/dist/llm.js.map +1 -0
- package/dist/manifest-consistency.d.ts +37 -0
- package/dist/manifest-consistency.d.ts.map +1 -0
- package/dist/manifest-consistency.js +659 -0
- package/dist/manifest-consistency.js.map +1 -0
- package/dist/mcp-detector.d.ts +4 -0
- package/dist/mcp-detector.d.ts.map +1 -0
- package/dist/mcp-detector.js +131 -0
- package/dist/mcp-detector.js.map +1 -0
- package/dist/missing-context.d.ts +15 -0
- package/dist/missing-context.d.ts.map +1 -0
- package/dist/missing-context.js +517 -0
- package/dist/missing-context.js.map +1 -0
- package/dist/native-tool-preference.d.ts +20 -0
- package/dist/native-tool-preference.d.ts.map +1 -0
- package/dist/native-tool-preference.js +94 -0
- package/dist/native-tool-preference.js.map +1 -0
- package/dist/output-verbosity.d.ts +3 -0
- package/dist/output-verbosity.d.ts.map +1 -0
- package/dist/output-verbosity.js +83 -0
- package/dist/output-verbosity.js.map +1 -0
- package/dist/product-boundary.d.ts +11 -0
- package/dist/product-boundary.d.ts.map +1 -0
- package/dist/product-boundary.js +301 -0
- package/dist/product-boundary.js.map +1 -0
- package/dist/project-type.d.ts +15 -0
- package/dist/project-type.d.ts.map +1 -0
- package/dist/project-type.js +116 -0
- package/dist/project-type.js.map +1 -0
- package/dist/prompt-cache.d.ts +3 -0
- package/dist/prompt-cache.d.ts.map +1 -0
- package/dist/prompt-cache.js +151 -0
- package/dist/prompt-cache.js.map +1 -0
- package/dist/repo-context.d.ts +37 -0
- package/dist/repo-context.d.ts.map +1 -0
- package/dist/repo-context.js +221 -0
- package/dist/repo-context.js.map +1 -0
- package/dist/report.d.ts +87 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +558 -0
- package/dist/report.js.map +1 -0
- package/dist/scan.d.ts +7 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +43 -0
- package/dist/scan.js.map +1 -0
- package/dist/scanner.d.ts +3 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +216 -0
- package/dist/scanner.js.map +1 -0
- package/dist/security-pack.d.ts +4 -0
- package/dist/security-pack.d.ts.map +1 -0
- package/dist/security-pack.js +403 -0
- package/dist/security-pack.js.map +1 -0
- package/dist/stale-instructions.d.ts +20 -0
- package/dist/stale-instructions.d.ts.map +1 -0
- package/dist/stale-instructions.js +269 -0
- package/dist/stale-instructions.js.map +1 -0
- package/dist/suppression.d.ts +64 -0
- package/dist/suppression.d.ts.map +1 -0
- package/dist/suppression.js +338 -0
- package/dist/suppression.js.map +1 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/vague-guidance.d.ts +12 -0
- package/dist/vague-guidance.d.ts.map +1 -0
- package/dist/vague-guidance.js +235 -0
- package/dist/vague-guidance.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* CI and Workflow Alignment Detector
|
|
4
|
+
*
|
|
5
|
+
* Compares what GitHub Actions workflows actually run against what instruction
|
|
6
|
+
* files tell agents to run locally. Surfaces drift between the CI gate and
|
|
7
|
+
* the agent verification loop so agents know which steps must pass before
|
|
8
|
+
* declaring work complete.
|
|
9
|
+
*
|
|
10
|
+
* Findings are heuristic — wording is intentionally cautious.
|
|
11
|
+
*/
|
|
12
|
+
function issueId(key) {
|
|
13
|
+
const hash = crypto.createHash('sha1').update(key).digest('hex').slice(0, 12);
|
|
14
|
+
return `ci-align-${hash}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Split a raw CI command that may contain multiple sub-commands joined with
|
|
18
|
+
* `&&` or newlines (multi-line `run:` blocks) into individual segments.
|
|
19
|
+
*/
|
|
20
|
+
function splitCommand(command) {
|
|
21
|
+
return command
|
|
22
|
+
.split(/&&|\n/)
|
|
23
|
+
.map((s) => s.trim())
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Normalizes a single command segment to identify a CommonTask.
|
|
28
|
+
* Returns the task name if recognised, otherwise null.
|
|
29
|
+
*/
|
|
30
|
+
function identifyTaskInSegment(segment) {
|
|
31
|
+
const cmd = segment.toLowerCase();
|
|
32
|
+
// Package-manager run patterns: "pnpm run lint", "npm test", "yarn build", etc.
|
|
33
|
+
const pmRunMatch = /\b(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?(test|lint|build|typecheck|format)\b/.exec(cmd);
|
|
34
|
+
if (pmRunMatch)
|
|
35
|
+
return pmRunMatch[1];
|
|
36
|
+
// Direct tool invocations
|
|
37
|
+
if (/\bjest\b|\bvitest\b|\bmocha\b|\bplaywright\s+test\b/.test(cmd))
|
|
38
|
+
return 'test';
|
|
39
|
+
if (/\beslint\b|\bprettier\s+--check\b/.test(cmd))
|
|
40
|
+
return 'lint';
|
|
41
|
+
// CI1: `\b` immediately before `--noemit` can never match — `\b` requires a
|
|
42
|
+
// word-char/non-word-char transition, but "--noemit" is always preceded by
|
|
43
|
+
// whitespace (non-word char before a non-word `-`), so `/\b--noemit\b/`
|
|
44
|
+
// never matched real input like "tsc --noEmit". This made `tsc --noEmit`
|
|
45
|
+
// in CI ALWAYS classify as 'build', never 'typecheck'. No leading boundary
|
|
46
|
+
// is needed — "--noemit" is unambiguous on its own.
|
|
47
|
+
if (/\btsc\b/.test(cmd) && /--noemit\b/i.test(cmd))
|
|
48
|
+
return 'typecheck';
|
|
49
|
+
if (/\btsc\b/.test(cmd) && !/--noemit\b/i.test(cmd))
|
|
50
|
+
return 'build';
|
|
51
|
+
if (/\bprettier\s+--write\b/.test(cmd))
|
|
52
|
+
return 'format';
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Returns all CommonTasks found in a (possibly multi-command) CI run: string.
|
|
57
|
+
* Handles `&&`-joined lines and multi-line blocks.
|
|
58
|
+
*/
|
|
59
|
+
function identifyTasksInCommand(command) {
|
|
60
|
+
const tasks = [];
|
|
61
|
+
for (const segment of splitCommand(command)) {
|
|
62
|
+
const t = identifyTaskInSegment(segment);
|
|
63
|
+
if (t && !tasks.includes(t))
|
|
64
|
+
tasks.push(t);
|
|
65
|
+
}
|
|
66
|
+
return tasks;
|
|
67
|
+
}
|
|
68
|
+
// ── Instruction-file task matching ────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Patterns that indicate an instruction file is actively directing the agent
|
|
71
|
+
* to run a given task. We look for command-like contexts to avoid matching
|
|
72
|
+
* the word "test" in prose like "make sure to test your assumptions".
|
|
73
|
+
*
|
|
74
|
+
* For each task we accept:
|
|
75
|
+
* - An explicit package-manager command (`pnpm lint`, `npm run lint`, …)
|
|
76
|
+
* - A heading or list item that names the task (## Lint, - Run lint)
|
|
77
|
+
* - The word in a run/execute/check context
|
|
78
|
+
*/
|
|
79
|
+
const TASK_INSTRUCTION_PATTERNS = {
|
|
80
|
+
lint: /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?lint|eslint\b|run\s+lint|lint\s+the\s+code|linting)\b/i,
|
|
81
|
+
typecheck: /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?typecheck|tsc\b|type.?check|run\s+typecheck)\b/i,
|
|
82
|
+
test: /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?test|vitest\b|jest\b|run\s+(?:the\s+)?tests?|pnpm\s+test)\b/i,
|
|
83
|
+
build: /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?build|tsc\b(?!\s+--noemit)|run\s+(?:the\s+)?build)\b/i,
|
|
84
|
+
format: /\b(?:(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?format|prettier\b|run\s+format)\b/i,
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Returns true when any scanned instruction file directs the agent to run the
|
|
88
|
+
* given task in a command-like context (not just mentions the word in prose).
|
|
89
|
+
*/
|
|
90
|
+
function isTaskInstructed(task, files) {
|
|
91
|
+
const pattern = TASK_INSTRUCTION_PATTERNS[task];
|
|
92
|
+
return files.some((f) => pattern.test(f.content));
|
|
93
|
+
}
|
|
94
|
+
// ── Package manager extraction ────────────────────────────────────────────────
|
|
95
|
+
/** Returns the package manager name used in a single command segment, or null. */
|
|
96
|
+
function extractPackageManager(command) {
|
|
97
|
+
const match = /\b(pnpm|npm|yarn|bun)\b/.exec(command.toLowerCase());
|
|
98
|
+
return match ? match[1] : null;
|
|
99
|
+
}
|
|
100
|
+
/** Collects all distinct package managers mentioned across all CI commands. */
|
|
101
|
+
function collectCiPackageManagers(commands) {
|
|
102
|
+
const pms = new Set();
|
|
103
|
+
for (const wc of commands) {
|
|
104
|
+
for (const segment of splitCommand(wc.command)) {
|
|
105
|
+
const pm = extractPackageManager(segment);
|
|
106
|
+
if (pm)
|
|
107
|
+
pms.add(pm);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return pms;
|
|
111
|
+
}
|
|
112
|
+
// ── Script normalisation ──────────────────────────────────────────────────────
|
|
113
|
+
/** Standard pm subcommands that are not user-defined package scripts. */
|
|
114
|
+
const STANDARD_SUBCOMMANDS = new Set([
|
|
115
|
+
'install', 'i', 'add', 'remove', 'uninstall', 'init', 'help',
|
|
116
|
+
'test', 'start', 'stop', 'restart', 'exec', 'dlx', 'run',
|
|
117
|
+
'workspace', 'workspaces',
|
|
118
|
+
]);
|
|
119
|
+
/**
|
|
120
|
+
* CI2: common English words that follow a package-manager name in ordinary
|
|
121
|
+
* PROSE, not a command invocation — "use pnpm instead of npm" and "npm
|
|
122
|
+
* packages are pinned" both matched the extraction regex below (which
|
|
123
|
+
* accepts ANY following alphanumeric word as a candidate script name),
|
|
124
|
+
* producing bogus orphan-script findings for "instead" and "packages".
|
|
125
|
+
* pnpm/yarn support a real bare `pnpm <script>` invocation (no "run"
|
|
126
|
+
* needed), so this can't be fixed by requiring "run" — only by excluding
|
|
127
|
+
* words that are clearly prose continuations, not script names.
|
|
128
|
+
*/
|
|
129
|
+
const ENGLISH_FILLER_WORDS = new Set([
|
|
130
|
+
'instead', 'of', 'packages', 'package', 'are', 'is', 'the', 'a', 'an',
|
|
131
|
+
'that', 'this', 'for', 'to', 'and', 'or', 'not', 'with', 'without', 'via',
|
|
132
|
+
'because', 'since', 'before', 'after', 'than', 'as', 'like', 'but', 'so',
|
|
133
|
+
]);
|
|
134
|
+
/** Extracts a user-defined script name from a pm run command, or null. */
|
|
135
|
+
function extractScriptName(command) {
|
|
136
|
+
const match = /\b(?:pnpm|npm|yarn|bun)\s+(?:run\s+)?([a-z0-9][a-z0-9:_-]*)\b/i.exec(command);
|
|
137
|
+
if (!match)
|
|
138
|
+
return null;
|
|
139
|
+
const name = match[1].toLowerCase();
|
|
140
|
+
if (STANDARD_SUBCOMMANDS.has(name) || ENGLISH_FILLER_WORDS.has(name))
|
|
141
|
+
return null;
|
|
142
|
+
return name;
|
|
143
|
+
}
|
|
144
|
+
// ── Check 1: CI runs a task that instructions do not mention ──────────────────
|
|
145
|
+
/**
|
|
146
|
+
* Flags tasks that CI enforces (lint, typecheck, test, build) but that no
|
|
147
|
+
* instruction file directs the agent to run.
|
|
148
|
+
*
|
|
149
|
+
* Only emits findings when at least one workflow file exists.
|
|
150
|
+
*/
|
|
151
|
+
function checkMissingCiTasks(context) {
|
|
152
|
+
const { workflows, files } = context;
|
|
153
|
+
if (workflows.files.length === 0)
|
|
154
|
+
return [];
|
|
155
|
+
// Collect tasks from ALL CI commands, handling && and multi-line blocks.
|
|
156
|
+
const ciTasks = new Map();
|
|
157
|
+
for (const wc of workflows.commands) {
|
|
158
|
+
for (const task of identifyTasksInCommand(wc.command)) {
|
|
159
|
+
if (!ciTasks.has(task))
|
|
160
|
+
ciTasks.set(task, []);
|
|
161
|
+
ciTasks.get(task).push(wc);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const issues = [];
|
|
165
|
+
for (const [task, wcs] of ciTasks.entries()) {
|
|
166
|
+
if (isTaskInstructed(task, files))
|
|
167
|
+
continue;
|
|
168
|
+
const sourceFiles = [...new Set(wcs.map((wc) => wc.filePath))];
|
|
169
|
+
issues.push({
|
|
170
|
+
id: issueId(`missing-ci-task:${task}`),
|
|
171
|
+
severity: 'warning',
|
|
172
|
+
category: 'missing_context',
|
|
173
|
+
title: `CI runs \`${task}\` but no instruction file appears to include it`,
|
|
174
|
+
summary: `The GitHub workflow${sourceFiles.length > 1 ? 's' : ''} (${sourceFiles.join(', ')}) ` +
|
|
175
|
+
`run \`${task}\`, but no instruction file appears to direct the agent to run this step ` +
|
|
176
|
+
`locally. Agents that follow only the instruction files may skip \`${task}\` and miss ` +
|
|
177
|
+
`failures before declaring work complete.`,
|
|
178
|
+
filePaths: files.map((f) => f.path),
|
|
179
|
+
locations: wcs.map((wc) => ({ filePath: wc.filePath, startLine: wc.line })),
|
|
180
|
+
evidence: wcs.map((wc) => `CI command: \`${wc.command}\` in ${wc.filePath} (line ${wc.line})`),
|
|
181
|
+
recommendation: `Consider adding \`${task}\` to the verification loop in the relevant instruction ` +
|
|
182
|
+
`file (e.g., AGENTS.md or CLAUDE.md) so agents run the same checks as CI.`,
|
|
183
|
+
confidence: 0.8,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return issues;
|
|
187
|
+
}
|
|
188
|
+
// ── Check 2: CI uses a different package manager than instructions ─────────────
|
|
189
|
+
/**
|
|
190
|
+
* Flags when instruction files direct the agent to use a different package
|
|
191
|
+
* manager than the one CI workflows actually use.
|
|
192
|
+
*
|
|
193
|
+
* Only emits findings when at least one workflow file exists and CI commands
|
|
194
|
+
* mention a package manager.
|
|
195
|
+
*/
|
|
196
|
+
function checkCiPackageManagerMismatch(context) {
|
|
197
|
+
const { workflows, files, packageJson } = context;
|
|
198
|
+
if (workflows.files.length === 0)
|
|
199
|
+
return [];
|
|
200
|
+
const ciPms = collectCiPackageManagers(workflows.commands);
|
|
201
|
+
if (ciPms.size === 0)
|
|
202
|
+
return [];
|
|
203
|
+
// Determine the project's preferred PM: package.json field > lockfile > CI
|
|
204
|
+
const preferredPm = packageJson.packageManagerName !== 'unknown'
|
|
205
|
+
? packageJson.packageManagerName
|
|
206
|
+
: Array.from(ciPms)[0];
|
|
207
|
+
if (!ciPms.has(preferredPm))
|
|
208
|
+
return [];
|
|
209
|
+
const issues = [];
|
|
210
|
+
for (const file of files) {
|
|
211
|
+
for (const pm of ['npm', 'pnpm', 'yarn', 'bun']) {
|
|
212
|
+
if (pm === preferredPm)
|
|
213
|
+
continue;
|
|
214
|
+
// Only match positive command usage (not negation lines)
|
|
215
|
+
const re = new RegExp(`\\b${pm}\\s+(?:install|add|run|exec|dlx|i)\\b`, 'gi');
|
|
216
|
+
let match;
|
|
217
|
+
let positiveHit = false;
|
|
218
|
+
while ((match = re.exec(file.content)) !== null) {
|
|
219
|
+
const lineStart = file.content.lastIndexOf('\n', match.index - 1) + 1;
|
|
220
|
+
const lineEnd = file.content.indexOf('\n', match.index);
|
|
221
|
+
const line = file.content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd);
|
|
222
|
+
const isNegation = /\b(?:do\s+not|don'?t|avoid|never|not\s+use|refrain)\b/i.test(line);
|
|
223
|
+
if (!isNegation) {
|
|
224
|
+
positiveHit = true;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!positiveHit)
|
|
229
|
+
continue;
|
|
230
|
+
issues.push({
|
|
231
|
+
id: issueId(`pm-mismatch-ci:${file.path}:${pm}`),
|
|
232
|
+
severity: 'warning',
|
|
233
|
+
category: 'conflict',
|
|
234
|
+
title: `Possible package manager mismatch: instructions use \`${pm}\` but CI uses \`${preferredPm}\``,
|
|
235
|
+
summary: `The instruction file appears to direct the agent to use \`${pm}\`, but the CI ` +
|
|
236
|
+
`workflows use \`${preferredPm}\`. This may lead to lockfile conflicts or unexpected ` +
|
|
237
|
+
`installation behaviour. Consider reviewing whether the instructions match the CI setup.`,
|
|
238
|
+
filePaths: [file.path],
|
|
239
|
+
locations: [{ filePath: file.path }],
|
|
240
|
+
evidence: [
|
|
241
|
+
`CI workflows use: ${Array.from(ciPms).join(', ')}`,
|
|
242
|
+
`Instruction file appears to use \`${pm}\``,
|
|
243
|
+
],
|
|
244
|
+
recommendation: `Update the instruction file to use \`${preferredPm}\` commands to align with CI.`,
|
|
245
|
+
confidence: 0.85,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return issues;
|
|
250
|
+
}
|
|
251
|
+
// ── Check 3: Instructions reference a script absent from CI and manifest ────────
|
|
252
|
+
/**
|
|
253
|
+
* Flags when an instruction file tells the agent to run a named package script
|
|
254
|
+
* that appears in neither package.json nor any CI workflow. These commands
|
|
255
|
+
* would fail immediately if executed.
|
|
256
|
+
*
|
|
257
|
+
* Only applied when at least one workflow file exists (otherwise the CI-absent
|
|
258
|
+
* half of the signal is meaningless).
|
|
259
|
+
*/
|
|
260
|
+
function checkOrphanedInstructionScripts(context) {
|
|
261
|
+
const { workflows, files, packageJson, manifests } = context;
|
|
262
|
+
if (workflows.files.length === 0)
|
|
263
|
+
return [];
|
|
264
|
+
// CI3: manifest-consistency.ts's checkMissingScripts already flags any
|
|
265
|
+
// instruction reference to a script missing from package.json — regardless
|
|
266
|
+
// of whether the script is used in CI — and it runs whenever
|
|
267
|
+
// manifests.packageJson is present. Every finding THIS check produces
|
|
268
|
+
// requires that same "missing from package.json" condition (see the
|
|
269
|
+
// `!packageScripts.has(scriptName)` check below), so whenever
|
|
270
|
+
// manifest-consistency.ts is active, its check is a strict superset of
|
|
271
|
+
// this one — the same underlying gap was reported TWICE (different ids,
|
|
272
|
+
// both 'stale_instruction') whenever a workflow file also existed. Defer
|
|
273
|
+
// entirely to manifest-consistency.ts in that case; this check only adds
|
|
274
|
+
// value when there's no package.json for that detector to compare against.
|
|
275
|
+
if (manifests.packageJson)
|
|
276
|
+
return [];
|
|
277
|
+
const packageScripts = new Set(Object.keys(packageJson.scripts));
|
|
278
|
+
// Collect all script names CI actually runs
|
|
279
|
+
const ciScriptNames = new Set();
|
|
280
|
+
for (const wc of workflows.commands) {
|
|
281
|
+
for (const segment of splitCommand(wc.command)) {
|
|
282
|
+
const name = extractScriptName(segment);
|
|
283
|
+
if (name)
|
|
284
|
+
ciScriptNames.add(name);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const reported = new Set();
|
|
288
|
+
const issues = [];
|
|
289
|
+
for (const file of files) {
|
|
290
|
+
const runRe = /\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?([a-z0-9][a-z0-9:_-]*)\b/gi;
|
|
291
|
+
let match;
|
|
292
|
+
while ((match = runRe.exec(file.content)) !== null) {
|
|
293
|
+
const scriptName = match[1].toLowerCase();
|
|
294
|
+
// CI2: also exclude common English prose continuations — see
|
|
295
|
+
// ENGLISH_FILLER_WORDS for why this can't be fixed by requiring "run".
|
|
296
|
+
if (STANDARD_SUBCOMMANDS.has(scriptName) || ENGLISH_FILLER_WORDS.has(scriptName))
|
|
297
|
+
continue;
|
|
298
|
+
if (!packageScripts.has(scriptName) && !ciScriptNames.has(scriptName)) {
|
|
299
|
+
const dedupeKey = `${file.path}:${scriptName}`;
|
|
300
|
+
if (reported.has(dedupeKey))
|
|
301
|
+
continue;
|
|
302
|
+
reported.add(dedupeKey);
|
|
303
|
+
issues.push({
|
|
304
|
+
id: issueId(`orphan-script:${file.path}:${scriptName}`),
|
|
305
|
+
severity: 'warning',
|
|
306
|
+
category: 'stale_instruction',
|
|
307
|
+
title: `Possible reference to missing script: \`${scriptName}\` (not in CI or package.json)`,
|
|
308
|
+
summary: `The instruction file appears to tell the agent to run \`${scriptName}\`, but this ` +
|
|
309
|
+
`script does not appear in package.json and is not used in any CI workflow. ` +
|
|
310
|
+
`This command may fail if executed. Consider reviewing whether the script name is current.`,
|
|
311
|
+
filePaths: [file.path],
|
|
312
|
+
locations: [{ filePath: file.path }],
|
|
313
|
+
evidence: [
|
|
314
|
+
`Found reference to \`${scriptName}\` in ${file.path}`,
|
|
315
|
+
`Script not found in package.json scripts`,
|
|
316
|
+
`Script not found in .github/workflows/*.yml`,
|
|
317
|
+
],
|
|
318
|
+
recommendation: `Verify the script name. If it was renamed, update the instruction file. ` +
|
|
319
|
+
`If it is a new script, add it to package.json.`,
|
|
320
|
+
confidence: 0.8,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return issues;
|
|
326
|
+
}
|
|
327
|
+
// ── Public detector ───────────────────────────────────────────────────────────
|
|
328
|
+
/**
|
|
329
|
+
* Entry point for the CI and Workflow Alignment detector.
|
|
330
|
+
*
|
|
331
|
+
* Returns an empty array when no workflow files exist so the detector never
|
|
332
|
+
* creates noise in repos without GitHub Actions.
|
|
333
|
+
*/
|
|
334
|
+
export function detectCiAlignment(context) {
|
|
335
|
+
if (context.workflows.files.length === 0)
|
|
336
|
+
return [];
|
|
337
|
+
return [
|
|
338
|
+
...checkMissingCiTasks(context),
|
|
339
|
+
...checkCiPackageManagerMismatch(context),
|
|
340
|
+
...checkOrphanedInstructionScripts(context),
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=ci-alignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci-alignment.js","sourceRoot":"","sources":["../src/ci-alignment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output filter detector for PromptCI.
|
|
3
|
+
*
|
|
4
|
+
* Checks whether instruction files include guidance on filtering verbose CLI
|
|
5
|
+
* output before it reaches the LLM context. Tools like RTK (Rust Token Killer)
|
|
6
|
+
* transparently proxy commands such as `npm test`, `git diff`, and `cargo test`,
|
|
7
|
+
* stripping boilerplate and keeping only signal — typically 60-90% token reduction
|
|
8
|
+
* on those commands.
|
|
9
|
+
*
|
|
10
|
+
* Only fires for non-trivial projects (>500 estimated instruction tokens) that
|
|
11
|
+
* have no existing output-filter guidance in any instruction file.
|
|
12
|
+
*/
|
|
13
|
+
import type { RepoContext } from './repo-context.js';
|
|
14
|
+
import type { PromptCiIssue } from './types.js';
|
|
15
|
+
export declare function detectCliOutputFilter(context: RepoContext): PromptCiIssue[];
|
|
16
|
+
//# sourceMappingURL=cli-output-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-output-filter.d.ts","sourceRoot":"","sources":["../src/cli-output-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA0BhD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CA6D3E"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI output filter detector for PromptCI.
|
|
3
|
+
*
|
|
4
|
+
* Checks whether instruction files include guidance on filtering verbose CLI
|
|
5
|
+
* output before it reaches the LLM context. Tools like RTK (Rust Token Killer)
|
|
6
|
+
* transparently proxy commands such as `npm test`, `git diff`, and `cargo test`,
|
|
7
|
+
* stripping boilerplate and keeping only signal — typically 60-90% token reduction
|
|
8
|
+
* on those commands.
|
|
9
|
+
*
|
|
10
|
+
* Only fires for non-trivial projects (>500 estimated instruction tokens) that
|
|
11
|
+
* have no existing output-filter guidance in any instruction file.
|
|
12
|
+
*/
|
|
13
|
+
// Signals that output-filter guidance already exists somewhere in the instructions.
|
|
14
|
+
const FILTER_SIGNALS = [
|
|
15
|
+
/\brtk\b/i,
|
|
16
|
+
/rust\s+token\s+killer/i,
|
|
17
|
+
/output\s+filter/i,
|
|
18
|
+
/token[- ]optimized\s+(cli|command|output)/i,
|
|
19
|
+
/cli\s+proxy/i,
|
|
20
|
+
/filter.*command.*output/i,
|
|
21
|
+
/compact.*output/i,
|
|
22
|
+
/--failures[- ]only/i,
|
|
23
|
+
];
|
|
24
|
+
// Commands that produce high-token output and benefit most from filtering.
|
|
25
|
+
// Used only to improve the evidence message — not a gate condition.
|
|
26
|
+
const NOISY_COMMANDS = [
|
|
27
|
+
'npm test', 'npm run test', 'yarn test', 'pnpm test',
|
|
28
|
+
'jest', 'vitest', 'pytest', 'cargo test', 'go test', 'rspec',
|
|
29
|
+
'git diff', 'git log', 'git status',
|
|
30
|
+
'next build', 'npm run build', 'tsc',
|
|
31
|
+
'eslint', 'ruff check', 'cargo clippy', 'golangci-lint',
|
|
32
|
+
'docker logs', 'kubectl logs',
|
|
33
|
+
'gh pr list', 'gh run list',
|
|
34
|
+
];
|
|
35
|
+
export function detectCliOutputFilter(context) {
|
|
36
|
+
const { files, metrics } = context;
|
|
37
|
+
if (files.length === 0)
|
|
38
|
+
return [];
|
|
39
|
+
// Skip trivially small instruction sets — not worth the noise.
|
|
40
|
+
if (metrics.estimatedInstructionTokens < 500)
|
|
41
|
+
return [];
|
|
42
|
+
const combinedContent = files.map((f) => f.content).join('\n');
|
|
43
|
+
const hasFilterGuidance = FILTER_SIGNALS.some((pat) => pat.test(combinedContent));
|
|
44
|
+
if (hasFilterGuidance)
|
|
45
|
+
return [];
|
|
46
|
+
// Surface whichever noisy commands are referenced in instructions (for evidence).
|
|
47
|
+
const referencedNoisyCommands = NOISY_COMMANDS.filter((cmd) => combinedContent.toLowerCase().includes(cmd.toLowerCase()));
|
|
48
|
+
const evidenceLine = referencedNoisyCommands.length > 0
|
|
49
|
+
? `Noisy commands referenced in instructions: ${referencedNoisyCommands.slice(0, 5).join(', ')}${referencedNoisyCommands.length > 5 ? ` (+${referencedNoisyCommands.length - 5} more)` : ''}.`
|
|
50
|
+
: 'No output-filter signals found across all instruction files.';
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
id: 'cli-output-filter-missing',
|
|
54
|
+
severity: 'info',
|
|
55
|
+
category: 'agent_practices',
|
|
56
|
+
title: 'No CLI output filtering guidance',
|
|
57
|
+
summary: 'Instruction files contain no guidance on filtering verbose CLI output before it reaches ' +
|
|
58
|
+
'the LLM context. Commands like `npm test`, `git diff`, and `cargo test` can produce ' +
|
|
59
|
+
'hundreds of boilerplate lines. A CLI proxy such as RTK (Rust Token Killer) intercepts ' +
|
|
60
|
+
'these transparently and reduces token consumption by 60-90% on affected commands.',
|
|
61
|
+
filePaths: files.map((f) => f.path),
|
|
62
|
+
locations: [],
|
|
63
|
+
evidence: [evidenceLine],
|
|
64
|
+
recommendation: 'Install a CLI output filter (e.g. RTK: github.com/rtk-ai/rtk) and document it in your ' +
|
|
65
|
+
'instruction files. For Claude Code, `rtk init -g` installs a PreToolUse hook that ' +
|
|
66
|
+
'transparently rewrites Bash commands — no per-command changes needed.',
|
|
67
|
+
fixRecipe: [
|
|
68
|
+
'## CLI Output Filtering',
|
|
69
|
+
'',
|
|
70
|
+
'Use [RTK](https://github.com/rtk-ai/rtk) to reduce token consumption from verbose commands:',
|
|
71
|
+
'',
|
|
72
|
+
'```bash',
|
|
73
|
+
'brew install rtk # macOS',
|
|
74
|
+
'# or: cargo install --git https://github.com/rtk-ai/rtk',
|
|
75
|
+
'rtk init -g # Claude Code (PreToolUse hook)',
|
|
76
|
+
'rtk init -g --codex # Codex (AGENTS.md)',
|
|
77
|
+
'rtk init --agent antigravity # Antigravity (project-scoped rules)',
|
|
78
|
+
'```',
|
|
79
|
+
'',
|
|
80
|
+
'The hook transparently rewrites `npm test` → `rtk npm test` (failures only),',
|
|
81
|
+
'`git diff` → `rtk git diff` (condensed), etc. Run `rtk gain` to see token savings.',
|
|
82
|
+
].join('\n'),
|
|
83
|
+
confidence: 0.75,
|
|
84
|
+
impact: 'medium',
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=cli-output-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-output-filter.js","sourceRoot":"","sources":["../src/cli-output-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RepoContext } from './repo-context.js';
|
|
2
|
+
import type { PromptCiIssue } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Validates commands documented in instruction files against the repository's
|
|
5
|
+
* actual scripts and file structure.
|
|
6
|
+
*
|
|
7
|
+
* Returns findings only for high-confidence breakages — missing package
|
|
8
|
+
* scripts and missing file references. Executable binary availability is
|
|
9
|
+
* out of scope.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectCommandValidity(context: RepoContext): PromptCiIssue[];
|
|
12
|
+
//# sourceMappingURL=command-validity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-validity.d.ts","sourceRoot":"","sources":["../src/command-validity.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA4hBhD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAkC3E"}
|