@hanzlaa/rcode 3.2.0 → 3.3.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/cli/generate-command-skills.cjs +203 -0
- package/cli/install.js +78 -23
- package/dist/rcode.js +56 -22
- package/package.json +1 -1
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Install-time generator: skill stubs that mirror slash commands.
|
|
4
|
+
*
|
|
5
|
+
* WHY: VS Code's Claude Code extension lists `.claude/skills/` in its
|
|
6
|
+
* sidebar, but slash commands at `.claude/commands/rihal/` are only
|
|
7
|
+
* reachable via the `/` autocomplete. Users coming from GSD (which ships
|
|
8
|
+
* a skill per command) expect to see lifecycle commands like `rihal-do`
|
|
9
|
+
* in the sidebar.
|
|
10
|
+
*
|
|
11
|
+
* This script creates ONE skill stub per slash command at install time,
|
|
12
|
+
* unless a real skill with the same name already exists at the source.
|
|
13
|
+
* The stubs live at the install destination only (`.claude/skills/`) —
|
|
14
|
+
* they are NEVER committed to the rcode source tree. That keeps the
|
|
15
|
+
* source codebase free of duplication while letting the sidebar feel
|
|
16
|
+
* full.
|
|
17
|
+
*
|
|
18
|
+
* Each generated stub is marked with `generated: true` and
|
|
19
|
+
* `generated-by: rcode-install` in frontmatter so it can be detected
|
|
20
|
+
* and refreshed on subsequent installs without confusing real skills.
|
|
21
|
+
*
|
|
22
|
+
* Run: node scripts/generate-command-skills.cjs <package-root> <target-skills-dir>
|
|
23
|
+
* (called from cli/install.js)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Curated list of commands that get skill stubs. Not every command
|
|
31
|
+
* deserves a sidebar entry — only the user-facing entry points and
|
|
32
|
+
* lifecycle verbs. Internal sub-commands stay slash-only.
|
|
33
|
+
*/
|
|
34
|
+
const SIDEBAR_COMMANDS = new Set([
|
|
35
|
+
'do', 'status', 'progress', 'next', 'plan', 'execute',
|
|
36
|
+
'council', 'discuss', 'ship', 'audit', 'autonomous',
|
|
37
|
+
'session-report', 'forensics', 'health', 'debug',
|
|
38
|
+
'verify-phase', 'verify-work', 'review', 'code-review',
|
|
39
|
+
'new-project', 'new-milestone', 'milestone-summary',
|
|
40
|
+
'note', 'add-todo', 'check-todos', 'pause-work', 'resume-work',
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
function parseFrontmatter(text) {
|
|
44
|
+
if (!text.startsWith('---\n')) return {};
|
|
45
|
+
const end = text.indexOf('\n---\n', 4);
|
|
46
|
+
if (end === -1) return {};
|
|
47
|
+
const block = text.slice(4, end);
|
|
48
|
+
const fm = {};
|
|
49
|
+
for (const raw of block.split('\n')) {
|
|
50
|
+
const m = raw.match(/^([a-zA-Z_-]+):\s*(.+)$/);
|
|
51
|
+
if (m) fm[m[1].trim()] = m[2].trim().replace(/^["']|["']$/g, '');
|
|
52
|
+
}
|
|
53
|
+
return fm;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function discoverRealSkills(packageRoot) {
|
|
57
|
+
const out = new Set();
|
|
58
|
+
const buckets = ['core', 'agents'];
|
|
59
|
+
for (const bucket of buckets) {
|
|
60
|
+
const dir = path.join(packageRoot, 'rihal', 'skills', bucket);
|
|
61
|
+
if (!fs.existsSync(dir)) continue;
|
|
62
|
+
for (const entry of fs.readdirSync(dir)) {
|
|
63
|
+
if (entry.startsWith('rihal-')) out.add(entry);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// actions are nested by phase
|
|
67
|
+
const actionsDir = path.join(packageRoot, 'rihal', 'skills', 'actions');
|
|
68
|
+
if (fs.existsSync(actionsDir)) {
|
|
69
|
+
for (const phase of fs.readdirSync(actionsDir)) {
|
|
70
|
+
const phaseDir = path.join(actionsDir, phase);
|
|
71
|
+
if (!fs.statSync(phaseDir).isDirectory()) continue;
|
|
72
|
+
for (const entry of fs.readdirSync(phaseDir)) {
|
|
73
|
+
if (entry.startsWith('rihal-')) out.add(entry);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function generateStub(cmdName, commandFm, version) {
|
|
81
|
+
const desc = commandFm.description || `Slash command shortcut for /rihal:${cmdName}.`;
|
|
82
|
+
const triggers = [
|
|
83
|
+
`rihal ${cmdName}`,
|
|
84
|
+
`rihal:${cmdName}`,
|
|
85
|
+
`/rihal:${cmdName}`,
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
return `---
|
|
89
|
+
name: rihal-${cmdName}
|
|
90
|
+
description: >
|
|
91
|
+
${desc.replace(/\n/g, ' ')}
|
|
92
|
+
Sidebar entry — invokes the same workflow as /rihal:${cmdName}.
|
|
93
|
+
triggers:
|
|
94
|
+
${triggers.map((t) => ` - "${t}"`).join('\n')}
|
|
95
|
+
user-invocable: true
|
|
96
|
+
generated: true
|
|
97
|
+
generated-by: rcode-install-v${version}
|
|
98
|
+
source: rihal/commands/${cmdName}.md
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
<!--
|
|
102
|
+
AUTO-GENERATED at install time by scripts/generate-command-skills.cjs.
|
|
103
|
+
Do NOT edit this file directly — your changes will be overwritten on the next
|
|
104
|
+
install or update. To customise, create a sibling \`.local.md\` file (which
|
|
105
|
+
is preserved across installs) or modify the source command at
|
|
106
|
+
rihal/commands/${cmdName}.md.
|
|
107
|
+
|
|
108
|
+
This stub exists so the slash command /rihal:${cmdName} appears in VS Code's
|
|
109
|
+
Claude Code sidebar (which lists skills only, not slash commands). The
|
|
110
|
+
behaviour is identical to /rihal:${cmdName} — both invoke the workflow at
|
|
111
|
+
.rihal/workflows/${cmdName}.md.
|
|
112
|
+
-->
|
|
113
|
+
|
|
114
|
+
## Overview
|
|
115
|
+
|
|
116
|
+
Sidebar entry for the \`/rihal:${cmdName}\` slash command. Phrase-activated alternative invocation route.
|
|
117
|
+
|
|
118
|
+
## Workflow
|
|
119
|
+
|
|
120
|
+
Read and execute \`@.rihal/workflows/${cmdName}.md\` end-to-end. The behaviour is the same as invoking \`/rihal:${cmdName}\` directly.
|
|
121
|
+
|
|
122
|
+
## Output Format
|
|
123
|
+
|
|
124
|
+
Identical to \`/rihal:${cmdName}\`. See the workflow file for the canonical output spec.
|
|
125
|
+
|
|
126
|
+
## Examples
|
|
127
|
+
|
|
128
|
+
**Happy path** — say "rihal ${cmdName}" or "/rihal:${cmdName}" → workflow runs identically either way.
|
|
129
|
+
|
|
130
|
+
**Negative — looking for the canonical command file** — see \`rihal/commands/${cmdName}.md\` (the source of truth) and \`rihal/workflows/${cmdName}.md\` (the orchestration logic).
|
|
131
|
+
|
|
132
|
+
## Memory Bank Hooks
|
|
133
|
+
|
|
134
|
+
- **Reads:** whatever \`.rihal/workflows/${cmdName}.md\` reads
|
|
135
|
+
- **Writes:** whatever the workflow writes
|
|
136
|
+
- This stub itself is read-only — it just dispatches to the workflow.
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function main(packageRoot, targetSkillsDir, version) {
|
|
141
|
+
if (!fs.existsSync(targetSkillsDir)) {
|
|
142
|
+
fs.mkdirSync(targetSkillsDir, { recursive: true });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const realSkills = discoverRealSkills(packageRoot);
|
|
146
|
+
const commandsDir = path.join(packageRoot, 'rihal', 'commands');
|
|
147
|
+
if (!fs.existsSync(commandsDir)) {
|
|
148
|
+
console.warn(`[generate-command-skills] commands dir not found: ${commandsDir}`);
|
|
149
|
+
return { generated: 0, skipped: 0 };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
let generated = 0;
|
|
153
|
+
let skipped = 0;
|
|
154
|
+
|
|
155
|
+
for (const file of fs.readdirSync(commandsDir)) {
|
|
156
|
+
if (!file.endsWith('.md')) continue;
|
|
157
|
+
if (file.startsWith('_')) continue; // internal aliases / metadata
|
|
158
|
+
const cmdName = file.replace(/\.md$/, '');
|
|
159
|
+
if (!SIDEBAR_COMMANDS.has(cmdName)) { skipped++; continue; }
|
|
160
|
+
|
|
161
|
+
const skillName = `rihal-${cmdName}`;
|
|
162
|
+
if (realSkills.has(skillName)) {
|
|
163
|
+
// A real skill with this name exists in the source tree — don't shadow it
|
|
164
|
+
skipped++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const cmdPath = path.join(commandsDir, file);
|
|
169
|
+
const cmdText = fs.readFileSync(cmdPath, 'utf8');
|
|
170
|
+
const cmdFm = parseFrontmatter(cmdText);
|
|
171
|
+
|
|
172
|
+
const stubDir = path.join(targetSkillsDir, skillName);
|
|
173
|
+
const stubFile = path.join(stubDir, 'SKILL.md');
|
|
174
|
+
|
|
175
|
+
// Idempotency: only overwrite if the file is missing OR is a previously
|
|
176
|
+
// generated stub (has the marker). Never clobber a user's hand-edited file.
|
|
177
|
+
if (fs.existsSync(stubFile)) {
|
|
178
|
+
const existing = fs.readFileSync(stubFile, 'utf8');
|
|
179
|
+
if (!/^generated:\s*true/m.test(existing)) {
|
|
180
|
+
skipped++;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
fs.mkdirSync(stubDir, { recursive: true });
|
|
186
|
+
fs.writeFileSync(stubFile, generateStub(cmdName, cmdFm, version), 'utf8');
|
|
187
|
+
generated++;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return { generated, skipped };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (require.main === module) {
|
|
194
|
+
const [packageRoot, targetSkillsDir, version = '0.0.0'] = process.argv.slice(2);
|
|
195
|
+
if (!packageRoot || !targetSkillsDir) {
|
|
196
|
+
console.error('Usage: generate-command-skills.cjs <package-root> <target-skills-dir> [version]');
|
|
197
|
+
process.exit(2);
|
|
198
|
+
}
|
|
199
|
+
const { generated, skipped } = main(packageRoot, targetSkillsDir, version);
|
|
200
|
+
console.log(`✓ ${generated} sidebar skill stub${generated === 1 ? '' : 's'} generated, ${skipped} skipped (already real skills or out of curated set)`);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = { main, SIDEBAR_COMMANDS };
|
package/cli/install.js
CHANGED
|
@@ -415,8 +415,33 @@ function getPathsForIde(ide, target) {
|
|
|
415
415
|
referencesDir: path.join(target, '.rihal', 'references'),
|
|
416
416
|
binDir: path.join(target, '.rihal', 'bin'),
|
|
417
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
|
+
};
|
|
418
443
|
default:
|
|
419
|
-
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini`);
|
|
444
|
+
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini, vscode, antigravity`);
|
|
420
445
|
}
|
|
421
446
|
}
|
|
422
447
|
|
|
@@ -1231,27 +1256,28 @@ async function install(opts) {
|
|
|
1231
1256
|
}
|
|
1232
1257
|
|
|
1233
1258
|
// Validate IDE — structured error for unsupported editors (#197).
|
|
1234
|
-
if (!['claude', 'cursor', 'gemini'].includes(opts.ide)) {
|
|
1259
|
+
if (!['claude', 'cursor', 'gemini', 'vscode', 'antigravity'].includes(opts.ide)) {
|
|
1235
1260
|
console.error(`✖ --ide ${opts.ide} is not supported in v${readPackageVersion()}.`);
|
|
1236
1261
|
console.error('');
|
|
1237
1262
|
console.error(' Currently supported:');
|
|
1238
|
-
console.error(' claude
|
|
1239
|
-
console.error(' cursor
|
|
1240
|
-
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)');
|
|
1241
1268
|
console.error('');
|
|
1242
|
-
console.error(' Tracked for
|
|
1243
|
-
console.error('
|
|
1244
|
-
console.error('
|
|
1245
|
-
console.error(' zed — Zed editor');
|
|
1269
|
+
console.error(' Tracked for future:');
|
|
1270
|
+
console.error(' jetbrains — IntelliJ / PyCharm');
|
|
1271
|
+
console.error(' zed — Zed editor');
|
|
1246
1272
|
console.error('');
|
|
1247
|
-
if (/^(vscode|vs-code|code)$/i.test(opts.ide)) {
|
|
1248
|
-
console.error(' Workaround: if you use VS Code WITH the Claude Code extension,');
|
|
1249
|
-
console.error(' run `--ide claude` — the extension reads from .claude/ too.');
|
|
1250
|
-
console.error('');
|
|
1251
|
-
}
|
|
1252
1273
|
return 1;
|
|
1253
1274
|
}
|
|
1254
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
|
+
|
|
1255
1281
|
// Gemini IDE support deferred
|
|
1256
1282
|
if (opts.ide === 'gemini') {
|
|
1257
1283
|
console.log(`\n⚠️ Gemini CLI install not yet implemented\n`);
|
|
@@ -1261,6 +1287,12 @@ async function install(opts) {
|
|
|
1261
1287
|
return 1;
|
|
1262
1288
|
}
|
|
1263
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
|
+
|
|
1264
1296
|
// Validate requested modules exist
|
|
1265
1297
|
if (opts.modules.length > 0) {
|
|
1266
1298
|
const available = listAvailableModules();
|
|
@@ -1587,7 +1619,24 @@ async function install(opts) {
|
|
|
1587
1619
|
|
|
1588
1620
|
// Install v1-style phrase-activated skills (scaffold-project, create-prd,
|
|
1589
1621
|
// retrospective, etc.) into .claude/skills/ alongside the v2 agents/commands.
|
|
1590
|
-
|
|
1622
|
+
let skillsInstalled = installSkills(PACKAGE_ROOT, opts.target);
|
|
1623
|
+
|
|
1624
|
+
// Generate install-time skill stubs that mirror sidebar-worthy slash commands.
|
|
1625
|
+
// Source codebase stays clean — these stubs only exist at the install
|
|
1626
|
+
// destination, marked with `generated: true` so they refresh idempotently.
|
|
1627
|
+
// See cli/generate-command-skills.cjs for rationale.
|
|
1628
|
+
try {
|
|
1629
|
+
const { main: generateCommandSkills } = require(path.join(PACKAGE_ROOT, 'cli', 'generate-command-skills.cjs'));
|
|
1630
|
+
const stubsDir = path.join(opts.target, '.claude', 'skills');
|
|
1631
|
+
const result = generateCommandSkills(PACKAGE_ROOT, stubsDir, readPackageVersion());
|
|
1632
|
+
if (result.generated > 0) {
|
|
1633
|
+
console.log(' ' + dim(`${result.generated} sidebar skill stub${result.generated === 1 ? '' : 's'} generated for command discoverability`));
|
|
1634
|
+
skillsInstalled += result.generated;
|
|
1635
|
+
}
|
|
1636
|
+
} catch (err) {
|
|
1637
|
+
// Non-fatal: install succeeds without sidebar stubs
|
|
1638
|
+
console.log(' ' + dim(`(sidebar stub generation skipped: ${err.message})`));
|
|
1639
|
+
}
|
|
1591
1640
|
|
|
1592
1641
|
// Seed .planning/ with starter ROADMAP + STATE so workflows work immediately
|
|
1593
1642
|
const starterSeeded = seedStarterPlanning(opts.target, opts.projectName);
|
|
@@ -1667,16 +1716,19 @@ async function install(opts) {
|
|
|
1667
1716
|
console.log('');
|
|
1668
1717
|
}
|
|
1669
1718
|
|
|
1670
|
-
// Count installed agents + commands dynamically (#190).
|
|
1671
|
-
|
|
1672
|
-
|
|
1719
|
+
// Count installed agents + commands dynamically (#190). Reads from the
|
|
1720
|
+
// IDE-specific install paths so cursor/gemini/vscode/antigravity don't
|
|
1721
|
+
// false-fail the health check.
|
|
1722
|
+
const idePaths = getPathsForIde(opts.ide, opts.target);
|
|
1723
|
+
const agentsDir = idePaths.agentsDir;
|
|
1724
|
+
const commandsDir = idePaths.commandsDir;
|
|
1673
1725
|
let agentCount = 0, commandCount = 0;
|
|
1674
1726
|
try {
|
|
1675
1727
|
if (fs.existsSync(agentsDir)) {
|
|
1676
|
-
agentCount = fs.readdirSync(agentsDir).filter(f => f.startsWith('rihal-') && f.endsWith('.md')).length;
|
|
1728
|
+
agentCount = fs.readdirSync(agentsDir).filter(f => (f.startsWith('rihal-') || f.startsWith('rcode-')) && (f.endsWith('.md') || f.endsWith('.mdc'))).length;
|
|
1677
1729
|
}
|
|
1678
1730
|
if (fs.existsSync(commandsDir)) {
|
|
1679
|
-
commandCount = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md')).length;
|
|
1731
|
+
commandCount = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md') || f.endsWith('.mdc')).length;
|
|
1680
1732
|
}
|
|
1681
1733
|
} catch {}
|
|
1682
1734
|
|
|
@@ -1688,9 +1740,12 @@ async function install(opts) {
|
|
|
1688
1740
|
console.log(` ${bold('Mode:')} ${opts.mode} ${dim('(guided=confirm at gates, yolo=autonomous)')}`);
|
|
1689
1741
|
console.log(` ${bold('Planning:')} ${opts.commitPlanning !== false ? 'committed' : 'gitignored'} ${dim('(flip: rihal-tools gitignore refresh)')}`);
|
|
1690
1742
|
console.log('');
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1743
|
+
// Show the actual install paths so cursor/gemini/antigravity output is accurate
|
|
1744
|
+
const relAgents = path.relative(opts.target, idePaths.agentsDir) || idePaths.agentsDir;
|
|
1745
|
+
const relCommands = path.relative(opts.target, idePaths.commandsDir) || idePaths.commandsDir;
|
|
1746
|
+
console.log(` ${bold('Agents:')} ${pc.green(String(agentCount))} in ${relAgents}/`);
|
|
1747
|
+
console.log(` ${bold('Commands:')} ${pc.green(String(commandCount))} slash commands in ${relCommands}/`);
|
|
1748
|
+
if (skillsInstalled > 0) console.log(` ${bold('Skills:')} ${pc.green(String(skillsInstalled))} phrase-activated`);
|
|
1694
1749
|
console.log('');
|
|
1695
1750
|
if (starterSeeded) {
|
|
1696
1751
|
console.log(' ' + ok('Starter planning scaffolded in .planning/ (ROADMAP, STATE, PROJECT)'));
|
package/dist/rcode.js
CHANGED
|
@@ -16065,8 +16065,25 @@ Installs (IDE-specific):
|
|
|
16065
16065
|
referencesDir: path2.join(target, ".rihal", "references"),
|
|
16066
16066
|
binDir: path2.join(target, ".rihal", "bin")
|
|
16067
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
|
+
};
|
|
16068
16085
|
default:
|
|
16069
|
-
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini`);
|
|
16086
|
+
throw new Error(`Unknown IDE: ${ide}. Supported: claude, cursor, gemini, vscode, antigravity`);
|
|
16070
16087
|
}
|
|
16071
16088
|
}
|
|
16072
16089
|
function walkFiles(dir, extraIgnore = []) {
|
|
@@ -16700,26 +16717,25 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16700
16717
|
console.error(`\u2716 Source tree not found at ${SOURCE_ROOT}. Running from wrong dir?`);
|
|
16701
16718
|
return 1;
|
|
16702
16719
|
}
|
|
16703
|
-
if (!["claude", "cursor", "gemini"].includes(opts.ide)) {
|
|
16720
|
+
if (!["claude", "cursor", "gemini", "vscode", "antigravity"].includes(opts.ide)) {
|
|
16704
16721
|
console.error(`\u2716 --ide ${opts.ide} is not supported in v${readPackageVersion()}.`);
|
|
16705
16722
|
console.error("");
|
|
16706
16723
|
console.error(" Currently supported:");
|
|
16707
|
-
console.error(" claude
|
|
16708
|
-
console.error(" cursor
|
|
16709
|
-
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)");
|
|
16710
16729
|
console.error("");
|
|
16711
|
-
console.error(" Tracked for
|
|
16712
|
-
console.error("
|
|
16713
|
-
console.error("
|
|
16714
|
-
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");
|
|
16715
16733
|
console.error("");
|
|
16716
|
-
if (/^(vscode|vs-code|code)$/i.test(opts.ide)) {
|
|
16717
|
-
console.error(" Workaround: if you use VS Code WITH the Claude Code extension,");
|
|
16718
|
-
console.error(" run `--ide claude` \u2014 the extension reads from .claude/ too.");
|
|
16719
|
-
console.error("");
|
|
16720
|
-
}
|
|
16721
16734
|
return 1;
|
|
16722
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
|
+
}
|
|
16723
16739
|
if (opts.ide === "gemini") {
|
|
16724
16740
|
console.log(`
|
|
16725
16741
|
\u26A0\uFE0F Gemini CLI install not yet implemented
|
|
@@ -16731,6 +16747,10 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16731
16747
|
`);
|
|
16732
16748
|
return 1;
|
|
16733
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
|
+
}
|
|
16734
16754
|
if (opts.modules.length > 0) {
|
|
16735
16755
|
const available = listAvailableModules();
|
|
16736
16756
|
const unknownModules = opts.modules.filter((m) => !available.includes(m));
|
|
@@ -16995,7 +17015,18 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
16995
17015
|
path2.join(configDir, "files-manifest.csv"),
|
|
16996
17016
|
generateFilesManifest(plan, opts.target)
|
|
16997
17017
|
);
|
|
16998
|
-
|
|
17018
|
+
let skillsInstalled = installSkills(PACKAGE_ROOT2, opts.target);
|
|
17019
|
+
try {
|
|
17020
|
+
const { main: generateCommandSkills } = require(path2.join(PACKAGE_ROOT2, "cli", "generate-command-skills.cjs"));
|
|
17021
|
+
const stubsDir = path2.join(opts.target, ".claude", "skills");
|
|
17022
|
+
const result = generateCommandSkills(PACKAGE_ROOT2, stubsDir, readPackageVersion());
|
|
17023
|
+
if (result.generated > 0) {
|
|
17024
|
+
console.log(" " + dim(`${result.generated} sidebar skill stub${result.generated === 1 ? "" : "s"} generated for command discoverability`));
|
|
17025
|
+
skillsInstalled += result.generated;
|
|
17026
|
+
}
|
|
17027
|
+
} catch (err) {
|
|
17028
|
+
console.log(" " + dim(`(sidebar stub generation skipped: ${err.message})`));
|
|
17029
|
+
}
|
|
16999
17030
|
const starterSeeded = seedStarterPlanning(opts.target, opts.projectName);
|
|
17000
17031
|
installBrainScaffold(PACKAGE_ROOT2, opts.target);
|
|
17001
17032
|
const gitignoreReport = ensureRcodeGitignore(opts.target, { commitPlanning: opts.commitPlanning });
|
|
@@ -17059,15 +17090,16 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
17059
17090
|
console.log(dim(" To overwrite: re-run with --force-overwrite | To see full diffs: --show-diff"));
|
|
17060
17091
|
console.log("");
|
|
17061
17092
|
}
|
|
17062
|
-
const
|
|
17063
|
-
const
|
|
17093
|
+
const idePaths = getPathsForIde(opts.ide, opts.target);
|
|
17094
|
+
const agentsDir = idePaths.agentsDir;
|
|
17095
|
+
const commandsDir = idePaths.commandsDir;
|
|
17064
17096
|
let agentCount = 0, commandCount = 0;
|
|
17065
17097
|
try {
|
|
17066
17098
|
if (fs2.existsSync(agentsDir)) {
|
|
17067
|
-
agentCount = fs2.readdirSync(agentsDir).filter((f) => f.startsWith("rihal-") && f.endsWith(".md")).length;
|
|
17099
|
+
agentCount = fs2.readdirSync(agentsDir).filter((f) => (f.startsWith("rihal-") || f.startsWith("rcode-")) && (f.endsWith(".md") || f.endsWith(".mdc"))).length;
|
|
17068
17100
|
}
|
|
17069
17101
|
if (fs2.existsSync(commandsDir)) {
|
|
17070
|
-
commandCount = fs2.readdirSync(commandsDir).filter((f) => f.endsWith(".md")).length;
|
|
17102
|
+
commandCount = fs2.readdirSync(commandsDir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc")).length;
|
|
17071
17103
|
}
|
|
17072
17104
|
} catch {
|
|
17073
17105
|
}
|
|
@@ -17079,9 +17111,11 @@ Say "plan a sprint" or run \`/rihal:sprint-planning\` to break Phase 01 into sto
|
|
|
17079
17111
|
console.log(` ${bold("Mode:")} ${opts.mode} ${dim("(guided=confirm at gates, yolo=autonomous)")}`);
|
|
17080
17112
|
console.log(` ${bold("Planning:")} ${opts.commitPlanning !== false ? "committed" : "gitignored"} ${dim("(flip: rihal-tools gitignore refresh)")}`);
|
|
17081
17113
|
console.log("");
|
|
17082
|
-
|
|
17083
|
-
|
|
17084
|
-
|
|
17114
|
+
const relAgents = path2.relative(opts.target, idePaths.agentsDir) || idePaths.agentsDir;
|
|
17115
|
+
const relCommands = path2.relative(opts.target, idePaths.commandsDir) || idePaths.commandsDir;
|
|
17116
|
+
console.log(` ${bold("Agents:")} ${pc.green(String(agentCount))} in ${relAgents}/`);
|
|
17117
|
+
console.log(` ${bold("Commands:")} ${pc.green(String(commandCount))} slash commands in ${relCommands}/`);
|
|
17118
|
+
if (skillsInstalled > 0) console.log(` ${bold("Skills:")} ${pc.green(String(skillsInstalled))} phrase-activated`);
|
|
17085
17119
|
console.log("");
|
|
17086
17120
|
if (starterSeeded) {
|
|
17087
17121
|
console.log(" " + ok("Starter planning scaffolded in .planning/ (ROADMAP, STATE, PROJECT)"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
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": {
|