@hanzlaa/rcode 3.4.14 → 3.4.15
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 +55 -0
- package/dist/rcode.js +45 -0
- package/package.json +1 -1
package/cli/install.js
CHANGED
|
@@ -1724,6 +1724,61 @@ async function install(opts) {
|
|
|
1724
1724
|
return 0;
|
|
1725
1725
|
}
|
|
1726
1726
|
|
|
1727
|
+
// Duplicate-prevention: if rihal commands already exist globally in ~/.claude/commands/,
|
|
1728
|
+
// skip writing agents/commands to the project's .claude/ directory. Without this,
|
|
1729
|
+
// running `npx rcode install` in the home dir AND then in a project creates two sets
|
|
1730
|
+
// of identical files — Claude Code shows both as duplicate slash commands.
|
|
1731
|
+
const globalClaudeCommands = path.join(os.homedir(), '.claude', 'commands');
|
|
1732
|
+
const projectClaudeCommands = path.join(opts.target, '.claude', 'commands');
|
|
1733
|
+
const isProjectInstall = opts.target !== os.homedir();
|
|
1734
|
+
if (isProjectInstall && !opts.force && !opts.forceOverwrite) {
|
|
1735
|
+
try {
|
|
1736
|
+
const globalHasRihal = fs.existsSync(globalClaudeCommands) &&
|
|
1737
|
+
fs.readdirSync(globalClaudeCommands).some(f => f.startsWith('rihal-') && f.endsWith('.md'));
|
|
1738
|
+
const projectHasRihal = fs.existsSync(projectClaudeCommands) &&
|
|
1739
|
+
fs.readdirSync(projectClaudeCommands).some(f => f.startsWith('rihal-') && f.endsWith('.md'));
|
|
1740
|
+
if (globalHasRihal && !projectHasRihal) {
|
|
1741
|
+
// Global commands exist, project has none yet — filter them out of the plan
|
|
1742
|
+
// so we don't create duplicates. Project gets .rihal/ state only.
|
|
1743
|
+
const before = plan.length;
|
|
1744
|
+
const filtered = plan.filter(e => {
|
|
1745
|
+
const rel = e.rel.split(path.sep).join('/');
|
|
1746
|
+
return !rel.startsWith('.claude/commands/') && !rel.startsWith('.claude/agents/');
|
|
1747
|
+
});
|
|
1748
|
+
if (filtered.length < before) {
|
|
1749
|
+
plan.length = 0;
|
|
1750
|
+
filtered.forEach(e => plan.push(e));
|
|
1751
|
+
console.log(' ' + dim('Global rihal commands detected in ~/.claude/ — skipping project-level agent/command install to avoid duplicates.'));
|
|
1752
|
+
console.log(' ' + dim('Use --force-overwrite to install locally anyway.'));
|
|
1753
|
+
}
|
|
1754
|
+
} else if (globalHasRihal && projectHasRihal) {
|
|
1755
|
+
// Both exist — project commands are duplicates. Remove project-level ones.
|
|
1756
|
+
try {
|
|
1757
|
+
const projectCommandFiles = fs.readdirSync(projectClaudeCommands)
|
|
1758
|
+
.filter(f => f.startsWith('rihal-') && f.endsWith('.md'));
|
|
1759
|
+
for (const f of projectCommandFiles) {
|
|
1760
|
+
fs.unlinkSync(path.join(projectClaudeCommands, f));
|
|
1761
|
+
}
|
|
1762
|
+
const projectAgentsDir = path.join(opts.target, '.claude', 'agents');
|
|
1763
|
+
if (fs.existsSync(projectAgentsDir)) {
|
|
1764
|
+
const agentFiles = fs.readdirSync(projectAgentsDir)
|
|
1765
|
+
.filter(f => f.startsWith('rihal-') && f.endsWith('.md'));
|
|
1766
|
+
for (const f of agentFiles) {
|
|
1767
|
+
fs.unlinkSync(path.join(projectAgentsDir, f));
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
console.log(' ' + dim('Removed duplicate project-level rihal commands (global ones in ~/.claude/ take precedence).'));
|
|
1771
|
+
} catch { /* non-fatal */ }
|
|
1772
|
+
const filtered = plan.filter(e => {
|
|
1773
|
+
const rel = e.rel.split(path.sep).join('/');
|
|
1774
|
+
return !rel.startsWith('.claude/commands/') && !rel.startsWith('.claude/agents/');
|
|
1775
|
+
});
|
|
1776
|
+
plan.length = 0;
|
|
1777
|
+
filtered.forEach(e => plan.push(e));
|
|
1778
|
+
}
|
|
1779
|
+
} catch { /* non-fatal — skip detection on permission errors */ }
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1727
1782
|
// Write .rihal/_config/manifest.yaml + agent-manifest.csv + files-manifest.csv
|
|
1728
1783
|
const configDir = path.join(opts.target, '.rihal', '_config');
|
|
1729
1784
|
ensureDir(configDir);
|
package/dist/rcode.js
CHANGED
|
@@ -16269,6 +16269,51 @@ ${BLOCK}`);
|
|
|
16269
16269
|
console.log(` ${dim(`${skillsInstalled2} skills installed globally`)}`);
|
|
16270
16270
|
return 0;
|
|
16271
16271
|
}
|
|
16272
|
+
const globalClaudeCommands = path2.join(os.homedir(), ".claude", "commands");
|
|
16273
|
+
const projectClaudeCommands = path2.join(opts.target, ".claude", "commands");
|
|
16274
|
+
const isProjectInstall = opts.target !== os.homedir();
|
|
16275
|
+
if (isProjectInstall && !opts.force && !opts.forceOverwrite) {
|
|
16276
|
+
try {
|
|
16277
|
+
const globalHasRihal = fs2.existsSync(globalClaudeCommands) && fs2.readdirSync(globalClaudeCommands).some((f) => f.startsWith("rihal-") && f.endsWith(".md"));
|
|
16278
|
+
const projectHasRihal = fs2.existsSync(projectClaudeCommands) && fs2.readdirSync(projectClaudeCommands).some((f) => f.startsWith("rihal-") && f.endsWith(".md"));
|
|
16279
|
+
if (globalHasRihal && !projectHasRihal) {
|
|
16280
|
+
const before = plan.length;
|
|
16281
|
+
const filtered = plan.filter((e) => {
|
|
16282
|
+
const rel = e.rel.split(path2.sep).join("/");
|
|
16283
|
+
return !rel.startsWith(".claude/commands/") && !rel.startsWith(".claude/agents/");
|
|
16284
|
+
});
|
|
16285
|
+
if (filtered.length < before) {
|
|
16286
|
+
plan.length = 0;
|
|
16287
|
+
filtered.forEach((e) => plan.push(e));
|
|
16288
|
+
console.log(" " + dim("Global rihal commands detected in ~/.claude/ \u2014 skipping project-level agent/command install to avoid duplicates."));
|
|
16289
|
+
console.log(" " + dim("Use --force-overwrite to install locally anyway."));
|
|
16290
|
+
}
|
|
16291
|
+
} else if (globalHasRihal && projectHasRihal) {
|
|
16292
|
+
try {
|
|
16293
|
+
const projectCommandFiles = fs2.readdirSync(projectClaudeCommands).filter((f) => f.startsWith("rihal-") && f.endsWith(".md"));
|
|
16294
|
+
for (const f of projectCommandFiles) {
|
|
16295
|
+
fs2.unlinkSync(path2.join(projectClaudeCommands, f));
|
|
16296
|
+
}
|
|
16297
|
+
const projectAgentsDir = path2.join(opts.target, ".claude", "agents");
|
|
16298
|
+
if (fs2.existsSync(projectAgentsDir)) {
|
|
16299
|
+
const agentFiles = fs2.readdirSync(projectAgentsDir).filter((f) => f.startsWith("rihal-") && f.endsWith(".md"));
|
|
16300
|
+
for (const f of agentFiles) {
|
|
16301
|
+
fs2.unlinkSync(path2.join(projectAgentsDir, f));
|
|
16302
|
+
}
|
|
16303
|
+
}
|
|
16304
|
+
console.log(" " + dim("Removed duplicate project-level rihal commands (global ones in ~/.claude/ take precedence)."));
|
|
16305
|
+
} catch {
|
|
16306
|
+
}
|
|
16307
|
+
const filtered = plan.filter((e) => {
|
|
16308
|
+
const rel = e.rel.split(path2.sep).join("/");
|
|
16309
|
+
return !rel.startsWith(".claude/commands/") && !rel.startsWith(".claude/agents/");
|
|
16310
|
+
});
|
|
16311
|
+
plan.length = 0;
|
|
16312
|
+
filtered.forEach((e) => plan.push(e));
|
|
16313
|
+
}
|
|
16314
|
+
} catch {
|
|
16315
|
+
}
|
|
16316
|
+
}
|
|
16272
16317
|
const configDir = path2.join(opts.target, ".rihal", "_config");
|
|
16273
16318
|
ensureDir(configDir);
|
|
16274
16319
|
fs2.writeFileSync(path2.join(configDir, "manifest.yaml"), generateInstallManifest(opts));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.15",
|
|
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": {
|