@hanzlaa/rcode 3.4.5 → 3.4.7

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.
@@ -32,11 +32,23 @@ const path = require('path');
32
32
  * lifecycle verbs. Internal sub-commands stay slash-only.
33
33
  */
34
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',
35
+ // Navigation & status
36
+ 'do', 'status', 'progress', 'next', 'health',
37
+ // Core planning & execution
38
+ 'plan', 'execute', 'add-phase', 'discuss-phase', 'complete-milestone',
39
+ 'plan-milestone-gaps', 'autonomous',
40
+ // Project setup
39
41
  'new-project', 'new-milestone', 'milestone-summary',
42
+ // Sprint workflow
43
+ 'sprint-planning', 'sprint-status', 'execute-sprint', 'dev-story',
44
+ 'create-story', 'create-epics-and-stories',
45
+ // Discussion & council
46
+ 'council', 'discuss', 'prfaq',
47
+ // Quality & review
48
+ 'ship', 'audit', 'verify-phase', 'verify-work', 'review', 'code-review',
49
+ 'feature-drift', 'ui-phase', 'ui-review',
50
+ // Utility
51
+ 'debug', 'session-report', 'forensics', 'map-codebase', 'quick',
40
52
  'note', 'add-todo', 'check-todos', 'pause-work', 'resume-work',
41
53
  ]);
42
54
 
package/cli/install.js CHANGED
@@ -137,6 +137,12 @@ function parseArgs(argv) {
137
137
  // #199 — git pre-commit hook. null = install if .git/ present (default).
138
138
  // Set false by --no-git-hooks, true by --git-hooks.
139
139
  gitHooks: null,
140
+ // global install mode — targets ~/.claude/, skips per-project artifacts
141
+ global: false,
142
+ // silent — suppress non-error output (used by postinstall auto-run)
143
+ silent: false,
144
+ // noPrompt — skip all interactive prompts (used by postinstall auto-run)
145
+ noPrompt: false,
140
146
  };
141
147
  const positional = [];
