@nerviq/cli 1.18.0 → 1.20.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 +131 -130
- 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 +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 +290 -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 +105 -33
- 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
package/src/benchmark.js
CHANGED
|
@@ -2,12 +2,12 @@ const fs = require('fs');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
|
|
5
|
-
const { version } = require('../package.json');
|
|
6
|
-
const { audit } = require('./audit');
|
|
7
|
-
const { setup } = require('./setup');
|
|
8
|
-
const { analyzeProject } = require('./analyze');
|
|
9
|
-
const { getGovernanceSummary } = require('./governance');
|
|
10
|
-
const { formatTerminologyLines } = require('./terminology');
|
|
5
|
+
const { version } = require('../package.json');
|
|
6
|
+
const { audit } = require('./audit');
|
|
7
|
+
const { setup } = require('./setup');
|
|
8
|
+
const { analyzeProject } = require('./analyze');
|
|
9
|
+
const { getGovernanceSummary } = require('./governance');
|
|
10
|
+
const { formatTerminologyLines } = require('./terminology');
|
|
11
11
|
|
|
12
12
|
function copyProject(sourceDir, targetDir) {
|
|
13
13
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
@@ -202,36 +202,36 @@ function buildCaseStudy(before, after, applyResult) {
|
|
|
202
202
|
};
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
function renderBenchmarkMarkdown(report) {
|
|
206
|
-
return [
|
|
207
|
-
'# NERVIQ CLI Benchmark Report',
|
|
208
|
-
'',
|
|
209
|
-
`- Generated by: ${report.generatedBy}`,
|
|
210
|
-
`- Created at: ${report.createdAt}`,
|
|
211
|
-
`- Source repo: ${report.directory}`,
|
|
212
|
-
'',
|
|
213
|
-
'## Score Semantics',
|
|
214
|
-
`- Baseline live audit score: ${report.scoreSemantics.baseline}`,
|
|
215
|
-
`- Projected benchmark score: ${report.scoreSemantics.projected}`,
|
|
216
|
-
`- Organic score: ${report.scoreSemantics.organic}`,
|
|
217
|
-
'',
|
|
218
|
-
'## Methodology',
|
|
219
|
-
...report.methodology.map(item => `- ${item}`),
|
|
220
|
-
'',
|
|
221
|
-
'## Baseline (Live Repo)',
|
|
222
|
-
`- Live audit score: ${report.before.score}/100`,
|
|
223
|
-
`- Organic live score: ${report.before.organicScore}/100`,
|
|
224
|
-
`- Passing checks: ${report.before.passed}/${report.before.checkCount}`,
|
|
225
|
-
'',
|
|
226
|
-
'## Projected (Isolated Benchmark Copy)',
|
|
227
|
-
`- Projected benchmark score: ${report.after.score}/100`,
|
|
228
|
-
`- Projected organic score: ${report.after.organicScore}/100`,
|
|
229
|
-
`- Passing checks: ${report.after.passed}/${report.after.checkCount}`,
|
|
230
|
-
'',
|
|
231
|
-
'## Delta',
|
|
232
|
-
`- Projected score delta: ${report.delta.score}`,
|
|
233
|
-
`- Projected organic score delta: ${report.delta.organicScore}`,
|
|
234
|
-
`- Passed checks delta: ${report.delta.passed}`,
|
|
205
|
+
function renderBenchmarkMarkdown(report) {
|
|
206
|
+
return [
|
|
207
|
+
'# NERVIQ CLI Benchmark Report',
|
|
208
|
+
'',
|
|
209
|
+
`- Generated by: ${report.generatedBy}`,
|
|
210
|
+
`- Created at: ${report.createdAt}`,
|
|
211
|
+
`- Source repo: ${report.directory}`,
|
|
212
|
+
'',
|
|
213
|
+
'## Score Semantics',
|
|
214
|
+
`- Baseline live audit score: ${report.scoreSemantics.baseline}`,
|
|
215
|
+
`- Projected benchmark score: ${report.scoreSemantics.projected}`,
|
|
216
|
+
`- Organic score: ${report.scoreSemantics.organic}`,
|
|
217
|
+
'',
|
|
218
|
+
'## Methodology',
|
|
219
|
+
...report.methodology.map(item => `- ${item}`),
|
|
220
|
+
'',
|
|
221
|
+
'## Baseline (Live Repo)',
|
|
222
|
+
`- Live audit score: ${report.before.score}/100`,
|
|
223
|
+
`- Organic live score: ${report.before.organicScore}/100`,
|
|
224
|
+
`- Passing checks: ${report.before.passed}/${report.before.checkCount}`,
|
|
225
|
+
'',
|
|
226
|
+
'## Projected (Isolated Benchmark Copy)',
|
|
227
|
+
`- Projected benchmark score: ${report.after.score}/100`,
|
|
228
|
+
`- Projected organic score: ${report.after.organicScore}/100`,
|
|
229
|
+
`- Passing checks: ${report.after.passed}/${report.after.checkCount}`,
|
|
230
|
+
'',
|
|
231
|
+
'## Delta',
|
|
232
|
+
`- Projected score delta: ${report.delta.score}`,
|
|
233
|
+
`- Projected organic score delta: ${report.delta.organicScore}`,
|
|
234
|
+
`- Passed checks delta: ${report.delta.passed}`,
|
|
235
235
|
'',
|
|
236
236
|
'## Executive Summary',
|
|
237
237
|
`- ${report.executiveSummary.headline}`,
|
|
@@ -291,14 +291,14 @@ async function runBenchmark(options) {
|
|
|
291
291
|
schemaVersion: 1,
|
|
292
292
|
generatedBy: `nerviq@${version}`,
|
|
293
293
|
createdAt: new Date().toISOString(),
|
|
294
|
-
directory: sourceDir,
|
|
295
|
-
platform,
|
|
296
|
-
scoreSemantics: {
|
|
297
|
-
baseline: 'current repo state before benchmark runs',
|
|
298
|
-
projected: 'starter-safe post-setup score measured on an isolated temp copy',
|
|
299
|
-
organic: 'repo-owned config quality excluding starter-generated Nerviq assets',
|
|
300
|
-
},
|
|
301
|
-
methodology: [
|
|
294
|
+
directory: sourceDir,
|
|
295
|
+
platform,
|
|
296
|
+
scoreSemantics: {
|
|
297
|
+
baseline: 'current repo state before benchmark runs',
|
|
298
|
+
projected: 'starter-safe post-setup score measured on an isolated temp copy',
|
|
299
|
+
organic: 'repo-owned config quality excluding starter-generated Nerviq assets',
|
|
300
|
+
},
|
|
301
|
+
methodology: [
|
|
302
302
|
'Run a baseline audit on the source repo.',
|
|
303
303
|
'Copy the repo into a temporary isolated workspace.',
|
|
304
304
|
`Apply starter-safe ${platform === 'codex' ? 'Codex' : 'Claude'} artifacts only on the isolated copy.`,
|
|
@@ -327,29 +327,29 @@ function printBenchmark(report, options = {}) {
|
|
|
327
327
|
return;
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
-
console.log('');
|
|
331
|
-
console.log(' nerviq benchmark');
|
|
332
|
-
console.log(' ═══════════════════════════════════════');
|
|
333
|
-
console.log(' Runs in an isolated temp copy. Your current repo is not modified.');
|
|
334
|
-
console.log(' Score type: baseline = live repo audit, projected = isolated post-setup benchmark.');
|
|
335
|
-
console.log('');
|
|
336
|
-
const orgDeltaSign = report.delta.organicScore >= 0 ? '+' : '';
|
|
337
|
-
const totalDeltaSign = report.delta.score >= 0 ? '+' : '';
|
|
338
|
-
console.log(` Projected organic delta: \x1b[1m${orgDeltaSign}${report.delta.organicScore} points\x1b[0m (repo-owned config quality)`);
|
|
339
|
-
console.log(` Projected total delta with nerviq setup: ${totalDeltaSign}${report.delta.score} points`);
|
|
340
|
-
console.log('');
|
|
341
|
-
console.log(` Baseline live audit: organic ${report.before.organicScore}/100, total ${report.before.score}/100`);
|
|
342
|
-
console.log(` Projected after setup: organic ${report.after.organicScore}/100, total ${report.after.score}/100`);
|
|
343
|
-
console.log('');
|
|
344
|
-
console.log(` ${report.executiveSummary.headline}`);
|
|
345
|
-
console.log(` Recommendation: ${report.executiveSummary.decisionGuidance}`);
|
|
346
|
-
console.log(` Workflow evidence: ${report.workflowEvidence.summary.passed}/${report.workflowEvidence.summary.total} tasks (${report.workflowEvidence.summary.coverageScore}%)`);
|
|
347
|
-
console.log('');
|
|
348
|
-
for (const line of formatTerminologyLines(['governance', 'hooks', 'mcp'])) {
|
|
349
|
-
console.log(line);
|
|
350
|
-
}
|
|
351
|
-
console.log('');
|
|
352
|
-
}
|
|
330
|
+
console.log('');
|
|
331
|
+
console.log(' nerviq benchmark');
|
|
332
|
+
console.log(' ═══════════════════════════════════════');
|
|
333
|
+
console.log(' Runs in an isolated temp copy. Your current repo is not modified.');
|
|
334
|
+
console.log(' Score type: baseline = live repo audit, projected = isolated post-setup benchmark.');
|
|
335
|
+
console.log('');
|
|
336
|
+
const orgDeltaSign = report.delta.organicScore >= 0 ? '+' : '';
|
|
337
|
+
const totalDeltaSign = report.delta.score >= 0 ? '+' : '';
|
|
338
|
+
console.log(` Projected organic delta: \x1b[1m${orgDeltaSign}${report.delta.organicScore} points\x1b[0m (repo-owned config quality)`);
|
|
339
|
+
console.log(` Projected total delta with nerviq setup: ${totalDeltaSign}${report.delta.score} points`);
|
|
340
|
+
console.log('');
|
|
341
|
+
console.log(` Baseline live audit: organic ${report.before.organicScore}/100, total ${report.before.score}/100`);
|
|
342
|
+
console.log(` Projected after setup: organic ${report.after.organicScore}/100, total ${report.after.score}/100`);
|
|
343
|
+
console.log('');
|
|
344
|
+
console.log(` ${report.executiveSummary.headline}`);
|
|
345
|
+
console.log(` Recommendation: ${report.executiveSummary.decisionGuidance}`);
|
|
346
|
+
console.log(` Workflow evidence: ${report.workflowEvidence.summary.passed}/${report.workflowEvidence.summary.total} tasks (${report.workflowEvidence.summary.coverageScore}%)`);
|
|
347
|
+
console.log('');
|
|
348
|
+
for (const line of formatTerminologyLines(['governance', 'hooks', 'mcp'])) {
|
|
349
|
+
console.log(line);
|
|
350
|
+
}
|
|
351
|
+
console.log('');
|
|
352
|
+
}
|
|
353
353
|
|
|
354
354
|
function writeBenchmarkReport(report, outFile) {
|
|
355
355
|
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
package/src/catalog.js
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public Check Catalog Generator
|
|
3
|
-
* Reads ALL technique files from all 8 platforms and generates a unified JSON catalog.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { version } = require('../package.json');
|
|
9
|
-
|
|
10
|
-
const { TECHNIQUES: CLAUDE_TECHNIQUES } = require('./techniques');
|
|
11
|
-
const { CODEX_TECHNIQUES } = require('./codex/techniques');
|
|
12
|
-
const { GEMINI_TECHNIQUES } = require('./gemini/techniques');
|
|
13
|
-
const { COPILOT_TECHNIQUES } = require('./copilot/techniques');
|
|
14
|
-
const { CURSOR_TECHNIQUES } = require('./cursor/techniques');
|
|
15
|
-
const { WINDSURF_TECHNIQUES } = require('./windsurf/techniques');
|
|
16
|
-
const { AIDER_TECHNIQUES } = require('./aider/techniques');
|
|
17
|
-
const { OPENCODE_TECHNIQUES } = require('./opencode/techniques');
|
|
18
|
-
const { attachSourceUrls } = require('./source-urls');
|
|
19
|
-
|
|
20
|
-
const PLATFORM_MAP = {
|
|
21
|
-
claude: CLAUDE_TECHNIQUES,
|
|
22
|
-
codex: CODEX_TECHNIQUES,
|
|
23
|
-
gemini: GEMINI_TECHNIQUES,
|
|
24
|
-
copilot: COPILOT_TECHNIQUES,
|
|
25
|
-
cursor: CURSOR_TECHNIQUES,
|
|
26
|
-
windsurf: WINDSURF_TECHNIQUES,
|
|
27
|
-
aider: AIDER_TECHNIQUES,
|
|
28
|
-
opencode: OPENCODE_TECHNIQUES,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Generate a unified catalog array from all platform technique files.
|
|
33
|
-
* Each entry contains:
|
|
34
|
-
* platform, id, key, name, category, impact, rating, fix, sourceUrl,
|
|
35
|
-
* confidence, lastVerified, template, deprecated
|
|
36
|
-
*/
|
|
37
|
-
function generateCatalog() {
|
|
38
|
-
const catalog = [];
|
|
39
|
-
|
|
40
|
-
for (const [platform, techniques] of Object.entries(PLATFORM_MAP)) {
|
|
41
|
-
// Clone techniques so we don't mutate the originals
|
|
42
|
-
const cloned = {};
|
|
43
|
-
for (const [key, tech] of Object.entries(techniques)) {
|
|
44
|
-
cloned[key] = { ...tech };
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Attach source URLs
|
|
48
|
-
try {
|
|
49
|
-
attachSourceUrls(platform, cloned);
|
|
50
|
-
} catch (_) {
|
|
51
|
-
// If source URLs fail for a platform, continue without them
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
for (const [key, tech] of Object.entries(cloned)) {
|
|
55
|
-
catalog.push({
|
|
56
|
-
platform,
|
|
57
|
-
id: tech.id ?? null,
|
|
58
|
-
key,
|
|
59
|
-
name: tech.name ?? null,
|
|
60
|
-
category: tech.category ?? null,
|
|
61
|
-
impact: tech.impact ?? null,
|
|
62
|
-
rating: tech.rating ?? null,
|
|
63
|
-
fix: tech.fix ?? null,
|
|
64
|
-
sourceUrl: tech.sourceUrl ?? null,
|
|
65
|
-
confidence: tech.confidence ?? null,
|
|
66
|
-
lastVerified: tech.lastVerified ?? null,
|
|
67
|
-
template: tech.template ?? null,
|
|
68
|
-
deprecated: tech.deprecated ?? false,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return catalog;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Generate a catalog envelope with version metadata.
|
|
78
|
-
* @returns {{ catalogVersion: string, generatedAt: string, totalChecks: number, checks: Object[] }}
|
|
79
|
-
*/
|
|
80
|
-
function generateCatalogWithVersion() {
|
|
81
|
-
const checks = generateCatalog();
|
|
82
|
-
return {
|
|
83
|
-
catalogVersion: version,
|
|
84
|
-
generatedAt: new Date().toISOString(),
|
|
85
|
-
totalChecks: checks.length,
|
|
86
|
-
checks,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Write the catalog as formatted JSON to the given output path.
|
|
92
|
-
* @param {string} outputPath - Absolute or relative path for the JSON file
|
|
93
|
-
* @returns {{ path: string, count: number }} Written path and entry count
|
|
94
|
-
*/
|
|
95
|
-
function writeCatalogJson(outputPath) {
|
|
96
|
-
const catalog = generateCatalog();
|
|
97
|
-
const resolved = path.resolve(outputPath);
|
|
98
|
-
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
99
|
-
fs.writeFileSync(resolved, JSON.stringify(catalog, null, 2) + '\n', 'utf8');
|
|
100
|
-
return { path: resolved, count: catalog.length };
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = { generateCatalog, generateCatalogWithVersion, writeCatalogJson };
|
|
1
|
+
/**
|
|
2
|
+
* Public Check Catalog Generator
|
|
3
|
+
* Reads ALL technique files from all 8 platforms and generates a unified JSON catalog.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const { version } = require('../package.json');
|
|
9
|
+
|
|
10
|
+
const { TECHNIQUES: CLAUDE_TECHNIQUES } = require('./techniques');
|
|
11
|
+
const { CODEX_TECHNIQUES } = require('./codex/techniques');
|
|
12
|
+
const { GEMINI_TECHNIQUES } = require('./gemini/techniques');
|
|
13
|
+
const { COPILOT_TECHNIQUES } = require('./copilot/techniques');
|
|
14
|
+
const { CURSOR_TECHNIQUES } = require('./cursor/techniques');
|
|
15
|
+
const { WINDSURF_TECHNIQUES } = require('./windsurf/techniques');
|
|
16
|
+
const { AIDER_TECHNIQUES } = require('./aider/techniques');
|
|
17
|
+
const { OPENCODE_TECHNIQUES } = require('./opencode/techniques');
|
|
18
|
+
const { attachSourceUrls } = require('./source-urls');
|
|
19
|
+
|
|
20
|
+
const PLATFORM_MAP = {
|
|
21
|
+
claude: CLAUDE_TECHNIQUES,
|
|
22
|
+
codex: CODEX_TECHNIQUES,
|
|
23
|
+
gemini: GEMINI_TECHNIQUES,
|
|
24
|
+
copilot: COPILOT_TECHNIQUES,
|
|
25
|
+
cursor: CURSOR_TECHNIQUES,
|
|
26
|
+
windsurf: WINDSURF_TECHNIQUES,
|
|
27
|
+
aider: AIDER_TECHNIQUES,
|
|
28
|
+
opencode: OPENCODE_TECHNIQUES,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Generate a unified catalog array from all platform technique files.
|
|
33
|
+
* Each entry contains:
|
|
34
|
+
* platform, id, key, name, category, impact, rating, fix, sourceUrl,
|
|
35
|
+
* confidence, lastVerified, template, deprecated
|
|
36
|
+
*/
|
|
37
|
+
function generateCatalog() {
|
|
38
|
+
const catalog = [];
|
|
39
|
+
|
|
40
|
+
for (const [platform, techniques] of Object.entries(PLATFORM_MAP)) {
|
|
41
|
+
// Clone techniques so we don't mutate the originals
|
|
42
|
+
const cloned = {};
|
|
43
|
+
for (const [key, tech] of Object.entries(techniques)) {
|
|
44
|
+
cloned[key] = { ...tech };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Attach source URLs
|
|
48
|
+
try {
|
|
49
|
+
attachSourceUrls(platform, cloned);
|
|
50
|
+
} catch (_) {
|
|
51
|
+
// If source URLs fail for a platform, continue without them
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const [key, tech] of Object.entries(cloned)) {
|
|
55
|
+
catalog.push({
|
|
56
|
+
platform,
|
|
57
|
+
id: tech.id ?? null,
|
|
58
|
+
key,
|
|
59
|
+
name: tech.name ?? null,
|
|
60
|
+
category: tech.category ?? null,
|
|
61
|
+
impact: tech.impact ?? null,
|
|
62
|
+
rating: tech.rating ?? null,
|
|
63
|
+
fix: tech.fix ?? null,
|
|
64
|
+
sourceUrl: tech.sourceUrl ?? null,
|
|
65
|
+
confidence: tech.confidence ?? null,
|
|
66
|
+
lastVerified: tech.lastVerified ?? null,
|
|
67
|
+
template: tech.template ?? null,
|
|
68
|
+
deprecated: tech.deprecated ?? false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return catalog;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Generate a catalog envelope with version metadata.
|
|
78
|
+
* @returns {{ catalogVersion: string, generatedAt: string, totalChecks: number, checks: Object[] }}
|
|
79
|
+
*/
|
|
80
|
+
function generateCatalogWithVersion() {
|
|
81
|
+
const checks = generateCatalog();
|
|
82
|
+
return {
|
|
83
|
+
catalogVersion: version,
|
|
84
|
+
generatedAt: new Date().toISOString(),
|
|
85
|
+
totalChecks: checks.length,
|
|
86
|
+
checks,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Write the catalog as formatted JSON to the given output path.
|
|
92
|
+
* @param {string} outputPath - Absolute or relative path for the JSON file
|
|
93
|
+
* @returns {{ path: string, count: number }} Written path and entry count
|
|
94
|
+
*/
|
|
95
|
+
function writeCatalogJson(outputPath) {
|
|
96
|
+
const catalog = generateCatalog();
|
|
97
|
+
const resolved = path.resolve(outputPath);
|
|
98
|
+
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
99
|
+
fs.writeFileSync(resolved, JSON.stringify(catalog, null, 2) + '\n', 'utf8');
|
|
100
|
+
return { path: resolved, count: catalog.length };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
module.exports = { generateCatalog, generateCatalogWithVersion, writeCatalogJson };
|
package/src/certification.js
CHANGED
|
@@ -1,128 +1,128 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Certification system for Nerviq.
|
|
3
|
-
* Evaluates a project against all active platforms and assigns a certification level.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const { audit } = require('./audit');
|
|
8
|
-
const { harmonyAudit } = require('./harmony/audit');
|
|
9
|
-
const { detectPlatforms } = require('./public-api');
|
|
10
|
-
|
|
11
|
-
const LEVELS = {
|
|
12
|
-
GOLD: 'Nerviq Certified Gold',
|
|
13
|
-
SILVER: 'Nerviq Certified Silver',
|
|
14
|
-
BRONZE: 'Nerviq Certified Bronze',
|
|
15
|
-
NONE: 'Not Certified',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const BADGE_COLORS = {
|
|
19
|
-
[LEVELS.GOLD]: 'gold',
|
|
20
|
-
[LEVELS.SILVER]: 'silver',
|
|
21
|
-
[LEVELS.BRONZE]: 'cd7f32',
|
|
22
|
-
[LEVELS.NONE]: 'lightgrey',
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Certify a project directory.
|
|
27
|
-
* Runs harmony audit and per-platform audits, then determines certification level.
|
|
28
|
-
*
|
|
29
|
-
* @param {string} dir - Project directory path
|
|
30
|
-
* @returns {Promise<{ level: string, harmonyScore: number, platformScores: Object, badge: string }>}
|
|
31
|
-
*/
|
|
32
|
-
async function certifyProject(dir) {
|
|
33
|
-
const resolvedDir = path.resolve(dir || '.');
|
|
34
|
-
|
|
35
|
-
// Detect active platforms
|
|
36
|
-
const platforms = detectPlatforms(resolvedDir);
|
|
37
|
-
|
|
38
|
-
// Run per-platform audits
|
|
39
|
-
const platformScores = {};
|
|
40
|
-
const allAuditResults = [];
|
|
41
|
-
for (const platform of platforms) {
|
|
42
|
-
try {
|
|
43
|
-
const result = await audit({ dir: resolvedDir, platform, silent: true });
|
|
44
|
-
platformScores[platform] = result.score;
|
|
45
|
-
if (Array.isArray(result.results)) {
|
|
46
|
-
allAuditResults.push(...result.results);
|
|
47
|
-
}
|
|
48
|
-
} catch {
|
|
49
|
-
platformScores[platform] = 0;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Run harmony audit
|
|
54
|
-
let harmonyScore = 0;
|
|
55
|
-
try {
|
|
56
|
-
const harmonyResult = await harmonyAudit({ dir: resolvedDir, silent: true });
|
|
57
|
-
harmonyScore = harmonyResult.harmonyScore || 0;
|
|
58
|
-
} catch {
|
|
59
|
-
harmonyScore = 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Determine certification level with security gates
|
|
63
|
-
const scores = Object.values(platformScores);
|
|
64
|
-
const allAbove70 = scores.length > 0 && scores.every(s => s >= 70);
|
|
65
|
-
const allAbove50 = scores.length > 0 && scores.every(s => s >= 50);
|
|
66
|
-
const anyAbove40 = scores.some(s => s >= 40);
|
|
67
|
-
|
|
68
|
-
// Security gate helpers — check whether specific audit checks passed
|
|
69
|
-
const checkPassed = (key) => {
|
|
70
|
-
const match = allAuditResults.find(r => r.key === key);
|
|
71
|
-
return match ? match.passed === true : false;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const gitIgnoreOk = checkPassed('gitIgnoreEnv');
|
|
75
|
-
const secretsOk = checkPassed('secretsProtection');
|
|
76
|
-
const criticalAntiPatterns = allAuditResults.filter(
|
|
77
|
-
r => r.passed === false && r.impact === 'critical'
|
|
78
|
-
);
|
|
79
|
-
const noCriticalAntiPatterns = criticalAntiPatterns.length === 0;
|
|
80
|
-
|
|
81
|
-
// Bronze gate: score >= 40 AND basic security (gitignore + secrets protection)
|
|
82
|
-
const bronzeSecurityGate = gitIgnoreOk && secretsOk;
|
|
83
|
-
// Silver gate: Bronze requirements AND no critical anti-patterns
|
|
84
|
-
const silverSecurityGate = bronzeSecurityGate && noCriticalAntiPatterns;
|
|
85
|
-
|
|
86
|
-
let level;
|
|
87
|
-
if (harmonyScore >= 80 && allAbove70 && silverSecurityGate) {
|
|
88
|
-
level = LEVELS.GOLD;
|
|
89
|
-
} else if (harmonyScore >= 60 && allAbove50 && silverSecurityGate) {
|
|
90
|
-
level = LEVELS.SILVER;
|
|
91
|
-
} else if (anyAbove40 && bronzeSecurityGate) {
|
|
92
|
-
level = LEVELS.BRONZE;
|
|
93
|
-
} else {
|
|
94
|
-
level = LEVELS.NONE;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const badge = generateCertBadge(level);
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
level,
|
|
101
|
-
harmonyScore,
|
|
102
|
-
platformScores,
|
|
103
|
-
platforms,
|
|
104
|
-
badge,
|
|
105
|
-
securityGates: {
|
|
106
|
-
gitIgnoreEnv: gitIgnoreOk,
|
|
107
|
-
secretsProtection: secretsOk,
|
|
108
|
-
noCriticalAntiPatterns,
|
|
109
|
-
criticalAntiPatternCount: criticalAntiPatterns.length,
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Generate a shields.io badge markdown string for a certification level.
|
|
116
|
-
*
|
|
117
|
-
* @param {string} level - One of the LEVELS values
|
|
118
|
-
* @returns {string} Markdown badge string
|
|
119
|
-
*/
|
|
120
|
-
function generateCertBadge(level) {
|
|
121
|
-
const color = BADGE_COLORS[level] || 'lightgrey';
|
|
122
|
-
const label = encodeURIComponent('Nerviq');
|
|
123
|
-
const message = encodeURIComponent(level);
|
|
124
|
-
const url = `https://img.shields.io/badge/${label}-${message}-${color}`;
|
|
125
|
-
return `[](https://nerviq.net)`;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
module.exports = { certifyProject, generateCertBadge, LEVELS };
|
|
1
|
+
/**
|
|
2
|
+
* Certification system for Nerviq.
|
|
3
|
+
* Evaluates a project against all active platforms and assigns a certification level.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { audit } = require('./audit');
|
|
8
|
+
const { harmonyAudit } = require('./harmony/audit');
|
|
9
|
+
const { detectPlatforms } = require('./public-api');
|
|
10
|
+
|
|
11
|
+
const LEVELS = {
|
|
12
|
+
GOLD: 'Nerviq Certified Gold',
|
|
13
|
+
SILVER: 'Nerviq Certified Silver',
|
|
14
|
+
BRONZE: 'Nerviq Certified Bronze',
|
|
15
|
+
NONE: 'Not Certified',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const BADGE_COLORS = {
|
|
19
|
+
[LEVELS.GOLD]: 'gold',
|
|
20
|
+
[LEVELS.SILVER]: 'silver',
|
|
21
|
+
[LEVELS.BRONZE]: 'cd7f32',
|
|
22
|
+
[LEVELS.NONE]: 'lightgrey',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Certify a project directory.
|
|
27
|
+
* Runs harmony audit and per-platform audits, then determines certification level.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} dir - Project directory path
|
|
30
|
+
* @returns {Promise<{ level: string, harmonyScore: number, platformScores: Object, badge: string }>}
|
|
31
|
+
*/
|
|
32
|
+
async function certifyProject(dir) {
|
|
33
|
+
const resolvedDir = path.resolve(dir || '.');
|
|
34
|
+
|
|
35
|
+
// Detect active platforms
|
|
36
|
+
const platforms = detectPlatforms(resolvedDir);
|
|
37
|
+
|
|
38
|
+
// Run per-platform audits
|
|
39
|
+
const platformScores = {};
|
|
40
|
+
const allAuditResults = [];
|
|
41
|
+
for (const platform of platforms) {
|
|
42
|
+
try {
|
|
43
|
+
const result = await audit({ dir: resolvedDir, platform, silent: true });
|
|
44
|
+
platformScores[platform] = result.score;
|
|
45
|
+
if (Array.isArray(result.results)) {
|
|
46
|
+
allAuditResults.push(...result.results);
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
platformScores[platform] = 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Run harmony audit
|
|
54
|
+
let harmonyScore = 0;
|
|
55
|
+
try {
|
|
56
|
+
const harmonyResult = await harmonyAudit({ dir: resolvedDir, silent: true });
|
|
57
|
+
harmonyScore = harmonyResult.harmonyScore || 0;
|
|
58
|
+
} catch {
|
|
59
|
+
harmonyScore = 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Determine certification level with security gates
|
|
63
|
+
const scores = Object.values(platformScores);
|
|
64
|
+
const allAbove70 = scores.length > 0 && scores.every(s => s >= 70);
|
|
65
|
+
const allAbove50 = scores.length > 0 && scores.every(s => s >= 50);
|
|
66
|
+
const anyAbove40 = scores.some(s => s >= 40);
|
|
67
|
+
|
|
68
|
+
// Security gate helpers — check whether specific audit checks passed
|
|
69
|
+
const checkPassed = (key) => {
|
|
70
|
+
const match = allAuditResults.find(r => r.key === key);
|
|
71
|
+
return match ? match.passed === true : false;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const gitIgnoreOk = checkPassed('gitIgnoreEnv');
|
|
75
|
+
const secretsOk = checkPassed('secretsProtection');
|
|
76
|
+
const criticalAntiPatterns = allAuditResults.filter(
|
|
77
|
+
r => r.passed === false && r.impact === 'critical'
|
|
78
|
+
);
|
|
79
|
+
const noCriticalAntiPatterns = criticalAntiPatterns.length === 0;
|
|
80
|
+
|
|
81
|
+
// Bronze gate: score >= 40 AND basic security (gitignore + secrets protection)
|
|
82
|
+
const bronzeSecurityGate = gitIgnoreOk && secretsOk;
|
|
83
|
+
// Silver gate: Bronze requirements AND no critical anti-patterns
|
|
84
|
+
const silverSecurityGate = bronzeSecurityGate && noCriticalAntiPatterns;
|
|
85
|
+
|
|
86
|
+
let level;
|
|
87
|
+
if (harmonyScore >= 80 && allAbove70 && silverSecurityGate) {
|
|
88
|
+
level = LEVELS.GOLD;
|
|
89
|
+
} else if (harmonyScore >= 60 && allAbove50 && silverSecurityGate) {
|
|
90
|
+
level = LEVELS.SILVER;
|
|
91
|
+
} else if (anyAbove40 && bronzeSecurityGate) {
|
|
92
|
+
level = LEVELS.BRONZE;
|
|
93
|
+
} else {
|
|
94
|
+
level = LEVELS.NONE;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const badge = generateCertBadge(level);
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
level,
|
|
101
|
+
harmonyScore,
|
|
102
|
+
platformScores,
|
|
103
|
+
platforms,
|
|
104
|
+
badge,
|
|
105
|
+
securityGates: {
|
|
106
|
+
gitIgnoreEnv: gitIgnoreOk,
|
|
107
|
+
secretsProtection: secretsOk,
|
|
108
|
+
noCriticalAntiPatterns,
|
|
109
|
+
criticalAntiPatternCount: criticalAntiPatterns.length,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Generate a shields.io badge markdown string for a certification level.
|
|
116
|
+
*
|
|
117
|
+
* @param {string} level - One of the LEVELS values
|
|
118
|
+
* @returns {string} Markdown badge string
|
|
119
|
+
*/
|
|
120
|
+
function generateCertBadge(level) {
|
|
121
|
+
const color = BADGE_COLORS[level] || 'lightgrey';
|
|
122
|
+
const label = encodeURIComponent('Nerviq');
|
|
123
|
+
const message = encodeURIComponent(level);
|
|
124
|
+
const url = `https://img.shields.io/badge/${label}-${message}-${color}`;
|
|
125
|
+
return `[](https://nerviq.net)`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = { certifyProject, generateCertBadge, LEVELS };
|