@nerviq/cli 0.0.1 → 0.9.0-beta.2
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/CHANGELOG.md +181 -0
- package/LICENSE +21 -0
- package/README.md +447 -0
- package/bin/cli.js +749 -0
- package/content/case-study-template.md +91 -0
- package/content/claims-governance.md +37 -0
- package/content/claude-code/audit-repo/SKILL.md +20 -0
- package/content/claude-native-integration.md +60 -0
- package/content/devto-article.json +9 -0
- package/content/launch-posts.md +226 -0
- package/content/pilot-rollout-kit.md +30 -0
- package/content/release-checklist.md +31 -0
- package/package.json +53 -4
- package/src/activity.js +529 -0
- package/src/aider/activity.js +226 -0
- package/src/aider/config-parser.js +166 -0
- package/src/aider/context.js +158 -0
- package/src/aider/deep-review.js +316 -0
- package/src/aider/domain-packs.js +278 -0
- package/src/aider/freshness.js +168 -0
- package/src/aider/governance.js +253 -0
- package/src/aider/interactive.js +334 -0
- package/src/aider/mcp-packs.js +98 -0
- package/src/aider/patch.js +214 -0
- package/src/aider/plans.js +186 -0
- package/src/aider/premium.js +360 -0
- package/src/aider/setup.js +404 -0
- package/src/aider/techniques.js +1323 -0
- package/src/analyze.js +821 -0
- package/src/audit.js +1003 -0
- package/src/badge.js +13 -0
- package/src/benchmark.js +339 -0
- package/src/claudex-sync.json +7 -0
- package/src/codex/activity.js +324 -0
- package/src/codex/config-parser.js +183 -0
- package/src/codex/context.js +221 -0
- package/src/codex/deep-review.js +493 -0
- package/src/codex/domain-packs.js +372 -0
- package/src/codex/freshness.js +167 -0
- package/src/codex/governance.js +192 -0
- package/src/codex/interactive.js +618 -0
- package/src/codex/mcp-packs.js +660 -0
- package/src/codex/patch.js +209 -0
- package/src/codex/plans.js +251 -0
- package/src/codex/premium.js +614 -0
- package/src/codex/setup.js +603 -0
- package/src/codex/techniques.js +2649 -0
- package/src/context.js +272 -0
- package/src/copilot/activity.js +309 -0
- package/src/copilot/config-parser.js +226 -0
- package/src/copilot/context.js +197 -0
- package/src/copilot/deep-review.js +346 -0
- package/src/copilot/domain-packs.js +350 -0
- package/src/copilot/freshness.js +197 -0
- package/src/copilot/governance.js +222 -0
- package/src/copilot/interactive.js +406 -0
- package/src/copilot/mcp-packs.js +572 -0
- package/src/copilot/patch.js +238 -0
- package/src/copilot/plans.js +253 -0
- package/src/copilot/premium.js +450 -0
- package/src/copilot/setup.js +488 -0
- package/src/copilot/techniques.js +1822 -0
- package/src/cursor/activity.js +301 -0
- package/src/cursor/config-parser.js +265 -0
- package/src/cursor/context.js +236 -0
- package/src/cursor/deep-review.js +334 -0
- package/src/cursor/domain-packs.js +346 -0
- package/src/cursor/freshness.js +214 -0
- package/src/cursor/governance.js +229 -0
- package/src/cursor/interactive.js +391 -0
- package/src/cursor/mcp-packs.js +571 -0
- package/src/cursor/patch.js +243 -0
- package/src/cursor/plans.js +254 -0
- package/src/cursor/premium.js +468 -0
- package/src/cursor/setup.js +488 -0
- package/src/cursor/techniques.js +1786 -0
- package/src/deep-review.js +345 -0
- package/src/domain-packs.js +364 -0
- package/src/formatters/sarif.js +115 -0
- package/src/gemini/activity.js +402 -0
- package/src/gemini/config-parser.js +275 -0
- package/src/gemini/context.js +221 -0
- package/src/gemini/deep-review.js +559 -0
- package/src/gemini/domain-packs.js +371 -0
- package/src/gemini/freshness.js +204 -0
- package/src/gemini/governance.js +201 -0
- package/src/gemini/interactive.js +860 -0
- package/src/gemini/mcp-packs.js +658 -0
- package/src/gemini/patch.js +229 -0
- package/src/gemini/plans.js +269 -0
- package/src/gemini/premium.js +759 -0
- package/src/gemini/setup.js +692 -0
- package/src/gemini/techniques.js +2084 -0
- package/src/governance.js +523 -0
- package/src/harmony/advisor.js +383 -0
- package/src/harmony/audit.js +303 -0
- package/src/harmony/canon.js +444 -0
- package/src/harmony/cli.js +331 -0
- package/src/harmony/drift.js +401 -0
- package/src/harmony/governance.js +313 -0
- package/src/harmony/memory.js +238 -0
- package/src/harmony/sync.js +458 -0
- package/src/harmony/watch.js +336 -0
- package/src/index.js +256 -0
- package/src/insights.js +119 -0
- package/src/interactive.js +118 -0
- package/src/mcp-packs.js +597 -0
- package/src/opencode/activity.js +286 -0
- package/src/opencode/config-parser.js +109 -0
- package/src/opencode/context.js +247 -0
- package/src/opencode/deep-review.js +313 -0
- package/src/opencode/domain-packs.js +240 -0
- package/src/opencode/freshness.js +158 -0
- package/src/opencode/governance.js +159 -0
- package/src/opencode/interactive.js +392 -0
- package/src/opencode/mcp-packs.js +474 -0
- package/src/opencode/patch.js +184 -0
- package/src/opencode/plans.js +231 -0
- package/src/opencode/premium.js +413 -0
- package/src/opencode/setup.js +449 -0
- package/src/opencode/techniques.js +1713 -0
- package/src/plans.js +655 -0
- package/src/secret-patterns.js +30 -0
- package/src/setup.js +1274 -0
- package/src/synergy/adaptive.js +261 -0
- package/src/synergy/compensation.js +156 -0
- package/src/synergy/evidence.js +193 -0
- package/src/synergy/learning.js +184 -0
- package/src/synergy/patterns.js +227 -0
- package/src/synergy/ranking.js +83 -0
- package/src/synergy/report.js +163 -0
- package/src/synergy/routing.js +152 -0
- package/src/techniques.js +1354 -0
- package/src/watch.js +229 -0
- package/src/windsurf/activity.js +302 -0
- package/src/windsurf/config-parser.js +267 -0
- package/src/windsurf/context.js +249 -0
- package/src/windsurf/deep-review.js +337 -0
- package/src/windsurf/domain-packs.js +348 -0
- package/src/windsurf/freshness.js +215 -0
- package/src/windsurf/governance.js +231 -0
- package/src/windsurf/interactive.js +388 -0
- package/src/windsurf/mcp-packs.js +535 -0
- package/src/windsurf/patch.js +231 -0
- package/src/windsurf/plans.js +247 -0
- package/src/windsurf/premium.js +467 -0
- package/src/windsurf/setup.js +471 -0
- package/src/windsurf/techniques.js +1758 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aider Interactive Wizard — 8-stage guided setup
|
|
3
|
+
*
|
|
4
|
+
* Simpler than IDE wizards — no hooks/MCP stages.
|
|
5
|
+
* Uses Node.js readline (zero dependencies).
|
|
6
|
+
*
|
|
7
|
+
* Stages:
|
|
8
|
+
* 1. Project Detection
|
|
9
|
+
* 2. Git Safety Posture
|
|
10
|
+
* 3. Model Configuration
|
|
11
|
+
* 4. Convention File
|
|
12
|
+
* 5. Domain Pack Selection
|
|
13
|
+
* 6. Verification Loop
|
|
14
|
+
* 7. CI Integration
|
|
15
|
+
* 8. Review & Generate
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const readline = require('readline');
|
|
21
|
+
const { STACKS } = require('../techniques');
|
|
22
|
+
const { AiderProjectContext } = require('./context');
|
|
23
|
+
const { AIDER_TECHNIQUES } = require('./techniques');
|
|
24
|
+
const { AIDER_DOMAIN_PACKS, detectAiderDomainPacks } = require('./domain-packs');
|
|
25
|
+
const { recommendAiderMcpPacks, AIDER_MCP_PACKS } = require('./mcp-packs');
|
|
26
|
+
const { setupAider } = require('./setup');
|
|
27
|
+
|
|
28
|
+
const COLORS = {
|
|
29
|
+
reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m',
|
|
30
|
+
red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m',
|
|
31
|
+
blue: '\x1b[36m', magenta: '\x1b[35m',
|
|
32
|
+
};
|
|
33
|
+
const c = (text, color) => `${COLORS[color] || ''}${text}${COLORS.reset}`;
|
|
34
|
+
|
|
35
|
+
function ask(rl, question) {
|
|
36
|
+
return new Promise(resolve => rl.question(question, resolve));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isTTY() {
|
|
40
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const STAGE_NAMES = [
|
|
44
|
+
'Project Detection',
|
|
45
|
+
'Git Safety Posture',
|
|
46
|
+
'Model Configuration',
|
|
47
|
+
'Convention File',
|
|
48
|
+
'Domain Pack Selection',
|
|
49
|
+
'Verification Loop',
|
|
50
|
+
'CI Integration',
|
|
51
|
+
'Review & Generate',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
function printStageHeader(index) {
|
|
55
|
+
const num = index + 1;
|
|
56
|
+
const total = STAGE_NAMES.length;
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(c(` ── Stage ${num}/${total}: ${STAGE_NAMES[index]} ──`, 'magenta'));
|
|
59
|
+
console.log('');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// --- Stage 1: Project Detection ---
|
|
63
|
+
|
|
64
|
+
function runProjectDetection(ctx) {
|
|
65
|
+
const stacks = ctx.detectStacks(STACKS);
|
|
66
|
+
const hasGit = ctx.hasGitRepo();
|
|
67
|
+
const hasConfYml = Boolean(ctx.configContent());
|
|
68
|
+
const hasConventions = ctx.conventionFiles().length > 0;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
stacks,
|
|
72
|
+
hasGit,
|
|
73
|
+
hasConfYml,
|
|
74
|
+
hasConventions,
|
|
75
|
+
projectName: path.basename(ctx.dir),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// --- Stage 2: Git Safety Posture ---
|
|
80
|
+
|
|
81
|
+
async function runGitSafety(rl, state) {
|
|
82
|
+
console.log(' Aider uses git as its ONLY safety mechanism.');
|
|
83
|
+
console.log(' Auto-commits create an undo trail for every change.');
|
|
84
|
+
console.log('');
|
|
85
|
+
|
|
86
|
+
const autoCommits = await ask(rl, c(' Enable auto-commits? (Y/n): ', 'blue'));
|
|
87
|
+
state.autoCommits = autoCommits.trim().toLowerCase() !== 'n';
|
|
88
|
+
|
|
89
|
+
const attribution = await ask(rl, c(' Enable commit attribution for AI traceability? (Y/n): ', 'blue'));
|
|
90
|
+
state.attribution = attribution.trim().toLowerCase() !== 'n';
|
|
91
|
+
|
|
92
|
+
const commitPrefix = await ask(rl, c(' Commit prefix for AI commits (default: "aider: "): ', 'blue'));
|
|
93
|
+
state.commitPrefix = commitPrefix.trim() || 'aider: ';
|
|
94
|
+
|
|
95
|
+
return 'next';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// --- Stage 3: Model Configuration ---
|
|
99
|
+
|
|
100
|
+
async function runModelConfig(rl, state) {
|
|
101
|
+
console.log(' Aider has 3 model roles:');
|
|
102
|
+
console.log(' - main: does the coding');
|
|
103
|
+
console.log(' - editor: applies edits to files');
|
|
104
|
+
console.log(' - weak: generates commit messages (cheapest)');
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
const mainModel = await ask(rl, c(' Main model (e.g., claude-sonnet-4-20250514, gpt-4o, leave blank for default): ', 'blue'));
|
|
108
|
+
state.mainModel = mainModel.trim() || null;
|
|
109
|
+
|
|
110
|
+
const architect = await ask(rl, c(' Enable architect mode (2-model planning + editing)? (y/N): ', 'blue'));
|
|
111
|
+
state.architect = architect.trim().toLowerCase() === 'y';
|
|
112
|
+
|
|
113
|
+
const cachePrompts = await ask(rl, c(' Enable prompt caching for cost savings? (Y/n): ', 'blue'));
|
|
114
|
+
state.cachePrompts = cachePrompts.trim().toLowerCase() !== 'n';
|
|
115
|
+
|
|
116
|
+
return 'next';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// --- Stage 4: Convention File ---
|
|
120
|
+
|
|
121
|
+
async function runConventions(rl, state, ctx) {
|
|
122
|
+
const existing = ctx.conventionFiles();
|
|
123
|
+
if (existing.length > 0) {
|
|
124
|
+
console.log(` Found existing convention files: ${existing.join(', ')}`);
|
|
125
|
+
const keep = await ask(rl, c(' Keep existing convention files? (Y/n): ', 'blue'));
|
|
126
|
+
if (keep.trim().toLowerCase() !== 'n') {
|
|
127
|
+
state.generateConventions = false;
|
|
128
|
+
return 'next';
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(' Aider has NO auto-discovery — convention files must be explicitly passed via read:');
|
|
133
|
+
const generate = await ask(rl, c(' Generate CONVENTIONS.md? (Y/n): ', 'blue'));
|
|
134
|
+
state.generateConventions = generate.trim().toLowerCase() !== 'n';
|
|
135
|
+
|
|
136
|
+
return 'next';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- Stage 5: Domain Pack Selection ---
|
|
140
|
+
|
|
141
|
+
async function runDomainPacks(rl, state, ctx) {
|
|
142
|
+
const detected = detectAiderDomainPacks(ctx);
|
|
143
|
+
console.log(' Detected domain packs:');
|
|
144
|
+
for (const pack of detected) {
|
|
145
|
+
console.log(` - ${pack.label}: ${pack.matchReasons[0] || pack.useWhen}`);
|
|
146
|
+
}
|
|
147
|
+
console.log('');
|
|
148
|
+
|
|
149
|
+
const accept = await ask(rl, c(' Accept detected domain packs? (Y/n): ', 'blue'));
|
|
150
|
+
if (accept.trim().toLowerCase() !== 'n') {
|
|
151
|
+
state.domainPacks = detected.map(p => p.key);
|
|
152
|
+
} else {
|
|
153
|
+
console.log(' Available packs:');
|
|
154
|
+
AIDER_DOMAIN_PACKS.forEach((p, i) => {
|
|
155
|
+
console.log(` ${i + 1}. ${p.label} — ${p.useWhen.slice(0, 60)}`);
|
|
156
|
+
});
|
|
157
|
+
const choices = await ask(rl, c(' Enter pack numbers (comma-separated): ', 'blue'));
|
|
158
|
+
const indices = choices.split(',').map(s => parseInt(s.trim(), 10) - 1).filter(i => i >= 0 && i < AIDER_DOMAIN_PACKS.length);
|
|
159
|
+
state.domainPacks = indices.map(i => AIDER_DOMAIN_PACKS[i].key);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return 'next';
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// --- Stage 6: Verification Loop ---
|
|
166
|
+
|
|
167
|
+
async function runVerificationLoop(rl, state) {
|
|
168
|
+
console.log(' Aider can auto-fix lint and test failures after edits.');
|
|
169
|
+
console.log('');
|
|
170
|
+
|
|
171
|
+
const lintCmd = await ask(rl, c(' Lint command (leave blank to skip): ', 'blue'));
|
|
172
|
+
state.lintCmd = lintCmd.trim() || null;
|
|
173
|
+
|
|
174
|
+
if (state.lintCmd) {
|
|
175
|
+
const autoLint = await ask(rl, c(' Enable auto-lint (auto-fix after edits)? (Y/n): ', 'blue'));
|
|
176
|
+
state.autoLint = autoLint.trim().toLowerCase() !== 'n';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const testCmd = await ask(rl, c(' Test command (leave blank to skip): ', 'blue'));
|
|
180
|
+
state.testCmd = testCmd.trim() || null;
|
|
181
|
+
|
|
182
|
+
if (state.testCmd) {
|
|
183
|
+
const autoTest = await ask(rl, c(' Enable auto-test (run tests after edits)? (Y/n): ', 'blue'));
|
|
184
|
+
state.autoTest = autoTest.trim().toLowerCase() !== 'n';
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return 'next';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// --- Stage 7: CI Integration ---
|
|
191
|
+
|
|
192
|
+
async function runCiIntegration(rl, state) {
|
|
193
|
+
console.log(' CI integration ensures Aider-generated code passes quality gates.');
|
|
194
|
+
console.log('');
|
|
195
|
+
|
|
196
|
+
const wantCi = await ask(rl, c(' Set up CI workflow for Aider PRs? (y/N): ', 'blue'));
|
|
197
|
+
state.wantCi = wantCi.trim().toLowerCase() === 'y';
|
|
198
|
+
|
|
199
|
+
return 'next';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// --- Stage 8: Review & Generate ---
|
|
203
|
+
|
|
204
|
+
async function runReviewGenerate(rl, state, dir) {
|
|
205
|
+
console.log(' Summary:');
|
|
206
|
+
console.log(` Auto-commits: ${state.autoCommits ? 'yes' : 'no'}`);
|
|
207
|
+
console.log(` Attribution: ${state.attribution ? 'yes' : 'no'}`);
|
|
208
|
+
console.log(` Commit prefix: "${state.commitPrefix}"`);
|
|
209
|
+
console.log(` Main model: ${state.mainModel || 'default'}`);
|
|
210
|
+
console.log(` Architect mode: ${state.architect ? 'yes' : 'no'}`);
|
|
211
|
+
console.log(` Prompt caching: ${state.cachePrompts ? 'yes' : 'no'}`);
|
|
212
|
+
console.log(` Generate conventions: ${state.generateConventions ? 'yes' : 'no'}`);
|
|
213
|
+
console.log(` Domain packs: ${(state.domainPacks || []).join(', ') || 'none'}`);
|
|
214
|
+
console.log(` Lint: ${state.lintCmd || 'none'} (auto: ${state.autoLint ? 'yes' : 'no'})`);
|
|
215
|
+
console.log(` Test: ${state.testCmd || 'none'} (auto: ${state.autoTest ? 'yes' : 'no'})`);
|
|
216
|
+
console.log(` CI workflow: ${state.wantCi ? 'yes' : 'no'}`);
|
|
217
|
+
console.log('');
|
|
218
|
+
|
|
219
|
+
const confirm = await ask(rl, c(' Generate files? (Y/n): ', 'blue'));
|
|
220
|
+
if (confirm.trim().toLowerCase() === 'n') {
|
|
221
|
+
return 'back';
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
setupAider({ dir, log: console.log });
|
|
225
|
+
return 'done';
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// --- Main wizard ---
|
|
229
|
+
|
|
230
|
+
async function aiderInteractive(dir) {
|
|
231
|
+
if (!isTTY()) {
|
|
232
|
+
console.log('Interactive mode requires a TTY. Use --setup instead.');
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const rl = readline.createInterface({
|
|
237
|
+
input: process.stdin,
|
|
238
|
+
output: process.stdout,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
console.log('');
|
|
242
|
+
console.log(c(' ╔══════════════════════════════════════╗', 'magenta'));
|
|
243
|
+
console.log(c(' ║ Aider Interactive Setup ║', 'magenta'));
|
|
244
|
+
console.log(c(' ║ powered by nerviq ║', 'magenta'));
|
|
245
|
+
console.log(c(' ╚══════════════════════════════════════╝', 'magenta'));
|
|
246
|
+
|
|
247
|
+
const ctx = new AiderProjectContext(dir);
|
|
248
|
+
const state = {
|
|
249
|
+
autoCommits: true,
|
|
250
|
+
attribution: true,
|
|
251
|
+
commitPrefix: 'aider: ',
|
|
252
|
+
mainModel: null,
|
|
253
|
+
architect: false,
|
|
254
|
+
cachePrompts: true,
|
|
255
|
+
generateConventions: true,
|
|
256
|
+
domainPacks: [],
|
|
257
|
+
lintCmd: null,
|
|
258
|
+
autoLint: false,
|
|
259
|
+
testCmd: null,
|
|
260
|
+
autoTest: false,
|
|
261
|
+
wantCi: false,
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const stages = [
|
|
265
|
+
// Stage 1 — auto, no interaction
|
|
266
|
+
async () => {
|
|
267
|
+
printStageHeader(0);
|
|
268
|
+
const detection = runProjectDetection(ctx);
|
|
269
|
+
console.log(` Project: ${detection.projectName}`);
|
|
270
|
+
console.log(` Git repo: ${detection.hasGit ? c('yes', 'green') : c('NO — required!', 'red')}`);
|
|
271
|
+
console.log(` .aider.conf.yml: ${detection.hasConfYml ? 'exists' : 'missing'}`);
|
|
272
|
+
console.log(` Convention files: ${detection.hasConventions ? 'found' : 'none'}`);
|
|
273
|
+
console.log(` Stacks: ${detection.stacks.map(s => s.key).join(', ') || 'none detected'}`);
|
|
274
|
+
|
|
275
|
+
if (!detection.hasGit) {
|
|
276
|
+
console.log('');
|
|
277
|
+
console.log(c(' Warning: Aider requires a git repo. Run `git init` first.', 'red'));
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return 'next';
|
|
281
|
+
},
|
|
282
|
+
// Stage 2
|
|
283
|
+
async () => { printStageHeader(1); return runGitSafety(rl, state); },
|
|
284
|
+
// Stage 3
|
|
285
|
+
async () => { printStageHeader(2); return runModelConfig(rl, state); },
|
|
286
|
+
// Stage 4
|
|
287
|
+
async () => { printStageHeader(3); return runConventions(rl, state, ctx); },
|
|
288
|
+
// Stage 5
|
|
289
|
+
async () => { printStageHeader(4); return runDomainPacks(rl, state, ctx); },
|
|
290
|
+
// Stage 6
|
|
291
|
+
async () => { printStageHeader(5); return runVerificationLoop(rl, state); },
|
|
292
|
+
// Stage 7
|
|
293
|
+
async () => { printStageHeader(6); return runCiIntegration(rl, state); },
|
|
294
|
+
// Stage 8
|
|
295
|
+
async () => { printStageHeader(7); return runReviewGenerate(rl, state, dir); },
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
let stageIndex = 0;
|
|
299
|
+
|
|
300
|
+
while (stageIndex < stages.length) {
|
|
301
|
+
const result = await stages[stageIndex]();
|
|
302
|
+
|
|
303
|
+
if (result === 'quit' || result === 'exit') {
|
|
304
|
+
rl.close();
|
|
305
|
+
console.log(c(' Setup cancelled.', 'yellow'));
|
|
306
|
+
return { cancelled: true };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
if (result === 'back') {
|
|
310
|
+
if (stageIndex > 0) {
|
|
311
|
+
stageIndex--;
|
|
312
|
+
} else {
|
|
313
|
+
console.log(c(' Already at the first stage.', 'dim'));
|
|
314
|
+
}
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (result === 'done') {
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
stageIndex++;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
rl.close();
|
|
326
|
+
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log(c(' Done! Run `npx nerviq --platform aider` to audit your setup.', 'green'));
|
|
329
|
+
console.log('');
|
|
330
|
+
|
|
331
|
+
return { cancelled: false, state };
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
module.exports = { aiderInteractive };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aider MCP Pack System — Minimal
|
|
3
|
+
*
|
|
4
|
+
* Aider has NO native MCP support. This module provides:
|
|
5
|
+
* - Recommendations for editor integrations that bridge MCP to Aider
|
|
6
|
+
* - Awareness of the --browser and /web commands for documentation
|
|
7
|
+
* - Future-proofing for when/if Aider adds MCP support
|
|
8
|
+
*
|
|
9
|
+
* Instead of MCP, Aider users should rely on:
|
|
10
|
+
* - /web command for pulling in web documentation
|
|
11
|
+
* - /read for adding files to context
|
|
12
|
+
* - Editor extensions (VS Code, NeoVim) that may have MCP bridges
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const AIDER_MCP_PACKS = [
|
|
16
|
+
{
|
|
17
|
+
key: 'editor-bridge-vscode',
|
|
18
|
+
label: 'VS Code Extension Bridge',
|
|
19
|
+
description: 'Use the Aider VS Code extension for tighter editor integration.',
|
|
20
|
+
useWhen: 'VS Code users who want in-editor Aider access.',
|
|
21
|
+
adoption: 'Recommended for VS Code users. Install from marketplace.',
|
|
22
|
+
trustLevel: 'high',
|
|
23
|
+
transport: 'editor-extension',
|
|
24
|
+
requiredAuth: [],
|
|
25
|
+
serverName: null,
|
|
26
|
+
configProjection: null,
|
|
27
|
+
recommendation: 'Install aider-chat VS Code extension for in-editor chat.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: 'editor-bridge-neovim',
|
|
31
|
+
label: 'NeoVim Plugin Bridge',
|
|
32
|
+
description: 'Use the Aider NeoVim plugin for terminal-native integration.',
|
|
33
|
+
useWhen: 'NeoVim users who want in-editor Aider access.',
|
|
34
|
+
adoption: 'Recommended for NeoVim users. Install via plugin manager.',
|
|
35
|
+
trustLevel: 'high',
|
|
36
|
+
transport: 'editor-plugin',
|
|
37
|
+
requiredAuth: [],
|
|
38
|
+
serverName: null,
|
|
39
|
+
configProjection: null,
|
|
40
|
+
recommendation: 'Install aider.nvim for NeoVim integration.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: 'web-docs',
|
|
44
|
+
label: 'Web Documentation (/web)',
|
|
45
|
+
description: 'Use Aider\'s built-in /web command to scrape documentation into context.',
|
|
46
|
+
useWhen: 'Any project where Aider needs live documentation context.',
|
|
47
|
+
adoption: 'Built-in feature, no setup required.',
|
|
48
|
+
trustLevel: 'high',
|
|
49
|
+
transport: 'built-in',
|
|
50
|
+
requiredAuth: [],
|
|
51
|
+
serverName: null,
|
|
52
|
+
configProjection: null,
|
|
53
|
+
recommendation: 'Use /web <url> to pull documentation into the Aider chat context.',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Recommend MCP-equivalent integrations for Aider.
|
|
59
|
+
* Since Aider has no native MCP, these are editor/workflow recommendations.
|
|
60
|
+
*/
|
|
61
|
+
function recommendAiderMcpPacks(ctx) {
|
|
62
|
+
const recommendations = [];
|
|
63
|
+
|
|
64
|
+
// Always recommend /web for docs
|
|
65
|
+
recommendations.push(AIDER_MCP_PACKS.find(p => p.key === 'web-docs'));
|
|
66
|
+
|
|
67
|
+
// Detect editor signals
|
|
68
|
+
const hasVscode = ctx.files.some(f => /\.vscode\//i.test(f));
|
|
69
|
+
const hasNvim = ctx.fileContent('.nvimrc') || ctx.fileContent('init.lua');
|
|
70
|
+
|
|
71
|
+
if (hasVscode) {
|
|
72
|
+
recommendations.push(AIDER_MCP_PACKS.find(p => p.key === 'editor-bridge-vscode'));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (hasNvim) {
|
|
76
|
+
recommendations.push(AIDER_MCP_PACKS.find(p => p.key === 'editor-bridge-neovim'));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return recommendations.filter(Boolean);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get preflight warnings for Aider MCP integration (minimal).
|
|
84
|
+
*/
|
|
85
|
+
function getAiderMcpPreflight() {
|
|
86
|
+
return {
|
|
87
|
+
warnings: [
|
|
88
|
+
'Aider has no native MCP support. Use /web command and editor extensions instead.',
|
|
89
|
+
],
|
|
90
|
+
ready: true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
AIDER_MCP_PACKS,
|
|
96
|
+
recommendAiderMcpPacks,
|
|
97
|
+
getAiderMcpPreflight,
|
|
98
|
+
};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aider Patch Intelligence — managed blocks for YAML config
|
|
3
|
+
*
|
|
4
|
+
* Safe patching of existing Aider files using managed blocks.
|
|
5
|
+
* Supports .aider.conf.yml (YAML comment blocks) and CONVENTIONS.md (HTML comment blocks).
|
|
6
|
+
*
|
|
7
|
+
* Managed blocks are sections that nerviq controls.
|
|
8
|
+
* Hand-authored content outside managed blocks is preserved.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { writeRollbackArtifact, writeActivityArtifact } = require('../activity');
|
|
14
|
+
|
|
15
|
+
// Managed block markers
|
|
16
|
+
const MANAGED_START_MD = '<!-- nerviq:managed:start -->';
|
|
17
|
+
const MANAGED_END_MD = '<!-- nerviq:managed:end -->';
|
|
18
|
+
const MANAGED_START_YAML = '# <!-- nerviq:managed:start -->';
|
|
19
|
+
const MANAGED_END_YAML = '# <!-- nerviq:managed:end -->';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Extract managed blocks from a file.
|
|
23
|
+
*/
|
|
24
|
+
function extractManagedBlock(content, startMarker, endMarker) {
|
|
25
|
+
const startIdx = content.indexOf(startMarker);
|
|
26
|
+
const endIdx = content.indexOf(endMarker);
|
|
27
|
+
|
|
28
|
+
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
|
|
29
|
+
return { before: content, managed: null, after: '' };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
before: content.substring(0, startIdx),
|
|
34
|
+
managed: content.substring(startIdx + startMarker.length, endIdx).trim(),
|
|
35
|
+
after: content.substring(endIdx + endMarker.length),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Replace or insert a managed block in a file.
|
|
41
|
+
*/
|
|
42
|
+
function upsertManagedBlock(content, newManaged, startMarker, endMarker) {
|
|
43
|
+
const { before, managed, after } = extractManagedBlock(content, startMarker, endMarker);
|
|
44
|
+
|
|
45
|
+
if (managed !== null) {
|
|
46
|
+
return `${before}${startMarker}\n${newManaged}\n${endMarker}${after}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const separator = content.endsWith('\n') ? '\n' : '\n\n';
|
|
50
|
+
return `${content}${separator}${startMarker}\n${newManaged}\n${endMarker}\n`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Patch CONVENTIONS.md with managed sections.
|
|
55
|
+
*/
|
|
56
|
+
function patchConventionsMd(existingContent, managedSections) {
|
|
57
|
+
const newManaged = Object.entries(managedSections)
|
|
58
|
+
.map(([section, content]) => `## ${section}\n${content}`)
|
|
59
|
+
.join('\n\n');
|
|
60
|
+
|
|
61
|
+
return upsertManagedBlock(existingContent, newManaged, MANAGED_START_MD, MANAGED_END_MD);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Patch .aider.conf.yml by safely adding new keys.
|
|
66
|
+
* Never weakens existing safety settings (auto-commits, etc.).
|
|
67
|
+
* Only adds keys that don't already exist.
|
|
68
|
+
*/
|
|
69
|
+
function patchAiderConfYml(existingContent, newKeys) {
|
|
70
|
+
const existingKeys = new Set();
|
|
71
|
+
const lines = existingContent.split(/\r?\n/);
|
|
72
|
+
|
|
73
|
+
for (const line of lines) {
|
|
74
|
+
const trimmed = line.trim();
|
|
75
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
76
|
+
const colonIdx = trimmed.indexOf(':');
|
|
77
|
+
if (colonIdx > 0) {
|
|
78
|
+
existingKeys.add(trimmed.slice(0, colonIdx).trim());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const additions = [];
|
|
83
|
+
for (const [key, value] of Object.entries(newKeys)) {
|
|
84
|
+
if (existingKeys.has(key)) continue;
|
|
85
|
+
|
|
86
|
+
// Safety: never weaken these settings
|
|
87
|
+
if (key === 'auto-commits' && value === false) continue;
|
|
88
|
+
if (key === 'yes-always' && value === true) continue;
|
|
89
|
+
|
|
90
|
+
if (typeof value === 'string') {
|
|
91
|
+
additions.push(`${key}: "${value}"`);
|
|
92
|
+
} else if (typeof value === 'boolean' || typeof value === 'number') {
|
|
93
|
+
additions.push(`${key}: ${value}`);
|
|
94
|
+
} else if (Array.isArray(value)) {
|
|
95
|
+
additions.push(`${key}:`);
|
|
96
|
+
for (const item of value) {
|
|
97
|
+
additions.push(` - ${item}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (additions.length === 0) return existingContent;
|
|
103
|
+
|
|
104
|
+
const newContent = additions.join('\n');
|
|
105
|
+
return upsertManagedBlock(existingContent, newContent, MANAGED_START_YAML, MANAGED_END_YAML);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Detect mixed-platform repo (e.g., has both .aider.conf.yml and CLAUDE.md).
|
|
110
|
+
*/
|
|
111
|
+
function detectMixedAiderRepo(ctx) {
|
|
112
|
+
const platforms = [];
|
|
113
|
+
|
|
114
|
+
if (ctx.fileContent('.aider.conf.yml')) platforms.push('aider');
|
|
115
|
+
if (ctx.fileContent('CLAUDE.md') || ctx.fileContent('.claude/CLAUDE.md')) platforms.push('claude');
|
|
116
|
+
if (ctx.fileContent('AGENTS.md') || ctx.fileContent('.codex')) platforms.push('codex');
|
|
117
|
+
if (ctx.fileContent('.cursor/rules') || ctx.fileContent('.cursorrules')) platforms.push('cursor');
|
|
118
|
+
if (ctx.fileContent('.github/copilot-instructions.md')) platforms.push('copilot');
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
isMultiPlatform: platforms.length > 1,
|
|
122
|
+
platforms,
|
|
123
|
+
primaryPlatform: platforms[0] || null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Generate a patch preview without writing.
|
|
129
|
+
*/
|
|
130
|
+
function generatePatchPreview(ctx, patches = {}) {
|
|
131
|
+
const previews = [];
|
|
132
|
+
|
|
133
|
+
if (patches.confYml) {
|
|
134
|
+
const existing = ctx.configContent ? (ctx.configContent() || '') : '';
|
|
135
|
+
const patched = existing
|
|
136
|
+
? patchAiderConfYml(existing, patches.confYml)
|
|
137
|
+
: Object.entries(patches.confYml).map(([k, v]) => `${k}: ${v}`).join('\n');
|
|
138
|
+
|
|
139
|
+
previews.push({
|
|
140
|
+
file: '.aider.conf.yml',
|
|
141
|
+
exists: Boolean(existing),
|
|
142
|
+
unchanged: patched === existing,
|
|
143
|
+
preview: patched,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (patches.conventions) {
|
|
148
|
+
const existing = ctx.fileContent('CONVENTIONS.md') || '';
|
|
149
|
+
const patched = existing
|
|
150
|
+
? patchConventionsMd(existing, patches.conventions)
|
|
151
|
+
: Object.entries(patches.conventions).map(([s, c]) => `## ${s}\n${c}`).join('\n\n');
|
|
152
|
+
|
|
153
|
+
previews.push({
|
|
154
|
+
file: 'CONVENTIONS.md',
|
|
155
|
+
exists: Boolean(existing),
|
|
156
|
+
unchanged: patched === existing,
|
|
157
|
+
preview: patched,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return previews;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Apply patches to disk with rollback support.
|
|
166
|
+
*/
|
|
167
|
+
function applyPatch(dir, filePath, newContent) {
|
|
168
|
+
const fullPath = path.join(dir, filePath);
|
|
169
|
+
const existed = fs.existsSync(fullPath);
|
|
170
|
+
const originalContent = existed ? fs.readFileSync(fullPath, 'utf8') : null;
|
|
171
|
+
|
|
172
|
+
if (existed && originalContent === newContent) {
|
|
173
|
+
return { success: true, reason: 'unchanged', unchanged: true };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const dirName = path.dirname(fullPath);
|
|
177
|
+
if (!fs.existsSync(dirName)) {
|
|
178
|
+
fs.mkdirSync(dirName, { recursive: true });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
fs.writeFileSync(fullPath, newContent, 'utf8');
|
|
182
|
+
|
|
183
|
+
const rollback = writeRollbackArtifact(dir, 'aider-patch', [filePath], {
|
|
184
|
+
[filePath]: originalContent,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const activity = writeActivityArtifact(dir, 'aider-patch', {
|
|
188
|
+
platform: 'aider',
|
|
189
|
+
patchedFiles: [filePath],
|
|
190
|
+
rollbackArtifact: rollback.relativePath,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
reason: 'patched',
|
|
196
|
+
unchanged: false,
|
|
197
|
+
rollbackArtifact: rollback.relativePath,
|
|
198
|
+
activityArtifact: activity.relativePath,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = {
|
|
203
|
+
MANAGED_START_MD,
|
|
204
|
+
MANAGED_END_MD,
|
|
205
|
+
MANAGED_START_YAML,
|
|
206
|
+
MANAGED_END_YAML,
|
|
207
|
+
extractManagedBlock,
|
|
208
|
+
upsertManagedBlock,
|
|
209
|
+
patchConventionsMd,
|
|
210
|
+
patchAiderConfYml,
|
|
211
|
+
detectMixedAiderRepo,
|
|
212
|
+
generatePatchPreview,
|
|
213
|
+
applyPatch,
|
|
214
|
+
};
|