142
148
  for (let i = 0; i < argv.length; i++) {
@@ -162,6 +168,9 @@ function parseArgs(argv) {
162
168
  else if (arg === '--no-backup') opts.noBackup = true; // #381
163
169
  else if (arg === '--no-git-hooks') opts.gitHooks = false; // #199
164
170
  else if (arg === '--git-hooks') opts.gitHooks = true; // #199
171
+ else if (arg === '--global') opts.global = true;
172
+ else if (arg === '--silent') opts.silent = true;
173
+ else if (arg === '--no-prompt') opts.noPrompt = true;
165
174
  else if (!arg.startsWith('--')) positional.push(arg);
166
175
  }
167
176
  if (positional[0]) {
@@ -305,6 +314,7 @@ function detectIdeSignals(target) {
305
314
  */
306
315
  async function resolveIde(opts) {
307
316
  if (opts.ideProvided) return [opts.ide]; // user passed --ide, respect it
317
+ if (opts.noPrompt || opts.global) return ['claude']; // auto-install: always claude
308
318
  if (opts.yes || !process.stdin.isTTY) {
309
319
  // #182 — non-interactive mode: install into every detected IDE, not just
310
320
  // the default claude. The interactive flow already preselects detected
@@ -352,6 +362,7 @@ async function resolveIde(opts) {
352
362
  */
353
363
  async function resolveCommitPlanning(opts) {
354
364
  if (opts.commitPlanning !== null) return opts.commitPlanning;
365
+ if (opts.noPrompt || opts.global) return false; // global install: no planning artifacts
355
366
  if (opts.yes || !process.stdin.isTTY) return true; // non-interactive default
356
367
 
357
368
  const choice = await clack.select({
@@ -408,7 +419,7 @@ function getPathsForIde(ide, target) {
408
419
  case 'claude':
409
420
  return {
410
421
  agentsDir: path.join(target, '.claude', 'agents'),
411
- commandsDir: path.join(target, '.claude', 'commands', 'rihal'),
422
+ commandsDir: path.join(target, '.claude', 'commands'),
412
423
  workflowsDir: path.join(target, '.rihal', 'workflows'),
413
424
  referencesDir: path.join(target, '.rihal', 'references'),
414
425
  binDir: path.join(target, '.rihal', 'bin'),
@@ -971,10 +982,15 @@ function buildInstallPlan(ide = 'claude', target = process.cwd()) {
971
982
  }
972
983
 
973
984
  // Commands — IDE-specific
985
+ // Claude: output as .claude/commands/rihal-{name}.md (hyphen namespace → /rihal-name)
986
+ // Cursor/Gemini: keep original flat name inside their rihal/ subdirectory
974
987
  for (const f of walkFiles(path.join(SOURCE_ROOT, 'commands'))) {
975
988
  const rel = path.relative(path.join(SOURCE_ROOT, 'commands'), f);
976
989
  const ext = ide === 'cursor' ? '.mdc' : '.md';
977
- const outName = path.basename(f, '.md') + ext;
990
+ const baseName = path.basename(f, '.md');
991
+ const outName = ide === 'claude'
992
+ ? `rihal-${baseName}${ext}`
993
+ : baseName + ext;
978
994
  plan.push({ src: f, rel: path.join(relCommands, path.dirname(rel), outName), ide, cursor: ide === 'cursor' });
979
995
  }
980
996
 
@@ -1050,7 +1066,7 @@ function filterPlanByModules(plan, moduleNames) {
1050
1066
  if (!mod) { console.warn(` ⚠ Unknown module: ${modName}`); continue; }
1051
1067
  for (const a of mod.agents) allowed.add(path.join('.claude', 'agents', a));
1052
1068
  for (const w of mod.workflows) allowed.add(path.join('.rihal', 'workflows', w));
1053
- for (const c of mod.commands) allowed.add(path.join('.claude', 'commands', 'rihal', c));
1069
+ for (const c of mod.commands) allowed.add(path.join('.claude', 'commands', `rihal-${c}`));
1054
1070
  for (const r of mod.references) allowed.add(path.join('.rihal', 'references', r));
1055
1071
  }
1056
1072
  // Always include bin/ (shared infrastructure, not module-specific)
@@ -1649,6 +1665,27 @@ async function install(opts) {
1649
1665
  console.log('');
1650
1666
  }
1651
1667
 
1668
+ // In global install mode (~/.claude/), skip per-project artifacts — those are
1669
+ // created by `rcode install` inside each project directory at project-init time.
1670
+ // Global install only ships the read-only tooling: commands, skills, workflows, bin.
1671
+ if (opts.global) {
1672
+ // Still write the manifest so the global install is traceable/upgradeable
1673
+ const configDir = path.join(opts.target, '.rihal', '_config');
1674
+ ensureDir(configDir);
1675
+ fs.writeFileSync(path.join(configDir, 'manifest.yaml'), generateInstallManifest(opts));
1676
+ // Install skills + sidebar stubs globally
1677
+ let skillsInstalled = installSkills(PACKAGE_ROOT, opts.target);
1678
+ try {
1679
+ const { main: generateCommandSkills } = require(path.join(PACKAGE_ROOT, 'cli', 'generate-command-skills.cjs'));
1680
+ const stubsDir = path.join(opts.target, '.claude', 'skills');
1681
+ const result = generateCommandSkills(PACKAGE_ROOT, stubsDir, readPackageVersion());
1682
+ skillsInstalled += result.generated;
1683
+ } catch { /* non-fatal */ }
1684
+ console.log('');
1685
+ console.log(` ${dim(`${skillsInstalled} skills installed globally`)}`);
1686
+ return 0;
1687
+ }
1688
+
1652
1689
  // Write .rihal/_config/manifest.yaml + agent-manifest.csv + files-manifest.csv
1653
1690
  const configDir = path.join(opts.target, '.rihal', '_config');
1654
1691
  ensureDir(configDir);
@@ -1858,7 +1895,12 @@ async function install(opts) {
1858
1895
  agentCount = fs.readdirSync(agentsDir).filter(f => (f.startsWith('rihal-') || f.startsWith('rcode-')) && (f.endsWith('.md') || f.endsWith('.mdc'))).length;
1859
1896
  }
1860
1897
  if (fs.existsSync(commandsDir)) {
1861
- commandCount = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md') || f.endsWith('.mdc')).length;
1898
+ commandCount = fs.readdirSync(commandsDir).filter(f => f.startsWith('rihal-') && (f.endsWith('.md') || f.endsWith('.mdc'))).length;
1899
+ }
1900
+ // Clean up legacy .claude/commands/rihal/ colon-namespace directory if it exists
1901
+ const legacyColonDir = path.join(opts.target, '.claude', 'commands', 'rihal');
1902
+ if (primaryIde === 'claude' && fs.existsSync(legacyColonDir)) {
1903
+ fs.rmSync(legacyColonDir, { recursive: true, force: true });
1862
1904
  }
1863
1905
  } catch {}
1864
1906
 
@@ -1,18 +1,78 @@
1
1
  /**
2
- * rihal-code postinstall hook — runs automatically after `npm install`
2
+ * rihal-code postinstall hook — runs automatically after `npm install -g`
3
+ *
4
+ * Auto-installs commands, skills, workflows, and bin tools into the global
5
+ * Claude Code directory (~/.claude/) so every project can use rihal immediately
6
+ * without needing a per-project `rcode install` run.
7
+ *
8
+ * Artifacts (.planning/, STATE.md, ROADMAP.md) are always created in the
9
+ * project CWD at runtime — the global install only ships read-only tooling.
3
10
  */
4
11
 
5
- // Only print the welcome if not running in CI/test environments
12
+ 'use strict';
13
+ const os = require('os');
14
+ const path = require('path');
15
+
16
+ // Skip in CI or test environments
6
17
  if (process.env.CI || process.env.NODE_ENV === 'test') {
7
18
  process.exit(0);
8
19
  }
9
20
 
10
- console.log(`
21
+ // Only auto-install when invoked as a global package (npm install -g).
22
+ // A local devDependency install should not touch the user's ~/.claude/.
23
+ const isGlobalInstall = (() => {
24
+ try {
25
+ // npm sets npm_config_global=true for global installs
26
+ if (process.env.npm_config_global === 'true') return true;
27
+ // Fallback: check if the install prefix is a global npm prefix
28
+ const prefix = process.env.npm_config_prefix || '';
29
+ const home = os.homedir();
30
+ if (prefix && !prefix.startsWith(home) && !prefix.includes('node_modules')) return true;
31
+ return false;
32
+ } catch {
33
+ return false;
34
+ }
35
+ })();
36
+
37
+ const globalTarget = path.join(os.homedir(), '.claude');
38
+
39
+ if (isGlobalInstall) {
40
+ // Run the global install in the background so npm output isn't blocked
41
+ const { install } = require('./install.js');
42
+ install({
43
+ target: globalTarget,
44
+ ides: ['claude'],
45
+ ide: 'claude',
46
+ yes: true,
47
+ noPrompt: true,
48
+ commitPlanning: false,
49
+ global: true, // signal: skip per-project artifacts (STATE.md, ROADMAP.md, .planning/)
50
+ silent: false,
51
+ }).then((code) => {
52
+ if (code === 0) {
53
+ console.log(`\n✓ Rihal commands + skills installed globally → ${globalTarget}`);
54
+ console.log(' All /rihal-* commands are now available in every project.\n');
55
+ } else {
56
+ console.warn(`\n⚠ Global auto-install exited with code ${code}. Run 'rcode install' manually if needed.\n`);
57
+ }
58
+ printWelcome();
59
+ }).catch((err) => {
60
+ console.warn(`\n⚠ Global auto-install failed: ${err.message}`);
61
+ console.warn(' Run "rcode install" manually to set up rihal commands.\n');
62
+ printWelcome();
63
+ });
64
+ } else {
65
+ printWelcome();
66
+ }
67
+
68
+ function printWelcome() {
69
+ console.log(`
11
70
  🕌 Rihal Code installed.
12
71
 
13
- First-time setup:
14
- rcode install # set up agents + slash commands
15
- rcode tiers # see the tier map
72
+ Commands are available globally in every Claude Code project.
73
+ To set up per-project state + planning structure, run inside your project:
74
+
75
+ rcode install # creates .rihal/config.yaml, .planning/, STATE.md
16
76
 
17
77
  🌱 The Golden Path (say these phrases in your AI IDE):
18
78
  1. "scaffold a new project" → rihal-scaffold-project
@@ -28,5 +88,5 @@ More:
28
88
  rcode dashboard # view-only Diwan on :7717
29
89
 
30
90
  Docs: https://github.com/hanzlahabib/rihal-code
31
- Tiers: docs/TIERS.md · Standards: docs/STANDARDS.md
32
91
  `);
92
+ }