@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 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.14",
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": {