@nerviq/cli 1.2.2 → 1.2.5
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/README.md +1 -0
- package/package.json +2 -2
- package/src/activity.js +12 -12
- package/src/aider/activity.js +1 -1
- package/src/claudex-sync.json +3 -3
- package/src/codex/activity.js +1 -1
- package/src/codex/patch.js +1 -1
- package/src/codex/techniques.js +32 -34
- package/src/copilot/patch.js +1 -1
- package/src/copilot/premium.js +2 -1
- package/src/cursor/patch.js +1 -1
- package/src/cursor/premium.js +2 -1
- package/src/feedback.js +13 -8
- package/src/gemini/activity.js +1 -1
- package/src/gemini/patch.js +1 -1
- package/src/gemini/premium.js +3 -2
- package/src/gemini/techniques.js +14 -13
- package/src/harmony/advisor.js +5 -65
- package/src/harmony/audit.js +3 -0
- package/src/harmony/canon.js +99 -1
- package/src/harmony/cli.js +21 -0
- package/src/harmony/drift.js +2 -2
- package/src/harmony/memory.js +9 -8
- package/src/insights.js +1 -1
- package/src/opencode/activity.js +1 -1
- package/src/opencode/patch.js +1 -1
- package/src/opencode/techniques.js +15 -13
- package/src/shared/capabilities.js +194 -0
- package/src/state-paths.js +85 -0
- package/src/synergy/compensation.js +1 -20
- package/src/synergy/learning.js +20 -5
- package/src/synergy/routing.js +8 -14
- package/src/techniques.js +2981 -2929
- package/src/windsurf/patch.js +1 -1
- package/src/windsurf/premium.js +2 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@nerviq/cli)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://github.com/nerviq/nerviq)
|
|
8
|
+
[](https://nerviq.net)
|
|
8
9
|
|
|
9
10
|
---
|
|
10
11
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nerviq/cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "The intelligent nervous system for AI coding agents — 2,306 checks across 8 platforms and 10 languages. Audit, align, and amplify.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"test": "node test/run.js",
|
|
19
19
|
"test:jest": "jest",
|
|
20
20
|
"test:coverage": "jest --coverage",
|
|
21
|
-
"test:all": "npm test && npx jest && node test/check-matrix.js && node test/codex-check-matrix.js && node test/gemini-check-matrix.js && node test/copilot-check-matrix.js && node test/cursor-check-matrix.js && node test/golden-matrix.js && node test/codex-golden-matrix.js && node test/gemini-golden-matrix.js && node test/copilot-golden-matrix.js && node test/cursor-golden-matrix.js",
|
|
21
|
+
"test:all": "npm test && npx jest && node test/check-matrix.js && node test/codex-check-matrix.js && node test/gemini-check-matrix.js && node test/copilot-check-matrix.js && node test/cursor-check-matrix.js && node test/windsurf-check-matrix.js && node test/aider-check-matrix.js && node test/opencode-check-matrix.js && node test/golden-matrix.js && node test/codex-golden-matrix.js && node test/gemini-golden-matrix.js && node test/copilot-golden-matrix.js && node test/cursor-golden-matrix.js && node test/windsurf-golden-matrix.js && node test/aider-golden-matrix.js && node test/opencode-golden-matrix.js",
|
|
22
22
|
"benchmark:perf": "node tools/benchmark.js",
|
|
23
23
|
"catalog": "node -e \"const {generateCatalog}=require('./src/catalog');console.log(JSON.stringify(generateCatalog(),null,2))\""
|
|
24
24
|
},
|
package/src/activity.js
CHANGED
|
@@ -2,6 +2,10 @@ const fs = require('fs');
|
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { version } = require('../package.json');
|
|
5
|
+
const {
|
|
6
|
+
resolveProjectStateReadPath,
|
|
7
|
+
ensureProjectStateDir,
|
|
8
|
+
} = require('./state-paths');
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Generate a machine-level user identity for audit tracking.
|
|
@@ -33,15 +37,11 @@ function timestampId() {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
function ensureArtifactDirs(dir) {
|
|
36
|
-
const root =
|
|
37
|
-
const activityDir =
|
|
38
|
-
const rollbackDir =
|
|
39
|
-
const snapshotDir =
|
|
40
|
-
const outcomesDir =
|
|
41
|
-
fs.mkdirSync(activityDir, { recursive: true });
|
|
42
|
-
fs.mkdirSync(rollbackDir, { recursive: true });
|
|
43
|
-
fs.mkdirSync(snapshotDir, { recursive: true });
|
|
44
|
-
fs.mkdirSync(outcomesDir, { recursive: true });
|
|
40
|
+
const root = ensureProjectStateDir(dir);
|
|
41
|
+
const activityDir = ensureProjectStateDir(dir, 'activity');
|
|
42
|
+
const rollbackDir = ensureProjectStateDir(dir, 'rollbacks');
|
|
43
|
+
const snapshotDir = ensureProjectStateDir(dir, 'snapshots');
|
|
44
|
+
const outcomesDir = ensureProjectStateDir(dir, 'outcomes');
|
|
45
45
|
return { root, activityDir, rollbackDir, snapshotDir, outcomesDir };
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -161,7 +161,7 @@ function updateSnapshotIndex(snapshotDir, record) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
/**
|
|
164
|
-
* Write a normalized snapshot artifact to .
|
|
164
|
+
* Write a normalized snapshot artifact to .nerviq/snapshots/ and update the index.
|
|
165
165
|
* @param {string} dir - Project root directory.
|
|
166
166
|
* @param {string} snapshotKind - Snapshot type ('audit', 'benchmark', 'governance', 'augment', 'suggest-only').
|
|
167
167
|
* @param {Object} payload - Full result payload to persist.
|
|
@@ -208,7 +208,7 @@ function writeSnapshotArtifact(dir, snapshotKind, payload, meta = {}) {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function readSnapshotIndex(dir) {
|
|
211
|
-
const indexPath =
|
|
211
|
+
const indexPath = resolveProjectStateReadPath(dir, 'snapshots', 'index.json');
|
|
212
212
|
if (!fs.existsSync(indexPath)) return [];
|
|
213
213
|
try {
|
|
214
214
|
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
@@ -344,7 +344,7 @@ function exportTrendReport(dir) {
|
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
function readOutcomeIndex(dir) {
|
|
347
|
-
const indexPath =
|
|
347
|
+
const indexPath = resolveProjectStateReadPath(dir, 'outcomes', 'index.json');
|
|
348
348
|
if (!fs.existsSync(indexPath)) return [];
|
|
349
349
|
try {
|
|
350
350
|
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
package/src/aider/activity.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Adapts the shared activity/snapshot backend for Aider platform.
|
|
5
5
|
* Provides: history, compare, trend, watch, feedback, insights.
|
|
6
6
|
*
|
|
7
|
-
* Aider snapshots stored in .claude/claudex-setup/snapshots/ filtered by platform='aider'.
|
|
7
|
+
* Aider snapshots stored in .nerviq/snapshots/ (legacy: .claude/claudex-setup/snapshots/) filtered by platform='aider'.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
const path = require('path');
|
package/src/claudex-sync.json
CHANGED
package/src/codex/activity.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides: history, compare, trend, watch, feedback, insights.
|
|
6
6
|
*
|
|
7
7
|
* Codex snapshots are stored alongside Claude snapshots in
|
|
8
|
-
* .claude/claudex-setup/snapshots/ but filtered by platform='codex'.
|
|
8
|
+
* .nerviq/snapshots/ (legacy: .claude/claudex-setup/snapshots/) but filtered by platform='codex'.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const path = require('path');
|
package/src/codex/patch.js
CHANGED
|
@@ -166,7 +166,7 @@ function applyPatch(dir, filePath, patchFn, options = {}) {
|
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// Backup + write
|
|
169
|
-
const backupPath = fullPath + '.
|
|
169
|
+
const backupPath = fullPath + '.nerviq-backup';
|
|
170
170
|
fs.writeFileSync(backupPath, original, 'utf8');
|
|
171
171
|
fs.writeFileSync(fullPath, patched, 'utf8');
|
|
172
172
|
|
package/src/codex/techniques.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { EMBEDDED_SECRET_PATTERNS, containsEmbeddedSecret } = require('../secret-patterns');
|
|
4
|
-
const { attachSourceUrls } = require('../source-urls');
|
|
5
|
-
const { buildSupplementalChecks } = require('../supplemental-checks');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { EMBEDDED_SECRET_PATTERNS, containsEmbeddedSecret } = require('../secret-patterns');
|
|
4
|
+
const { attachSourceUrls } = require('../source-urls');
|
|
5
|
+
const { buildSupplementalChecks } = require('../supplemental-checks');
|
|
6
|
+
const { resolveProjectStateReadPath } = require('../state-paths');
|
|
6
7
|
|
|
7
8
|
const CODEX_SUPPLEMENTAL_SOURCE_URLS = {
|
|
8
9
|
'testing-strategy': 'https://developers.openai.com/codex/cli',
|
|
@@ -3097,16 +3098,15 @@ const CODEX_TECHNIQUES = {
|
|
|
3097
3098
|
// CP-08: New checks (O. Repeat-Usage Hygiene)
|
|
3098
3099
|
// =============================================
|
|
3099
3100
|
|
|
3100
|
-
codexSnapshotRetention: {
|
|
3101
|
-
id: 'CX-O01',
|
|
3102
|
-
name: 'At least one prior audit snapshot exists for repeat-usage',
|
|
3103
|
-
check: (ctx) => {
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
const
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3101
|
+
codexSnapshotRetention: {
|
|
3102
|
+
id: 'CX-O01',
|
|
3103
|
+
name: 'At least one prior audit snapshot exists for repeat-usage',
|
|
3104
|
+
check: (ctx) => {
|
|
3105
|
+
try {
|
|
3106
|
+
const indexPath = resolveProjectStateReadPath(ctx.dir, 'snapshots', 'index.json');
|
|
3107
|
+
const fs = require('fs');
|
|
3108
|
+
if (!fs.existsSync(indexPath)) return null; // No snapshots yet, not a failure
|
|
3109
|
+
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3110
3110
|
return Array.isArray(entries) && entries.length > 0;
|
|
3111
3111
|
} catch {
|
|
3112
3112
|
return null;
|
|
@@ -3121,16 +3121,15 @@ const CODEX_TECHNIQUES = {
|
|
|
3121
3121
|
line: () => null,
|
|
3122
3122
|
},
|
|
3123
3123
|
|
|
3124
|
-
codexFeedbackLoopHealth: {
|
|
3125
|
-
id: 'CX-O02',
|
|
3126
|
-
name: 'Feedback loop is functional when feedback has been submitted',
|
|
3127
|
-
check: (ctx) => {
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
const
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3124
|
+
codexFeedbackLoopHealth: {
|
|
3125
|
+
id: 'CX-O02',
|
|
3126
|
+
name: 'Feedback loop is functional when feedback has been submitted',
|
|
3127
|
+
check: (ctx) => {
|
|
3128
|
+
try {
|
|
3129
|
+
const indexPath = resolveProjectStateReadPath(ctx.dir, 'outcomes', 'index.json');
|
|
3130
|
+
const fs = require('fs');
|
|
3131
|
+
if (!fs.existsSync(indexPath)) return null; // No feedback yet, not a failure
|
|
3132
|
+
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3134
3133
|
return Array.isArray(entries) && entries.length > 0;
|
|
3135
3134
|
} catch {
|
|
3136
3135
|
return null;
|
|
@@ -3145,16 +3144,15 @@ const CODEX_TECHNIQUES = {
|
|
|
3145
3144
|
line: () => null,
|
|
3146
3145
|
},
|
|
3147
3146
|
|
|
3148
|
-
codexTrendDataAvailability: {
|
|
3149
|
-
id: 'CX-O03',
|
|
3150
|
-
name: 'Trend data is computable (2+ snapshots with compatible schemas)',
|
|
3151
|
-
check: (ctx) => {
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
const
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3147
|
+
codexTrendDataAvailability: {
|
|
3148
|
+
id: 'CX-O03',
|
|
3149
|
+
name: 'Trend data is computable (2+ snapshots with compatible schemas)',
|
|
3150
|
+
check: (ctx) => {
|
|
3151
|
+
try {
|
|
3152
|
+
const indexPath = resolveProjectStateReadPath(ctx.dir, 'snapshots', 'index.json');
|
|
3153
|
+
const fs = require('fs');
|
|
3154
|
+
if (!fs.existsSync(indexPath)) return null;
|
|
3155
|
+
const entries = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
|
3158
3156
|
const audits = (Array.isArray(entries) ? entries : []).filter(e => e.snapshotKind === 'audit');
|
|
3159
3157
|
return audits.length >= 2;
|
|
3160
3158
|
} catch {
|
package/src/copilot/patch.js
CHANGED
|
@@ -196,7 +196,7 @@ function applyPatch(dir, filePath, patchFn, options = {}) {
|
|
|
196
196
|
return { success: true, reason: 'dry run', preview, unchanged: false };
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
const backupPath = fullPath + '.
|
|
199
|
+
const backupPath = fullPath + '.nerviq-backup';
|
|
200
200
|
fs.writeFileSync(backupPath, original, 'utf8');
|
|
201
201
|
fs.writeFileSync(fullPath, patched, 'utf8');
|
|
202
202
|
|
package/src/copilot/premium.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const { COPILOT_DOMAIN_PACKS } = require('./domain-packs');
|
|
12
12
|
const { COPILOT_MCP_PACKS } = require('./mcp-packs');
|
|
13
|
+
const { resolveProjectStateReadPath } = require('../state-paths');
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// 1. Multi-Pack Composition Engine
|
|
@@ -388,7 +389,7 @@ const GATE_THRESHOLDS = {
|
|
|
388
389
|
|
|
389
390
|
function getCopilotHistory(dir, limit = 20) {
|
|
390
391
|
const fs = require('fs');
|
|
391
|
-
const snapshotDir =
|
|
392
|
+
const snapshotDir = resolveProjectStateReadPath(dir, 'snapshots');
|
|
392
393
|
try {
|
|
393
394
|
const files = fs.readdirSync(snapshotDir)
|
|
394
395
|
.filter(f => f.endsWith('.json'))
|
package/src/cursor/patch.js
CHANGED
|
@@ -201,7 +201,7 @@ function applyPatch(dir, filePath, patchFn, options = {}) {
|
|
|
201
201
|
return { success: true, reason: 'dry run', preview, unchanged: false };
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
const backupPath = fullPath + '.
|
|
204
|
+
const backupPath = fullPath + '.nerviq-backup';
|
|
205
205
|
fs.writeFileSync(backupPath, original, 'utf8');
|
|
206
206
|
fs.writeFileSync(fullPath, patched, 'utf8');
|
|
207
207
|
|
package/src/cursor/premium.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const { CURSOR_DOMAIN_PACKS } = require('./domain-packs');
|
|
12
12
|
const { CURSOR_MCP_PACKS } = require('./mcp-packs');
|
|
13
|
+
const { resolveProjectStateReadPath } = require('../state-paths');
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// 1. Multi-Pack Composition Engine (with MDC awareness)
|
|
@@ -406,7 +407,7 @@ const GATE_THRESHOLDS = {
|
|
|
406
407
|
|
|
407
408
|
function getCursorHistory(dir, limit = 20) {
|
|
408
409
|
const fs = require('fs');
|
|
409
|
-
const snapshotDir =
|
|
410
|
+
const snapshotDir = resolveProjectStateReadPath(dir, 'snapshots');
|
|
410
411
|
try {
|
|
411
412
|
const files = fs.readdirSync(snapshotDir)
|
|
412
413
|
.filter(f => f.endsWith('.json'))
|
package/src/feedback.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const readline = require('readline');
|
|
4
|
+
const { ensureProjectStateDir, resolveProjectStateReadPath } = require('./state-paths');
|
|
4
5
|
|
|
5
6
|
let lastTimestamp = '';
|
|
6
7
|
let counter = 0;
|
|
@@ -17,9 +18,11 @@ function timestampId() {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
function ensureFeedbackDir(dir) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
return ensureProjectStateDir(dir, 'feedback');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveFeedbackDir(dir) {
|
|
25
|
+
return resolveProjectStateReadPath(dir, 'feedback');
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function writeJson(filePath, payload) {
|
|
@@ -47,8 +50,10 @@ function saveFeedback(dir, payload) {
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
function getFeedbackSummary(dir) {
|
|
50
|
-
const feedbackDir =
|
|
51
|
-
const files = fs.
|
|
53
|
+
const feedbackDir = resolveFeedbackDir(dir);
|
|
54
|
+
const files = fs.existsSync(feedbackDir)
|
|
55
|
+
? fs.readdirSync(feedbackDir).filter((name) => name.endsWith('.json'))
|
|
56
|
+
: [];
|
|
52
57
|
const entries = [];
|
|
53
58
|
|
|
54
59
|
for (const file of files) {
|
|
@@ -107,7 +112,7 @@ async function collectFeedback(dir, options = {}) {
|
|
|
107
112
|
helpful: 0,
|
|
108
113
|
unhelpful: 0,
|
|
109
114
|
entries: [],
|
|
110
|
-
relativeDir: path.relative(dir,
|
|
115
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
|
|
@@ -119,7 +124,7 @@ async function collectFeedback(dir, options = {}) {
|
|
|
119
124
|
helpful: 0,
|
|
120
125
|
unhelpful: 0,
|
|
121
126
|
entries: [],
|
|
122
|
-
relativeDir: path.relative(dir,
|
|
127
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
123
128
|
};
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -161,7 +166,7 @@ async function collectFeedback(dir, options = {}) {
|
|
|
161
166
|
helpful,
|
|
162
167
|
unhelpful,
|
|
163
168
|
entries,
|
|
164
|
-
relativeDir: path.relative(dir,
|
|
169
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
165
170
|
summary: getFeedbackSummary(dir),
|
|
166
171
|
};
|
|
167
172
|
}
|
package/src/gemini/activity.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides: history, compare, trend, feedback, insights.
|
|
6
6
|
*
|
|
7
7
|
* Gemini snapshots are stored alongside Claude snapshots in
|
|
8
|
-
* .claude/claudex-setup/snapshots/ but filtered by platform='gemini'.
|
|
8
|
+
* .nerviq/snapshots/ (legacy: .claude/claudex-setup/snapshots/) but filtered by platform='gemini'.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
const path = require('path');
|
package/src/gemini/patch.js
CHANGED
|
@@ -187,7 +187,7 @@ function applyPatch(dir, filePath, patchFn, options = {}) {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
// Backup + write
|
|
190
|
-
const backupPath = fullPath + '.
|
|
190
|
+
const backupPath = fullPath + '.nerviq-backup';
|
|
191
191
|
fs.writeFileSync(backupPath, original, 'utf8');
|
|
192
192
|
fs.writeFileSync(fullPath, patched, 'utf8');
|
|
193
193
|
|
package/src/gemini/premium.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const { GEMINI_DOMAIN_PACKS } = require('./domain-packs');
|
|
12
12
|
const { GEMINI_MCP_PACKS } = require('./mcp-packs');
|
|
13
|
+
const { resolveGeminiStateReadPath } = require('../state-paths');
|
|
13
14
|
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
15
16
|
// 1. Multi-Pack Composition Engine
|
|
@@ -666,14 +667,14 @@ const GATE_THRESHOLDS = {
|
|
|
666
667
|
};
|
|
667
668
|
|
|
668
669
|
/**
|
|
669
|
-
* Read Gemini audit snapshot history from the local .gemini/.
|
|
670
|
+
* Read Gemini audit snapshot history from the local .gemini/.nerviq/ directory.
|
|
670
671
|
* @param {string} dir - Project directory
|
|
671
672
|
* @param {number} limit - Max snapshots to read
|
|
672
673
|
* @returns {object[]} Array of snapshot objects
|
|
673
674
|
*/
|
|
674
675
|
function getGeminiHistory(dir, limit = 20) {
|
|
675
676
|
const fs = require('fs');
|
|
676
|
-
const snapshotDir =
|
|
677
|
+
const snapshotDir = resolveGeminiStateReadPath(dir, 'snapshots');
|
|
677
678
|
try {
|
|
678
679
|
const files = fs.readdirSync(snapshotDir)
|
|
679
680
|
.filter(f => f.endsWith('.json'))
|
package/src/gemini/techniques.js
CHANGED
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
const os = require('os');
|
|
15
15
|
const path = require('path');
|
|
16
16
|
const { GeminiProjectContext } = require('./context');
|
|
17
|
-
const { EMBEDDED_SECRET_PATTERNS, containsEmbeddedSecret } = require('../secret-patterns');
|
|
18
|
-
const { attachSourceUrls } = require('../source-urls');
|
|
19
|
-
const { buildSupplementalChecks } = require('../supplemental-checks');
|
|
20
|
-
const { buildStackChecks } = require('../stack-checks');
|
|
17
|
+
const { EMBEDDED_SECRET_PATTERNS, containsEmbeddedSecret } = require('../secret-patterns');
|
|
18
|
+
const { attachSourceUrls } = require('../source-urls');
|
|
19
|
+
const { buildSupplementalChecks } = require('../supplemental-checks');
|
|
20
|
+
const { buildStackChecks } = require('../stack-checks');
|
|
21
|
+
const { resolveProjectStateReadPath } = require('../state-paths');
|
|
21
22
|
|
|
22
23
|
const GEMINI_SUPPLEMENTAL_SOURCE_URLS = {
|
|
23
24
|
'testing-strategy': 'https://geminicli.com/docs/get-started/',
|
|
@@ -2062,23 +2063,23 @@ const GEMINI_TECHNIQUES = {
|
|
|
2062
2063
|
},
|
|
2063
2064
|
|
|
2064
2065
|
// CP-08: O. Repeat-Usage Hygiene (3 checks)
|
|
2065
|
-
geminiSnapshotRetention: {
|
|
2066
|
-
id: 'GM-O01', name: 'At least one prior audit snapshot exists',
|
|
2067
|
-
check: (ctx) => { try { const fs = require('fs'); const p =
|
|
2066
|
+
geminiSnapshotRetention: {
|
|
2067
|
+
id: 'GM-O01', name: 'At least one prior audit snapshot exists',
|
|
2068
|
+
check: (ctx) => { try { const fs = require('fs'); const p = resolveProjectStateReadPath(ctx.dir, 'snapshots', 'index.json'); if (!fs.existsSync(p)) return null; const e = JSON.parse(fs.readFileSync(p, 'utf8')); return Array.isArray(e) && e.length > 0; } catch { return null; } },
|
|
2068
2069
|
impact: 'medium', rating: 3, category: 'repeat-usage',
|
|
2069
2070
|
fix: 'Run `npx nerviq --platform gemini --snapshot` to save your first snapshot.',
|
|
2070
2071
|
template: null, file: () => null, line: () => null,
|
|
2071
2072
|
},
|
|
2072
|
-
geminiFeedbackLoopHealth: {
|
|
2073
|
-
id: 'GM-O02', name: 'Feedback loop functional when feedback submitted',
|
|
2074
|
-
check: (ctx) => { try { const fs = require('fs'); const p =
|
|
2073
|
+
geminiFeedbackLoopHealth: {
|
|
2074
|
+
id: 'GM-O02', name: 'Feedback loop functional when feedback submitted',
|
|
2075
|
+
check: (ctx) => { try { const fs = require('fs'); const p = resolveProjectStateReadPath(ctx.dir, 'outcomes', 'index.json'); if (!fs.existsSync(p)) return null; const e = JSON.parse(fs.readFileSync(p, 'utf8')); return Array.isArray(e) && e.length > 0; } catch { return null; } },
|
|
2075
2076
|
impact: 'medium', rating: 3, category: 'repeat-usage',
|
|
2076
2077
|
fix: 'Submit feedback using `npx nerviq --platform gemini feedback`.',
|
|
2077
2078
|
template: null, file: () => null, line: () => null,
|
|
2078
2079
|
},
|
|
2079
|
-
geminiTrendDataAvailability: {
|
|
2080
|
-
id: 'GM-O03', name: 'Trend data computable (2+ snapshots)',
|
|
2081
|
-
check: (ctx) => { try { const fs = require('fs'); const p =
|
|
2080
|
+
geminiTrendDataAvailability: {
|
|
2081
|
+
id: 'GM-O03', name: 'Trend data computable (2+ snapshots)',
|
|
2082
|
+
check: (ctx) => { try { const fs = require('fs'); const p = resolveProjectStateReadPath(ctx.dir, 'snapshots', 'index.json'); if (!fs.existsSync(p)) return null; const e = JSON.parse(fs.readFileSync(p, 'utf8')); return (Array.isArray(e) ? e : []).filter(x => x.snapshotKind === 'audit').length >= 2; } catch { return null; } },
|
|
2082
2083
|
impact: 'low', rating: 2, category: 'repeat-usage',
|
|
2083
2084
|
fix: 'Run at least 2 audits with --snapshot for trend tracking.',
|
|
2084
2085
|
template: null, file: () => null, line: () => null,
|
package/src/harmony/advisor.js
CHANGED
|
@@ -8,69 +8,9 @@
|
|
|
8
8
|
* Zero external dependencies - imports only from sibling/parent modules.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
// ─── Platform Strength Matrix (
|
|
12
|
-
|
|
13
|
-
const PLATFORM_STRENGTHS =
|
|
14
|
-
claude: {
|
|
15
|
-
label: 'Claude Code',
|
|
16
|
-
reasoning: 5,
|
|
17
|
-
refactoring: 5,
|
|
18
|
-
ci: 2,
|
|
19
|
-
ide: 2,
|
|
20
|
-
sandbox: 3,
|
|
21
|
-
inline: 3,
|
|
22
|
-
context: 4,
|
|
23
|
-
automation: 4,
|
|
24
|
-
},
|
|
25
|
-
codex: {
|
|
26
|
-
label: 'Codex',
|
|
27
|
-
reasoning: 4,
|
|
28
|
-
ci: 5,
|
|
29
|
-
cloud: 5,
|
|
30
|
-
ide: 3,
|
|
31
|
-
sandbox: 4,
|
|
32
|
-
refactoring: 4,
|
|
33
|
-
inline: 2,
|
|
34
|
-
context: 3,
|
|
35
|
-
automation: 4,
|
|
36
|
-
},
|
|
37
|
-
gemini: {
|
|
38
|
-
label: 'Gemini CLI',
|
|
39
|
-
reasoning: 4,
|
|
40
|
-
context: 5,
|
|
41
|
-
sandbox: 5,
|
|
42
|
-
ci: 3,
|
|
43
|
-
ide: 3,
|
|
44
|
-
refactoring: 3,
|
|
45
|
-
inline: 2,
|
|
46
|
-
cloud: 4,
|
|
47
|
-
automation: 3,
|
|
48
|
-
},
|
|
49
|
-
copilot: {
|
|
50
|
-
label: 'GitHub Copilot',
|
|
51
|
-
inline: 5,
|
|
52
|
-
'cloud-agent': 4,
|
|
53
|
-
ide: 4,
|
|
54
|
-
ci: 4,
|
|
55
|
-
governance: 3,
|
|
56
|
-
reasoning: 3,
|
|
57
|
-
refactoring: 3,
|
|
58
|
-
context: 3,
|
|
59
|
-
automation: 3,
|
|
60
|
-
},
|
|
61
|
-
cursor: {
|
|
62
|
-
label: 'Cursor',
|
|
63
|
-
ide: 5,
|
|
64
|
-
ui: 5,
|
|
65
|
-
background: 4,
|
|
66
|
-
automation: 4,
|
|
67
|
-
reasoning: 3,
|
|
68
|
-
refactoring: 3,
|
|
69
|
-
inline: 4,
|
|
70
|
-
context: 3,
|
|
71
|
-
ci: 2,
|
|
72
|
-
},
|
|
73
|
-
};
|
|
11
|
+
// ─── Platform Strength Matrix (canonical source: shared/capabilities.js) ─────
|
|
12
|
+
|
|
13
|
+
const { PLATFORM_CAPABILITIES: PLATFORM_STRENGTHS } = require('../shared/capabilities');
|
|
74
14
|
|
|
75
15
|
// ─── Task-type to platform-strength mapping ───────────────────────────────────
|
|
76
16
|
|
|
@@ -82,7 +22,7 @@ const TASK_TYPE_PROFILES = {
|
|
|
82
22
|
},
|
|
83
23
|
'ci-review': {
|
|
84
24
|
label: 'CI / Async Review',
|
|
85
|
-
requiredStrengths: { ci: 0.
|
|
25
|
+
requiredStrengths: { ci: 0.4, cloudTasks: 0.3, async: 0.2, automation: 0.1 },
|
|
86
26
|
description: 'Asynchronous code review and CI-integrated workflows.',
|
|
87
27
|
},
|
|
88
28
|
'ui-work': {
|
|
@@ -97,7 +37,7 @@ const TASK_TYPE_PROFILES = {
|
|
|
97
37
|
},
|
|
98
38
|
'infrastructure': {
|
|
99
39
|
label: 'Infrastructure',
|
|
100
|
-
requiredStrengths: { sandbox: 0.4,
|
|
40
|
+
requiredStrengths: { sandbox: 0.4, cloudTasks: 0.3, reasoning: 0.3 },
|
|
101
41
|
description: 'Infrastructure, DevOps, and sandbox-heavy workflows.',
|
|
102
42
|
},
|
|
103
43
|
'refactoring': {
|
package/src/harmony/audit.js
CHANGED