@hanzlaa/rcode 3.4.6 → 3.4.8

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
@@ -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({
@@ -1654,6 +1665,27 @@ async function install(opts) {
1654
1665
  console.log('');
1655
1666
  }
1656
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
+
1657
1689
  // Write .rihal/_config/manifest.yaml + agent-manifest.csv + files-manifest.csv
1658
1690
  const configDir = path.join(opts.target, '.rihal', '_config');
1659
1691
  ensureDir(configDir);
@@ -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
+ }
package/dist/rcode.js CHANGED
@@ -15020,7 +15020,13 @@ var require_install = __commonJS({
15020
15020
  noBackup: false,
15021
15021
  // #199 — git pre-commit hook. null = install if .git/ present (default).
15022
15022
  // Set false by --no-git-hooks, true by --git-hooks.
15023
- gitHooks: null
15023
+ gitHooks: null,
15024
+ // global install mode — targets ~/.claude/, skips per-project artifacts
15025
+ global: false,
15026
+ // silent — suppress non-error output (used by postinstall auto-run)
15027
+ silent: false,
15028
+ // noPrompt — skip all interactive prompts (used by postinstall auto-run)
15029
+ noPrompt: false
15024
15030
  };
15025
15031
  const positional = [];
15026
15032
  for (let i = 0; i < argv.length; i++) {
@@ -15048,6 +15054,9 @@ var require_install = __commonJS({
15048
15054
  else if (arg === "--no-backup") opts.noBackup = true;
15049
15055
  else if (arg === "--no-git-hooks") opts.gitHooks = false;
15050
15056
  else if (arg === "--git-hooks") opts.gitHooks = true;
15057
+ else if (arg === "--global") opts.global = true;
15058
+ else if (arg === "--silent") opts.silent = true;
15059
+ else if (arg === "--no-prompt") opts.noPrompt = true;
15051
15060
  else if (!arg.startsWith("--")) positional.push(arg);
15052
15061
  }
15053
15062
  if (positional[0]) {
@@ -15146,6 +15155,7 @@ var require_install = __commonJS({
15146
15155
  }
15147
15156
  async function resolveIde(opts) {
15148
15157
  if (opts.ideProvided) return [opts.ide];
15158
+ if (opts.noPrompt || opts.global) return ["claude"];
15149
15159
  if (opts.yes || !process.stdin.isTTY) {
15150
15160
  const signals2 = detectIdeSignals(opts.target);
15151
15161
  const detected2 = ["claude", "cursor", "gemini", "vscode", "antigravity"].filter((k) => signals2[k]);
@@ -15174,6 +15184,7 @@ var require_install = __commonJS({
15174
15184
  }
15175
15185
  async function resolveCommitPlanning(opts) {
15176
15186
  if (opts.commitPlanning !== null) return opts.commitPlanning;
15187
+ if (opts.noPrompt || opts.global) return false;
15177
15188
  if (opts.yes || !process.stdin.isTTY) return true;
15178
15189
  const choice = await clack.select({
15179
15190
  message: "\u{1F4CB} .planning/ holds PRDs, roadmaps, sprints, SUMMARY files. How should they be tracked?",
@@ -16213,6 +16224,22 @@ ${BLOCK}`);
16213
16224
  }
16214
16225
  console.log("");
16215
16226
  }
16227
+ if (opts.global) {
16228
+ const configDir2 = path2.join(opts.target, ".rihal", "_config");
16229
+ ensureDir(configDir2);
16230
+ fs2.writeFileSync(path2.join(configDir2, "manifest.yaml"), generateInstallManifest(opts));
16231
+ let skillsInstalled2 = installSkills(PACKAGE_ROOT2, opts.target);
16232
+ try {
16233
+ const { main: generateCommandSkills } = require(path2.join(PACKAGE_ROOT2, "cli", "generate-command-skills.cjs"));
16234
+ const stubsDir = path2.join(opts.target, ".claude", "skills");
16235
+ const result = generateCommandSkills(PACKAGE_ROOT2, stubsDir, readPackageVersion());
16236
+ skillsInstalled2 += result.generated;
16237
+ } catch {
16238
+ }
16239
+ console.log("");
16240
+ console.log(` ${dim(`${skillsInstalled2} skills installed globally`)}`);
16241
+ return 0;
16242
+ }
16216
16243
  const configDir = path2.join(opts.target, ".rihal", "_config");
16217
16244
  ensureDir(configDir);
16218
16245
  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.6",
3
+ "version": "3.4.8",
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": {
@@ -6,6 +6,26 @@ After completing a task's implementation, follow this protocol to atomically com
6
6
 
7
7
  ---
8
8
 
9
+ ## Step 0: Detect Project Commit Standard (Run Once Per Sprint)
10
+
11
+ Before writing any commit messages, read the project's commit standard from source — do NOT invent one or ask the user unless nothing is found.
12
+
13
+ **Check in this order (stop at first hit):**
14
+
15
+ 1. `.github/COMMIT_CONVENTION.md` — explicit commit format doc
16
+ 2. `CONTRIBUTING.md` — look for a "Commit" or "Git" section
17
+ 3. `.commitlintrc`, `.commitlintrc.json`, `.commitlintrc.yaml`, `commitlint.config.js`, `commitlint.config.cjs` — commitlint config
18
+ 4. `package.json` → `"commitlint"` key
19
+ 5. `.github/pull_request_template.md` — PR template reveals expected format (e.g., ticket prefix, changelog format)
20
+
21
+ **If a standard is found:** Use it silently for all commits in this sprint. No need to confirm with user.
22
+
23
+ **If nothing is found:** Default to Conventional Commits (`type(scope): subject`). Mention the format once in your sprint opening summary — do not ask the user to choose.
24
+
25
+ **Never ask the user "what commit format do you want?"** — that's noise. Read first, decide, proceed.
26
+
27
+ ---
28
+
9
29
  ## Step 1: Check Git Status
10
30
  ```bash
11
31
  git status --short
@@ -62,14 +82,16 @@ Match the change to a conventional commit type:
62
82
 
63
83
  ## Step 4: Choose Scope
64
84
 
65
- Scope is the area affected, in parentheses:
85
+ Scope is the **subsystem or domain** affected, in parentheses — NOT the phase/sprint number.
66
86
 
67
87
  - `feat(auth)` - authentication feature
68
88
  - `fix(payments)` - payments bug fix
69
89
  - `test(api)` - API tests
70
90
  - `refactor(ui)` - UI code cleanup
71
91
 
72
- Scope should match the PLAN task name or subsystem.
92
+ **NEVER use a phase or sprint number as the scope.** `fix(114):` or `feat(114-03):` are wrong.
93
+ Use the name of the subsystem the task touches (e.g., `sequence-builder`, `auth`, `dashboard`, `api`).
94
+ If no obvious subsystem exists, omit the scope: `fix: correct delay type in email templates`.
73
95
 
74
96
  ---
75
97
 
@@ -210,6 +232,8 @@ Bad:
210
232
  feat(auth): Adds JWT refresh tokens.
211
233
  fix: I fixed the payment thing
212
234
  Updated auth code
235
+ fix(114): correct delay type ← phase number as scope — WRONG
236
+ feat(114-03): add drag-and-drop ← sprint ID as scope — WRONG
213
237
  ```
214
238
 
215
239
  ---
@@ -0,0 +1,104 @@
1
+ # Auto-Init Guard
2
+
3
+ Run this check at the very start of any workflow that needs project state.
4
+
5
+ ## Step: Detect project initialization
6
+
7
+ ```bash
8
+ test -f .rihal/config.yaml && echo "rihal-ready" || echo "rihal-not-initialized"
9
+ ```
10
+
11
+ **If `rihal-ready`:** continue with the workflow normally.
12
+
13
+ **If `rihal-not-initialized`:** the user has never set up Rihal for this project. Do NOT fail or continue blindly. Run the project init flow inline before proceeding:
14
+
15
+ ---
16
+
17
+ ### Inline init flow (when config.yaml is missing)
18
+
19
+ Tell the user:
20
+
21
+ ```
22
+ Rihal isn't configured for this project yet. Let me set it up — takes 30 seconds.
23
+ ```
24
+
25
+ **1. Bootstrap local tooling** — copy bin and workflows from the global install:
26
+
27
+ ```bash
28
+ GLOBAL_RIHAL="$HOME/.rihal"
29
+ if [ -d "$GLOBAL_RIHAL/bin" ]; then
30
+ mkdir -p .rihal/bin .rihal/workflows .rihal/references
31
+ cp "$GLOBAL_RIHAL/bin/rihal-tools.cjs" .rihal/bin/ 2>/dev/null || true
32
+ # workflows and references are read from ~/.rihal at runtime via @.rihal/ resolution
33
+ fi
34
+ ```
35
+
36
+ **2. Ask the 5 config questions** using AskUserQuestion:
37
+
38
+ | # | Question | Options | Default |
39
+ |---|----------|---------|---------|
40
+ | 1 | Your name (what Rihal calls you) | free text | `$USER` |
41
+ | 2 | Language for agent responses | English / Arabic / Urdu / Roman Urdu | English |
42
+ | 3 | Mode (how Rihal handles decision gates) | `guided` / `yolo` | guided |
43
+ | 4 | Model profile (cost vs quality) | `quality` / `balanced` / `budget` | balanced |
44
+ | 5 | Commit planning artifacts to git? | yes / no | yes |
45
+
46
+ **3. Write `.rihal/config.yaml` directly** (no rihal-tools needed — plain Bash):
47
+
48
+ ```bash
49
+ mkdir -p .rihal
50
+ cat > .rihal/config.yaml << 'YAML'
51
+ # Rihal project config — edit any time
52
+ user_name: "{name}"
53
+ project_name: "{basename_of_cwd}"
54
+ communication_language: "{lang}"
55
+ mode: "{mode}"
56
+ model_profile: "{profile}"
57
+ commit_planning: {commit_planning_bool}
58
+ rihal_source_path: ""
59
+ workflow:
60
+ research_by_default: false
61
+ plan_checker: true
62
+ post_execute_gates: true
63
+ ui_safety_gate: true
64
+ git:
65
+ branching_strategy: "none"
66
+ YAML
67
+ ```
68
+
69
+ **4. Seed `.rihal/state.json` and `.planning/` structure**:
70
+
71
+ ```bash
72
+ mkdir -p .planning/phases .planning/council-sessions .rihal/context
73
+
74
+ # state.json
75
+ cat > .rihal/state.json << 'JSON'
76
+ {"project":"{project_name}","phase":null,"sprint":null,"sessions":[],"initialized":"now"}
77
+ JSON
78
+
79
+ # context stubs
80
+ echo "# Active Context\n\n_Run /rihal-init for full setup._" > .rihal/context/active.md
81
+ echo "# Project Brief\n\n_Run /rihal-init for full setup._" > .rihal/context/project-brief.md
82
+ ```
83
+
84
+ **5. Tell the user:**
85
+
86
+ ```
87
+ ✓ Rihal configured for this project.
88
+
89
+ Config saved to .rihal/config.yaml — edit any time.
90
+ Run /rihal-init for a full project scan and context setup.
91
+
92
+ Continuing with your original request...
93
+ ```
94
+
95
+ **6. Continue** with the original workflow as if it had been initialized from the start.
96
+
97
+ ---
98
+
99
+ ## Notes
100
+
101
+ - This guard is **non-blocking** — it asks questions but does not stop the session; once config is written it resumes the original request automatically.
102
+ - If `AskUserQuestion` is unavailable (non-interactive mode), use all defaults and skip the questions.
103
+ - If the bootstrap `cp` fails (global rihal not found), print a warning and attempt to continue — some workflows work without local rihal-tools if they only need config.
104
+ - On **subsequent runs**, the guard exits immediately (config exists) with zero overhead.
@@ -28,6 +28,7 @@ Closure: `RIHAL ► COUNCIL COMPLETE ✓` + Next Up with decision options.
28
28
  </output_format>
29
29
 
30
30
  <required_reading>
31
+ @.rihal/references/auto-init-guard.md
31
32
  @.rihal/references/output-format.md
32
33
  @.rihal/references/council-protocol.md
33
34
  </required_reading>
@@ -3,6 +3,7 @@ Analyze freeform text from the user and route to the most appropriate Rihal comm
3
3
  </purpose>
4
4
 
5
5
  <required_reading>
6
+ @.rihal/references/auto-init-guard.md
6
7
  @.rihal/references/output-format.md
7
8
  @.rihal/references/verb-dictionary.md
8
9
  @.rihal/references/dispatch-banner.md
@@ -11,6 +12,11 @@ Read all files referenced by the invoking prompt's execution_context before star
11
12
 
12
13
  <process>
13
14
 
15
+ <step name="auto_init_check">
16
+ Run the auto-init guard from `@.rihal/references/auto-init-guard.md` before anything else.
17
+ If the project is not initialized, complete the inline init flow, then continue.
18
+ </step>
19
+
14
20
  <step name="parse_args">
15
21
  Extract `$ARGUMENTS`, detect `--auto` flag, and check config mode:
16
22
 
@@ -143,6 +143,7 @@ via filesystem and git state.
143
143
  </runtime_compatibility>
144
144
 
145
145
  <required_reading>
146
+ @.rihal/references/auto-init-guard.md
146
147
  @.rihal/references/output-format.md
147
148
  Read STATE.md before any operation to load project context.
148
149
 
@@ -1,9 +1,9 @@
1
1
  # Workflow: rihal-init
2
2
 
3
3
  <purpose>
4
- Begin the rihla. This is the first command a user runs after dropping Rihal files into a project. It detects project state, asks a handful of configuration questions, scans existing context (if any), writes `.rihal/RIHLA.md` as the journey baseline, and routes to the right next command.
4
+ Begin the rihla. This is the entry point for configuring Rihal in a project. Runs automatically on first use of any rihal command (via auto-init-guard in do.md), or explicitly via /rihal-init for a full setup with codebase scan.
5
5
 
6
- This replaces the older `/rihal-generate-project-context` workflow init is the single entry point for configuring Rihal in a project.
6
+ No manual "rcode install" needed per project — just use any /rihal-* command and this triggers automatically when config is missing.
7
7
  </purpose>
8
8
 
9
9
  ## Step 0 — Usage check
@@ -4,6 +4,7 @@ Initialize a new project through unified flow: questioning, research (optional),
4
4
  </purpose>
5
5
 
6
6
  <required_reading>
7
+ @.rihal/references/auto-init-guard.md
7
8
  @.rihal/references/output-format.md
8
9
 
9
10
  Read all files referenced by the invoking prompt's execution_context before starting.
@@ -41,6 +41,7 @@ End with Next Up routing to /rihal-execute.
41
41
  </output_format>
42
42
 
43
43
  <required_reading>
44
+ @.rihal/references/auto-init-guard.md
44
45
  @.rihal/references/output-format.md
45
46
  Read all files referenced by the invoking prompt's execution_context before starting.
46
47
 
@@ -7,6 +7,7 @@ Render a human-readable project status dashboard. All data comes from a single `
7
7
  </purpose>
8
8
 
9
9
  <required_reading>
10
+ @.rihal/references/auto-init-guard.md
10
11
  @.rihal/references/output-format.md
11
12
  </required_reading>
12
13