@nerviq/cli 1.20.0 → 1.21.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 +1 -0
- package/package.json +2 -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 +6 -2
- 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 +312 -67
- 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 +10 -4
- 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/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/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 +120 -10
- 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 +155 -33
- package/src/workspace.js +375 -375
|
@@ -160,10 +160,23 @@ function isValidWindsurfFrontmatter(frontmatter) {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
function docsBundle(ctx) {
|
|
163
|
+
// PP-03: broadened to include the surfaces real Windsurf-using repos
|
|
164
|
+
// actually use for instructions (AGENTS.md, CLAUDE.md, CONTRIBUTING.md,
|
|
165
|
+
// ARCHITECTURE.md, DEVELOPMENT.md) plus the `.ai/` convention observed
|
|
166
|
+
// in ShareX/XerahS and wepublish/wepublish. This mirrors the Gemini
|
|
167
|
+
// PP-02 broadening and ensures docs-quality checks do not FP on repos
|
|
168
|
+
// that keep guidance outside `.windsurf/rules/` alone.
|
|
163
169
|
const rules = allRulesContent(ctx) || '';
|
|
164
170
|
const readme = ctx.fileContent('README.md') || '';
|
|
165
171
|
const legacy = ctx.legacyWindsurfrules ? (ctx.legacyWindsurfrules() || '') : '';
|
|
166
|
-
|
|
172
|
+
const agents = ctx.fileContent('AGENTS.md') || '';
|
|
173
|
+
const claudeMd = ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md') || '';
|
|
174
|
+
const contributing = ctx.fileContent('CONTRIBUTING.md') || '';
|
|
175
|
+
const architecture = ctx.fileContent('ARCHITECTURE.md') || '';
|
|
176
|
+
const development = ctx.fileContent('DEVELOPMENT.md') || ctx.fileContent('DEVELOPING.md') || '';
|
|
177
|
+
const aiInstructions = ctx.fileContent('.ai/instructions.md') || ctx.fileContent('.ai/tech-stack.md') || '';
|
|
178
|
+
const windsurfMd = ctx.fileContent('WINDSURF.md') || ctx.fileContent('windsurf_rules.md') || '';
|
|
179
|
+
return `${rules}\n${readme}\n${legacy}\n${agents}\n${claudeMd}\n${contributing}\n${architecture}\n${development}\n${aiInstructions}\n${windsurfMd}`;
|
|
167
180
|
}
|
|
168
181
|
|
|
169
182
|
function expectedVerificationCategories(ctx) {
|
|
@@ -257,8 +270,14 @@ const WINDSURF_TECHNIQUES = {
|
|
|
257
270
|
id: 'WS-A01',
|
|
258
271
|
name: '.windsurf/rules/ directory exists with .md files',
|
|
259
272
|
check: (ctx) => {
|
|
273
|
+
// PP-03: `windsurfRules()` now also enumerates the
|
|
274
|
+
// `.windsurfrules/` directory form. In addition, pointer-style
|
|
275
|
+
// `.windsurfrules` (one-liner referencing e.g. `.ai/instructions.md`)
|
|
276
|
+
// counts because it resolves to a real instruction body.
|
|
260
277
|
const rules = ctx.windsurfRules ? ctx.windsurfRules() : [];
|
|
261
|
-
|
|
278
|
+
if (rules.length > 0) return true;
|
|
279
|
+
const legacy = ctx.legacyWindsurfrules ? ctx.legacyWindsurfrules() : null;
|
|
280
|
+
return Boolean(legacy && legacy.trim().length > 0);
|
|
262
281
|
},
|
|
263
282
|
impact: 'critical',
|
|
264
283
|
rating: 5,
|
|
@@ -273,8 +292,13 @@ const WINDSURF_TECHNIQUES = {
|
|
|
273
292
|
id: 'WS-A02',
|
|
274
293
|
name: 'No .windsurfrules without migration to .windsurf/rules/',
|
|
275
294
|
check: (ctx) => {
|
|
276
|
-
|
|
277
|
-
|
|
295
|
+
// PP-03: only raw legacy single-file `.windsurfrules` (non-pointer,
|
|
296
|
+
// non-directory) counts as the deprecated form. Pointer files
|
|
297
|
+
// delegating to a modern instruction surface (e.g.
|
|
298
|
+
// `.ai/instructions.md`) and the `.windsurfrules/` directory
|
|
299
|
+
// convention are both acceptable modern patterns.
|
|
300
|
+
const raw = ctx.hasRawLegacyWindsurfrules ? ctx.hasRawLegacyWindsurfrules() : false;
|
|
301
|
+
return !raw;
|
|
278
302
|
},
|
|
279
303
|
impact: 'critical',
|
|
280
304
|
rating: 5,
|
|
@@ -306,9 +330,12 @@ const WINDSURF_TECHNIQUES = {
|
|
|
306
330
|
id: 'WS-A04',
|
|
307
331
|
name: 'Rules have valid YAML frontmatter',
|
|
308
332
|
check: (ctx) => {
|
|
333
|
+
// PP-03: absent frontmatter is acceptable — Windsurf defaults such
|
|
334
|
+
// rules to `always_on`. Only flag when frontmatter *is* present
|
|
335
|
+
// and malformed, or when the declared trigger/field is invalid.
|
|
309
336
|
const rules = ctx.windsurfRules ? ctx.windsurfRules() : [];
|
|
310
337
|
if (rules.length === 0) return null;
|
|
311
|
-
return rules.every((rule) => isValidWindsurfFrontmatter(rule.frontmatter));
|
|
338
|
+
return rules.every((rule) => rule.frontmatter == null || isValidWindsurfFrontmatter(rule.frontmatter));
|
|
312
339
|
},
|
|
313
340
|
impact: 'high',
|
|
314
341
|
rating: 4,
|
|
@@ -462,8 +489,13 @@ const WINDSURF_TECHNIQUES = {
|
|
|
462
489
|
id: 'WS-B03',
|
|
463
490
|
name: 'Workflow slash commands exist in .windsurf/workflows/',
|
|
464
491
|
check: (ctx) => {
|
|
492
|
+
// PP-03: workflows are opt-in. N/A when the repo has no
|
|
493
|
+
// `.windsurf/workflows/` directory at all — firing a fail on every
|
|
494
|
+
// Windsurf repo without workflows produced systematic bias.
|
|
465
495
|
const files = ctx.workflowFiles ? ctx.workflowFiles() : [];
|
|
466
|
-
|
|
496
|
+
if (files.length > 0) return true;
|
|
497
|
+
if (!ctx.hasDir || !ctx.hasDir('.windsurf/workflows')) return null;
|
|
498
|
+
return false;
|
|
467
499
|
},
|
|
468
500
|
impact: 'medium',
|
|
469
501
|
rating: 3,
|
|
@@ -498,8 +530,15 @@ const WINDSURF_TECHNIQUES = {
|
|
|
498
530
|
id: 'WS-B05',
|
|
499
531
|
name: 'Memories configured for persistent context',
|
|
500
532
|
check: (ctx) => {
|
|
533
|
+
// PP-03: memories are workspace-local and strictly opt-in. The
|
|
534
|
+
// technique docs themselves warn not to rely on them (see
|
|
535
|
+
// windsurfMemoryScopeDocumented). Firing a fail on every repo that
|
|
536
|
+
// doesn't ship a `.windsurf/memories/` directory produced a 10/10
|
|
537
|
+
// FP rate. N/A when the repo doesn't opt in.
|
|
501
538
|
const memories = ctx.memoryFiles ? ctx.memoryFiles() : [];
|
|
502
|
-
|
|
539
|
+
if (memories.length > 0) return true;
|
|
540
|
+
if (!ctx.hasDir || !ctx.hasDir('.windsurf/memories')) return null;
|
|
541
|
+
return false;
|
|
503
542
|
},
|
|
504
543
|
impact: 'medium',
|
|
505
544
|
rating: 3,
|
|
@@ -740,10 +779,18 @@ const WINDSURF_TECHNIQUES = {
|
|
|
740
779
|
id: 'WS-D01',
|
|
741
780
|
name: 'Rules properly reach Cascade (not just .windsurfrules)',
|
|
742
781
|
check: (ctx) => {
|
|
782
|
+
// PP-03: `windsurfRules()` now includes `.windsurfrules/`
|
|
783
|
+
// directory form. Pointer-style legacy `.windsurfrules` that
|
|
784
|
+
// points at a modern instruction file (`.ai/instructions.md`,
|
|
785
|
+
// AGENTS.md, etc.) is also acceptable since the referenced body
|
|
786
|
+
// is what Cascade actually receives.
|
|
743
787
|
const rules = ctx.windsurfRules ? ctx.windsurfRules() : [];
|
|
744
788
|
const hasLegacy = ctx.hasLegacyRules ? ctx.hasLegacyRules() : false;
|
|
745
789
|
if (rules.length === 0 && !hasLegacy) return null;
|
|
746
|
-
|
|
790
|
+
if (rules.length > 0) return true;
|
|
791
|
+
// Raw legacy single-file is a genuine miss; pointer/dir is fine.
|
|
792
|
+
const raw = ctx.hasRawLegacyWindsurfrules ? ctx.hasRawLegacyWindsurfrules() : false;
|
|
793
|
+
return !raw;
|
|
747
794
|
},
|
|
748
795
|
impact: 'critical',
|
|
749
796
|
rating: 5,
|
|
@@ -758,9 +805,15 @@ const WINDSURF_TECHNIQUES = {
|
|
|
758
805
|
id: 'WS-D02',
|
|
759
806
|
name: 'Cascade multi-file editing awareness documented',
|
|
760
807
|
check: (ctx) => {
|
|
808
|
+
// PP-03: this is a Cascade-specific awareness advisory. It should
|
|
809
|
+
// only fire when the repo has actual `.windsurf/rules/` content
|
|
810
|
+
// that could reasonably cover Cascade guidance. Pointer-only
|
|
811
|
+
// `.windsurfrules` repos and repos with just a README keep this
|
|
812
|
+
// check N/A — the README is not the right place for Cascade
|
|
813
|
+
// multi-file editing notes.
|
|
761
814
|
const rules = allRulesContent(ctx);
|
|
762
815
|
if (!rules.trim()) return null;
|
|
763
|
-
return /multi.?file|cross.?file|cascade.*edit|multiple.*file/i.test(
|
|
816
|
+
return /multi.?file|cross.?file|cascade.*edit|multiple.*file/i.test(docsBundle(ctx));
|
|
764
817
|
},
|
|
765
818
|
impact: 'medium',
|
|
766
819
|
rating: 3,
|
|
@@ -775,9 +828,11 @@ const WINDSURF_TECHNIQUES = {
|
|
|
775
828
|
id: 'WS-D03',
|
|
776
829
|
name: 'Steps automation awareness documented',
|
|
777
830
|
check: (ctx) => {
|
|
831
|
+
// PP-03: Cascade-specific advisory; N/A when no
|
|
832
|
+
// `.windsurf/rules/` content exists.
|
|
778
833
|
const rules = allRulesContent(ctx);
|
|
779
834
|
if (!rules.trim()) return null;
|
|
780
|
-
return /steps|automation|step.?by.?step|cascade.*step/i.test(
|
|
835
|
+
return /steps|automation|step.?by.?step|cascade.*step/i.test(docsBundle(ctx));
|
|
781
836
|
},
|
|
782
837
|
impact: 'medium',
|
|
783
838
|
rating: 3,
|
|
@@ -792,9 +847,12 @@ const WINDSURF_TECHNIQUES = {
|
|
|
792
847
|
id: 'WS-D04',
|
|
793
848
|
name: 'Agent session length awareness',
|
|
794
849
|
check: (ctx) => {
|
|
850
|
+
// PP-03: Cascade-specific advisory; N/A when no
|
|
851
|
+
// `.windsurf/rules/` content exists (advisory belongs in rules,
|
|
852
|
+
// not in README).
|
|
795
853
|
const rules = allRulesContent(ctx);
|
|
796
854
|
if (!rules.trim()) return null;
|
|
797
|
-
return /session.*length|session.*limit|context.*drift|long.*session/i.test(
|
|
855
|
+
return /session.*length|session.*limit|context.*drift|long.*session/i.test(docsBundle(ctx));
|
|
798
856
|
},
|
|
799
857
|
impact: 'low',
|
|
800
858
|
rating: 2,
|
|
@@ -809,9 +867,13 @@ const WINDSURF_TECHNIQUES = {
|
|
|
809
867
|
id: 'WS-D05',
|
|
810
868
|
name: 'Cascade skills configured for project needs',
|
|
811
869
|
check: (ctx) => {
|
|
870
|
+
// PP-03: the `.windsurf/skills/` directory is itself a valid
|
|
871
|
+
// signal (observed in snyk/snyk-intellij-plugin). Otherwise
|
|
872
|
+
// N/A unless the repo has `.windsurf/rules/` content.
|
|
873
|
+
if (ctx.hasDir && ctx.hasDir('.windsurf/skills')) return true;
|
|
812
874
|
const rules = allRulesContent(ctx);
|
|
813
875
|
if (!rules.trim()) return null;
|
|
814
|
-
return
|
|
876
|
+
return /\bskill\b|\bcapability\b|tool.*use|cascade.*skill/i.test(docsBundle(ctx));
|
|
815
877
|
},
|
|
816
878
|
impact: 'medium',
|
|
817
879
|
rating: 3,
|
|
@@ -925,11 +987,21 @@ const WINDSURF_TECHNIQUES = {
|
|
|
925
987
|
id: 'WS-F01',
|
|
926
988
|
name: 'Rules include build/test/lint commands',
|
|
927
989
|
check: (ctx) => {
|
|
928
|
-
|
|
929
|
-
|
|
990
|
+
// PP-03: verification commands often live in README / AGENTS /
|
|
991
|
+
// CONTRIBUTING. Fall back to the full docsBundle if the core
|
|
992
|
+
// rules don't mention them, so we don't FP on repos that keep
|
|
993
|
+
// commands in a standard README section.
|
|
994
|
+
const core = coreRulesContent(ctx) || allRulesContent(ctx);
|
|
930
995
|
const expected = expectedVerificationCategories(ctx);
|
|
931
|
-
if (expected.length === 0)
|
|
932
|
-
|
|
996
|
+
if (expected.length === 0) {
|
|
997
|
+
const combined = core || docsBundle(ctx);
|
|
998
|
+
if (!combined.trim()) return null;
|
|
999
|
+
return /\bverify\b|\btest\b|\blint\b|\bbuild\b/i.test(combined);
|
|
1000
|
+
}
|
|
1001
|
+
if (expected.every(cat => hasCommandMention(core, cat))) return true;
|
|
1002
|
+
const docs = docsBundle(ctx);
|
|
1003
|
+
if (!docs.trim()) return null;
|
|
1004
|
+
return expected.every(cat => hasCommandMention(docs, cat));
|
|
933
1005
|
},
|
|
934
1006
|
impact: 'high',
|
|
935
1007
|
rating: 5,
|
|
@@ -944,9 +1016,13 @@ const WINDSURF_TECHNIQUES = {
|
|
|
944
1016
|
id: 'WS-F02',
|
|
945
1017
|
name: 'Rules include architecture section or Mermaid diagram',
|
|
946
1018
|
check: (ctx) => {
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
1019
|
+
// PP-03: architecture content commonly lives in ARCHITECTURE.md
|
|
1020
|
+
// or a README section, not duplicated inside rules. Widen to
|
|
1021
|
+
// docsBundle. N/A only when the repo has no instruction surface
|
|
1022
|
+
// whatsoever (not even a README).
|
|
1023
|
+
const bundle = docsBundle(ctx);
|
|
1024
|
+
if (!bundle.trim()) return null;
|
|
1025
|
+
return hasArchitecture(bundle);
|
|
950
1026
|
},
|
|
951
1027
|
impact: 'medium',
|
|
952
1028
|
rating: 4,
|
|
@@ -997,12 +1073,17 @@ const WINDSURF_TECHNIQUES = {
|
|
|
997
1073
|
id: 'WS-F05',
|
|
998
1074
|
name: 'Rules reference project-specific patterns (not generic)',
|
|
999
1075
|
check: (ctx) => {
|
|
1000
|
-
|
|
1076
|
+
// PP-03: widen to docsBundle and add stack-agnostic project
|
|
1077
|
+
// directory markers (internal/, pkg/, cmd/, crates/, modules/,
|
|
1078
|
+
// packages/, tests/, docs/, examples/). The previous JS-heavy
|
|
1079
|
+
// regex produced FPs on Rust/Go/Java/Swift/Kotlin repos whose
|
|
1080
|
+
// project layouts never mention src/app/api etc.
|
|
1081
|
+
const content = docsBundle(ctx);
|
|
1001
1082
|
if (!content.trim()) return null;
|
|
1002
1083
|
const pkg = ctx.jsonFile ? ctx.jsonFile('package.json') : null;
|
|
1003
1084
|
const projectName = (pkg && pkg.name) || path.basename(ctx.dir);
|
|
1004
1085
|
const hasSpecific = content.includes(projectName) ||
|
|
1005
|
-
|
|
1086
|
+
/\b(src|app|api|routes|services|components|lib|cmd|internal|pkg|crates|modules|packages|tests?|docs|examples|scripts)\//i.test(content);
|
|
1006
1087
|
return hasSpecific;
|
|
1007
1088
|
},
|
|
1008
1089
|
impact: 'medium',
|
|
@@ -1471,7 +1552,11 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1471
1552
|
id: 'WS-L01',
|
|
1472
1553
|
name: 'Rules mention modern Windsurf features (Steps, Memories, Workflows)',
|
|
1473
1554
|
check: (ctx) => {
|
|
1474
|
-
|
|
1555
|
+
// PP-03: widen to docsBundle; also credit `.windsurf/workflows` or
|
|
1556
|
+
// `.windsurf/skills` directories as structural evidence that the
|
|
1557
|
+
// repo has adopted modern Windsurf features.
|
|
1558
|
+
if (ctx.hasDir && (ctx.hasDir('.windsurf/workflows') || ctx.hasDir('.windsurf/skills'))) return true;
|
|
1559
|
+
const content = docsBundle(ctx);
|
|
1475
1560
|
if (!content.trim()) return null;
|
|
1476
1561
|
return /steps|memories|workflow|cascade|skill|slash command/i.test(content);
|
|
1477
1562
|
},
|
|
@@ -1488,9 +1573,12 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1488
1573
|
id: 'WS-L02',
|
|
1489
1574
|
name: 'No deprecated patterns (.windsurfrules for agent)',
|
|
1490
1575
|
check: (ctx) => {
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1576
|
+
// PP-03: only the raw single-file legacy form is deprecated.
|
|
1577
|
+
// Pointer-style `.windsurfrules` and the `.windsurfrules/`
|
|
1578
|
+
// directory convention are not.
|
|
1579
|
+
const raw = ctx.hasRawLegacyWindsurfrules ? ctx.hasRawLegacyWindsurfrules() : false;
|
|
1580
|
+
if (!raw) return null;
|
|
1581
|
+
return false;
|
|
1494
1582
|
},
|
|
1495
1583
|
impact: 'high',
|
|
1496
1584
|
rating: 4,
|
|
@@ -1556,7 +1644,11 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1556
1644
|
id: 'WS-L06',
|
|
1557
1645
|
name: 'Rules guide Cascade context usage (@-mentions, file refs)',
|
|
1558
1646
|
check: (ctx) => {
|
|
1559
|
-
|
|
1647
|
+
// PP-03: Cascade-specific deep-quality advisory; N/A when no
|
|
1648
|
+
// `.windsurf/rules/` content exists.
|
|
1649
|
+
const rules = allRulesContent(ctx);
|
|
1650
|
+
if (!rules.trim()) return null;
|
|
1651
|
+
const content = docsBundle(ctx);
|
|
1560
1652
|
if (!content.trim()) return null;
|
|
1561
1653
|
return /@|file.*reference|context.*include|codebase|index/i.test(content);
|
|
1562
1654
|
},
|
|
@@ -1573,9 +1665,11 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1573
1665
|
id: 'WS-L07',
|
|
1574
1666
|
name: 'Session drift awareness documented',
|
|
1575
1667
|
check: (ctx) => {
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1668
|
+
// PP-03: Cascade-specific deep-quality advisory; N/A when no
|
|
1669
|
+
// `.windsurf/rules/` content exists.
|
|
1670
|
+
const rules = allRulesContent(ctx);
|
|
1671
|
+
if (!rules.trim()) return null;
|
|
1672
|
+
return /session.*drift|context.*window|long.*session|session.*length|refresh.*context/i.test(docsBundle(ctx));
|
|
1579
1673
|
},
|
|
1580
1674
|
impact: 'low',
|
|
1581
1675
|
rating: 2,
|
|
@@ -1650,9 +1744,13 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1650
1744
|
id: 'WS-M04',
|
|
1651
1745
|
name: 'Windows/WSL usage includes a Windsurf stability caveat',
|
|
1652
1746
|
check: (ctx) => {
|
|
1747
|
+
// PP-03: relevance was keyed off `os.platform()`, which is the
|
|
1748
|
+
// *host* running the audit (always Windows in our environment),
|
|
1749
|
+
// causing a systematic 10/10 fail on every target repo. This
|
|
1750
|
+
// check should only fire when the *target repo* itself documents
|
|
1751
|
+
// Windows/WSL use — otherwise the advisory is not applicable.
|
|
1653
1752
|
const docs = docsBundle(ctx);
|
|
1654
|
-
|
|
1655
|
-
if (!relevant) return null;
|
|
1753
|
+
if (!/\bwsl\b|\bnative windows\b|\bwindows subsystem\b/i.test(docs)) return null;
|
|
1656
1754
|
return /\bwsl\b.{0,40}\b(crash|unstable|avoid|native windows)\b|\bnative windows\b|\bavoid wsl\b/i.test(docs);
|
|
1657
1755
|
},
|
|
1658
1756
|
impact: 'medium',
|
|
@@ -1672,8 +1770,23 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1672
1770
|
id: 'WS-N01',
|
|
1673
1771
|
name: 'Domain pack detection returns relevant results',
|
|
1674
1772
|
check: (ctx) => {
|
|
1773
|
+
// PP-03: expand stack markers so we also recognise Kotlin/Java
|
|
1774
|
+
// (build.gradle, build.gradle.kts, pom.xml), Swift
|
|
1775
|
+
// (Package.swift, *.xcodeproj), .NET (*.csproj / *.sln), Ruby
|
|
1776
|
+
// (Gemfile), PHP (composer.json), requirements.txt and
|
|
1777
|
+
// Pipfile/poetry. Without these the check FP'd on every
|
|
1778
|
+
// non-JS/Go/Rust/Python repo.
|
|
1675
1779
|
const pkg = ctx.jsonFile ? ctx.jsonFile('package.json') : null;
|
|
1676
|
-
|
|
1780
|
+
if (pkg) return true;
|
|
1781
|
+
const simple = [
|
|
1782
|
+
'go.mod', 'Cargo.toml', 'pyproject.toml', 'requirements.txt',
|
|
1783
|
+
'Pipfile', 'poetry.lock', 'Gemfile', 'composer.json', 'pom.xml',
|
|
1784
|
+
'build.gradle', 'build.gradle.kts', 'Package.swift', 'mix.exs',
|
|
1785
|
+
];
|
|
1786
|
+
if (simple.some(f => ctx.fileContent(f))) return true;
|
|
1787
|
+
const files = ctx.files || [];
|
|
1788
|
+
if (files.some(f => /\.(csproj|sln|fsproj|vbproj|xcodeproj|xcworkspace)\/?$/i.test(f))) return true;
|
|
1789
|
+
return false;
|
|
1677
1790
|
},
|
|
1678
1791
|
impact: 'low',
|
|
1679
1792
|
rating: 2,
|
|
@@ -1688,9 +1801,18 @@ const WINDSURF_TECHNIQUES = {
|
|
|
1688
1801
|
id: 'WS-N02',
|
|
1689
1802
|
name: 'MCP packs recommended based on project signals',
|
|
1690
1803
|
check: (ctx) => {
|
|
1804
|
+
// PP-03: only relevant when the repo actually opts in to MCP
|
|
1805
|
+
// (either documents it or ships a project-local `.windsurf/mcp.json`).
|
|
1806
|
+
// Previously fired on every repo without global MCP config, which
|
|
1807
|
+
// is 10/10 FP against real Windsurf repos that don't use MCP.
|
|
1691
1808
|
const mcp = mcpJsonData(ctx);
|
|
1692
1809
|
const servers = mcp && mcp.mcpServers ? mcp.mcpServers : {};
|
|
1693
|
-
|
|
1810
|
+
if (Object.keys(servers).length > 0) return true;
|
|
1811
|
+
const projectMcp = ctx.mcpConfig ? ctx.mcpConfig() : null;
|
|
1812
|
+
if (projectMcp && projectMcp.ok) return true;
|
|
1813
|
+
const docs = docsBundle(ctx);
|
|
1814
|
+
if (!/\bmcp\b/i.test(docs)) return null;
|
|
1815
|
+
return false;
|
|
1694
1816
|
},
|
|
1695
1817
|
impact: 'low',
|
|
1696
1818
|
rating: 2,
|