@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
package/dist/types.d.ts
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
/** Core data types for PromptCI */
|
|
2
|
-
export type FileType = 'claude' | 'agents' | 'cursor' | 'copilot' | 'readme' | 'docs' | 'prompt' | 'unknown';
|
|
2
|
+
export type FileType = 'claude' | 'agents' | 'cursor' | 'windsurf' | 'copilot' | 'gemini' | 'cline' | 'persona' | 'readme' | 'docs' | 'prompt' | 'skill' | 'agent' | 'unknown';
|
|
3
|
+
/**
|
|
4
|
+
* Persistent, always-loaded agent instruction file types: the allowlist the
|
|
5
|
+
* prose detectors (negative-instruction overload, buried-critical, within-
|
|
6
|
+
* section dedup, prompt-cache friendliness) target. `context optimize` uses it
|
|
7
|
+
* minus 'persona', which it never rewrites.
|
|
8
|
+
*
|
|
9
|
+
* One shared definition on purpose (BUG-19): each detector used to carry its
|
|
10
|
+
* own copy, so a newly discovered file type was scanned and counted toward
|
|
11
|
+
* context cost but silently skipped by every copy nobody remembered to update.
|
|
12
|
+
* README/docs are human-facing and deliberately excluded.
|
|
13
|
+
*/
|
|
14
|
+
export declare const INSTRUCTION_FILE_TYPES: ReadonlySet<FileType>;
|
|
15
|
+
export declare function isOnDemandFileType(fileType: FileType): boolean;
|
|
3
16
|
export type IssueSeverity = 'info' | 'warning' | 'high' | 'critical';
|
|
4
|
-
export type IssueCategory = 'duplicate' | 'conflict' | 'context_bloat' | 'missing_context' | 'stale_instruction' | 'vague_guidance' | 'structure' | 'command_validity' | 'agent_practices' | 'security';
|
|
17
|
+
export type IssueCategory = 'duplicate' | 'conflict' | 'context_bloat' | 'missing_context' | 'stale_instruction' | 'vague_guidance' | 'structure' | 'command_validity' | 'agent_practices' | 'ai_config' | 'security' | 'custom';
|
|
5
18
|
export type InstructionSection = {
|
|
6
19
|
id: string;
|
|
7
20
|
filePath: string;
|
|
21
|
+
/**
|
|
22
|
+
* `filePath` relative to the scan root, forward slashes. Set by the scanner;
|
|
23
|
+
* finding ids hash this instead of the absolute path so one repo scanned from
|
|
24
|
+
* two checkout locations yields identical ids (see finding-id.ts).
|
|
25
|
+
*/
|
|
26
|
+
relativePath?: string;
|
|
8
27
|
heading?: string;
|
|
9
28
|
startLine: number;
|
|
10
29
|
endLine: number;
|
|
@@ -13,6 +32,18 @@ export type InstructionSection = {
|
|
|
13
32
|
};
|
|
14
33
|
export type InstructionFile = {
|
|
15
34
|
path: string;
|
|
35
|
+
/**
|
|
36
|
+
* `path` relative to the scan root, forward slashes. Set by the scanner;
|
|
37
|
+
* finding ids hash this instead of the absolute path (see finding-id.ts).
|
|
38
|
+
* Optional so hand-built test fixtures keep type-checking.
|
|
39
|
+
*/
|
|
40
|
+
relativePath?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Set only on a symlink ALIAS: the `relativePath` of the file this name is a
|
|
43
|
+
* symlink to, which is the copy detectors scan (the alias is listed in the
|
|
44
|
+
* report inventory but never scanned, so its content is not double-counted).
|
|
45
|
+
*/
|
|
46
|
+
aliasOf?: string;
|
|
16
47
|
fileType: FileType;
|
|
17
48
|
content: string;
|
|
18
49
|
sections: InstructionSection[];
|
|
@@ -34,7 +65,15 @@ export type PromptCiIssue = {
|
|
|
34
65
|
}>;
|
|
35
66
|
evidence: string[];
|
|
36
67
|
recommendation: string;
|
|
68
|
+
/** Advisory, human-readable "here's how to fix it" text. Not machine-applied. */
|
|
37
69
|
fixRecipe?: string;
|
|
70
|
+
/**
|
|
71
|
+
* True only when `applyFixRecipe` implements a mechanical, reversible edit for
|
|
72
|
+
* this issue and it is safe to auto-apply. Gates `promptci fix` (see
|
|
73
|
+
* `isRepairable`). Detectors set this deliberately per recipe — it is never
|
|
74
|
+
* inferred from the presence of `fixRecipe`, which is usually advisory prose.
|
|
75
|
+
*/
|
|
76
|
+
autoApplySafe?: boolean;
|
|
38
77
|
confidence: number;
|
|
39
78
|
tags?: string[];
|
|
40
79
|
impact?: 'high' | 'medium' | 'low';
|
|
@@ -44,7 +83,8 @@ export type TopFix = {
|
|
|
44
83
|
reason: string;
|
|
45
84
|
suggestedAction: string;
|
|
46
85
|
};
|
|
47
|
-
export
|
|
86
|
+
export declare const PROJECT_TYPES: readonly ["auto", "typescript", "nextjs", "unity", "dotnet", "python", "go", "rust", "unknown"];
|
|
87
|
+
export type ProjectType = (typeof PROJECT_TYPES)[number];
|
|
48
88
|
export type ScanTrend = {
|
|
49
89
|
previousScanDate?: string;
|
|
50
90
|
scoreDelta: number;
|
|
@@ -83,6 +123,8 @@ export type ScanMetrics = {
|
|
|
83
123
|
path: string;
|
|
84
124
|
estimatedTokens: number;
|
|
85
125
|
}>;
|
|
126
|
+
onDemandFileCount?: number;
|
|
127
|
+
estimatedOnDemandTokens?: number;
|
|
86
128
|
};
|
|
87
129
|
/**
|
|
88
130
|
* R1: report.json intentionally omits InstructionFile's `content` and
|
|
@@ -98,7 +140,10 @@ export type ScanMetrics = {
|
|
|
98
140
|
* that matches what's really on disk, instead of the full in-memory
|
|
99
141
|
* `ScanReport`/`InstructionFile` types.
|
|
100
142
|
*/
|
|
101
|
-
export type CompactFileSummary = Pick<InstructionFile, 'path' | 'fileType' | 'lineCount' | 'charCount' | 'estimatedTokens'
|
|
143
|
+
export type CompactFileSummary = Pick<InstructionFile, 'path' | 'fileType' | 'lineCount' | 'charCount' | 'estimatedTokens'> & {
|
|
144
|
+
/** Repo-relative path of the file this entry is a symlink to (aliases only). */
|
|
145
|
+
aliasOf?: string;
|
|
146
|
+
};
|
|
102
147
|
export type ScanReportJson = Omit<ScanReport, 'filesScanned'> & {
|
|
103
148
|
filesScanned: CompactFileSummary[];
|
|
104
149
|
};
|
|
@@ -124,5 +169,18 @@ export type ScanInput = {
|
|
|
124
169
|
baseline?: Baseline;
|
|
125
170
|
contextBudget?: number;
|
|
126
171
|
fileContextBudget?: number;
|
|
172
|
+
/**
|
|
173
|
+
* FEAT-012: a target-model preset name (e.g. `claude-opus-5`) that scales the
|
|
174
|
+
* context-bloat thresholds to that model's context window. An explicit
|
|
175
|
+
* `contextBudget`/`fileContextBudget` always overrides the preset. Surfaced
|
|
176
|
+
* as the `targetModel` config key and `--target-model` flag.
|
|
177
|
+
*/
|
|
178
|
+
targetModel?: string;
|
|
179
|
+
/**
|
|
180
|
+
* FEAT-004: force every vague-guidance finding to this severity, overriding
|
|
181
|
+
* the detector's high-signal/soft tiering. Surfaced as the
|
|
182
|
+
* `vagueGuidanceSeverity` config key.
|
|
183
|
+
*/
|
|
184
|
+
vagueGuidanceSeverity?: 'info' | 'warning';
|
|
127
185
|
};
|
|
128
186
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mCAAmC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
1
|
/** Core data types for PromptCI */
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Persistent, always-loaded agent instruction file types: the allowlist the
|
|
4
|
+
* prose detectors (negative-instruction overload, buried-critical, within-
|
|
5
|
+
* section dedup, prompt-cache friendliness) target. `context optimize` uses it
|
|
6
|
+
* minus 'persona', which it never rewrites.
|
|
7
|
+
*
|
|
8
|
+
* One shared definition on purpose (BUG-19): each detector used to carry its
|
|
9
|
+
* own copy, so a newly discovered file type was scanned and counted toward
|
|
10
|
+
* context cost but silently skipped by every copy nobody remembered to update.
|
|
11
|
+
* README/docs are human-facing and deliberately excluded.
|
|
12
|
+
*/
|
|
13
|
+
export const INSTRUCTION_FILE_TYPES = new Set([
|
|
14
|
+
'claude',
|
|
15
|
+
'agents',
|
|
16
|
+
'cursor',
|
|
17
|
+
'windsurf',
|
|
18
|
+
'copilot',
|
|
19
|
+
'gemini',
|
|
20
|
+
'cline',
|
|
21
|
+
'persona',
|
|
22
|
+
'prompt',
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* On-demand file types are loaded by an agent only when a skill/subagent is
|
|
26
|
+
* invoked, not on every turn. They do not count toward always-loaded context
|
|
27
|
+
* cost and are owned by the ai_config detectors, so the generic prose detectors
|
|
28
|
+
* skip them.
|
|
29
|
+
*/
|
|
30
|
+
const ON_DEMAND_FILE_TYPES = new Set(['skill', 'agent']);
|
|
31
|
+
export function isOnDemandFileType(fileType) {
|
|
32
|
+
return ON_DEMAND_FILE_TYPES.has(fileType);
|
|
33
|
+
}
|
|
34
|
+
// Single source of truth: consumers that need to *validate* a project type at
|
|
35
|
+
// runtime (the CLI's config loader, `promptci init`) import this array rather
|
|
36
|
+
// than keeping their own copy, which is how `python`/`go`/`rust` previously
|
|
37
|
+
// ended up writable by `init` but rejected by `loadConfig`.
|
|
38
|
+
export const PROJECT_TYPES = [
|
|
39
|
+
'auto',
|
|
40
|
+
'typescript',
|
|
41
|
+
'nextjs',
|
|
42
|
+
'unity',
|
|
43
|
+
'dotnet',
|
|
44
|
+
'python',
|
|
45
|
+
'go',
|
|
46
|
+
'rust',
|
|
47
|
+
'unknown',
|
|
48
|
+
];
|
|
3
49
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mCAAmC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mCAAmC;AA0BnC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA0B,IAAI,GAAG,CAAW;IAC7E,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,SAAS;IACT,QAAQ;IACR,OAAO;IACP,SAAS;IACT,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,oBAAoB,GAA0B,IAAI,GAAG,CAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAE1F,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,OAAO,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAuFD,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,MAAM;IACN,YAAY;IACZ,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,MAAM;IACN,SAAS;CACD,CAAC"}
|
package/dist/vague-guidance.d.ts
CHANGED
|
@@ -5,8 +5,21 @@
|
|
|
5
5
|
* Emits at most one issue per section regardless of how many vague phrases
|
|
6
6
|
* appear in it.
|
|
7
7
|
*
|
|
8
|
-
* Heuristic detector
|
|
8
|
+
* Heuristic detector. Findings are tiered (FEAT-004): high-signal platitudes
|
|
9
|
+
* ("write clean code", "best practices", "SOLID principles", …) are
|
|
10
|
+
* warning 0.80; soft style/UX/paradigm phrases are info 0.75. A team can force
|
|
11
|
+
* one severity for every finding via the `severityOverride` option (wired to
|
|
12
|
+
* the `vagueGuidanceSeverity` config key).
|
|
9
13
|
*/
|
|
10
14
|
import type { InstructionFile, PromptCiIssue } from './types.js';
|
|
11
|
-
export
|
|
15
|
+
export type VagueGuidanceOptions = {
|
|
16
|
+
/**
|
|
17
|
+
* FEAT-004: force every vague-guidance finding to this severity, overriding
|
|
18
|
+
* the per-section high-signal/soft tiering. Wired to the `vagueGuidanceSeverity`
|
|
19
|
+
* config key so teams can enforce a stricter (all-warning) or looser
|
|
20
|
+
* (all-info) posture. Confidence still reflects the matched tier.
|
|
21
|
+
*/
|
|
22
|
+
severityOverride?: 'info' | 'warning';
|
|
23
|
+
};
|
|
24
|
+
export declare function detectVagueGuidance(files: InstructionFile[], options?: VagueGuidanceOptions): PromptCiIssue[];
|
|
12
25
|
//# sourceMappingURL=vague-guidance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vague-guidance.d.ts","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vague-guidance.d.ts","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAqC,aAAa,EAAE,MAAM,YAAY,CAAC;AAsLpG,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EAAE,EACxB,OAAO,GAAE,oBAAyB,GACjC,aAAa,EAAE,CA8DjB"}
|
package/dist/vague-guidance.js
CHANGED
|
@@ -5,9 +5,15 @@
|
|
|
5
5
|
* Emits at most one issue per section regardless of how many vague phrases
|
|
6
6
|
* appear in it.
|
|
7
7
|
*
|
|
8
|
-
* Heuristic detector
|
|
8
|
+
* Heuristic detector. Findings are tiered (FEAT-004): high-signal platitudes
|
|
9
|
+
* ("write clean code", "best practices", "SOLID principles", …) are
|
|
10
|
+
* warning 0.80; soft style/UX/paradigm phrases are info 0.75. A team can force
|
|
11
|
+
* one severity for every finding via the `severityOverride` option (wired to
|
|
12
|
+
* the `vagueGuidanceSeverity` config key).
|
|
9
13
|
*/
|
|
10
14
|
import * as crypto from 'node:crypto';
|
|
15
|
+
import { stripCodeBlocks } from './markdown-fences.js';
|
|
16
|
+
import { sectionIdPath } from './finding-id.js';
|
|
11
17
|
const VAGUE_PHRASES = [
|
|
12
18
|
'write clean code',
|
|
13
19
|
'write clean', // catches "write clean Go code", "write clean Python code", etc.
|
|
@@ -105,6 +111,31 @@ function expandHyphenVariants(phrases) {
|
|
|
105
111
|
return [...expanded];
|
|
106
112
|
}
|
|
107
113
|
const ALL_VAGUE_PHRASES = expandHyphenVariants(VAGUE_PHRASES);
|
|
114
|
+
/**
|
|
115
|
+
* FEAT-004: High-signal platitudes. These are the phrases that most reliably
|
|
116
|
+
* mark instruction rot — broad quality/effort exhortations that give an agent
|
|
117
|
+
* no constraint at all. A section containing any of them is emitted at
|
|
118
|
+
* `warning` (0.80); sections whose only matches are softer style/UX/paradigm
|
|
119
|
+
* phrases stay `info` (0.75). Listed in the post-hyphen-expansion form so the
|
|
120
|
+
* no-hyphen twins ("production ready" ↔ "production-ready") both qualify.
|
|
121
|
+
*/
|
|
122
|
+
const HIGH_SIGNAL_PHRASES = new Set([
|
|
123
|
+
'write clean code',
|
|
124
|
+
'write clean',
|
|
125
|
+
'use best practices',
|
|
126
|
+
'best practices',
|
|
127
|
+
'follow best practices',
|
|
128
|
+
'make it production ready',
|
|
129
|
+
'production ready',
|
|
130
|
+
'production-ready',
|
|
131
|
+
'production quality',
|
|
132
|
+
'production-quality',
|
|
133
|
+
'be careful',
|
|
134
|
+
'solid principles',
|
|
135
|
+
'follow solid',
|
|
136
|
+
'clean architecture',
|
|
137
|
+
'make it maintainable',
|
|
138
|
+
]);
|
|
108
139
|
function escapeRegExp(text) {
|
|
109
140
|
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
110
141
|
}
|
|
@@ -115,41 +146,6 @@ function escapeRegExp(text) {
|
|
|
115
146
|
* reused across every section/file.
|
|
116
147
|
*/
|
|
117
148
|
const PHRASE_PATTERNS = new Map(ALL_VAGUE_PHRASES.map((phrase) => [phrase, new RegExp(`\\b${escapeRegExp(phrase)}\\b`)]));
|
|
118
|
-
/**
|
|
119
|
-
* V4: Strip fenced code blocks (``` and ~~~, matching either fence
|
|
120
|
-
* character/length per CommonMark — see scanner.ts) and inline code spans
|
|
121
|
-
* before matching. A fenced example that quotes a vague phrase is
|
|
122
|
-
* documentation about the phrase, not real guidance directed at the agent.
|
|
123
|
-
*/
|
|
124
|
-
function stripCodeBlocks(text) {
|
|
125
|
-
const lines = text.split('\n');
|
|
126
|
-
const kept = [];
|
|
127
|
-
let inBlock = false;
|
|
128
|
-
let fenceChar = null;
|
|
129
|
-
let fenceLen = 0;
|
|
130
|
-
for (const line of lines) {
|
|
131
|
-
if (!inBlock) {
|
|
132
|
-
const openMatch = /^ {0,3}([`~]{3,})/.exec(line);
|
|
133
|
-
if (openMatch) {
|
|
134
|
-
inBlock = true;
|
|
135
|
-
fenceChar = openMatch[1][0] ?? null;
|
|
136
|
-
fenceLen = openMatch[1].length;
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
kept.push(line);
|
|
140
|
-
}
|
|
141
|
-
else {
|
|
142
|
-
const closeMatch = /^ {0,3}([`~]{3,})\s*$/.exec(line);
|
|
143
|
-
if (closeMatch && closeMatch[1][0] === fenceChar && closeMatch[1].length >= fenceLen) {
|
|
144
|
-
inBlock = false;
|
|
145
|
-
fenceChar = null;
|
|
146
|
-
fenceLen = 0;
|
|
147
|
-
}
|
|
148
|
-
// else: still inside the fence — drop the line
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
return kept.join('\n').replace(/`[^`\n]+`/g, '');
|
|
152
|
-
}
|
|
153
149
|
/**
|
|
154
150
|
* V1: Find lines (or pairs of consecutive wrapped lines) containing `phraseRe`
|
|
155
151
|
* within the per-line length budget. Hard-wrapped guidance like:
|
|
@@ -177,11 +173,11 @@ function findPhraseMatches(scanText, phraseRe) {
|
|
|
177
173
|
return matches;
|
|
178
174
|
}
|
|
179
175
|
function issueId(section) {
|
|
180
|
-
const key = `${section
|
|
176
|
+
const key = `${sectionIdPath(section)}:${section.startLine}:vague`;
|
|
181
177
|
const hash = crypto.createHash('sha1').update(key).digest('hex').slice(0, 12);
|
|
182
178
|
return `vague-${hash}`;
|
|
183
179
|
}
|
|
184
|
-
export function detectVagueGuidance(files) {
|
|
180
|
+
export function detectVagueGuidance(files, options = {}) {
|
|
185
181
|
const issues = [];
|
|
186
182
|
// One issue per section — collect all matching phrases and lines first
|
|
187
183
|
const seen = new Set();
|
|
@@ -190,7 +186,7 @@ export function detectVagueGuidance(files) {
|
|
|
190
186
|
const sectionKey = `${file.path}:${section.startLine}`;
|
|
191
187
|
if (seen.has(sectionKey))
|
|
192
188
|
continue;
|
|
193
|
-
const scanText = stripCodeBlocks(section.text);
|
|
189
|
+
const scanText = stripCodeBlocks(section.text, { stripInlineCode: true });
|
|
194
190
|
// V1: collapse newlines to spaces for this fast pre-filter only, so a
|
|
195
191
|
// phrase hard-wrapped across two lines still passes the gate. The actual
|
|
196
192
|
// evidence extraction below (findPhraseMatches) independently re-checks
|
|
@@ -214,9 +210,16 @@ export function detectVagueGuidance(files) {
|
|
|
214
210
|
continue;
|
|
215
211
|
seen.add(sectionKey);
|
|
216
212
|
const phraseList = matchedPhrases.map((p) => `"${p}"`).join(', ');
|
|
213
|
+
// FEAT-004: tier by the strongest phrase in the section. Any high-signal
|
|
214
|
+
// platitude escalates the whole finding to warning; a config override,
|
|
215
|
+
// when set, wins over the derived tier (but not the tier-based confidence).
|
|
216
|
+
const isHighSignal = matchedPhrases.some((p) => HIGH_SIGNAL_PHRASES.has(p));
|
|
217
|
+
const tierSeverity = isHighSignal ? 'warning' : 'info';
|
|
218
|
+
const severity = options.severityOverride ?? tierSeverity;
|
|
219
|
+
const confidence = isHighSignal ? 0.8 : 0.75;
|
|
217
220
|
issues.push({
|
|
218
221
|
id: issueId(section),
|
|
219
|
-
severity
|
|
222
|
+
severity,
|
|
220
223
|
category: 'vague_guidance',
|
|
221
224
|
title: 'Vague guidance detected',
|
|
222
225
|
summary: `This section contains guidance that may be too vague to be actionable: ${phraseList}.`,
|
|
@@ -226,7 +229,7 @@ export function detectVagueGuidance(files) {
|
|
|
226
229
|
recommendation: 'Replace vague guidance with concrete constraints — specific commands, forbidden ' +
|
|
227
230
|
'patterns, or measurable criteria. For example, replace "write clean code" with ' +
|
|
228
231
|
'"functions must be ≤ 50 lines; no unused variables".',
|
|
229
|
-
confidence
|
|
232
|
+
confidence,
|
|
230
233
|
});
|
|
231
234
|
}
|
|
232
235
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vague-guidance.js","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"vague-guidance.js","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,aAAa,GAAG;IACpB,kBAAkB;IAClB,aAAa,EAAU,iEAAiE;IACxF,oBAAoB;IACpB,0BAA0B;IAC1B,kBAAkB,EAAQ,gDAAgD;IAC1E,kBAAkB;IAClB,YAAY;IACZ,oBAAoB;IACpB,sBAAsB;IACtB,kBAAkB;IAClB,gBAAgB;IAChB,oBAAoB;IACpB,gBAAgB,EAAY,oDAAoD;IAChF,oBAAoB,EAAQ,kCAAkC;IAC9D,oBAAoB,EAAQ,yBAAyB;IACrD,uBAAuB,EAAK,gBAAgB;IAC5C,gBAAgB,EAAY,yBAAyB;IACrD,4BAA4B;IAC5B,gBAAgB;IAChB,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,+EAA+E;IAC/E,kBAAkB,EAAU,uCAAuC;IACnE,cAAc,EAAc,mBAAmB;IAC/C,kBAAkB,EAAU,kCAAkC;IAC9D,sBAAsB,EAAM,yBAAyB;IACrD,oBAAoB,EAAQ,6BAA6B;IACzD,kBAAkB,EAAU,+BAA+B;IAC3D,+FAA+F;IAC/F,oBAAoB,EAAQ,2DAA2D;IACvF,mBAAmB,EAAS,0DAA0D;IACtF,eAAe,EAAa,wDAAwD;IACpF,mBAAmB,EAAS,qDAAqD;IACjF,mBAAmB,EAAS,yBAAyB;IACrD,2BAA2B,EAAE,gDAAgD;IAC7E,oFAAoF;IACpF,qFAAqF;IACrF,+EAA+E;IAC/E,mCAAmC,EAAG,6CAA6C;IACnF,iBAAiB,EAAqB,4CAA4C;IAClF,gFAAgF;IAChF,2BAA2B,EAAK,uCAAuC;IACvE,gBAAgB;IAChB,wBAAwB,EAAQ,2BAA2B;IAC3D,mBAAmB;IACnB,cAAc;IACd,aAAa;IACb,aAAa;IACb,uBAAuB,EAAS,8DAA8D;IAC9F,uBAAuB,EAAS,0BAA0B;IAC1D,uBAAuB;IACvB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,eAAe;IACf,aAAa;IACb,YAAY;IACZ,sDAAsD;IACtD,YAAY,EAAgB,4BAA4B;IACxD,oBAAoB,EAAQ,+BAA+B;IAC3D,aAAa,EAAe,0BAA0B;IACtD,gFAAgF;IAChF,0BAA0B,EAAE,gDAAgD;IAC5E,4BAA4B;IAC5B,8BAA8B;IAC9B,cAAc,EAAc,4BAA4B;IACxD,gBAAgB;IAChB,kBAAkB;IAClB,kBAAkB;IAClB,sBAAsB;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAEpC;;;;;;GAMG;AACH,SAAS,oBAAoB,CAAC,OAAiB;IAC7C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACrB,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAS;IAC1C,kBAAkB;IAClB,aAAa;IACb,oBAAoB;IACpB,gBAAgB;IAChB,uBAAuB;IACvB,0BAA0B;IAC1B,kBAAkB;IAClB,kBAAkB;IAClB,oBAAoB;IACpB,oBAAoB;IACpB,YAAY;IACZ,kBAAkB;IAClB,cAAc;IACd,oBAAoB;IACpB,sBAAsB;CACvB,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,iBAAiB,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CACzF,CAAC;AAGF;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,QAAgB,EAAE,QAAgB;IAC3D,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;QAChC,IAAI,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,uBAAuB,EAAE,CAAC;YAC9F,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAED,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,MAAM,MAAM,GAAG,GAAG,MAAM,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,uBAAuB,EAAE,CAAC;gBACpF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,OAAO,CAAC,OAA2B;IAC1C,MAAM,GAAG,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,SAAS,QAAQ,CAAC;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9E,OAAO,SAAS,IAAI,EAAE,CAAC;AACzB,CAAC;AAYD,MAAM,UAAU,mBAAmB,CACjC,KAAwB,EACxB,UAAgC,EAAE;IAElC,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,uEAAuE;IACvE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,UAAU,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACvD,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;gBAAE,SAAS;YAEnC,MAAM,QAAQ,GAAG,eAAe,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;YAC1E,sEAAsE;YACtE,yEAAyE;YACzE,wEAAwE;YACxE,0EAA0E;YAC1E,6CAA6C;YAC7C,MAAM,kBAAkB,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACtE,MAAM,cAAc,GAAa,EAAE,CAAC;YACpC,MAAM,YAAY,GAAa,EAAE,CAAC;YAElC,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;gBACvC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;gBAC9C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,kBAAkB,CAAC;oBAAE,SAAS;gBAEjD,KAAK,MAAM,IAAI,IAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;oBACzD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC;wBAAE,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAClE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;wBAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC;YAED,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YAC1C,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAErB,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAElE,yEAAyE;YACzE,uEAAuE;YACvE,4EAA4E;YAC5E,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,MAAM,YAAY,GAAkB,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;YACtE,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,IAAI,YAAY,CAAC;YAC1D,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAE7C,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC;gBACpB,QAAQ;gBACR,QAAQ,EAAE,gBAAgB;gBAC1B,KAAK,EAAE,yBAAyB;gBAChC,OAAO,EAAE,0EAA0E,UAAU,GAAG;gBAChG,SAAS,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;gBACtB,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC5F,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC7D,cAAc,EACZ,kFAAkF;oBAClF,iFAAiF;oBACjF,sDAAsD;gBACxD,UAAU;aACX,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf Rules Detector (issue #67)
|
|
3
|
+
*
|
|
4
|
+
* `.windsurfrules` is Windsurf's legacy, always-on, workspace-wide rules file:
|
|
5
|
+
* every rule in it is fed to the model on every request for the whole
|
|
6
|
+
* workspace. Windsurf also supports scoped `.windsurf/rules/*.md` files with
|
|
7
|
+
* glob / manual / model-decision activation.
|
|
8
|
+
*
|
|
9
|
+
* This detector flags one thing the generic prose detectors miss: a workspace
|
|
10
|
+
* `.windsurfrules` that clearly carries language- or framework-specific rules,
|
|
11
|
+
* which are cheaper as glob-scoped rules that load only for matching files. It
|
|
12
|
+
* emits a single cautious `info` suggesting the author clarify intended scope.
|
|
13
|
+
*
|
|
14
|
+
* The Windsurf-specific size/truncation check for `.windsurfrules` lives in
|
|
15
|
+
* `context-bloat.ts`, alongside the other file-type-specific size thresholds.
|
|
16
|
+
*
|
|
17
|
+
* Deterministic and offline.
|
|
18
|
+
*/
|
|
19
|
+
import type { RepoContext } from './repo-context.js';
|
|
20
|
+
import type { PromptCiIssue } from './types.js';
|
|
21
|
+
export declare function detectWindsurfRules(context: RepoContext): PromptCiIssue[];
|
|
22
|
+
//# sourceMappingURL=windsurf-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windsurf-detector.d.ts","sourceRoot":"","sources":["../src/windsurf-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAA6B,aAAa,EAAE,MAAM,YAAY,CAAC;AAoC3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAiDzE"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windsurf Rules Detector (issue #67)
|
|
3
|
+
*
|
|
4
|
+
* `.windsurfrules` is Windsurf's legacy, always-on, workspace-wide rules file:
|
|
5
|
+
* every rule in it is fed to the model on every request for the whole
|
|
6
|
+
* workspace. Windsurf also supports scoped `.windsurf/rules/*.md` files with
|
|
7
|
+
* glob / manual / model-decision activation.
|
|
8
|
+
*
|
|
9
|
+
* This detector flags one thing the generic prose detectors miss: a workspace
|
|
10
|
+
* `.windsurfrules` that clearly carries language- or framework-specific rules,
|
|
11
|
+
* which are cheaper as glob-scoped rules that load only for matching files. It
|
|
12
|
+
* emits a single cautious `info` suggesting the author clarify intended scope.
|
|
13
|
+
*
|
|
14
|
+
* The Windsurf-specific size/truncation check for `.windsurfrules` lives in
|
|
15
|
+
* `context-bloat.ts`, alongside the other file-type-specific size thresholds.
|
|
16
|
+
*
|
|
17
|
+
* Deterministic and offline.
|
|
18
|
+
*/
|
|
19
|
+
import { shortHash } from './ai-config.js';
|
|
20
|
+
import { fileIdPath } from './finding-id.js';
|
|
21
|
+
import { aliasesWithNewType, groupAliasesByTarget } from './alias-files.js';
|
|
22
|
+
/**
|
|
23
|
+
* Language / framework signals that, when they appear as SECTION HEADINGS in an
|
|
24
|
+
* always-on workspace file, indicate rules scoped to only part of the codebase.
|
|
25
|
+
* Heading-only matching keeps this precise: a passing mention of "python" in
|
|
26
|
+
* prose does not count, but a `## Python` section does. Terms are chosen to be
|
|
27
|
+
* unambiguous in a heading (e.g. `golang`, not bare `go`).
|
|
28
|
+
*/
|
|
29
|
+
const SCOPED_TOPICS = [
|
|
30
|
+
{ label: 'TypeScript', re: /\btypescript\b/i },
|
|
31
|
+
{ label: 'JavaScript', re: /\bjavascript\b/i },
|
|
32
|
+
{ label: 'Python', re: /\bpython\b/i },
|
|
33
|
+
{ label: 'Rust', re: /\brust\b/i },
|
|
34
|
+
{ label: 'Go', re: /\bgolang\b/i },
|
|
35
|
+
{ label: 'Ruby', re: /\bruby\b|\brails\b/i },
|
|
36
|
+
{ label: 'Java', re: /\bjava\b(?!script)/i },
|
|
37
|
+
{ label: 'Kotlin', re: /\bkotlin\b/i },
|
|
38
|
+
{ label: 'Swift', re: /\bswift\b/i },
|
|
39
|
+
{ label: 'C#', re: /\bc#|\bcsharp\b|\bdotnet\b|\.net\b/i },
|
|
40
|
+
{ label: 'React', re: /\breact\b/i },
|
|
41
|
+
{ label: 'Vue', re: /\bvue\b/i },
|
|
42
|
+
{ label: 'Svelte', re: /\bsvelte\b/i },
|
|
43
|
+
{ label: 'Django', re: /\bdjango\b/i },
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Two or more distinct scoped topics in headings is a strong, low-noise signal
|
|
47
|
+
* that an always-on file mixes rule sets that would be better glob-scoped. One
|
|
48
|
+
* topic is left alone — a single `## Python` section in a Python repo is normal.
|
|
49
|
+
*/
|
|
50
|
+
const MIN_DISTINCT_TOPICS = 2;
|
|
51
|
+
export function detectWindsurfRules(context) {
|
|
52
|
+
const issues = [];
|
|
53
|
+
// `.windsurfrules -> AGENTS.md`: Windsurf loads that content always-on under the alias's name, so the
|
|
54
|
+
// check runs for the alias (against the real content) unless the real file is already a Windsurf file.
|
|
55
|
+
// Several links to one file are one finding listing every link, not one per link.
|
|
56
|
+
const isWindsurf = (type) => type === 'windsurf';
|
|
57
|
+
const groups = [
|
|
58
|
+
...context.files.filter((file) => file.fileType === 'windsurf').map((file) => [file]),
|
|
59
|
+
...groupAliasesByTarget(aliasesWithNewType(context.files, context.aliasFiles ?? [], isWindsurf)),
|
|
60
|
+
];
|
|
61
|
+
for (const group of groups) {
|
|
62
|
+
const file = group[0];
|
|
63
|
+
const topics = new Set();
|
|
64
|
+
for (const section of file.sections) {
|
|
65
|
+
const heading = section.heading;
|
|
66
|
+
if (!heading)
|
|
67
|
+
continue;
|
|
68
|
+
for (const topic of SCOPED_TOPICS) {
|
|
69
|
+
if (topic.re.test(heading))
|
|
70
|
+
topics.add(topic.label);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (topics.size >= MIN_DISTINCT_TOPICS) {
|
|
74
|
+
const found = [...topics].sort();
|
|
75
|
+
issues.push({
|
|
76
|
+
id: `ai-config-windsurf-scope-${shortHash(fileIdPath(file))}`,
|
|
77
|
+
severity: 'info',
|
|
78
|
+
category: 'ai_config',
|
|
79
|
+
title: '.windsurfrules mixes language-specific rules in a workspace-wide file',
|
|
80
|
+
summary: `This \`.windsurfrules\` has headings for multiple languages/frameworks ` +
|
|
81
|
+
`(${found.join(', ')}), but it applies to the whole workspace on every ` +
|
|
82
|
+
`request. Language- or framework-specific rules are cheaper as glob-scoped ` +
|
|
83
|
+
`rules that load only for matching files.`,
|
|
84
|
+
filePaths: group.map((f) => f.path),
|
|
85
|
+
locations: group.map((f) => ({ filePath: f.path, startLine: 1 })),
|
|
86
|
+
evidence: [`Scoped topics found in headings: ${found.join(', ')}`],
|
|
87
|
+
recommendation: 'Clarify the intended scope: keep genuinely workspace-wide conventions in ' +
|
|
88
|
+
'`.windsurfrules`, and move language- or framework-specific rules into ' +
|
|
89
|
+
'glob-scoped `.windsurf/rules/*.md` files, each with a glob trigger.',
|
|
90
|
+
confidence: 0.6,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return issues;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=windsurf-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windsurf-detector.js","sourceRoot":"","sources":["../src/windsurf-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Within-section semantic dedup detector (FEAT-013).
|
|
3
|
+
*
|
|
4
|
+
* The cross-file `detectDuplicates` detector works at section granularity and
|
|
5
|
+
* misses a single section that restates the same point several ways. This
|
|
6
|
+
* detector looks *inside* a section: for sections with more than five
|
|
7
|
+
* paragraphs, it computes pairwise Jaccard similarity on the paragraphs and
|
|
8
|
+
* flags any pair that is ≥ 0.65 similar, naming the paragraph numbers.
|
|
9
|
+
*
|
|
10
|
+
* Info severity only — near-duplicate prose within one section is worth a
|
|
11
|
+
* gentle nudge, not a hard failure. Deterministic: no clock, network, or
|
|
12
|
+
* randomness.
|
|
13
|
+
*/
|
|
14
|
+
import type { InstructionFile, PromptCiIssue } from './types.js';
|
|
15
|
+
export declare function detectWithinSectionDedup(files: InstructionFile[]): PromptCiIssue[];
|
|
16
|
+
//# sourceMappingURL=within-section-dedup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"within-section-dedup.d.ts","sourceRoot":"","sources":["../src/within-section-dedup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AA6FrF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,aAAa,EAAE,CA2DlF"}
|