@nerviq/cli 1.18.0 → 1.19.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 +23 -23
- package/README.md +2 -2
- package/bin/cli.js +130 -130
- package/package.json +1 -1
- package/src/activity.js +1039 -1039
- package/src/adoption-advisor.js +299 -299
- package/src/aider/config-parser.js +166 -166
- package/src/aider/context.js +158 -158
- package/src/aider/deep-review.js +316 -316
- package/src/aider/domain-packs.js +303 -303
- package/src/aider/freshness.js +93 -93
- package/src/aider/governance.js +253 -253
- package/src/aider/interactive.js +334 -334
- package/src/aider/mcp-packs.js +329 -329
- package/src/aider/patch.js +214 -214
- package/src/aider/plans.js +186 -186
- package/src/aider/premium.js +360 -360
- package/src/aider/setup.js +404 -404
- package/src/aider/techniques.js +16 -16
- package/src/analyze.js +951 -951
- package/src/anti-patterns.js +485 -485
- package/src/audit/instruction-files.js +180 -180
- package/src/audit/recommendations.js +577 -577
- package/src/auto-suggest.js +154 -154
- package/src/badge.js +13 -13
- package/src/behavioral-drift.js +801 -801
- package/src/benchmark.js +67 -67
- package/src/catalog.js +103 -103
- package/src/certification.js +128 -128
- package/src/codex/config-parser.js +183 -183
- package/src/codex/context.js +223 -223
- package/src/codex/deep-review.js +493 -493
- package/src/codex/domain-packs.js +394 -394
- package/src/codex/freshness.js +84 -84
- package/src/codex/governance.js +192 -192
- package/src/codex/interactive.js +618 -618
- package/src/codex/mcp-packs.js +914 -914
- package/src/codex/patch.js +209 -209
- package/src/codex/plans.js +251 -251
- package/src/codex/premium.js +614 -614
- package/src/codex/setup.js +591 -591
- package/src/context.js +320 -320
- package/src/continuous-ops.js +681 -681
- package/src/copilot/activity.js +309 -309
- package/src/copilot/deep-review.js +346 -346
- package/src/copilot/domain-packs.js +372 -372
- package/src/copilot/freshness.js +57 -57
- package/src/copilot/governance.js +222 -222
- package/src/copilot/interactive.js +406 -406
- package/src/copilot/mcp-packs.js +826 -826
- package/src/copilot/plans.js +253 -253
- package/src/copilot/premium.js +451 -451
- package/src/copilot/setup.js +488 -488
- package/src/cost-tracking.js +61 -61
- package/src/cursor/activity.js +301 -301
- package/src/cursor/config-parser.js +265 -265
- package/src/cursor/context.js +256 -256
- package/src/cursor/deep-review.js +334 -334
- package/src/cursor/domain-packs.js +368 -368
- package/src/cursor/freshness.js +65 -65
- package/src/cursor/governance.js +229 -229
- package/src/cursor/interactive.js +391 -391
- package/src/cursor/mcp-packs.js +828 -828
- package/src/cursor/plans.js +254 -254
- package/src/cursor/premium.js +469 -469
- package/src/cursor/setup.js +488 -488
- package/src/dashboard.js +493 -493
- package/src/deep-review.js +428 -428
- package/src/deprecation.js +98 -98
- package/src/diff-only.js +280 -280
- package/src/doctor.js +119 -119
- package/src/domain-pack-expansion.js +1033 -1033
- package/src/domain-packs.js +387 -387
- package/src/feedback.js +178 -178
- package/src/fix-engine.js +783 -783
- package/src/fix-prompts.js +122 -122
- package/src/formatters/sarif.js +115 -115
- package/src/freshness.js +74 -74
- package/src/gemini/config-parser.js +275 -275
- package/src/gemini/context.js +221 -221
- package/src/gemini/deep-review.js +559 -559
- package/src/gemini/domain-packs.js +393 -393
- package/src/gemini/freshness.js +66 -66
- package/src/gemini/governance.js +201 -201
- package/src/gemini/interactive.js +860 -860
- package/src/gemini/mcp-packs.js +915 -915
- package/src/gemini/plans.js +269 -269
- package/src/gemini/premium.js +760 -760
- package/src/gemini/setup.js +692 -692
- package/src/gemini/techniques.js +14 -14
- package/src/governance.js +72 -72
- package/src/harmony/add.js +68 -68
- package/src/harmony/advisor.js +333 -333
- package/src/harmony/canon.js +565 -565
- package/src/harmony/cli.js +591 -591
- package/src/harmony/drift.js +401 -401
- package/src/harmony/governance.js +313 -313
- package/src/harmony/memory.js +239 -239
- package/src/harmony/sync.js +475 -475
- package/src/harmony/watch.js +370 -370
- package/src/hook-validation.js +342 -342
- package/src/index.js +271 -271
- package/src/init.js +184 -184
- package/src/instruction-surfaces.js +185 -185
- package/src/integrations.js +144 -144
- package/src/interactive.js +118 -118
- package/src/locales/en.json +1 -1
- package/src/locales/es.json +1 -1
- package/src/mcp-packs.js +830 -830
- package/src/mcp-server.js +726 -726
- package/src/mcp-validation.js +337 -337
- package/src/nerviq-sync.json +7 -7
- package/src/opencode/config-parser.js +109 -109
- package/src/opencode/context.js +247 -247
- package/src/opencode/deep-review.js +313 -313
- package/src/opencode/domain-packs.js +262 -262
- package/src/opencode/freshness.js +66 -66
- package/src/opencode/governance.js +159 -159
- package/src/opencode/interactive.js +392 -392
- package/src/opencode/mcp-packs.js +705 -705
- package/src/opencode/patch.js +184 -184
- package/src/opencode/plans.js +231 -231
- package/src/opencode/premium.js +413 -413
- package/src/opencode/setup.js +449 -449
- package/src/opencode/techniques.js +27 -27
- package/src/operating-profile.js +574 -574
- package/src/org.js +152 -152
- package/src/permission-rules.js +218 -218
- package/src/plans.js +839 -839
- package/src/platform-change-manifest.js +86 -86
- package/src/plugins.js +110 -110
- package/src/policy-layers.js +210 -210
- package/src/profiles.js +124 -124
- package/src/prompt-injection.js +74 -74
- package/src/public-api.js +173 -173
- package/src/recommendation-rules.js +84 -84
- package/src/repo-archetype.js +386 -386
- package/src/secret-patterns.js +39 -39
- package/src/server.js +527 -527
- package/src/setup/analysis.js +607 -607
- package/src/setup/runtime.js +172 -172
- package/src/setup.js +677 -677
- package/src/shared/capabilities.js +194 -194
- package/src/source-urls.js +132 -132
- package/src/stack-checks.js +565 -565
- package/src/supplemental-checks.js +13 -13
- package/src/synergy/adaptive.js +261 -261
- package/src/synergy/compensation.js +137 -137
- package/src/synergy/evidence.js +193 -193
- package/src/synergy/learning.js +199 -199
- package/src/synergy/patterns.js +227 -227
- package/src/synergy/ranking.js +83 -83
- package/src/synergy/report.js +165 -165
- package/src/synergy/routing.js +146 -146
- package/src/techniques/api.js +407 -407
- package/src/techniques/automation.js +316 -316
- package/src/techniques/compliance.js +257 -257
- package/src/techniques/hygiene.js +294 -294
- package/src/techniques/instructions.js +243 -243
- package/src/techniques/observability.js +226 -226
- package/src/techniques/optimization.js +142 -142
- package/src/techniques/quality.js +318 -318
- package/src/techniques/security.js +237 -237
- package/src/techniques/shared.js +443 -443
- package/src/techniques/stacks.js +2294 -2294
- package/src/techniques/tools.js +106 -106
- package/src/techniques/workflow.js +413 -413
- package/src/techniques.js +81 -81
- package/src/terminology.js +73 -73
- package/src/token-estimate.js +35 -35
- package/src/usage-patterns.js +99 -99
- package/src/verification-metadata.js +145 -145
- package/src/watch.js +247 -247
- package/src/windsurf/activity.js +302 -302
- package/src/windsurf/config-parser.js +267 -267
- package/src/windsurf/context.js +249 -249
- package/src/windsurf/deep-review.js +337 -337
- package/src/windsurf/domain-packs.js +370 -370
- package/src/windsurf/freshness.js +36 -36
- package/src/windsurf/governance.js +231 -231
- package/src/windsurf/interactive.js +388 -388
- package/src/windsurf/mcp-packs.js +792 -792
- package/src/windsurf/plans.js +247 -247
- package/src/windsurf/premium.js +468 -468
- package/src/windsurf/setup.js +471 -471
- package/src/windsurf/techniques.js +17 -17
- package/src/workspace.js +375 -375
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
const { hasWorkspaceConfig, detectWorkspaceGlobs, detectWorkspaces } = require('../workspace');
|
|
4
|
-
const { estimateTokenCount } = require('../token-estimate');
|
|
5
|
-
|
|
6
|
-
const LARGE_INSTRUCTION_WARN_TOKENS = 12000;
|
|
7
|
-
const LARGE_INSTRUCTION_SKIP_TOKENS = 240000;
|
|
8
|
-
|
|
9
|
-
function normalizeRelativePath(filePath) {
|
|
10
|
-
return String(filePath || '').replace(/\\/g, '/').replace(/^\.\//, '');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function formatCount(value) {
|
|
14
|
-
return Number(value || 0).toLocaleString('en-US');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function addPath(target, filePath) {
|
|
18
|
-
if (!filePath || typeof filePath !== 'string') return;
|
|
19
|
-
target.add(normalizeRelativePath(filePath));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function addDirFiles(ctx, target, dirPath, filter) {
|
|
23
|
-
if (typeof ctx.dirFiles !== 'function') return;
|
|
24
|
-
for (const file of ctx.dirFiles(dirPath)) {
|
|
25
|
-
if (filter && !filter.test(file)) continue;
|
|
26
|
-
addPath(target, path.join(dirPath, file));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function instructionFileCandidates(spec, ctx) {
|
|
31
|
-
const candidates = new Set();
|
|
32
|
-
|
|
33
|
-
if (spec.platform === 'claude') {
|
|
34
|
-
addPath(candidates, 'CLAUDE.md');
|
|
35
|
-
addPath(candidates, '.claude/CLAUDE.md');
|
|
36
|
-
addDirFiles(ctx, candidates, '.claude/rules', /\.md$/i);
|
|
37
|
-
addDirFiles(ctx, candidates, '.claude/commands', /\.md$/i);
|
|
38
|
-
addDirFiles(ctx, candidates, '.claude/agents', /\.md$/i);
|
|
39
|
-
if (typeof ctx.dirFiles === 'function') {
|
|
40
|
-
for (const skillDir of ctx.dirFiles('.claude/skills')) {
|
|
41
|
-
addPath(candidates, path.join('.claude', 'skills', skillDir, 'SKILL.md'));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (spec.platform === 'codex') {
|
|
47
|
-
addPath(candidates, 'AGENTS.md');
|
|
48
|
-
addPath(candidates, 'AGENTS.override.md');
|
|
49
|
-
addPath(candidates, typeof ctx.agentsMdPath === 'function' ? ctx.agentsMdPath() : null);
|
|
50
|
-
addDirFiles(ctx, candidates, 'codex/rules');
|
|
51
|
-
addDirFiles(ctx, candidates, '.codex/rules');
|
|
52
|
-
if (typeof ctx.skillDirs === 'function') {
|
|
53
|
-
for (const skillDir of ctx.skillDirs()) {
|
|
54
|
-
addPath(candidates, path.join('.agents', 'skills', skillDir, 'SKILL.md'));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (spec.platform === 'gemini') {
|
|
60
|
-
addPath(candidates, 'GEMINI.md');
|
|
61
|
-
addPath(candidates, '.gemini/GEMINI.md');
|
|
62
|
-
addDirFiles(ctx, candidates, '.gemini/agents', /\.md$/i);
|
|
63
|
-
if (typeof ctx.skillDirs === 'function') {
|
|
64
|
-
for (const skillDir of ctx.skillDirs()) {
|
|
65
|
-
addPath(candidates, path.join('.gemini', 'skills', skillDir, 'SKILL.md'));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (spec.platform === 'copilot') {
|
|
71
|
-
addPath(candidates, '.github/copilot-instructions.md');
|
|
72
|
-
addDirFiles(ctx, candidates, '.github/instructions', /\.instructions\.md$/i);
|
|
73
|
-
addDirFiles(ctx, candidates, '.github/prompts', /\.prompt\.md$/i);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (spec.platform === 'cursor') {
|
|
77
|
-
addPath(candidates, '.cursorrules');
|
|
78
|
-
addDirFiles(ctx, candidates, '.cursor/rules', /\.mdc$/i);
|
|
79
|
-
addDirFiles(ctx, candidates, '.cursor/commands', /\.md$/i);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (spec.platform === 'windsurf') {
|
|
83
|
-
addPath(candidates, '.windsurfrules');
|
|
84
|
-
addDirFiles(ctx, candidates, '.windsurf/rules', /\.md$/i);
|
|
85
|
-
addDirFiles(ctx, candidates, '.windsurf/workflows', /\.md$/i);
|
|
86
|
-
addDirFiles(ctx, candidates, '.windsurf/memories', /\.(md|json)$/i);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (spec.platform === 'aider' && typeof ctx.conventionFiles === 'function') {
|
|
90
|
-
for (const file of ctx.conventionFiles()) {
|
|
91
|
-
addPath(candidates, file);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (spec.platform === 'opencode') {
|
|
96
|
-
addPath(candidates, 'AGENTS.md');
|
|
97
|
-
addPath(candidates, 'CLAUDE.md');
|
|
98
|
-
addDirFiles(ctx, candidates, '.opencode/commands', /\.(md|markdown|ya?ml)$/i);
|
|
99
|
-
if (typeof ctx.skillDirs === 'function') {
|
|
100
|
-
for (const skillDir of ctx.skillDirs()) {
|
|
101
|
-
addPath(candidates, path.join('.opencode', 'commands', skillDir, 'SKILL.md'));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return [...candidates];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function inspectInstructionFiles(spec, ctx) {
|
|
110
|
-
const warnings = [];
|
|
111
|
-
|
|
112
|
-
for (const filePath of instructionFileCandidates(spec, ctx)) {
|
|
113
|
-
const content = typeof ctx.fileContent === 'function' ? ctx.fileContent(filePath) : null;
|
|
114
|
-
const byteCount = typeof ctx.fileSizeBytes === 'function' ? ctx.fileSizeBytes(filePath) : null;
|
|
115
|
-
const tokenCount = typeof content === 'string' ? estimateTokenCount(content) : null;
|
|
116
|
-
if (!Number.isFinite(tokenCount) || tokenCount <= LARGE_INSTRUCTION_WARN_TOKENS) continue;
|
|
117
|
-
|
|
118
|
-
warnings.push({
|
|
119
|
-
file: normalizeRelativePath(filePath),
|
|
120
|
-
byteCount,
|
|
121
|
-
tokenCount,
|
|
122
|
-
lineCount: typeof content === 'string' ? content.split(/\r?\n/).length : null,
|
|
123
|
-
skipped: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS,
|
|
124
|
-
severity: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS ? 'critical' : 'warning',
|
|
125
|
-
message: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS
|
|
126
|
-
? 'Instruction file exceeds ~240,000 tokens and will be skipped during audit.'
|
|
127
|
-
: 'Instruction file exceeds ~12,000 tokens. Audit will continue, but this file may reduce runtime clarity.',
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return warnings;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function guardSkippedInstructionFiles(ctx, warnings) {
|
|
135
|
-
const skippedFiles = new Set(
|
|
136
|
-
warnings.filter((item) => item.skipped).map((item) => normalizeRelativePath(item.file))
|
|
137
|
-
);
|
|
138
|
-
if (skippedFiles.size === 0) return;
|
|
139
|
-
|
|
140
|
-
const originalFileContent = typeof ctx.fileContent === 'function' ? ctx.fileContent.bind(ctx) : null;
|
|
141
|
-
const originalLineNumber = typeof ctx.lineNumber === 'function' ? ctx.lineNumber.bind(ctx) : null;
|
|
142
|
-
|
|
143
|
-
if (originalFileContent) {
|
|
144
|
-
ctx.fileContent = (filePath) => {
|
|
145
|
-
if (skippedFiles.has(normalizeRelativePath(filePath))) return null;
|
|
146
|
-
return originalFileContent(filePath);
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (originalLineNumber) {
|
|
151
|
-
ctx.lineNumber = (filePath, matcher) => {
|
|
152
|
-
if (skippedFiles.has(normalizeRelativePath(filePath))) return null;
|
|
153
|
-
return originalLineNumber(filePath, matcher);
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function buildWorkspaceHint(dir) {
|
|
159
|
-
if (!hasWorkspaceConfig(dir)) return null;
|
|
160
|
-
|
|
161
|
-
const patterns = detectWorkspaceGlobs(dir);
|
|
162
|
-
const workspaces = detectWorkspaces(dir);
|
|
163
|
-
if (patterns.length === 0 && workspaces.length === 0) return null;
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
detected: true,
|
|
167
|
-
patterns,
|
|
168
|
-
workspaces,
|
|
169
|
-
suggestedCommand: patterns.length > 0
|
|
170
|
-
? `npx nerviq audit --workspace ${patterns.join(',')}`
|
|
171
|
-
: `npx nerviq audit --workspace ${workspaces.join(',')}`,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
module.exports = {
|
|
176
|
-
buildWorkspaceHint,
|
|
177
|
-
formatCount,
|
|
178
|
-
guardSkippedInstructionFiles,
|
|
179
|
-
inspectInstructionFiles,
|
|
180
|
-
};
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const { hasWorkspaceConfig, detectWorkspaceGlobs, detectWorkspaces } = require('../workspace');
|
|
4
|
+
const { estimateTokenCount } = require('../token-estimate');
|
|
5
|
+
|
|
6
|
+
const LARGE_INSTRUCTION_WARN_TOKENS = 12000;
|
|
7
|
+
const LARGE_INSTRUCTION_SKIP_TOKENS = 240000;
|
|
8
|
+
|
|
9
|
+
function normalizeRelativePath(filePath) {
|
|
10
|
+
return String(filePath || '').replace(/\\/g, '/').replace(/^\.\//, '');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function formatCount(value) {
|
|
14
|
+
return Number(value || 0).toLocaleString('en-US');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function addPath(target, filePath) {
|
|
18
|
+
if (!filePath || typeof filePath !== 'string') return;
|
|
19
|
+
target.add(normalizeRelativePath(filePath));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function addDirFiles(ctx, target, dirPath, filter) {
|
|
23
|
+
if (typeof ctx.dirFiles !== 'function') return;
|
|
24
|
+
for (const file of ctx.dirFiles(dirPath)) {
|
|
25
|
+
if (filter && !filter.test(file)) continue;
|
|
26
|
+
addPath(target, path.join(dirPath, file));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function instructionFileCandidates(spec, ctx) {
|
|
31
|
+
const candidates = new Set();
|
|
32
|
+
|
|
33
|
+
if (spec.platform === 'claude') {
|
|
34
|
+
addPath(candidates, 'CLAUDE.md');
|
|
35
|
+
addPath(candidates, '.claude/CLAUDE.md');
|
|
36
|
+
addDirFiles(ctx, candidates, '.claude/rules', /\.md$/i);
|
|
37
|
+
addDirFiles(ctx, candidates, '.claude/commands', /\.md$/i);
|
|
38
|
+
addDirFiles(ctx, candidates, '.claude/agents', /\.md$/i);
|
|
39
|
+
if (typeof ctx.dirFiles === 'function') {
|
|
40
|
+
for (const skillDir of ctx.dirFiles('.claude/skills')) {
|
|
41
|
+
addPath(candidates, path.join('.claude', 'skills', skillDir, 'SKILL.md'));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (spec.platform === 'codex') {
|
|
47
|
+
addPath(candidates, 'AGENTS.md');
|
|
48
|
+
addPath(candidates, 'AGENTS.override.md');
|
|
49
|
+
addPath(candidates, typeof ctx.agentsMdPath === 'function' ? ctx.agentsMdPath() : null);
|
|
50
|
+
addDirFiles(ctx, candidates, 'codex/rules');
|
|
51
|
+
addDirFiles(ctx, candidates, '.codex/rules');
|
|
52
|
+
if (typeof ctx.skillDirs === 'function') {
|
|
53
|
+
for (const skillDir of ctx.skillDirs()) {
|
|
54
|
+
addPath(candidates, path.join('.agents', 'skills', skillDir, 'SKILL.md'));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (spec.platform === 'gemini') {
|
|
60
|
+
addPath(candidates, 'GEMINI.md');
|
|
61
|
+
addPath(candidates, '.gemini/GEMINI.md');
|
|
62
|
+
addDirFiles(ctx, candidates, '.gemini/agents', /\.md$/i);
|
|
63
|
+
if (typeof ctx.skillDirs === 'function') {
|
|
64
|
+
for (const skillDir of ctx.skillDirs()) {
|
|
65
|
+
addPath(candidates, path.join('.gemini', 'skills', skillDir, 'SKILL.md'));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (spec.platform === 'copilot') {
|
|
71
|
+
addPath(candidates, '.github/copilot-instructions.md');
|
|
72
|
+
addDirFiles(ctx, candidates, '.github/instructions', /\.instructions\.md$/i);
|
|
73
|
+
addDirFiles(ctx, candidates, '.github/prompts', /\.prompt\.md$/i);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (spec.platform === 'cursor') {
|
|
77
|
+
addPath(candidates, '.cursorrules');
|
|
78
|
+
addDirFiles(ctx, candidates, '.cursor/rules', /\.mdc$/i);
|
|
79
|
+
addDirFiles(ctx, candidates, '.cursor/commands', /\.md$/i);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (spec.platform === 'windsurf') {
|
|
83
|
+
addPath(candidates, '.windsurfrules');
|
|
84
|
+
addDirFiles(ctx, candidates, '.windsurf/rules', /\.md$/i);
|
|
85
|
+
addDirFiles(ctx, candidates, '.windsurf/workflows', /\.md$/i);
|
|
86
|
+
addDirFiles(ctx, candidates, '.windsurf/memories', /\.(md|json)$/i);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (spec.platform === 'aider' && typeof ctx.conventionFiles === 'function') {
|
|
90
|
+
for (const file of ctx.conventionFiles()) {
|
|
91
|
+
addPath(candidates, file);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (spec.platform === 'opencode') {
|
|
96
|
+
addPath(candidates, 'AGENTS.md');
|
|
97
|
+
addPath(candidates, 'CLAUDE.md');
|
|
98
|
+
addDirFiles(ctx, candidates, '.opencode/commands', /\.(md|markdown|ya?ml)$/i);
|
|
99
|
+
if (typeof ctx.skillDirs === 'function') {
|
|
100
|
+
for (const skillDir of ctx.skillDirs()) {
|
|
101
|
+
addPath(candidates, path.join('.opencode', 'commands', skillDir, 'SKILL.md'));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return [...candidates];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function inspectInstructionFiles(spec, ctx) {
|
|
110
|
+
const warnings = [];
|
|
111
|
+
|
|
112
|
+
for (const filePath of instructionFileCandidates(spec, ctx)) {
|
|
113
|
+
const content = typeof ctx.fileContent === 'function' ? ctx.fileContent(filePath) : null;
|
|
114
|
+
const byteCount = typeof ctx.fileSizeBytes === 'function' ? ctx.fileSizeBytes(filePath) : null;
|
|
115
|
+
const tokenCount = typeof content === 'string' ? estimateTokenCount(content) : null;
|
|
116
|
+
if (!Number.isFinite(tokenCount) || tokenCount <= LARGE_INSTRUCTION_WARN_TOKENS) continue;
|
|
117
|
+
|
|
118
|
+
warnings.push({
|
|
119
|
+
file: normalizeRelativePath(filePath),
|
|
120
|
+
byteCount,
|
|
121
|
+
tokenCount,
|
|
122
|
+
lineCount: typeof content === 'string' ? content.split(/\r?\n/).length : null,
|
|
123
|
+
skipped: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS,
|
|
124
|
+
severity: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS ? 'critical' : 'warning',
|
|
125
|
+
message: tokenCount > LARGE_INSTRUCTION_SKIP_TOKENS
|
|
126
|
+
? 'Instruction file exceeds ~240,000 tokens and will be skipped during audit.'
|
|
127
|
+
: 'Instruction file exceeds ~12,000 tokens. Audit will continue, but this file may reduce runtime clarity.',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return warnings;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function guardSkippedInstructionFiles(ctx, warnings) {
|
|
135
|
+
const skippedFiles = new Set(
|
|
136
|
+
warnings.filter((item) => item.skipped).map((item) => normalizeRelativePath(item.file))
|
|
137
|
+
);
|
|
138
|
+
if (skippedFiles.size === 0) return;
|
|
139
|
+
|
|
140
|
+
const originalFileContent = typeof ctx.fileContent === 'function' ? ctx.fileContent.bind(ctx) : null;
|
|
141
|
+
const originalLineNumber = typeof ctx.lineNumber === 'function' ? ctx.lineNumber.bind(ctx) : null;
|
|
142
|
+
|
|
143
|
+
if (originalFileContent) {
|
|
144
|
+
ctx.fileContent = (filePath) => {
|
|
145
|
+
if (skippedFiles.has(normalizeRelativePath(filePath))) return null;
|
|
146
|
+
return originalFileContent(filePath);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (originalLineNumber) {
|
|
151
|
+
ctx.lineNumber = (filePath, matcher) => {
|
|
152
|
+
if (skippedFiles.has(normalizeRelativePath(filePath))) return null;
|
|
153
|
+
return originalLineNumber(filePath, matcher);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function buildWorkspaceHint(dir) {
|
|
159
|
+
if (!hasWorkspaceConfig(dir)) return null;
|
|
160
|
+
|
|
161
|
+
const patterns = detectWorkspaceGlobs(dir);
|
|
162
|
+
const workspaces = detectWorkspaces(dir);
|
|
163
|
+
if (patterns.length === 0 && workspaces.length === 0) return null;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
detected: true,
|
|
167
|
+
patterns,
|
|
168
|
+
workspaces,
|
|
169
|
+
suggestedCommand: patterns.length > 0
|
|
170
|
+
? `npx nerviq audit --workspace ${patterns.join(',')}`
|
|
171
|
+
: `npx nerviq audit --workspace ${workspaces.join(',')}`,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
module.exports = {
|
|
176
|
+
buildWorkspaceHint,
|
|
177
|
+
formatCount,
|
|
178
|
+
guardSkippedInstructionFiles,
|
|
179
|
+
inspectInstructionFiles,
|
|
180
|
+
};
|