@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
package/src/feedback.js
CHANGED
|
@@ -1,178 +1,178 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const readline = require('readline');
|
|
4
|
-
const { ensureProjectStateDir, resolveProjectStateReadPath } = require('./state-paths');
|
|
5
|
-
|
|
6
|
-
let lastTimestamp = '';
|
|
7
|
-
let counter = 0;
|
|
8
|
-
|
|
9
|
-
function timestampId() {
|
|
10
|
-
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
11
|
-
if (ts === lastTimestamp) {
|
|
12
|
-
counter += 1;
|
|
13
|
-
return `${ts}-${counter}`;
|
|
14
|
-
}
|
|
15
|
-
lastTimestamp = ts;
|
|
16
|
-
counter = 0;
|
|
17
|
-
return ts;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function ensureFeedbackDir(dir) {
|
|
21
|
-
return ensureProjectStateDir(dir, 'feedback');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function resolveFeedbackDir(dir) {
|
|
25
|
-
return resolveProjectStateReadPath(dir, 'feedback');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeJson(filePath, payload) {
|
|
29
|
-
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
30
|
-
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function saveFeedback(dir, payload) {
|
|
34
|
-
const feedbackDir = ensureFeedbackDir(dir);
|
|
35
|
-
const id = timestampId();
|
|
36
|
-
const keySlug = String(payload.key || 'finding').replace(/[^a-z0-9_-]+/gi, '-').toLowerCase();
|
|
37
|
-
const filePath = path.join(feedbackDir, `${id}-${keySlug}.json`);
|
|
38
|
-
const envelope = {
|
|
39
|
-
schemaVersion: 1,
|
|
40
|
-
id,
|
|
41
|
-
createdAt: new Date().toISOString(),
|
|
42
|
-
...payload,
|
|
43
|
-
};
|
|
44
|
-
writeJson(filePath, envelope);
|
|
45
|
-
return {
|
|
46
|
-
...envelope,
|
|
47
|
-
filePath,
|
|
48
|
-
relativePath: path.relative(dir, filePath),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function getFeedbackSummary(dir) {
|
|
53
|
-
const feedbackDir = resolveFeedbackDir(dir);
|
|
54
|
-
const files = fs.existsSync(feedbackDir)
|
|
55
|
-
? fs.readdirSync(feedbackDir).filter((name) => name.endsWith('.json'))
|
|
56
|
-
: [];
|
|
57
|
-
const entries = [];
|
|
58
|
-
|
|
59
|
-
for (const file of files) {
|
|
60
|
-
const filePath = path.join(feedbackDir, file);
|
|
61
|
-
try {
|
|
62
|
-
entries.push(JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
|
63
|
-
} catch {
|
|
64
|
-
// Ignore malformed artifacts so one bad file does not break the summary.
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const summary = {
|
|
69
|
-
totalEntries: entries.length,
|
|
70
|
-
helpful: 0,
|
|
71
|
-
unhelpful: 0,
|
|
72
|
-
byKey: {},
|
|
73
|
-
relativeDir: path.relative(dir, feedbackDir),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
for (const entry of entries) {
|
|
77
|
-
const helpful = entry.helpful === true;
|
|
78
|
-
if (helpful) {
|
|
79
|
-
summary.helpful += 1;
|
|
80
|
-
} else if (entry.helpful === false) {
|
|
81
|
-
summary.unhelpful += 1;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const bucket = summary.byKey[entry.key] || { total: 0, helpful: 0, unhelpful: 0 };
|
|
85
|
-
bucket.total += 1;
|
|
86
|
-
if (helpful) {
|
|
87
|
-
bucket.helpful += 1;
|
|
88
|
-
} else if (entry.helpful === false) {
|
|
89
|
-
bucket.unhelpful += 1;
|
|
90
|
-
}
|
|
91
|
-
summary.byKey[entry.key] = bucket;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return summary;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function askQuestion(rl, prompt) {
|
|
98
|
-
return new Promise((resolve) => {
|
|
99
|
-
rl.question(prompt, resolve);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async function collectFeedback(dir, options = {}) {
|
|
104
|
-
const findings = Array.isArray(options.findings) ? options.findings : [];
|
|
105
|
-
const stdin = options.stdin || process.stdin;
|
|
106
|
-
const stdout = options.stdout || process.stdout;
|
|
107
|
-
|
|
108
|
-
if (findings.length === 0) {
|
|
109
|
-
return {
|
|
110
|
-
saved: 0,
|
|
111
|
-
skipped: 0,
|
|
112
|
-
helpful: 0,
|
|
113
|
-
unhelpful: 0,
|
|
114
|
-
entries: [],
|
|
115
|
-
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (!(stdin.isTTY && stdout.isTTY)) {
|
|
120
|
-
return {
|
|
121
|
-
mode: 'skipped-noninteractive',
|
|
122
|
-
saved: 0,
|
|
123
|
-
skipped: findings.length,
|
|
124
|
-
helpful: 0,
|
|
125
|
-
unhelpful: 0,
|
|
126
|
-
entries: [],
|
|
127
|
-
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
132
|
-
const entries = [];
|
|
133
|
-
|
|
134
|
-
try {
|
|
135
|
-
for (const finding of findings) {
|
|
136
|
-
stdout.write(`\n Feedback for ${finding.name} (${finding.key})\n`);
|
|
137
|
-
let answer = await askQuestion(rl, ' Was this helpful? (y/n) ');
|
|
138
|
-
answer = String(answer || '').trim().toLowerCase();
|
|
139
|
-
|
|
140
|
-
if (!['y', 'yes', 'n', 'no'].includes(answer)) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
entries.push(saveFeedback(dir, {
|
|
145
|
-
key: finding.key,
|
|
146
|
-
name: finding.name,
|
|
147
|
-
helpful: answer === 'y' || answer === 'yes',
|
|
148
|
-
platform: options.platform || null,
|
|
149
|
-
sourceCommand: options.sourceCommand || 'audit',
|
|
150
|
-
sourceUrl: finding.sourceUrl || null,
|
|
151
|
-
impact: finding.impact || null,
|
|
152
|
-
category: finding.category || null,
|
|
153
|
-
score: Number.isFinite(options.score) ? options.score : null,
|
|
154
|
-
}));
|
|
155
|
-
}
|
|
156
|
-
} finally {
|
|
157
|
-
rl.close();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const helpful = entries.filter((entry) => entry.helpful).length;
|
|
161
|
-
const unhelpful = entries.filter((entry) => entry.helpful === false).length;
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
saved: entries.length,
|
|
165
|
-
skipped: findings.length - entries.length,
|
|
166
|
-
helpful,
|
|
167
|
-
unhelpful,
|
|
168
|
-
entries,
|
|
169
|
-
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
170
|
-
summary: getFeedbackSummary(dir),
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
module.exports = {
|
|
175
|
-
collectFeedback,
|
|
176
|
-
saveFeedback,
|
|
177
|
-
getFeedbackSummary,
|
|
178
|
-
};
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
const { ensureProjectStateDir, resolveProjectStateReadPath } = require('./state-paths');
|
|
5
|
+
|
|
6
|
+
let lastTimestamp = '';
|
|
7
|
+
let counter = 0;
|
|
8
|
+
|
|
9
|
+
function timestampId() {
|
|
10
|
+
const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
11
|
+
if (ts === lastTimestamp) {
|
|
12
|
+
counter += 1;
|
|
13
|
+
return `${ts}-${counter}`;
|
|
14
|
+
}
|
|
15
|
+
lastTimestamp = ts;
|
|
16
|
+
counter = 0;
|
|
17
|
+
return ts;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function ensureFeedbackDir(dir) {
|
|
21
|
+
return ensureProjectStateDir(dir, 'feedback');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function resolveFeedbackDir(dir) {
|
|
25
|
+
return resolveProjectStateReadPath(dir, 'feedback');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeJson(filePath, payload) {
|
|
29
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
30
|
+
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2), 'utf8');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function saveFeedback(dir, payload) {
|
|
34
|
+
const feedbackDir = ensureFeedbackDir(dir);
|
|
35
|
+
const id = timestampId();
|
|
36
|
+
const keySlug = String(payload.key || 'finding').replace(/[^a-z0-9_-]+/gi, '-').toLowerCase();
|
|
37
|
+
const filePath = path.join(feedbackDir, `${id}-${keySlug}.json`);
|
|
38
|
+
const envelope = {
|
|
39
|
+
schemaVersion: 1,
|
|
40
|
+
id,
|
|
41
|
+
createdAt: new Date().toISOString(),
|
|
42
|
+
...payload,
|
|
43
|
+
};
|
|
44
|
+
writeJson(filePath, envelope);
|
|
45
|
+
return {
|
|
46
|
+
...envelope,
|
|
47
|
+
filePath,
|
|
48
|
+
relativePath: path.relative(dir, filePath),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getFeedbackSummary(dir) {
|
|
53
|
+
const feedbackDir = resolveFeedbackDir(dir);
|
|
54
|
+
const files = fs.existsSync(feedbackDir)
|
|
55
|
+
? fs.readdirSync(feedbackDir).filter((name) => name.endsWith('.json'))
|
|
56
|
+
: [];
|
|
57
|
+
const entries = [];
|
|
58
|
+
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
const filePath = path.join(feedbackDir, file);
|
|
61
|
+
try {
|
|
62
|
+
entries.push(JSON.parse(fs.readFileSync(filePath, 'utf8')));
|
|
63
|
+
} catch {
|
|
64
|
+
// Ignore malformed artifacts so one bad file does not break the summary.
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const summary = {
|
|
69
|
+
totalEntries: entries.length,
|
|
70
|
+
helpful: 0,
|
|
71
|
+
unhelpful: 0,
|
|
72
|
+
byKey: {},
|
|
73
|
+
relativeDir: path.relative(dir, feedbackDir),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const helpful = entry.helpful === true;
|
|
78
|
+
if (helpful) {
|
|
79
|
+
summary.helpful += 1;
|
|
80
|
+
} else if (entry.helpful === false) {
|
|
81
|
+
summary.unhelpful += 1;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const bucket = summary.byKey[entry.key] || { total: 0, helpful: 0, unhelpful: 0 };
|
|
85
|
+
bucket.total += 1;
|
|
86
|
+
if (helpful) {
|
|
87
|
+
bucket.helpful += 1;
|
|
88
|
+
} else if (entry.helpful === false) {
|
|
89
|
+
bucket.unhelpful += 1;
|
|
90
|
+
}
|
|
91
|
+
summary.byKey[entry.key] = bucket;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return summary;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function askQuestion(rl, prompt) {
|
|
98
|
+
return new Promise((resolve) => {
|
|
99
|
+
rl.question(prompt, resolve);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function collectFeedback(dir, options = {}) {
|
|
104
|
+
const findings = Array.isArray(options.findings) ? options.findings : [];
|
|
105
|
+
const stdin = options.stdin || process.stdin;
|
|
106
|
+
const stdout = options.stdout || process.stdout;
|
|
107
|
+
|
|
108
|
+
if (findings.length === 0) {
|
|
109
|
+
return {
|
|
110
|
+
saved: 0,
|
|
111
|
+
skipped: 0,
|
|
112
|
+
helpful: 0,
|
|
113
|
+
unhelpful: 0,
|
|
114
|
+
entries: [],
|
|
115
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!(stdin.isTTY && stdout.isTTY)) {
|
|
120
|
+
return {
|
|
121
|
+
mode: 'skipped-noninteractive',
|
|
122
|
+
saved: 0,
|
|
123
|
+
skipped: findings.length,
|
|
124
|
+
helpful: 0,
|
|
125
|
+
unhelpful: 0,
|
|
126
|
+
entries: [],
|
|
127
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
132
|
+
const entries = [];
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
for (const finding of findings) {
|
|
136
|
+
stdout.write(`\n Feedback for ${finding.name} (${finding.key})\n`);
|
|
137
|
+
let answer = await askQuestion(rl, ' Was this helpful? (y/n) ');
|
|
138
|
+
answer = String(answer || '').trim().toLowerCase();
|
|
139
|
+
|
|
140
|
+
if (!['y', 'yes', 'n', 'no'].includes(answer)) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
entries.push(saveFeedback(dir, {
|
|
145
|
+
key: finding.key,
|
|
146
|
+
name: finding.name,
|
|
147
|
+
helpful: answer === 'y' || answer === 'yes',
|
|
148
|
+
platform: options.platform || null,
|
|
149
|
+
sourceCommand: options.sourceCommand || 'audit',
|
|
150
|
+
sourceUrl: finding.sourceUrl || null,
|
|
151
|
+
impact: finding.impact || null,
|
|
152
|
+
category: finding.category || null,
|
|
153
|
+
score: Number.isFinite(options.score) ? options.score : null,
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
} finally {
|
|
157
|
+
rl.close();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const helpful = entries.filter((entry) => entry.helpful).length;
|
|
161
|
+
const unhelpful = entries.filter((entry) => entry.helpful === false).length;
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
saved: entries.length,
|
|
165
|
+
skipped: findings.length - entries.length,
|
|
166
|
+
helpful,
|
|
167
|
+
unhelpful,
|
|
168
|
+
entries,
|
|
169
|
+
relativeDir: path.relative(dir, resolveFeedbackDir(dir)),
|
|
170
|
+
summary: getFeedbackSummary(dir),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
module.exports = {
|
|
175
|
+
collectFeedback,
|
|
176
|
+
saveFeedback,
|
|
177
|
+
getFeedbackSummary,
|
|
178
|
+
};
|