@promptci/core 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -201
- package/README.md +29 -30
- package/dist/action-pinning.d.ts +37 -0
- package/dist/action-pinning.d.ts.map +1 -0
- package/dist/action-pinning.js +277 -0
- package/dist/action-pinning.js.map +1 -0
- package/dist/agent-practices.d.ts +3 -1
- package/dist/agent-practices.d.ts.map +1 -1
- package/dist/agent-practices.js +198 -94
- package/dist/agent-practices.js.map +1 -1
- package/dist/ai-config.d.ts +178 -0
- package/dist/ai-config.d.ts.map +1 -0
- package/dist/ai-config.js +721 -0
- package/dist/ai-config.js.map +1 -0
- package/dist/alias-files.d.ts +33 -0
- package/dist/alias-files.d.ts.map +1 -0
- package/dist/alias-files.js +60 -0
- package/dist/alias-files.js.map +1 -0
- package/dist/baseline.d.ts +17 -1
- package/dist/baseline.d.ts.map +1 -1
- package/dist/baseline.js +5 -1
- package/dist/baseline.js.map +1 -1
- package/dist/buried-critical.d.ts +17 -0
- package/dist/buried-critical.d.ts.map +1 -0
- package/dist/buried-critical.js +107 -0
- package/dist/buried-critical.js.map +1 -0
- package/dist/canonical-owner.d.ts.map +1 -1
- package/dist/canonical-owner.js +60 -30
- package/dist/canonical-owner.js.map +1 -1
- package/dist/ci-alignment.d.ts.map +1 -1
- package/dist/ci-alignment.js +3 -2
- package/dist/ci-alignment.js.map +1 -1
- package/dist/command-validity.d.ts +16 -0
- package/dist/command-validity.d.ts.map +1 -1
- package/dist/command-validity.js +387 -134
- package/dist/command-validity.js.map +1 -1
- package/dist/conflicts.d.ts.map +1 -1
- package/dist/conflicts.js +4 -44
- package/dist/conflicts.js.map +1 -1
- package/dist/context-analysis.d.ts.map +1 -1
- package/dist/context-analysis.js +13 -2
- package/dist/context-analysis.js.map +1 -1
- package/dist/context-bloat.d.ts +20 -1
- package/dist/context-bloat.d.ts.map +1 -1
- package/dist/context-bloat.js +99 -15
- package/dist/context-bloat.js.map +1 -1
- package/dist/context-optimizer.d.ts.map +1 -1
- package/dist/context-optimizer.js +18 -54
- package/dist/context-optimizer.js.map +1 -1
- package/dist/copilot-instructions-detector.d.ts +24 -0
- package/dist/copilot-instructions-detector.d.ts.map +1 -0
- package/dist/copilot-instructions-detector.js +145 -0
- package/dist/copilot-instructions-detector.js.map +1 -0
- package/dist/cursor-rules-detector.d.ts +17 -0
- package/dist/cursor-rules-detector.d.ts.map +1 -0
- package/dist/cursor-rules-detector.js +110 -0
- package/dist/cursor-rules-detector.js.map +1 -0
- package/dist/custom-rules.d.ts +52 -0
- package/dist/custom-rules.d.ts.map +1 -0
- package/dist/custom-rules.js +303 -0
- package/dist/custom-rules.js.map +1 -0
- package/dist/dead-references.d.ts +8 -2
- package/dist/dead-references.d.ts.map +1 -1
- package/dist/dead-references.js +315 -68
- package/dist/dead-references.js.map +1 -1
- package/dist/dependency-staleness.d.ts +35 -0
- package/dist/dependency-staleness.d.ts.map +1 -0
- package/dist/dependency-staleness.js +1001 -0
- package/dist/dependency-staleness.js.map +1 -0
- package/dist/detectors.d.ts +1 -3
- package/dist/detectors.d.ts.map +1 -1
- package/dist/detectors.js +74 -56
- package/dist/detectors.js.map +1 -1
- package/dist/duplicates.d.ts.map +1 -1
- package/dist/duplicates.js +15 -9
- package/dist/duplicates.js.map +1 -1
- package/dist/evidence.d.ts +39 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +78 -0
- package/dist/evidence.js.map +1 -0
- package/dist/finding-id.d.ts +21 -0
- package/dist/finding-id.d.ts.map +1 -0
- package/dist/finding-id.js +31 -0
- package/dist/finding-id.js.map +1 -0
- package/dist/fix-engine.d.ts +11 -0
- package/dist/fix-engine.d.ts.map +1 -1
- package/dist/fix-engine.js +88 -71
- package/dist/fix-engine.js.map +1 -1
- package/dist/frameworks/dotnet.js +2 -2
- package/dist/frameworks/dotnet.js.map +1 -1
- package/dist/frameworks/python.d.ts.map +1 -1
- package/dist/frameworks/python.js +5 -2
- package/dist/frameworks/python.js.map +1 -1
- package/dist/frameworks/rust.d.ts.map +1 -1
- package/dist/frameworks/rust.js +2 -1
- package/dist/frameworks/rust.js.map +1 -1
- package/dist/git-symlinks.d.ts +30 -0
- package/dist/git-symlinks.d.ts.map +1 -0
- package/dist/git-symlinks.js +161 -0
- package/dist/git-symlinks.js.map +1 -0
- package/dist/gitignore.d.ts +22 -0
- package/dist/gitignore.d.ts.map +1 -0
- package/dist/gitignore.js +157 -0
- package/dist/gitignore.js.map +1 -0
- package/dist/health-score.d.ts.map +1 -1
- package/dist/health-score.js +35 -5
- package/dist/health-score.js.map +1 -1
- package/dist/hooks-settings-detector.d.ts +17 -0
- package/dist/hooks-settings-detector.d.ts.map +1 -0
- package/dist/hooks-settings-detector.js +228 -0
- package/dist/hooks-settings-detector.js.map +1 -0
- package/dist/index.d.ts +29 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -6
- package/dist/index.js.map +1 -1
- package/dist/makefile.d.ts +37 -0
- package/dist/makefile.d.ts.map +1 -0
- package/dist/makefile.js +156 -0
- package/dist/makefile.js.map +1 -0
- package/dist/manifest-consistency.d.ts +6 -0
- package/dist/manifest-consistency.d.ts.map +1 -1
- package/dist/manifest-consistency.js +75 -10
- package/dist/manifest-consistency.js.map +1 -1
- package/dist/markdown-fences.d.ts +112 -0
- package/dist/markdown-fences.d.ts.map +1 -0
- package/dist/markdown-fences.js +174 -0
- package/dist/markdown-fences.js.map +1 -0
- package/dist/mcp-config-detector.d.ts +20 -0
- package/dist/mcp-config-detector.d.ts.map +1 -0
- package/dist/mcp-config-detector.js +237 -0
- package/dist/mcp-config-detector.js.map +1 -0
- package/dist/missing-context.d.ts.map +1 -1
- package/dist/missing-context.js +2 -52
- package/dist/missing-context.js.map +1 -1
- package/dist/model-budgets.d.ts +69 -0
- package/dist/model-budgets.d.ts.map +1 -0
- package/dist/model-budgets.js +110 -0
- package/dist/model-budgets.js.map +1 -0
- package/dist/negative-instructions.d.ts +26 -0
- package/dist/negative-instructions.d.ts.map +1 -0
- package/dist/negative-instructions.js +169 -0
- package/dist/negative-instructions.js.map +1 -0
- package/dist/path-containment.d.ts +41 -0
- package/dist/path-containment.d.ts.map +1 -0
- package/dist/path-containment.js +123 -0
- package/dist/path-containment.js.map +1 -0
- package/dist/project-type.d.ts +12 -2
- package/dist/project-type.d.ts.map +1 -1
- package/dist/project-type.js +25 -12
- package/dist/project-type.js.map +1 -1
- package/dist/prompt-cache.d.ts.map +1 -1
- package/dist/prompt-cache.js +33 -24
- package/dist/prompt-cache.js.map +1 -1
- package/dist/promptci-gitignore.d.ts +34 -0
- package/dist/promptci-gitignore.d.ts.map +1 -0
- package/dist/promptci-gitignore.js +42 -0
- package/dist/promptci-gitignore.js.map +1 -0
- package/dist/repo-context.d.ts +80 -0
- package/dist/repo-context.d.ts.map +1 -1
- package/dist/repo-context.js +170 -16
- package/dist/repo-context.js.map +1 -1
- package/dist/report.d.ts +8 -0
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +163 -63
- package/dist/report.js.map +1 -1
- package/dist/scan.d.ts.map +1 -1
- package/dist/scan.js +47 -4
- package/dist/scan.js.map +1 -1
- package/dist/scanner.d.ts +61 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +367 -70
- package/dist/scanner.js.map +1 -1
- package/dist/security-pack.d.ts +20 -0
- package/dist/security-pack.d.ts.map +1 -1
- package/dist/security-pack.js +33 -14
- package/dist/security-pack.js.map +1 -1
- package/dist/skill-supply-chain.d.ts +132 -0
- package/dist/skill-supply-chain.d.ts.map +1 -0
- package/dist/skill-supply-chain.js +2954 -0
- package/dist/skill-supply-chain.js.map +1 -0
- package/dist/skills-detector.d.ts +23 -0
- package/dist/skills-detector.d.ts.map +1 -0
- package/dist/skills-detector.js +279 -0
- package/dist/skills-detector.js.map +1 -0
- package/dist/stale-instructions.d.ts +4 -1
- package/dist/stale-instructions.d.ts.map +1 -1
- package/dist/stale-instructions.js +53 -55
- package/dist/stale-instructions.js.map +1 -1
- package/dist/subagents-detector.d.ts +19 -0
- package/dist/subagents-detector.d.ts.map +1 -0
- package/dist/subagents-detector.js +155 -0
- package/dist/subagents-detector.js.map +1 -0
- package/dist/suppression.d.ts +2 -0
- package/dist/suppression.d.ts.map +1 -1
- package/dist/suppression.js +16 -47
- package/dist/suppression.js.map +1 -1
- package/dist/types.d.ts +62 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +47 -1
- package/dist/types.js.map +1 -1
- package/dist/vague-guidance.d.ts +15 -2
- package/dist/vague-guidance.d.ts.map +1 -1
- package/dist/vague-guidance.js +44 -41
- package/dist/vague-guidance.js.map +1 -1
- package/dist/windsurf-detector.d.ts +22 -0
- package/dist/windsurf-detector.d.ts.map +1 -0
- package/dist/windsurf-detector.js +96 -0
- package/dist/windsurf-detector.js.map +1 -0
- package/dist/within-section-dedup.d.ts +16 -0
- package/dist/within-section-dedup.d.ts.map +1 -0
- package/dist/within-section-dedup.js +148 -0
- package/dist/within-section-dedup.js.map +1 -0
- package/dist/workspace-manifests.d.ts +80 -0
- package/dist/workspace-manifests.d.ts.map +1 -0
- package/dist/workspace-manifests.js +333 -0
- package/dist/workspace-manifests.js.map +1 -0
- package/package.json +11 -8
- package/dist/cheap-model-routing.d.ts +0 -4
- package/dist/cheap-model-routing.d.ts.map +0 -1
- package/dist/cheap-model-routing.js +0 -43
- package/dist/cheap-model-routing.js.map +0 -1
- package/dist/cli-output-filter.d.ts +0 -16
- package/dist/cli-output-filter.d.ts.map +0 -1
- package/dist/cli-output-filter.js +0 -88
- package/dist/cli-output-filter.js.map +0 -1
- package/dist/context-cost.d.ts +0 -4
- package/dist/context-cost.d.ts.map +0 -1
- package/dist/context-cost.js +0 -70
- package/dist/context-cost.js.map +0 -1
- package/dist/context-recommender.d.ts +0 -3
- package/dist/context-recommender.d.ts.map +0 -1
- package/dist/context-recommender.js +0 -329
- package/dist/context-recommender.js.map +0 -1
- package/dist/llm.d.ts +0 -6
- package/dist/llm.d.ts.map +0 -1
- package/dist/llm.js +0 -67
- package/dist/llm.js.map +0 -1
- package/dist/mcp-detector.d.ts +0 -4
- package/dist/mcp-detector.d.ts.map +0 -1
- package/dist/mcp-detector.js +0 -131
- package/dist/mcp-detector.js.map +0 -1
- package/dist/native-tool-preference.d.ts +0 -20
- package/dist/native-tool-preference.d.ts.map +0 -1
- package/dist/native-tool-preference.js +0 -94
- package/dist/native-tool-preference.js.map +0 -1
- package/dist/output-verbosity.d.ts +0 -3
- package/dist/output-verbosity.d.ts.map +0 -1
- package/dist/output-verbosity.js +0 -83
- package/dist/output-verbosity.js.map +0 -1
- package/dist/product-boundary.d.ts +0 -11
- package/dist/product-boundary.d.ts.map +0 -1
- package/dist/product-boundary.js +0 -301
- package/dist/product-boundary.js.map +0 -1
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom-rules engine (Decision D10) — a deterministic interpreter for
|
|
3
|
+
* `.promptci/custom-rules.json`. It lets a repo add its own instruction checks
|
|
4
|
+
* without shipping code, and those findings behave exactly like built-in ones:
|
|
5
|
+
* they carry `custom:*` ids, participate in suppression and the baseline/ratchet,
|
|
6
|
+
* and run identically in a local scan and the GitHub Action (both go through
|
|
7
|
+
* `buildRepoContext`).
|
|
8
|
+
*
|
|
9
|
+
* Four rule types:
|
|
10
|
+
* - `forbiddenPattern` — flag each file whose text matches a regex.
|
|
11
|
+
* - `absentPattern` — flag the repo when a required regex is absent from all targeted files.
|
|
12
|
+
* - `requiredSection` — flag the repo when a required heading appears in no targeted file.
|
|
13
|
+
* - `crossFileConflict` — flag when a regex's captured value differs across files.
|
|
14
|
+
*
|
|
15
|
+
* Everything here is deterministic: no clock, network, or randomness. Malformed
|
|
16
|
+
* config is rejected with a clear, actionable error naming the offending key —
|
|
17
|
+
* never a crash or a silent skip.
|
|
18
|
+
*/
|
|
19
|
+
import * as crypto from 'node:crypto';
|
|
20
|
+
import * as fs from 'node:fs/promises';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import micromatch from 'micromatch';
|
|
23
|
+
import { snippet } from './evidence.js';
|
|
24
|
+
import { fileIdPath } from './finding-id.js';
|
|
25
|
+
import { realPathWithinRoot } from './path-containment.js';
|
|
26
|
+
export const CUSTOM_RULES_FILE = path.join('.promptci', 'custom-rules.json');
|
|
27
|
+
export const CUSTOM_RULE_TYPES = [
|
|
28
|
+
'forbiddenPattern',
|
|
29
|
+
'absentPattern',
|
|
30
|
+
'requiredSection',
|
|
31
|
+
'crossFileConflict',
|
|
32
|
+
];
|
|
33
|
+
const VALID_SEVERITIES = ['info', 'warning', 'high', 'critical'];
|
|
34
|
+
const VALID_REGEX_FLAGS = /^[gimsuy]*$/;
|
|
35
|
+
// ── Validation ──────────────────────────────────────────────────────────────
|
|
36
|
+
/** All validation failures throw this so callers can present them cleanly. */
|
|
37
|
+
export class CustomRulesError extends Error {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(`Invalid ${CUSTOM_RULES_FILE}: ${message}`);
|
|
40
|
+
this.name = 'CustomRulesError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function requireString(obj, key, where) {
|
|
44
|
+
const value = obj[key];
|
|
45
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
46
|
+
throw new CustomRulesError(`${where} is missing a non-empty string "${key}".`);
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
function requireStringArray(value, key, where) {
|
|
51
|
+
if (!Array.isArray(value) || !value.every((v) => typeof v === 'string')) {
|
|
52
|
+
throw new CustomRulesError(`${where}: "${key}" must be an array of strings.`);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
function validateRegex(pattern, flags, where) {
|
|
57
|
+
if (flags !== undefined && !VALID_REGEX_FLAGS.test(flags)) {
|
|
58
|
+
throw new CustomRulesError(`${where}: "flags" may only contain regex flags (gimsuy).`);
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
void new RegExp(pattern, flags);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
throw new CustomRulesError(`${where}: "pattern" is not a valid regular expression: ${err instanceof Error ? err.message : String(err)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate a parsed `.promptci/custom-rules.json` value into typed rules.
|
|
69
|
+
* Accepts either `{ "rules": [...] }` or a bare `[...]` array. Throws a
|
|
70
|
+
* {@link CustomRulesError} naming the offending key on any problem.
|
|
71
|
+
*/
|
|
72
|
+
export function parseCustomRules(raw) {
|
|
73
|
+
let rawRules;
|
|
74
|
+
if (Array.isArray(raw)) {
|
|
75
|
+
rawRules = raw;
|
|
76
|
+
}
|
|
77
|
+
else if (raw && typeof raw === 'object' && 'rules' in raw) {
|
|
78
|
+
rawRules = raw.rules;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw new CustomRulesError('top level must be an object with a "rules" array (or a bare array of rules).');
|
|
82
|
+
}
|
|
83
|
+
if (!Array.isArray(rawRules)) {
|
|
84
|
+
throw new CustomRulesError('"rules" must be an array.');
|
|
85
|
+
}
|
|
86
|
+
const rules = [];
|
|
87
|
+
const seenIds = new Set();
|
|
88
|
+
for (let i = 0; i < rawRules.length; i++) {
|
|
89
|
+
const entry = rawRules[i];
|
|
90
|
+
const where = `rule at index ${i}`;
|
|
91
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
|
|
92
|
+
throw new CustomRulesError(`${where} must be an object.`);
|
|
93
|
+
}
|
|
94
|
+
const obj = entry;
|
|
95
|
+
const id = requireString(obj, 'id', where);
|
|
96
|
+
const ruleWhere = `rule "${id}"`;
|
|
97
|
+
if (seenIds.has(id)) {
|
|
98
|
+
throw new CustomRulesError(`${ruleWhere}: duplicate rule id (ids must be unique).`);
|
|
99
|
+
}
|
|
100
|
+
seenIds.add(id);
|
|
101
|
+
const type = requireString(obj, 'type', ruleWhere);
|
|
102
|
+
if (!CUSTOM_RULE_TYPES.includes(type)) {
|
|
103
|
+
throw new CustomRulesError(`${ruleWhere}: "type" must be one of ${CUSTOM_RULE_TYPES.join(', ')} (got "${type}").`);
|
|
104
|
+
}
|
|
105
|
+
const message = requireString(obj, 'message', ruleWhere);
|
|
106
|
+
let severity = 'warning';
|
|
107
|
+
if ('severity' in obj) {
|
|
108
|
+
if (typeof obj.severity !== 'string' || !VALID_SEVERITIES.includes(obj.severity)) {
|
|
109
|
+
throw new CustomRulesError(`${ruleWhere}: "severity" must be one of ${VALID_SEVERITIES.join(', ')}.`);
|
|
110
|
+
}
|
|
111
|
+
severity = obj.severity;
|
|
112
|
+
}
|
|
113
|
+
const rule = { id, type: type, message, severity };
|
|
114
|
+
if ('files' in obj)
|
|
115
|
+
rule.files = requireStringArray(obj.files, 'files', ruleWhere);
|
|
116
|
+
if ('flags' in obj) {
|
|
117
|
+
if (typeof obj.flags !== 'string') {
|
|
118
|
+
throw new CustomRulesError(`${ruleWhere}: "flags" must be a string.`);
|
|
119
|
+
}
|
|
120
|
+
rule.flags = obj.flags;
|
|
121
|
+
}
|
|
122
|
+
if (type === 'requiredSection') {
|
|
123
|
+
rule.heading = requireString(obj, 'heading', ruleWhere);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// pattern-based types
|
|
127
|
+
rule.pattern = requireString(obj, 'pattern', ruleWhere);
|
|
128
|
+
validateRegex(rule.pattern, rule.flags, ruleWhere);
|
|
129
|
+
}
|
|
130
|
+
rules.push(rule);
|
|
131
|
+
}
|
|
132
|
+
return rules;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Load and validate `.promptci/custom-rules.json` from a repo root. A missing
|
|
136
|
+
* file yields no rules; invalid JSON or an invalid schema throws a
|
|
137
|
+
* {@link CustomRulesError} with an actionable message.
|
|
138
|
+
*/
|
|
139
|
+
export async function loadCustomRules(repoRoot) {
|
|
140
|
+
const filePath = path.join(repoRoot, CUSTOM_RULES_FILE);
|
|
141
|
+
// A config committed as a symlink to a file outside the repo is not read.
|
|
142
|
+
if (!realPathWithinRoot(repoRoot, filePath))
|
|
143
|
+
return [];
|
|
144
|
+
let raw;
|
|
145
|
+
try {
|
|
146
|
+
raw = await fs.readFile(filePath, 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
if (err.code === 'ENOENT')
|
|
150
|
+
return [];
|
|
151
|
+
throw err;
|
|
152
|
+
}
|
|
153
|
+
let parsed;
|
|
154
|
+
try {
|
|
155
|
+
parsed = JSON.parse(raw);
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
throw new CustomRulesError('file is not valid JSON.');
|
|
159
|
+
}
|
|
160
|
+
return parseCustomRules(parsed);
|
|
161
|
+
}
|
|
162
|
+
// ── Interpreter ─────────────────────────────────────────────────────────────
|
|
163
|
+
function shortHash(value) {
|
|
164
|
+
return crypto.createHash('sha1').update(value).digest('hex').slice(0, 12);
|
|
165
|
+
}
|
|
166
|
+
/** 1-based line number of a character offset within `content`. */
|
|
167
|
+
function lineOfOffset(content, offset) {
|
|
168
|
+
let line = 1;
|
|
169
|
+
for (let i = 0; i < offset && i < content.length; i++) {
|
|
170
|
+
if (content[i] === '\n')
|
|
171
|
+
line++;
|
|
172
|
+
}
|
|
173
|
+
return line;
|
|
174
|
+
}
|
|
175
|
+
/** Files a rule targets: all instruction files, or those matching its globs. */
|
|
176
|
+
function targetedFiles(files, rule, repoRoot) {
|
|
177
|
+
if (!rule.files || rule.files.length === 0)
|
|
178
|
+
return files;
|
|
179
|
+
return files.filter((f) => {
|
|
180
|
+
const rel = path.relative(repoRoot, f.path).replace(/\\/g, '/');
|
|
181
|
+
return micromatch.isMatch(rel, rule.files, { dot: true });
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function freshRegex(rule) {
|
|
185
|
+
// A fresh instance per use so a shared `g` flag never leaks lastIndex.
|
|
186
|
+
return new RegExp(rule.pattern, rule.flags);
|
|
187
|
+
}
|
|
188
|
+
function baseIssue(rule) {
|
|
189
|
+
return { severity: rule.severity, category: 'custom', confidence: 1.0, tags: ['custom-rule'] };
|
|
190
|
+
}
|
|
191
|
+
function runForbiddenPattern(files, rule) {
|
|
192
|
+
const issues = [];
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
const match = freshRegex(rule).exec(file.content);
|
|
195
|
+
if (!match)
|
|
196
|
+
continue;
|
|
197
|
+
const line = lineOfOffset(file.content, match.index);
|
|
198
|
+
issues.push({
|
|
199
|
+
id: `custom:${rule.id}:${shortHash(fileIdPath(file))}`,
|
|
200
|
+
...baseIssue(rule),
|
|
201
|
+
title: rule.message,
|
|
202
|
+
summary: `Custom rule "${rule.id}": a forbidden pattern was found in this file.`,
|
|
203
|
+
filePaths: [file.path],
|
|
204
|
+
locations: [{ filePath: file.path, startLine: line, endLine: line }],
|
|
205
|
+
evidence: [`Matched text: "${snippet(match[0], 120)}" (line ${line})`],
|
|
206
|
+
recommendation: `Remove or revise the flagged content to satisfy custom rule "${rule.id}".`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return issues;
|
|
210
|
+
}
|
|
211
|
+
function runAbsentPattern(files, rule) {
|
|
212
|
+
const present = files.some((f) => freshRegex(rule).test(f.content));
|
|
213
|
+
if (present)
|
|
214
|
+
return [];
|
|
215
|
+
return [
|
|
216
|
+
{
|
|
217
|
+
id: `custom:${rule.id}`,
|
|
218
|
+
...baseIssue(rule),
|
|
219
|
+
title: rule.message,
|
|
220
|
+
summary: `Custom rule "${rule.id}": a required pattern is absent from all checked instruction files.`,
|
|
221
|
+
filePaths: files.map((f) => f.path),
|
|
222
|
+
locations: files.map((f) => ({ filePath: f.path })),
|
|
223
|
+
evidence: [`Required pattern was not found in any of ${files.length} checked file(s).`],
|
|
224
|
+
recommendation: `Add content matching custom rule "${rule.id}" to one of the instruction files.`,
|
|
225
|
+
},
|
|
226
|
+
];
|
|
227
|
+
}
|
|
228
|
+
function normalizeHeading(h) {
|
|
229
|
+
return h.toLowerCase().replace(/^#+\s*/, '').replace(/\s+/g, ' ').trim();
|
|
230
|
+
}
|
|
231
|
+
function runRequiredSection(files, rule) {
|
|
232
|
+
const wanted = normalizeHeading(rule.heading);
|
|
233
|
+
const found = files.some((f) => f.sections.some((s) => s.heading !== undefined && normalizeHeading(s.heading).includes(wanted)));
|
|
234
|
+
if (found)
|
|
235
|
+
return [];
|
|
236
|
+
return [
|
|
237
|
+
{
|
|
238
|
+
id: `custom:${rule.id}`,
|
|
239
|
+
...baseIssue(rule),
|
|
240
|
+
title: rule.message,
|
|
241
|
+
summary: `Custom rule "${rule.id}": a required section heading ("${rule.heading}") is missing from all checked files.`,
|
|
242
|
+
filePaths: files.map((f) => f.path),
|
|
243
|
+
locations: files.map((f) => ({ filePath: f.path })),
|
|
244
|
+
evidence: [`No section heading matching "${rule.heading}" was found in ${files.length} checked file(s).`],
|
|
245
|
+
recommendation: `Add a "${rule.heading}" section to one of the instruction files to satisfy custom rule "${rule.id}".`,
|
|
246
|
+
},
|
|
247
|
+
];
|
|
248
|
+
}
|
|
249
|
+
function runCrossFileConflict(files, rule) {
|
|
250
|
+
// value → the files (and the line) where it was captured.
|
|
251
|
+
const byValue = new Map();
|
|
252
|
+
for (const file of files) {
|
|
253
|
+
const match = freshRegex(rule).exec(file.content);
|
|
254
|
+
if (!match)
|
|
255
|
+
continue;
|
|
256
|
+
// Prefer the first capture group when present, else the whole match.
|
|
257
|
+
const value = (match[1] ?? match[0]).trim();
|
|
258
|
+
const line = lineOfOffset(file.content, match.index);
|
|
259
|
+
const list = byValue.get(value) ?? [];
|
|
260
|
+
list.push({ filePath: file.path, line });
|
|
261
|
+
byValue.set(value, list);
|
|
262
|
+
}
|
|
263
|
+
if (byValue.size < 2)
|
|
264
|
+
return [];
|
|
265
|
+
const filePaths = [...new Set([...byValue.values()].flat().map((v) => v.filePath))];
|
|
266
|
+
const locations = [...byValue.values()].flat().map((v) => ({ filePath: v.filePath, startLine: v.line, endLine: v.line }));
|
|
267
|
+
const evidence = [...byValue.entries()].map(([value, where]) => `"${snippet(value, 60)}" in ${where.map((w) => path.basename(w.filePath)).join(', ')}`);
|
|
268
|
+
return [
|
|
269
|
+
{
|
|
270
|
+
id: `custom:${rule.id}`,
|
|
271
|
+
...baseIssue(rule),
|
|
272
|
+
title: rule.message,
|
|
273
|
+
summary: `Custom rule "${rule.id}": the tracked value differs across files (${byValue.size} distinct values).`,
|
|
274
|
+
filePaths,
|
|
275
|
+
locations,
|
|
276
|
+
evidence,
|
|
277
|
+
recommendation: `Reconcile the conflicting values so custom rule "${rule.id}" sees a single consistent value.`,
|
|
278
|
+
},
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
/** Run all validated custom rules over the scanned instruction files. */
|
|
282
|
+
export function runCustomRules(files, rules, repoRoot) {
|
|
283
|
+
const issues = [];
|
|
284
|
+
for (const rule of rules) {
|
|
285
|
+
const scoped = targetedFiles(files, rule, repoRoot);
|
|
286
|
+
switch (rule.type) {
|
|
287
|
+
case 'forbiddenPattern':
|
|
288
|
+
issues.push(...runForbiddenPattern(scoped, rule));
|
|
289
|
+
break;
|
|
290
|
+
case 'absentPattern':
|
|
291
|
+
issues.push(...runAbsentPattern(scoped, rule));
|
|
292
|
+
break;
|
|
293
|
+
case 'requiredSection':
|
|
294
|
+
issues.push(...runRequiredSection(scoped, rule));
|
|
295
|
+
break;
|
|
296
|
+
case 'crossFileConflict':
|
|
297
|
+
issues.push(...runCrossFileConflict(scoped, rule));
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return issues;
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=custom-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-rules.js","sourceRoot":"","sources":["../src/custom-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,13 +7,19 @@
|
|
|
7
7
|
* - Reference-style links: [text][ref] with a `[ref]: path` definition
|
|
8
8
|
* - @-file refs: @AGENTS.md | @docs/guide.md
|
|
9
9
|
*
|
|
10
|
+
* - Directory / extension-less paths (pcic-2b6.8): links like
|
|
11
|
+
* [api](./src/api/) and code spans like `apps/admin/` or `src/payments`
|
|
12
|
+
*
|
|
10
13
|
* External URLs (http/https), anchor-only links (#section), and mailto:
|
|
11
|
-
* are always skipped.
|
|
12
|
-
*
|
|
14
|
+
* are always skipped. File paths need a recognisable extension; a directory or
|
|
15
|
+
* extension-less path in a code span is only checked when its FIRST segment
|
|
16
|
+
* exists in the repository (so `owner/repo`, `origin/main`, `@scope/pkg` and
|
|
17
|
+
* paths describing some other project stay silent).
|
|
13
18
|
*
|
|
14
19
|
* Findings are heuristic — wording is intentionally cautious.
|
|
15
20
|
*/
|
|
16
21
|
import type { InstructionFile, PromptCiIssue } from './types.js';
|
|
22
|
+
export declare function isHomeRooted(ref: string): boolean;
|
|
17
23
|
/**
|
|
18
24
|
* Detect broken file references across all instruction files.
|
|
19
25
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dead-references.d.ts","sourceRoot":"","sources":["../src/dead-references.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dead-references.d.ts","sourceRoot":"","sources":["../src/dead-references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAgTjE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD;AAigBD;;;;;GAKG;AACH;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,eAAe,EAAE,EACxB,QAAQ,EAAE,MAAM,GACf,aAAa,EAAE,CAuGjB"}
|