@hanzlaa/rcode 3.1.0 → 3.2.1
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/cli/install.js +205 -69
- package/dist/rcode.js +178 -64
- package/package.json +2 -2
package/cli/install.js
CHANGED
|
@@ -268,20 +268,26 @@ function printInstallHeader(targetVersion) {
|
|
|
268
268
|
* Returns a set like { claude: true, cursor: false, gemini: false }.
|
|
269
269
|
*/
|
|
270
270
|
function detectIdeSignals(target) {
|
|
271
|
-
const signals = { claude: false, cursor: false, gemini: false };
|
|
271
|
+
const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false };
|
|
272
272
|
// 1. Project-local install dirs (strongest signal — they already use one)
|
|
273
273
|
if (fs.existsSync(path.join(target, '.claude'))) signals.claude = true;
|
|
274
274
|
if (fs.existsSync(path.join(target, '.cursor'))) signals.cursor = true;
|
|
275
275
|
if (fs.existsSync(path.join(target, '.gemini'))) signals.gemini = true;
|
|
276
|
+
if (fs.existsSync(path.join(target, '.vscode'))) signals.vscode = true;
|
|
277
|
+
if (fs.existsSync(path.join(target, '.antigravity'))) signals.antigravity = true;
|
|
276
278
|
// 2. User-level config dirs
|
|
277
279
|
const home = os.homedir();
|
|
278
280
|
if (fs.existsSync(path.join(home, '.claude'))) signals.claude = true;
|
|
279
281
|
if (fs.existsSync(path.join(home, '.cursor'))) signals.cursor = true;
|
|
280
282
|
if (fs.existsSync(path.join(home, '.config', 'Cursor'))) signals.cursor = true;
|
|
281
283
|
if (fs.existsSync(path.join(home, '.gemini'))) signals.gemini = true;
|
|
284
|
+
if (fs.existsSync(path.join(home, '.vscode'))) signals.vscode = true;
|
|
285
|
+
if (fs.existsSync(path.join(home, '.config', 'Code'))) signals.vscode = true;
|
|
286
|
+
if (fs.existsSync(path.join(home, '.antigravity'))) signals.antigravity = true;
|
|
282
287
|
// 3. Env vars commonly set by editor terminals
|
|
283
288
|
if (process.env.CURSOR_TRACE_ID || /cursor/i.test(process.env.TERM_PROGRAM || '')) signals.cursor = true;
|
|
284
289
|
if (process.env.CLAUDECODE === '1' || process.env.CLAUDE_CODE_ENTRYPOINT) signals.claude = true;
|
|
290
|
+
if (process.env.VSCODE_PID || /vscode/i.test(process.env.TERM_PROGRAM || '')) signals.vscode = true;
|
|
285
291
|
return signals;
|
|
286
292
|
}
|
|
287
293
|
|
|
@@ -297,43 +303,32 @@ async function resolveIde(opts) {
|
|
|
297
303
|
if (opts.yes || !process.stdin.isTTY) return opts.ide || 'claude';
|
|
298
304
|
|
|
299
305
|
const signals = detectIdeSignals(opts.target);
|
|
300
|
-
const detected = ['claude', 'cursor', 'gemini'].filter(k => signals[k]);
|
|
301
|
-
|
|
302
|
-
// Build the menu — detected IDEs marked with a hint
|
|
303
|
-
const choices = [
|
|
304
|
-
{ key: '1', value: 'claude', label: 'Claude Code', hint: signals.claude ? dim('(detected)') : '' },
|
|
305
|
-
{ key: '2', value: 'cursor', label: 'Cursor', hint: signals.cursor ? dim('(detected)') : '' },
|
|
306
|
-
{ key: '3', value: 'gemini', label: 'Gemini CLI', hint: signals.gemini ? dim('(detected)') : dim('(beta — limited)') },
|
|
307
|
-
];
|
|
306
|
+
const detected = ['claude', 'cursor', 'gemini', 'vscode'].filter(k => signals[k]);
|
|
308
307
|
|
|
309
308
|
// Pick a default: prefer the single detected IDE; otherwise claude
|
|
310
309
|
let defaultValue = 'claude';
|
|
311
310
|
if (detected.length === 1) defaultValue = detected[0];
|
|
312
311
|
|
|
313
|
-
|
|
314
|
-
const
|
|
315
|
-
|
|
312
|
+
// Use @clack/prompts for arrow-key navigation. Closes #449 / #450.
|
|
313
|
+
const choice = await clack.select({
|
|
314
|
+
message: '🎯 Which editor will you use rcode with?',
|
|
315
|
+
initialValue: defaultValue,
|
|
316
|
+
options: [
|
|
317
|
+
{ value: 'claude', label: 'Claude Code', hint: signals.claude ? '(detected)' : undefined },
|
|
318
|
+
{ value: 'cursor', label: 'Cursor', hint: signals.cursor ? '(detected)' : undefined },
|
|
319
|
+
{ value: 'gemini', label: 'Gemini CLI', hint: signals.gemini ? '(detected)' : '(beta — limited)' },
|
|
320
|
+
{ value: 'vscode', label: 'VS Code', hint: signals.vscode ? '(detected)' : '(via Continue / Copilot extensions)' },
|
|
321
|
+
{ value: 'antigravity', label: 'Antigravity', hint: '(experimental — installs to .antigravity/)' },
|
|
322
|
+
],
|
|
323
|
+
});
|
|
316
324
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const label = c.value === defaultValue ? pc.bold(c.label) : c.label;
|
|
322
|
-
console.log(` ${marker} ${pc.cyan('[' + c.key + ']')} ${label} ${c.hint}`);
|
|
325
|
+
// Handle Ctrl-C cleanly
|
|
326
|
+
if (clack.isCancel(choice)) {
|
|
327
|
+
clack.cancel('Install cancelled.');
|
|
328
|
+
process.exit(0);
|
|
323
329
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const answer = (await prompt(` Pick an editor [${defaultKey}]: `)).trim().toLowerCase();
|
|
327
|
-
rl.close();
|
|
328
|
-
|
|
329
|
-
if (!answer) return defaultValue;
|
|
330
|
-
// Accept either the number key or the name
|
|
331
|
-
const byKey = choices.find(c => c.key === answer);
|
|
332
|
-
if (byKey) return byKey.value;
|
|
333
|
-
const byName = choices.find(c => c.value === answer || c.label.toLowerCase().startsWith(answer));
|
|
334
|
-
if (byName) return byName.value;
|
|
335
|
-
console.log(dim(` Unrecognised choice "${answer}" — falling back to ${defaultValue}.`));
|
|
336
|
-
return defaultValue;
|
|
330
|
+
|
|
331
|
+
return choice;
|
|
337
332
|
}
|
|
338
333
|
|
|
339
334
|
/**
|
|
@@ -345,19 +340,21 @@ async function resolveCommitPlanning(opts) {
|
|
|
345
340
|
if (opts.commitPlanning !== null) return opts.commitPlanning;
|
|
346
341
|
if (opts.yes || !process.stdin.isTTY) return true; // non-interactive default
|
|
347
342
|
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
343
|
+
const choice = await clack.select({
|
|
344
|
+
message: '📋 .planning/ holds PRDs, roadmaps, sprints, SUMMARY files. How should they be tracked?',
|
|
345
|
+
initialValue: 'commit',
|
|
346
|
+
options: [
|
|
347
|
+
{ value: 'commit', label: 'Commit', hint: 'collaborators see the same plans (recommended)' },
|
|
348
|
+
{ value: 'gitignore', label: 'Gitignore', hint: 'planning stays local (good for sensitive PRDs)' },
|
|
349
|
+
],
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
if (clack.isCancel(choice)) {
|
|
353
|
+
clack.cancel('Install cancelled.');
|
|
354
|
+
process.exit(0);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return choice === 'commit';
|
|
361
358
|
}
|
|
362
359
|
|
|
363
360
|
function printHelp() {
|
|
@@ -418,8 +415,33 @@ function getPathsForIde(ide, target) {
|
|
|
418
415
|
referencesDir: path.join(target, '.rihal', 'references'),
|
|
419
416
|
binDir: path.join(target, '.rihal', 'bin'),
|
|
420
417
|
};
|
|
418
|
+
case 'vscode':
|
|
419
|
+
// VS Code's Claude Code / Continue / Copilot extensions all read from
|
|
420
|
+
// .claude/ (Claude Code's canonical paths). We install there directly
|
|
421
|
+
// and additionally write a .vscode/rihal/ marker so VS Code workspace
|
|
422
|
+
// settings can pin behaviour.
|
|
423
|
+
return {
|
|
424
|
+
agentsDir: path.join(target, '.claude', 'agents'),
|
|
425
|
+
commandsDir: path.join(target, '.claude', 'commands', 'rihal'),
|
|
426
|
+
workflowsDir: path.join(target, '.rihal', 'workflows'),
|
|
427
|
+
referencesDir: path.join(target, '.rihal', 'references'),
|
|
428
|
+
binDir: path.join(target, '.rihal', 'bin'),
|
|
429
|
+
markerDir: path.join(target, '.vscode', 'rihal'),
|
|
430
|
+
};
|
|
431
|
+
case 'antigravity':
|
|
432
|
+
// Antigravity (Google's agentic IDE) — install to .antigravity/ mirroring
|
|
433
|
+
// the .gemini/ structure. Antigravity's plugin protocol is still firming
|
|
434
|
+
// up; the user can adjust paths via .rihal/config.yaml's `extra_install_paths`
|
|
435
|
+
// if Antigravity expects different routing.
|
|
436
|
+
return {
|
|
437
|
+
agentsDir: path.join(target, '.antigravity', 'rihal', 'agents'),
|
|
438
|
+
commandsDir: path.join(target, '.antigravity', 'rihal', 'commands'),
|
|
439
|
+
workflowsDir: path.join(target, '.rihal', 'workflows'),
|
|
440
|
+
referencesDir: path.join(target, '.rihal', 'references'),
|
|
441
|
+
binDir: path.join(target, '.rihal', 'bin'),
|
|
442
|
+
};
|
|
421
443
|
default:
|
|
422
|
-
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini`);
|
|
444
|
+
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini, vscode, antigravity`);
|
|
423
445
|
}
|
|
424
446
|
}
|
|
425
447
|
|
|
@@ -1234,27 +1256,28 @@ async function install(opts) {
|
|
|
1234
1256
|
}
|
|
1235
1257
|
|
|
1236
1258
|
// Validate IDE — structured error for unsupported editors (#197).
|
|
1237
|
-
if (!['claude', 'cursor', 'gemini'].includes(opts.ide)) {
|
|
1259
|
+
if (!['claude', 'cursor', 'gemini', 'vscode', 'antigravity'].includes(opts.ide)) {
|
|
1238
1260
|
console.error(`✖ --ide ${opts.ide} is not supported in v${readPackageVersion()}.`);
|
|
1239
1261
|
console.error('');
|
|
1240
1262
|
console.error(' Currently supported:');
|
|
1241
|
-
console.error(' claude
|
|
1242
|
-
console.error(' cursor
|
|
1243
|
-
console.error(' gemini
|
|
1263
|
+
console.error(' claude — Claude Code native (recommended)');
|
|
1264
|
+
console.error(' cursor — Cursor IDE');
|
|
1265
|
+
console.error(' gemini — Gemini CLI');
|
|
1266
|
+
console.error(' vscode — VS Code (with Claude Code / Continue / Copilot extension)');
|
|
1267
|
+
console.error(' antigravity — Antigravity (experimental)');
|
|
1244
1268
|
console.error('');
|
|
1245
|
-
console.error(' Tracked for
|
|
1246
|
-
console.error('
|
|
1247
|
-
console.error('
|
|
1248
|
-
console.error(' zed — Zed editor');
|
|
1269
|
+
console.error(' Tracked for future:');
|
|
1270
|
+
console.error(' jetbrains — IntelliJ / PyCharm');
|
|
1271
|
+
console.error(' zed — Zed editor');
|
|
1249
1272
|
console.error('');
|
|
1250
|
-
if (/^(vscode|vs-code|code)$/i.test(opts.ide)) {
|
|
1251
|
-
console.error(' Workaround: if you use VS Code WITH the Claude Code extension,');
|
|
1252
|
-
console.error(' run `--ide claude` — the extension reads from .claude/ too.');
|
|
1253
|
-
console.error('');
|
|
1254
|
-
}
|
|
1255
1273
|
return 1;
|
|
1256
1274
|
}
|
|
1257
1275
|
|
|
1276
|
+
// VS Code installs to .claude/ paths (extension reads from there). Inform the user.
|
|
1277
|
+
if (opts.ide === 'vscode') {
|
|
1278
|
+
console.log(' ' + dim('VS Code → installing to .claude/ paths (read by Claude Code / Continue / Copilot extensions).'));
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1258
1281
|
// Gemini IDE support deferred
|
|
1259
1282
|
if (opts.ide === 'gemini') {
|
|
1260
1283
|
console.log(`\n⚠️ Gemini CLI install not yet implemented\n`);
|
|
@@ -1264,6 +1287,12 @@ async function install(opts) {
|
|
|
1264
1287
|
return 1;
|
|
1265
1288
|
}
|
|
1266
1289
|
|
|
1290
|
+
// Antigravity install is experimental — best-effort path, user may need to adjust
|
|
1291
|
+
if (opts.ide === 'antigravity') {
|
|
1292
|
+
console.log(' ' + warn('Antigravity install is experimental. Files land at .antigravity/rihal/{agents,commands}/.'));
|
|
1293
|
+
console.log(' ' + dim('If Antigravity expects a different path, adjust .rihal/config.yaml and re-run.'));
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1267
1296
|
// Validate requested modules exist
|
|
1268
1297
|
if (opts.modules.length > 0) {
|
|
1269
1298
|
const available = listAvailableModules();
|
|
@@ -1342,6 +1371,7 @@ async function install(opts) {
|
|
|
1342
1371
|
let preserved = 0;
|
|
1343
1372
|
const preservedFiles = [];
|
|
1344
1373
|
const preservedDiffs = []; // { rel, insertions, deletions, patch } for #251
|
|
1374
|
+
const conflictedFiles = []; // { rel, src, destPath, existingContent, sourceContent } for #451 / #453
|
|
1345
1375
|
const spinner = createSpinner(dim(`Installing ${plan.length} files…`), { color: 'cyan' }).start();
|
|
1346
1376
|
|
|
1347
1377
|
for (const entry of plan) {
|
|
@@ -1381,9 +1411,15 @@ async function install(opts) {
|
|
|
1381
1411
|
const sourceHash = sha256(fs.readFileSync(entry.src));
|
|
1382
1412
|
if (existingHash === sourceHash) { skipped++; continue; }
|
|
1383
1413
|
if (!opts.yes && !opts.nonDestructive) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1414
|
+
// Buffer the conflict instead of spamming a warning per file (#451).
|
|
1415
|
+
// Surfaced as a categorised summary post-install + interactive offer (#453).
|
|
1416
|
+
conflictedFiles.push({
|
|
1417
|
+
rel: relForward,
|
|
1418
|
+
src: entry.src,
|
|
1419
|
+
destPath,
|
|
1420
|
+
existingContent: fs.readFileSync(destPath, 'utf8'),
|
|
1421
|
+
sourceContent: fs.readFileSync(entry.src, 'utf8'),
|
|
1422
|
+
});
|
|
1387
1423
|
skipped++;
|
|
1388
1424
|
continue;
|
|
1389
1425
|
}
|
|
@@ -1406,6 +1442,100 @@ async function install(opts) {
|
|
|
1406
1442
|
|
|
1407
1443
|
spinner.success({ text: ok(`${copied} files installed`) });
|
|
1408
1444
|
|
|
1445
|
+
// Categorised conflict summary (#451) + interactive resolution offer (#453).
|
|
1446
|
+
// Replaces the per-file 'differs from package version' warning spam.
|
|
1447
|
+
if (conflictedFiles.length > 0) {
|
|
1448
|
+
const byCategory = { workflows: [], agents: [], commands: [], skills: [], references: [], other: [] };
|
|
1449
|
+
for (const c of conflictedFiles) {
|
|
1450
|
+
if (c.rel.includes('/workflows/')) byCategory.workflows.push(c);
|
|
1451
|
+
else if (c.rel.includes('/agents/')) byCategory.agents.push(c);
|
|
1452
|
+
else if (c.rel.includes('/commands/')) byCategory.commands.push(c);
|
|
1453
|
+
else if (c.rel.includes('/skills/')) byCategory.skills.push(c);
|
|
1454
|
+
else if (c.rel.includes('/references/')) byCategory.references.push(c);
|
|
1455
|
+
else byCategory.other.push(c);
|
|
1456
|
+
}
|
|
1457
|
+
console.log('');
|
|
1458
|
+
console.log(' ' + warn(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? '' : 's'} have local edits AND v${readPackageVersion()} updates:`));
|
|
1459
|
+
for (const [cat, list] of Object.entries(byCategory)) {
|
|
1460
|
+
if (list.length === 0) continue;
|
|
1461
|
+
console.log(' ' + dim(`${list.length} ${cat}`));
|
|
1462
|
+
}
|
|
1463
|
+
console.log('');
|
|
1464
|
+
|
|
1465
|
+
if (!opts.yes && process.stdin.isTTY) {
|
|
1466
|
+
const action = await clack.select({
|
|
1467
|
+
message: 'How should we handle these?',
|
|
1468
|
+
initialValue: 'review',
|
|
1469
|
+
options: [
|
|
1470
|
+
{ value: 'review', label: 'Review each one', hint: 'see the diff, decide per file' },
|
|
1471
|
+
{ value: 'upstream', label: 'Take v' + readPackageVersion() + ' for all', hint: 'lose local edits, get all bug fixes' },
|
|
1472
|
+
{ value: 'keep', label: 'Keep my local edits', hint: 'skip v' + readPackageVersion() + ' updates for these files (current behaviour)' },
|
|
1473
|
+
],
|
|
1474
|
+
});
|
|
1475
|
+
if (clack.isCancel(action)) {
|
|
1476
|
+
clack.note('Skipped — local edits preserved.');
|
|
1477
|
+
} else if (action === 'upstream') {
|
|
1478
|
+
let applied = 0;
|
|
1479
|
+
for (const c of conflictedFiles) {
|
|
1480
|
+
fs.writeFileSync(c.destPath, c.sourceContent, 'utf8');
|
|
1481
|
+
applied++;
|
|
1482
|
+
}
|
|
1483
|
+
console.log(' ' + ok(`Applied v${readPackageVersion()} to ${applied} file${applied === 1 ? '' : 's'}.`));
|
|
1484
|
+
} else if (action === 'review') {
|
|
1485
|
+
let applied = 0, kept = 0;
|
|
1486
|
+
for (const c of conflictedFiles) {
|
|
1487
|
+
const patch = createTwoFilesPatch(c.rel, c.rel, c.existingContent, c.sourceContent, 'local', 'v' + readPackageVersion());
|
|
1488
|
+
let ins = 0, del = 0;
|
|
1489
|
+
for (const line of patch.split('\n')) {
|
|
1490
|
+
if (line.startsWith('+') && !line.startsWith('+++')) ins++;
|
|
1491
|
+
if (line.startsWith('-') && !line.startsWith('---')) del++;
|
|
1492
|
+
}
|
|
1493
|
+
console.log('');
|
|
1494
|
+
console.log(' ' + pc.bold(c.rel) + dim(' ') + pc.green(`+${ins}`) + ' ' + pc.red(`-${del}`));
|
|
1495
|
+
const decision = await clack.select({
|
|
1496
|
+
message: 'Take upstream, keep local, or view diff?',
|
|
1497
|
+
initialValue: 'view',
|
|
1498
|
+
options: [
|
|
1499
|
+
{ value: 'upstream', label: 'Take v' + readPackageVersion() },
|
|
1500
|
+
{ value: 'keep', label: 'Keep local' },
|
|
1501
|
+
{ value: 'view', label: 'View diff first' },
|
|
1502
|
+
],
|
|
1503
|
+
});
|
|
1504
|
+
let finalAction = decision;
|
|
1505
|
+
if (clack.isCancel(decision) || decision === 'view') {
|
|
1506
|
+
for (const line of patch.split('\n').slice(4)) {
|
|
1507
|
+
if (line.startsWith('+')) process.stdout.write(pc.green(line) + '\n');
|
|
1508
|
+
else if (line.startsWith('-')) process.stdout.write(pc.red(line) + '\n');
|
|
1509
|
+
else if (line.startsWith('@')) process.stdout.write(pc.cyan(line) + '\n');
|
|
1510
|
+
else process.stdout.write(dim(line) + '\n');
|
|
1511
|
+
}
|
|
1512
|
+
const after = await clack.select({
|
|
1513
|
+
message: 'Now: take upstream or keep local?',
|
|
1514
|
+
initialValue: 'keep',
|
|
1515
|
+
options: [
|
|
1516
|
+
{ value: 'upstream', label: 'Take v' + readPackageVersion() },
|
|
1517
|
+
{ value: 'keep', label: 'Keep local' },
|
|
1518
|
+
],
|
|
1519
|
+
});
|
|
1520
|
+
finalAction = clack.isCancel(after) ? 'keep' : after;
|
|
1521
|
+
}
|
|
1522
|
+
if (finalAction === 'upstream') {
|
|
1523
|
+
fs.writeFileSync(c.destPath, c.sourceContent, 'utf8');
|
|
1524
|
+
applied++;
|
|
1525
|
+
} else {
|
|
1526
|
+
kept++;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
console.log(' ' + ok(`Review complete: ${applied} applied, ${kept} kept local.`));
|
|
1530
|
+
} else {
|
|
1531
|
+
console.log(' ' + dim(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? '' : 's'} kept local. Re-run with --force-overwrite or 'rcode update' anytime.`));
|
|
1532
|
+
}
|
|
1533
|
+
} else {
|
|
1534
|
+
console.log(' ' + dim(`Re-run with --force-overwrite to apply v${readPackageVersion()} updates, or pipe through an interactive shell to resolve per-file.`));
|
|
1535
|
+
}
|
|
1536
|
+
console.log('');
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1409
1539
|
// Write .rihal/_config/manifest.yaml + agent-manifest.csv + files-manifest.csv
|
|
1410
1540
|
const configDir = path.join(opts.target, '.rihal', '_config');
|
|
1411
1541
|
ensureDir(configDir);
|
|
@@ -1569,16 +1699,19 @@ async function install(opts) {
|
|
|
1569
1699
|
console.log('');
|
|
1570
1700
|
}
|
|
1571
1701
|
|
|
1572
|
-
// Count installed agents + commands dynamically (#190).
|
|
1573
|
-
|
|
1574
|
-
|
|
1702
|
+
// Count installed agents + commands dynamically (#190). Reads from the
|
|
1703
|
+
// IDE-specific install paths so cursor/gemini/vscode/antigravity don't
|
|
1704
|
+
// false-fail the health check.
|
|
1705
|
+
const idePaths = getPathsForIde(opts.ide, opts.target);
|
|
1706
|
+
const agentsDir = idePaths.agentsDir;
|
|
1707
|
+
const commandsDir = idePaths.commandsDir;
|
|
1575
1708
|
let agentCount = 0, commandCount = 0;
|
|
1576
1709
|
try {
|
|
1577
1710
|
if (fs.existsSync(agentsDir)) {
|
|
1578
|
-
agentCount = fs.readdirSync(agentsDir).filter(f => f.startsWith('rihal-') && f.endsWith('.md')).length;
|
|
1711
|
+
agentCount = fs.readdirSync(agentsDir).filter(f => (f.startsWith('rihal-') || f.startsWith('rcode-')) && (f.endsWith('.md') || f.endsWith('.mdc'))).length;
|
|
1579
1712
|
}
|
|
1580
1713
|
if (fs.existsSync(commandsDir)) {
|
|
1581
|
-
commandCount = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md')).length;
|
|
1714
|
+
commandCount = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md') || f.endsWith('.mdc')).length;
|
|
1582
1715
|
}
|
|
1583
1716
|
} catch {}
|
|
1584
1717
|
|
|
@@ -1590,9 +1723,12 @@ async function install(opts) {
|
|
|
1590
1723
|
console.log(` ${bold('Mode:')} ${opts.mode} ${dim('(guided=confirm at gates, yolo=autonomous)')}`);
|
|
1591
1724
|
console.log(` ${bold('Planning:')} ${opts.commitPlanning !== false ? 'committed' : 'gitignored'} ${dim('(flip: rihal-tools gitignore refresh)')}`);
|
|
1592
1725
|
console.log('');
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1726
|
+
// Show the actual install paths so cursor/gemini/antigravity output is accurate
|
|
1727
|
+
const relAgents = path.relative(opts.target, idePaths.agentsDir) || idePaths.agentsDir;
|
|
1728
|
+
const relCommands = path.relative(opts.target, idePaths.commandsDir) || idePaths.commandsDir;
|
|
1729
|
+
console.log(` ${bold('Agents:')} ${pc.green(String(agentCount))} in ${relAgents}/`);
|
|
1730
|
+
console.log(` ${bold('Commands:')} ${pc.green(String(commandCount))} slash commands in ${relCommands}/`);
|
|
1731
|
+
if (skillsInstalled > 0) console.log(` ${bold('Skills:')} ${pc.green(String(skillsInstalled))} phrase-activated`);
|
|
1596
1732
|
console.log('');
|
|
1597
1733
|
if (starterSeeded) {
|
|
1598
1734
|
console.log(' ' + ok('Starter planning scaffolded in .planning/ (ROADMAP, STATE, PROJECT)'));
|
package/dist/rcode.js
CHANGED
|
@@ -15952,69 +15952,65 @@ var require_install = __commonJS({
|
|
|
15952
15952
|
console.log(lines.join("\n"));
|
|
15953
15953
|
}
|
|
15954
15954
|
function detectIdeSignals(target) {
|
|
15955
|
-
const signals = { claude: false, cursor: false, gemini: false };
|
|
15955
|
+
const signals = { claude: false, cursor: false, gemini: false, vscode: false, antigravity: false };
|
|
15956
15956
|
if (fs2.existsSync(path2.join(target, ".claude"))) signals.claude = true;
|
|
15957
15957
|
if (fs2.existsSync(path2.join(target, ".cursor"))) signals.cursor = true;
|
|
15958
15958
|
if (fs2.existsSync(path2.join(target, ".gemini"))) signals.gemini = true;
|
|
15959
|
+
if (fs2.existsSync(path2.join(target, ".vscode"))) signals.vscode = true;
|
|
15960
|
+
if (fs2.existsSync(path2.join(target, ".antigravity"))) signals.antigravity = true;
|
|
15959
15961
|
const home = os.homedir();
|
|
15960
15962
|
if (fs2.existsSync(path2.join(home, ".claude"))) signals.claude = true;
|
|
15961
15963
|
if (fs2.existsSync(path2.join(home, ".cursor"))) signals.cursor = true;
|
|
15962
15964
|
if (fs2.existsSync(path2.join(home, ".config", "Cursor"))) signals.cursor = true;
|
|
15963
15965
|
if (fs2.existsSync(path2.join(home, ".gemini"))) signals.gemini = true;
|
|
15966
|
+
if (fs2.existsSync(path2.join(home, ".vscode"))) signals.vscode = true;
|
|
15967
|
+
if (fs2.existsSync(path2.join(home, ".config", "Code"))) signals.vscode = true;
|
|
15968
|
+
if (fs2.existsSync(path2.join(home, ".antigravity"))) signals.antigravity = true;
|
|
15964
15969
|
if (process.env.CURSOR_TRACE_ID || /cursor/i.test(process.env.TERM_PROGRAM || "")) signals.cursor = true;
|
|
15965
15970
|
if (process.env.CLAUDECODE === "1" || process.env.CLAUDE_CODE_ENTRYPOINT) signals.claude = true;
|
|
15971
|
+
if (process.env.VSCODE_PID || /vscode/i.test(process.env.TERM_PROGRAM || "")) signals.vscode = true;
|
|
15966
15972
|
return signals;
|
|
15967
15973
|
}
|
|
15968
15974
|
async function resolveIde(opts) {
|
|
15969
15975
|
if (opts.ideProvided) return opts.ide;
|
|
15970
15976
|
if (opts.yes || !process.stdin.isTTY) return opts.ide || "claude";
|
|
15971
15977
|
const signals = detectIdeSignals(opts.target);
|
|
15972
|
-
const detected = ["claude", "cursor", "gemini"].filter((k) => signals[k]);
|
|
15973
|
-
const choices = [
|
|
15974
|
-
{ key: "1", value: "claude", label: "Claude Code", hint: signals.claude ? dim("(detected)") : "" },
|
|
15975
|
-
{ key: "2", value: "cursor", label: "Cursor", hint: signals.cursor ? dim("(detected)") : "" },
|
|
15976
|
-
{ key: "3", value: "gemini", label: "Gemini CLI", hint: signals.gemini ? dim("(detected)") : dim("(beta \u2014 limited)") }
|
|
15977
|
-
];
|
|
15978
|
+
const detected = ["claude", "cursor", "gemini", "vscode"].filter((k) => signals[k]);
|
|
15978
15979
|
let defaultValue = "claude";
|
|
15979
15980
|
if (detected.length === 1) defaultValue = detected[0];
|
|
15980
|
-
const
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15981
|
+
const choice = await clack.select({
|
|
15982
|
+
message: "\u{1F3AF} Which editor will you use rcode with?",
|
|
15983
|
+
initialValue: defaultValue,
|
|
15984
|
+
options: [
|
|
15985
|
+
{ value: "claude", label: "Claude Code", hint: signals.claude ? "(detected)" : void 0 },
|
|
15986
|
+
{ value: "cursor", label: "Cursor", hint: signals.cursor ? "(detected)" : void 0 },
|
|
15987
|
+
{ value: "gemini", label: "Gemini CLI", hint: signals.gemini ? "(detected)" : "(beta \u2014 limited)" },
|
|
15988
|
+
{ value: "vscode", label: "VS Code", hint: signals.vscode ? "(detected)" : "(via Continue / Copilot extensions)" },
|
|
15989
|
+
{ value: "antigravity", label: "Antigravity", hint: "(experimental \u2014 installs to .antigravity/)" }
|
|
15990
|
+
]
|
|
15991
|
+
});
|
|
15992
|
+
if (clack.isCancel(choice)) {
|
|
15993
|
+
clack.cancel("Install cancelled.");
|
|
15994
|
+
process.exit(0);
|
|
15989
15995
|
}
|
|
15990
|
-
|
|
15991
|
-
const defaultKey = choices.find((c) => c.value === defaultValue).key;
|
|
15992
|
-
const answer = (await prompt(` Pick an editor [${defaultKey}]: `)).trim().toLowerCase();
|
|
15993
|
-
rl.close();
|
|
15994
|
-
if (!answer) return defaultValue;
|
|
15995
|
-
const byKey = choices.find((c) => c.key === answer);
|
|
15996
|
-
if (byKey) return byKey.value;
|
|
15997
|
-
const byName = choices.find((c) => c.value === answer || c.label.toLowerCase().startsWith(answer));
|
|
15998
|
-
if (byName) return byName.value;
|
|
15999
|
-
console.log(dim(` Unrecognised choice "${answer}" \u2014 falling back to ${defaultValue}.`));
|
|
16000
|
-
return defaultValue;
|
|
15996
|
+
return choice;
|
|
16001
15997
|
}
|
|
16002
15998
|
async function resolveCommitPlanning(opts) {
|
|
16003
15999
|
if (opts.commitPlanning !== null) return opts.commitPlanning;
|
|
16004
16000
|
if (opts.yes || !process.stdin.isTTY) return true;
|
|
16005
|
-
const
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
return
|
|
16001
|
+
const choice = await clack.select({
|
|
16002
|
+
message: "\u{1F4CB} .planning/ holds PRDs, roadmaps, sprints, SUMMARY files. How should they be tracked?",
|
|
16003
|
+
initialValue: "commit",
|
|
16004
|
+
options: [
|
|
16005
|
+
{ value: "commit", label: "Commit", hint: "collaborators see the same plans (recommended)" },
|
|
16006
|
+
{ value: "gitignore", label: "Gitignore", hint: "planning stays local (good for sensitive PRDs)" }
|
|
16007
|
+
]
|
|
16008
|
+
});
|
|
16009
|
+
if (clack.isCancel(choice)) {
|
|
16010
|
+
clack.cancel("Install cancelled.");
|
|
16011
|
+
process.exit(0);
|
|
16012
|
+
}
|
|
16013
|
+
return choice === "commit";
|
|
16018
16014
|
}
|
|
16019
16015
|
function printHelp2() {
|
|
16020
16016
|
console.log(`
|
|
@@ -16069,8 +16065,25 @@ Installs (IDE-specific):
|
|
|
16069
16065
|
referencesDir: path2.join(target, ".rihal", "references"),
|
|
16070
16066
|
binDir: path2.join(target, ".rihal", "bin")
|
|
16071
16067
|
};
|
|
16068
|
+
case "vscode":
|
|
16069
|
+
return {
|
|
16070
|
+
agentsDir: path2.join(target, ".claude", "agents"),
|
|
16071
|
+
commandsDir: path2.join(target, ".claude", "commands", "rihal"),
|
|
16072
|
+
workflowsDir: path2.join(target, ".rihal", "workflows"),
|
|
16073
|
+
referencesDir: path2.join(target, ".rihal", "references"),
|
|
16074
|
+
binDir: path2.join(target, ".rihal", "bin"),
|
|
16075
|
+
markerDir: path2.join(target, ".vscode", "rihal")
|
|
16076
|
+
};
|
|
16077
|
+
case "antigravity":
|
|
16078
|
+
return {
|
|
16079
|
+
agentsDir: path2.join(target, ".antigravity", "rihal", "agents"),
|
|
16080
|
+
commandsDir: path2.join(target, ".antigravity", "rihal", "commands"),
|
|
16081
|
+
workflowsDir: path2.join(target, ".rihal", "workflows"),
|
|
16082
|
+
referencesDir: path2.join(target, ".rihal", "references"),
|
|
16083
|
+
binDir: path2.join(target, ".rihal", "bin")
|
|
16084
|
+
};
|
|
16072
16085
|
default:
|
|
16073
|
-
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini`);
|
|
16086
|
+
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini, vscode, antigravity`);
|
|
16074
16087
|
}
|
|
16075
16088
|
}
|
|
16076
16089
|
function walkFiles(dir, extraIgnore = []) {
|
|
@@ -16704,26 +16717,25 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16704
16717
|
console.error(`\u2716 Source tree not found at ${SOURCE_ROOT}. Running from wrong dir?`);
|
|
16705
16718
|
return 1;
|
|
16706
16719
|
}
|
|
16707
|
-
if (!["claude", "cursor", "gemini"].includes(opts.ide)) {
|
|
16720
|
+
if (!["claude", "cursor", "gemini", "vscode", "antigravity"].includes(opts.ide)) {
|
|
16708
16721
|
console.error(`\u2716 --ide ${opts.ide} is not supported in v${readPackageVersion()}.`);
|
|
16709
16722
|
console.error("");
|
|
16710
16723
|
console.error(" Currently supported:");
|
|
16711
|
-
console.error(" claude
|
|
16712
|
-
console.error(" cursor
|
|
16713
|
-
console.error(" gemini
|
|
16724
|
+
console.error(" claude \u2014 Claude Code native (recommended)");
|
|
16725
|
+
console.error(" cursor \u2014 Cursor IDE");
|
|
16726
|
+
console.error(" gemini \u2014 Gemini CLI");
|
|
16727
|
+
console.error(" vscode \u2014 VS Code (with Claude Code / Continue / Copilot extension)");
|
|
16728
|
+
console.error(" antigravity \u2014 Antigravity (experimental)");
|
|
16714
16729
|
console.error("");
|
|
16715
|
-
console.error(" Tracked for
|
|
16716
|
-
console.error("
|
|
16717
|
-
console.error("
|
|
16718
|
-
console.error(" zed \u2014 Zed editor");
|
|
16730
|
+
console.error(" Tracked for future:");
|
|
16731
|
+
console.error(" jetbrains \u2014 IntelliJ / PyCharm");
|
|
16732
|
+
console.error(" zed \u2014 Zed editor");
|
|
16719
16733
|
console.error("");
|
|
16720
|
-
if (/^(vscode|vs-code|code)$/i.test(opts.ide)) {
|
|
16721
|
-
console.error(" Workaround: if you use VS Code WITH the Claude Code extension,");
|
|
16722
|
-
console.error(" run `--ide claude` \u2014 the extension reads from .claude/ too.");
|
|
16723
|
-
console.error("");
|
|
16724
|
-
}
|
|
16725
16734
|
return 1;
|
|
16726
16735
|
}
|
|
16736
|
+
if (opts.ide === "vscode") {
|
|
16737
|
+
console.log(" " + dim("VS Code \u2192 installing to .claude/ paths (read by Claude Code / Continue / Copilot extensions)."));
|
|
16738
|
+
}
|
|
16727
16739
|
if (opts.ide === "gemini") {
|
|
16728
16740
|
console.log(`
|
|
16729
16741
|
\u26A0\uFE0F Gemini CLI install not yet implemented
|
|
@@ -16735,6 +16747,10 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16735
16747
|
`);
|
|
16736
16748
|
return 1;
|
|
16737
16749
|
}
|
|
16750
|
+
if (opts.ide === "antigravity") {
|
|
16751
|
+
console.log(" " + warn("Antigravity install is experimental. Files land at .antigravity/rihal/{agents,commands}/."));
|
|
16752
|
+
console.log(" " + dim("If Antigravity expects a different path, adjust .rihal/config.yaml and re-run."));
|
|
16753
|
+
}
|
|
16738
16754
|
if (opts.modules.length > 0) {
|
|
16739
16755
|
const available = listAvailableModules();
|
|
16740
16756
|
const unknownModules = opts.modules.filter((m) => !available.includes(m));
|
|
@@ -16791,6 +16807,7 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16791
16807
|
let preserved = 0;
|
|
16792
16808
|
const preservedFiles = [];
|
|
16793
16809
|
const preservedDiffs = [];
|
|
16810
|
+
const conflictedFiles = [];
|
|
16794
16811
|
const spinner = createSpinner(dim(`Installing ${plan.length} files\u2026`), { color: "cyan" }).start();
|
|
16795
16812
|
for (const entry of plan) {
|
|
16796
16813
|
const destPath = path2.join(opts.target, entry.rel);
|
|
@@ -16825,9 +16842,13 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16825
16842
|
continue;
|
|
16826
16843
|
}
|
|
16827
16844
|
if (!opts.yes && !opts.nonDestructive) {
|
|
16828
|
-
|
|
16829
|
-
|
|
16830
|
-
|
|
16845
|
+
conflictedFiles.push({
|
|
16846
|
+
rel: relForward,
|
|
16847
|
+
src: entry.src,
|
|
16848
|
+
destPath,
|
|
16849
|
+
existingContent: fs2.readFileSync(destPath, "utf8"),
|
|
16850
|
+
sourceContent: fs2.readFileSync(entry.src, "utf8")
|
|
16851
|
+
});
|
|
16831
16852
|
skipped++;
|
|
16832
16853
|
continue;
|
|
16833
16854
|
}
|
|
@@ -16846,6 +16867,96 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16846
16867
|
copied++;
|
|
16847
16868
|
}
|
|
16848
16869
|
spinner.success({ text: ok(`${copied} files installed`) });
|
|
16870
|
+
if (conflictedFiles.length > 0) {
|
|
16871
|
+
const byCategory = { workflows: [], agents: [], commands: [], skills: [], references: [], other: [] };
|
|
16872
|
+
for (const c of conflictedFiles) {
|
|
16873
|
+
if (c.rel.includes("/workflows/")) byCategory.workflows.push(c);
|
|
16874
|
+
else if (c.rel.includes("/agents/")) byCategory.agents.push(c);
|
|
16875
|
+
else if (c.rel.includes("/commands/")) byCategory.commands.push(c);
|
|
16876
|
+
else if (c.rel.includes("/skills/")) byCategory.skills.push(c);
|
|
16877
|
+
else if (c.rel.includes("/references/")) byCategory.references.push(c);
|
|
16878
|
+
else byCategory.other.push(c);
|
|
16879
|
+
}
|
|
16880
|
+
console.log("");
|
|
16881
|
+
console.log(" " + warn(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? "" : "s"} have local edits AND v${readPackageVersion()} updates:`));
|
|
16882
|
+
for (const [cat, list] of Object.entries(byCategory)) {
|
|
16883
|
+
if (list.length === 0) continue;
|
|
16884
|
+
console.log(" " + dim(`${list.length} ${cat}`));
|
|
16885
|
+
}
|
|
16886
|
+
console.log("");
|
|
16887
|
+
if (!opts.yes && process.stdin.isTTY) {
|
|
16888
|
+
const action = await clack.select({
|
|
16889
|
+
message: "How should we handle these?",
|
|
16890
|
+
initialValue: "review",
|
|
16891
|
+
options: [
|
|
16892
|
+
{ value: "review", label: "Review each one", hint: "see the diff, decide per file" },
|
|
16893
|
+
{ value: "upstream", label: "Take v" + readPackageVersion() + " for all", hint: "lose local edits, get all bug fixes" },
|
|
16894
|
+
{ value: "keep", label: "Keep my local edits", hint: "skip v" + readPackageVersion() + " updates for these files (current behaviour)" }
|
|
16895
|
+
]
|
|
16896
|
+
});
|
|
16897
|
+
if (clack.isCancel(action)) {
|
|
16898
|
+
clack.note("Skipped \u2014 local edits preserved.");
|
|
16899
|
+
} else if (action === "upstream") {
|
|
16900
|
+
let applied = 0;
|
|
16901
|
+
for (const c of conflictedFiles) {
|
|
16902
|
+
fs2.writeFileSync(c.destPath, c.sourceContent, "utf8");
|
|
16903
|
+
applied++;
|
|
16904
|
+
}
|
|
16905
|
+
console.log(" " + ok(`Applied v${readPackageVersion()} to ${applied} file${applied === 1 ? "" : "s"}.`));
|
|
16906
|
+
} else if (action === "review") {
|
|
16907
|
+
let applied = 0, kept = 0;
|
|
16908
|
+
for (const c of conflictedFiles) {
|
|
16909
|
+
const patch = createTwoFilesPatch(c.rel, c.rel, c.existingContent, c.sourceContent, "local", "v" + readPackageVersion());
|
|
16910
|
+
let ins = 0, del = 0;
|
|
16911
|
+
for (const line of patch.split("\n")) {
|
|
16912
|
+
if (line.startsWith("+") && !line.startsWith("+++")) ins++;
|
|
16913
|
+
if (line.startsWith("-") && !line.startsWith("---")) del++;
|
|
16914
|
+
}
|
|
16915
|
+
console.log("");
|
|
16916
|
+
console.log(" " + pc.bold(c.rel) + dim(" ") + pc.green(`+${ins}`) + " " + pc.red(`-${del}`));
|
|
16917
|
+
const decision = await clack.select({
|
|
16918
|
+
message: "Take upstream, keep local, or view diff?",
|
|
16919
|
+
initialValue: "view",
|
|
16920
|
+
options: [
|
|
16921
|
+
{ value: "upstream", label: "Take v" + readPackageVersion() },
|
|
16922
|
+
{ value: "keep", label: "Keep local" },
|
|
16923
|
+
{ value: "view", label: "View diff first" }
|
|
16924
|
+
]
|
|
16925
|
+
});
|
|
16926
|
+
let finalAction = decision;
|
|
16927
|
+
if (clack.isCancel(decision) || decision === "view") {
|
|
16928
|
+
for (const line of patch.split("\n").slice(4)) {
|
|
16929
|
+
if (line.startsWith("+")) process.stdout.write(pc.green(line) + "\n");
|
|
16930
|
+
else if (line.startsWith("-")) process.stdout.write(pc.red(line) + "\n");
|
|
16931
|
+
else if (line.startsWith("@")) process.stdout.write(pc.cyan(line) + "\n");
|
|
16932
|
+
else process.stdout.write(dim(line) + "\n");
|
|
16933
|
+
}
|
|
16934
|
+
const after = await clack.select({
|
|
16935
|
+
message: "Now: take upstream or keep local?",
|
|
16936
|
+
initialValue: "keep",
|
|
16937
|
+
options: [
|
|
16938
|
+
{ value: "upstream", label: "Take v" + readPackageVersion() },
|
|
16939
|
+
{ value: "keep", label: "Keep local" }
|
|
16940
|
+
]
|
|
16941
|
+
});
|
|
16942
|
+
finalAction = clack.isCancel(after) ? "keep" : after;
|
|
16943
|
+
}
|
|
16944
|
+
if (finalAction === "upstream") {
|
|
16945
|
+
fs2.writeFileSync(c.destPath, c.sourceContent, "utf8");
|
|
16946
|
+
applied++;
|
|
16947
|
+
} else {
|
|
16948
|
+
kept++;
|
|
16949
|
+
}
|
|
16950
|
+
}
|
|
16951
|
+
console.log(" " + ok(`Review complete: ${applied} applied, ${kept} kept local.`));
|
|
16952
|
+
} else {
|
|
16953
|
+
console.log(" " + dim(`${conflictedFiles.length} file${conflictedFiles.length === 1 ? "" : "s"} kept local. Re-run with --force-overwrite or 'rcode update' anytime.`));
|
|
16954
|
+
}
|
|
16955
|
+
} else {
|
|
16956
|
+
console.log(" " + dim(`Re-run with --force-overwrite to apply v${readPackageVersion()} updates, or pipe through an interactive shell to resolve per-file.`));
|
|
16957
|
+
}
|
|
16958
|
+
console.log("");
|
|
16959
|
+
}
|
|
16849
16960
|
const configDir = path2.join(opts.target, ".rihal", "_config");
|
|
16850
16961
|
ensureDir(configDir);
|
|
16851
16962
|
fs2.writeFileSync(path2.join(configDir, "manifest.yaml"), generateInstallManifest(opts));
|
|
@@ -16968,15 +17079,16 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16968
17079
|
console.log(dim(" To overwrite: re-run with --force-overwrite | To see full diffs: --show-diff"));
|
|
16969
17080
|
console.log("");
|
|
16970
17081
|
}
|
|
16971
|
-
const
|
|
16972
|
-
const
|
|
17082
|
+
const idePaths = getPathsForIde(opts.ide, opts.target);
|
|
17083
|
+
const agentsDir = idePaths.agentsDir;
|
|
17084
|
+
const commandsDir = idePaths.commandsDir;
|
|
16973
17085
|
let agentCount = 0, commandCount = 0;
|
|
16974
17086
|
try {
|
|
16975
17087
|
if (fs2.existsSync(agentsDir)) {
|
|
16976
|
-
agentCount = fs2.readdirSync(agentsDir).filter((f) => f.startsWith("rihal-") && f.endsWith(".md")).length;
|
|
17088
|
+
agentCount = fs2.readdirSync(agentsDir).filter((f) => (f.startsWith("rihal-") || f.startsWith("rcode-")) && (f.endsWith(".md") || f.endsWith(".mdc"))).length;
|
|
16977
17089
|
}
|
|
16978
17090
|
if (fs2.existsSync(commandsDir)) {
|
|
16979
|
-
commandCount = fs2.readdirSync(commandsDir).filter((f) => f.endsWith(".md")).length;
|
|
17091
|
+
commandCount = fs2.readdirSync(commandsDir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc")).length;
|
|
16980
17092
|
}
|
|
16981
17093
|
} catch {
|
|
16982
17094
|
}
|
|
@@ -16988,9 +17100,11 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16988
17100
|
console.log(` ${bold("Mode:")} ${opts.mode} ${dim("(guided=confirm at gates, yolo=autonomous)")}`);
|
|
16989
17101
|
console.log(` ${bold("Planning:")} ${opts.commitPlanning !== false ? "committed" : "gitignored"} ${dim("(flip: rihal-tools gitignore refresh)")}`);
|
|
16990
17102
|
console.log("");
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
17103
|
+
const relAgents = path2.relative(opts.target, idePaths.agentsDir) || idePaths.agentsDir;
|
|
17104
|
+
const relCommands = path2.relative(opts.target, idePaths.commandsDir) || idePaths.commandsDir;
|
|
17105
|
+
console.log(` ${bold("Agents:")} ${pc.green(String(agentCount))} in ${relAgents}/`);
|
|
17106
|
+
console.log(` ${bold("Commands:")} ${pc.green(String(commandCount))} slash commands in ${relCommands}/`);
|
|
17107
|
+
if (skillsInstalled > 0) console.log(` ${bold("Skills:")} ${pc.green(String(skillsInstalled))} phrase-activated`);
|
|
16994
17108
|
console.log("");
|
|
16995
17109
|
if (starterSeeded) {
|
|
16996
17110
|
console.log(" " + ok("Starter planning scaffolded in .planning/ (ROADMAP, STATE, PROJECT)"));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "3.1
|
|
4
|
-
"description": "rcode — the memory bank for AI-driven SaaS teams. Persistent project context, distinctive engineering personas, and phase-based workflows. Built by Rihal. Works in Claude Code, Cursor, and
|
|
3
|
+
"version": "3.2.1",
|
|
4
|
+
"description": "rcode — the memory bank for AI-driven SaaS teams. Persistent project context, distinctive engineering personas, and phase-based workflows. Built by Rihal. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"rcode": "dist/rcode.js",
|