@hanzlaa/rcode 3.4.26 → 3.4.28

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/AGENTS.md CHANGED
@@ -24,7 +24,7 @@ If a user says "just keep going" or "don't stop until done", that authorization
24
24
 
25
25
  - Follow [Conventional Commits](https://www.conventionalcommits.org/) format: `type(scope): subject`
26
26
  - Types allowed: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`, `perf`, `revert`
27
- - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`, `commands`, `memory`, `brand`, `cli`, `ci`, `release`, `meta`, `tasks`, `migrations`, `refs`, `state`, `hooks`, `install`, `parity`, `triggers`, `dogfood`, `namespace`, `planning`, `insights`, `help`, `roadmap`, `session`, `audits`, `execute`, `executor`, `plan`, `planner`, `readme`, `sync`, `sprint`, `agent-exp`, `extensibility`, `lens-audit`, `tiers`, plus numeric phase/sprint scopes (e.g. `docs(15)`, `feat(8.3)`)
27
+ - Scopes allowed: `agents`, `skills`, `workflows`, `templates`, `dashboard`, `docs`, `config`, `github`, `commands`, `memory`, `brand`, `cli`, `ci`, `release`, `meta`, `tasks`, `migrations`, `refs`, `state`, `hooks`, `install`, `parity`, `triggers`, `dogfood`, `namespace`, `planning`, `insights`, `help`, `roadmap`, `session`, `audits`, `execute`, `executor`, `plan`, `planner`, `readme`, `sync`, `sprint`, `agent-exp`, `extensibility`, `lens-audit`, `tiers`, `build`, `council`, `doctor`, `postinstall`, `progress`, `security`, `tools`, `uninstall`, `test`, plus numeric phase/sprint scopes (e.g. `docs(15)`, `feat(8.3)`)
28
28
  - Subject: lowercase first letter, imperative mood, no trailing period, under 72 chars
29
29
  - **NEVER add Claude/AI attribution to commit messages.** No "Generated with Claude Code", no "Co-Authored-By: Claude", no "🤖 Generated". The user does not want this.
30
30
  - **NEVER use `--no-verify`** to bypass hooks. If hooks fail, fix the underlying issue.
package/CONTRIBUTING.md CHANGED
@@ -298,6 +298,15 @@ We use [Conventional Commits](https://www.conventionalcommits.org/) format. The
298
298
  - `extensibility` — extensibility and plugin hooks
299
299
  - `lens-audit` — 15-lens audit system and lenses
300
300
  - `tiers` — TIERS.md and tier-related documentation
301
+ - `build` — `scripts/build.cjs`, esbuild config, bundle artifacts
302
+ - `council` — `/rihal-council` workflow + spawning logic
303
+ - `doctor` — `cli/doctor.js` health checks
304
+ - `postinstall` — `cli/postinstall.js` lifecycle hook
305
+ - `progress` — `/rihal-progress` workflow
306
+ - `security` — security guardrails (symlink guards, integrity checks)
307
+ - `test` — test files under `test/` (test-only changes)
308
+ - `tools` — `rihal/bin/rihal-tools.cjs` subcommands
309
+ - `uninstall` — `cli/uninstall.js` flow
301
310
  - `<phase-id>` — numeric phase scope when committing inside a phase (e.g. `docs(15)`, `feat(8.3)`)
302
311
  - `<sprint-id>` — numeric sprint scope inside a phase (e.g. `feat(15.1)`)
303
312
 
package/cli/install.js CHANGED
@@ -79,6 +79,18 @@ const bold = (s) => pc.bold(s);
79
79
  const PACKAGE_ROOT = path.resolve(__dirname, '..');
80
80
  const SOURCE_ROOT = path.join(PACKAGE_ROOT, 'rihal');
81
81
 
82
+ /**
83
+ * Single source of truth for supported IDEs (#697 — W4.3).
84
+ *
85
+ * Order matters: this is the order used in detection, prompts, and error
86
+ * messages. Anywhere code used to inline `['claude','cursor','gemini',
87
+ * 'vscode','antigravity']` it now references this constant. Adding a new
88
+ * IDE is now: append here, add a case to getPathsForIde, add a signal to
89
+ * detectIdeSignals, plus a row to runInstallWizard's multiselect — three
90
+ * sites instead of ten.
91
+ */
92
+ const SUPPORTED_IDES = Object.freeze(['claude', 'cursor', 'gemini', 'vscode', 'antigravity']);
93
+
82
94
  // Zod schema for .rihal/config.yaml validation (#250).
83
95
  const ConfigSchema = z.object({
84
96
  user_name: z.string().min(1),
@@ -338,12 +350,16 @@ async function resolveIde(opts) {
338
350
  // nothing detected. (Note: opts.ide defaults to 'claude' from parseArgs,
339
351
  // so check opts.ideProvided not opts.ide to honor real --ide overrides.)
340
352
  const signals = detectIdeSignals(opts.target);
341
- const detected = ['claude', 'cursor', 'gemini', 'vscode', 'antigravity'].filter(k => signals[k]);
353
+ const detected = SUPPORTED_IDES.filter(k => signals[k]);
342
354
  return detected.length > 0 ? detected : ['claude'];
343
355
  }
344
356
 
345
357
  const signals = detectIdeSignals(opts.target);
346
- const detected = ['claude', 'cursor', 'gemini', 'vscode'].filter(k => signals[k]);
358
+ // Antigravity is intentionally excluded from the interactive auto-detect
359
+ // because it's experimental and we don't want to opt-in users without
360
+ // explicit consent. Use SUPPORTED_IDES.filter(k => k !== 'antigravity')
361
+ // to keep the inclusion criteria self-documenting.
362
+ const detected = SUPPORTED_IDES.filter(k => k !== 'antigravity' && signals[k]);
347
363
 
348
364
  // Pre-select detected IDEs, or default to claude
349
365
  const initialValues = detected.length > 0 ? detected : ['claude'];
@@ -1613,7 +1629,7 @@ async function installInner(opts) {
1613
1629
  }
1614
1630
 
1615
1631
  // Validate IDE(s) — structured error for unsupported editors (#197).
1616
- const SUPPORTED_IDES = ['claude', 'cursor', 'gemini', 'vscode', 'antigravity'];
1632
+ // SUPPORTED_IDES is the module-level constant (#697 / W4.3).
1617
1633
  const unsupported = opts.ides.filter(ide => !SUPPORTED_IDES.includes(ide));
1618
1634
  if (unsupported.length > 0) {
1619
1635
  console.error(`✖ --ide ${unsupported.join(', ')} is not supported in v${readPackageVersion()}.`);
@@ -2597,3 +2613,4 @@ module.exports = runFromCli;
2597
2613
  module.exports.parseArgs = parseArgs;
2598
2614
  module.exports.buildInstallPlan = buildInstallPlan;
2599
2615
  module.exports.install = install;
2616
+ module.exports.SUPPORTED_IDES = SUPPORTED_IDES;
@@ -109,7 +109,12 @@ function diffSet(editor, kind, expected, installed) {
109
109
  * makes doctor report drift like "agents 119/23" when nothing is wrong.
110
110
  * That's why the agent count comes from .claude/agents/, not .claude/skills/.
111
111
  */
112
- function verifyClaudeInstall(cwd, packageRoot) {
112
+ function verifyClaudeInstall(cwd, packageRoot, options = {}) {
113
+ // Issue #698: tests assert against an isolated tempdir cwd. The global
114
+ // fallback (#664) makes that impossible because it reads the contributor's
115
+ // real ~/.claude/. Tests can pass { globalFallback: false } to disable it.
116
+ // Default remains true to preserve the runtime behavior introduced in #664.
117
+ const globalFallback = options.globalFallback !== false;
113
118
  const pkg = readPackageManifest(packageRoot);
114
119
  const agentsDir = path.join(cwd, '.claude/agents');
115
120
  const skillsDir = path.join(cwd, '.claude/skills');
@@ -129,7 +134,7 @@ function verifyClaudeInstall(cwd, packageRoot) {
129
134
  // level .claude/agents/rihal-*.md when the user's ~/.claude/ already has
130
135
  // them, to avoid duplicate commands. Without this fallback the verifier
131
136
  // reports 0 agents on every successful install in that scenario.
132
- if (installedAgents.size === 0) {
137
+ if (installedAgents.size === 0 && globalFallback) {
133
138
  try {
134
139
  const os = require('os');
135
140
  const globalAgentsDir = path.join(os.homedir(), '.claude/agents');
@@ -143,12 +148,13 @@ function verifyClaudeInstall(cwd, packageRoot) {
143
148
  } catch { /* non-fatal — permission errors etc. */ }
144
149
  }
145
150
 
146
- // Actions: .claude/skills/<bare-name>/ exclude rihal-* dirs (those are
147
- // either agent stubs or command stubs, never action skills).
151
+ // Actions: .claude/skills/rihal-<name>/. installSkills (cli/install.js)
152
+ // prefixes every action with rihal-, and readPackageManifest does the
153
+ // same — so both sides are normalized. The previous version filtered OUT
154
+ // rihal-* dirs which excluded ALL real actions and made the diff always
155
+ // report "everything missing." Compare directly against the prefixed set.
148
156
  const allInstalled = readInstalledDirs(skillsDir);
149
- const actionsInstalled = new Set(
150
- [...allInstalled].filter((n) => !n.startsWith('rihal-'))
151
- );
157
+ const actionsInstalled = new Set([...allInstalled].filter((n) => pkg.actions.has(n)));
152
158
 
153
159
  return [
154
160
  diffSet('claude', 'agents', pkg.agents, installedAgents),
@@ -13,42 +13,52 @@
13
13
  const os = require('os');
14
14
  const path = require('path');
15
15
 
16
- // Skip in CI or test environments
17
- if (process.env.CI || process.env.NODE_ENV === 'test') {
18
- process.exit(0);
19
- }
20
-
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 = (() => {
16
+ /**
17
+ * Decide whether the current postinstall invocation represents a GLOBAL
18
+ * `npm install -g @hanzlaa/rcode` (true) or a transitive devDep install
19
+ * inside someone's project (false).
20
+ *
21
+ * Pure function takes its inputs explicitly so tests can drive every
22
+ * branch without needing to mutate process.env / __dirname / process.cwd.
23
+ *
24
+ * @param {object} env process.env-like
25
+ * @param {string} dirname __dirname of the postinstall script
26
+ * @param {string} cwd process.cwd() at invocation time
27
+ */
28
+ function isGlobalInstall(env, dirname, cwd) {
24
29
  try {
25
- // npm sets npm_config_global=true for global installs
26
- if (process.env.npm_config_global === 'true') return true;
27
- // pnpm sets npm_config_global too, but check PNPM_HOME as a fallback
28
- if (process.env.PNPM_HOME && __dirname.startsWith(process.env.PNPM_HOME)) return true;
29
- // Check if __dirname is inside a known global node_modules path.
30
- // Covers: /usr/local/lib, /usr/lib, ~/.nvm/.../lib, ~/.pnpm/..., ~/.yarn/...
30
+ if (env.npm_config_global === 'true') return true;
31
+ if (env.PNPM_HOME && dirname.startsWith(env.PNPM_HOME)) return true;
31
32
  const globalPatterns = [
32
- /\/node_modules\/@hanzlaa\/rcode/, // any global node_modules
33
- /[/\\]lib[/\\]node_modules[/\\]/, // /usr/local/lib/node_modules
34
- /\.nvm[/\\]versions[/\\]/, // nvm
35
- /\.pnpm[/\\]/, // pnpm global store
36
- /\.yarn[/\\]global/, // yarn global
33
+ /\/node_modules\/@hanzlaa\/rcode/,
34
+ /[/\\]lib[/\\]node_modules[/\\]/,
35
+ /\.nvm[/\\]versions[/\\]/,
36
+ /\.pnpm[/\\]/,
37
+ /\.yarn[/\\]global/,
37
38
  ];
38
- if (globalPatterns.some((re) => re.test(__dirname))) return true;
39
- // Last resort: package is NOT inside a project's local node_modules
40
- // (local installs have .../project/node_modules/@hanzlaa/rcode/cli)
41
- const localNodeModules = path.join(process.cwd(), 'node_modules');
42
- if (!__dirname.startsWith(localNodeModules)) return true;
39
+ if (globalPatterns.some((re) => re.test(dirname))) return true;
40
+ const localNodeModules = path.join(cwd, 'node_modules');
41
+ if (!dirname.startsWith(localNodeModules)) return true;
43
42
  return false;
44
43
  } catch {
45
44
  return false;
46
45
  }
47
- })();
46
+ }
47
+
48
+ // Skip in CI or test environments. Tests that import this module bypass
49
+ // the top-level effect by checking require.main !== module.
50
+ if (require.main === module) {
51
+ if (process.env.CI || process.env.NODE_ENV === 'test') {
52
+ process.exit(0);
53
+ }
54
+ runPostInstall();
55
+ }
56
+
57
+ function runPostInstall() {
48
58
 
49
59
  const globalTarget = path.join(os.homedir(), '.claude');
50
60
 
51
- if (isGlobalInstall) {
61
+ if (isGlobalInstall(process.env, __dirname, process.cwd())) {
52
62
  // Spawn dist/rcode.js (fully bundled — no devDep requires) to do the global
53
63
  // install. Calling cli/install.js directly fails in global npm installs because
54
64
  // devDependencies (picocolors, semver, etc.) are not installed for global packages.
@@ -101,3 +111,7 @@ More:
101
111
  Docs: https://github.com/hanzlahabib/rihal-code
102
112
  `);
103
113
  }
114
+
115
+ } // end runPostInstall
116
+
117
+ module.exports = { isGlobalInstall };
package/cli/uninstall.js CHANGED
@@ -68,6 +68,25 @@ function isLocalOverride(name) {
68
68
  return /\.local\.(md|mdc|json|yaml|yml|toml|js|ts)$/.test(name);
69
69
  }
70
70
 
71
+ /**
72
+ * Strip the rcode-managed block from a .gitignore string.
73
+ *
74
+ * Pure function (no fs) so it can be unit-tested independently. Issue #684
75
+ * fixed the over-broad legacy regex; this helper centralises the logic so
76
+ * any future shape change has exactly one site to update.
77
+ *
78
+ * Both supported shapes require BOTH the opener AND the closer to match —
79
+ * user comments starting with "# rcode" are safe.
80
+ */
81
+ function stripRihalGitignoreBlock(text) {
82
+ return text
83
+ // Current shape (install.js BEGIN/END markers — exact match).
84
+ .replace(/\n?# ===== rcode-managed gitignore block[\s\S]*?# ===== end rcode-managed gitignore block =====\n?/g, '\n')
85
+ // Legacy >>> / <<< fenced shape.
86
+ .replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, '\n')
87
+ .replace(/\n{3,}/g, '\n\n');
88
+ }
89
+
71
90
  /**
72
91
  * Walk a directory and remove all files/subdirs whose name matches a predicate.
73
92
  * Returns the number of entries removed. Always skips local overrides (#382).
@@ -419,15 +438,13 @@ async function runUninstall(args) {
419
438
  const opts = parseArgs(args);
420
439
  const cwd = process.cwd();
421
440
 
422
- // Issue #693: keep the IDE list in sync with the installer. The installer
423
- // ships claude/cursor/gemini/vscode/antigravity. The previous uninstaller
424
- // list (claude/cursor/windsurf/antigravity) was missing gemini + vscode
425
- // and included windsurf (which the installer never writes). Result: a
426
- // user with vscode-style commands could never `rcode uninstall`.
427
- const SUPPORTED_EDITORS = ['claude', 'cursor', 'gemini', 'vscode', 'antigravity'];
441
+ // Issue #693 + #697 (W4.3): keep the IDE list in sync with the installer
442
+ // by importing the single source of truth. Adding an IDE to install.js
443
+ // SUPPORTED_IDES is now the only edit needed for parity.
444
+ const { SUPPORTED_IDES } = require('./install.js');
428
445
  const editors = opts.editor
429
- ? (opts.editor === 'all' ? SUPPORTED_EDITORS : [opts.editor])
430
- : SUPPORTED_EDITORS;
446
+ ? (opts.editor === 'all' ? Array.from(SUPPORTED_IDES) : [opts.editor])
447
+ : Array.from(SUPPORTED_IDES);
431
448
 
432
449
  console.log(`\n🕌 Rihal Code — Uninstall\n`);
433
450
  console.log(` Project: ${cwd}`);
@@ -731,12 +748,7 @@ async function runUninstall(args) {
731
748
  if (fs.existsSync(gitignorePath)) {
732
749
  try {
733
750
  const before = fs.readFileSync(gitignorePath, 'utf8');
734
- const stripped = before
735
- // Current shape (install.js BEGIN/END markers — exact match).
736
- .replace(/\n?# ===== rcode-managed gitignore block[\s\S]*?# ===== end rcode-managed gitignore block =====\n?/g, '\n')
737
- // Legacy >>> / <<< fenced shape.
738
- .replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, '\n')
739
- .replace(/\n{3,}/g, '\n\n');
751
+ const stripped = stripRihalGitignoreBlock(before);
740
752
  if (stripped !== before) {
741
753
  fs.writeFileSync(gitignorePath, stripped);
742
754
  console.log(` ✓ stripped rcode block from .gitignore (--purge)`);
@@ -773,6 +785,14 @@ async function runUninstall(args) {
773
785
  console.log(` rcode install`);
774
786
  }
775
787
 
788
+ // Re-exports for unit tests (W3.2 — issue #694 follow-up). The default
789
+ // export remains the async runner; these are attached afterwards so pure
790
+ // functions can be exercised without spawning a child process.
791
+ module.exports.isLocalOverride = isLocalOverride;
792
+ module.exports.planToPathList = planToPathList;
793
+ module.exports.discoverKnownActionSkills = discoverKnownActionSkills;
794
+ module.exports.stripRihalGitignoreBlock = stripRihalGitignoreBlock;
795
+
776
796
  // Direct invocation — allow `node cli/uninstall.js [flags]` to run end-to-end.
777
797
  // When called via cli/index.js, module.exports is invoked directly.
778
798
  if (require.main === module) {
package/cli/update.js CHANGED
@@ -383,3 +383,7 @@ async function runUpdate(args, { packageRoot, packageJson }) {
383
383
  }
384
384
  console.log();
385
385
  }
386
+
387
+ // Re-exports for unit tests (W3.4 — issue #694 follow-up).
388
+ module.exports.parseArgs = parseArgs;
389
+ module.exports.detectInstalledEditors = detectInstalledEditors;
package/dist/rcode.js CHANGED
@@ -15073,7 +15073,8 @@ var require_manifest = __commonJS({
15073
15073
  extra
15074
15074
  };
15075
15075
  }
15076
- function verifyClaudeInstall(cwd, packageRoot) {
15076
+ function verifyClaudeInstall(cwd, packageRoot, options = {}) {
15077
+ const globalFallback = options.globalFallback !== false;
15077
15078
  const pkg = readPackageManifest(packageRoot);
15078
15079
  const agentsDir = path2.join(cwd, ".claude/agents");
15079
15080
  const skillsDir = path2.join(cwd, ".claude/skills");
@@ -15085,7 +15086,7 @@ var require_manifest = __commonJS({
15085
15086
  }
15086
15087
  }
15087
15088
  }
15088
- if (installedAgents.size === 0) {
15089
+ if (installedAgents.size === 0 && globalFallback) {
15089
15090
  try {
15090
15091
  const os = require("os");
15091
15092
  const globalAgentsDir = path2.join(os.homedir(), ".claude/agents");
@@ -15100,9 +15101,7 @@ var require_manifest = __commonJS({
15100
15101
  }
15101
15102
  }
15102
15103
  const allInstalled = readInstalledDirs(skillsDir);
15103
- const actionsInstalled = new Set(
15104
- [...allInstalled].filter((n) => !n.startsWith("rihal-"))
15105
- );
15104
+ const actionsInstalled = new Set([...allInstalled].filter((n) => pkg.actions.has(n)));
15106
15105
  return [
15107
15106
  diffSet("claude", "agents", pkg.agents, installedAgents),
15108
15107
  diffSet("claude", "actions", pkg.actions, actionsInstalled)
@@ -15218,6 +15217,7 @@ var require_install = __commonJS({
15218
15217
  var bold = (s) => pc.bold(s);
15219
15218
  var PACKAGE_ROOT2 = path2.resolve(__dirname, "..");
15220
15219
  var SOURCE_ROOT = path2.join(PACKAGE_ROOT2, "rihal");
15220
+ var SUPPORTED_IDES = Object.freeze(["claude", "cursor", "gemini", "vscode", "antigravity"]);
15221
15221
  var ConfigSchema = z.object({
15222
15222
  user_name: z.string().min(1),
15223
15223
  project_name: z.string().min(1),
@@ -15419,11 +15419,11 @@ var require_install = __commonJS({
15419
15419
  if (opts.noPrompt || opts.global) return ["claude"];
15420
15420
  if (opts.yes || !process.stdin.isTTY) {
15421
15421
  const signals2 = detectIdeSignals(opts.target);
15422
- const detected2 = ["claude", "cursor", "gemini", "vscode", "antigravity"].filter((k) => signals2[k]);
15422
+ const detected2 = SUPPORTED_IDES.filter((k) => signals2[k]);
15423
15423
  return detected2.length > 0 ? detected2 : ["claude"];
15424
15424
  }
15425
15425
  const signals = detectIdeSignals(opts.target);
15426
- const detected = ["claude", "cursor", "gemini", "vscode"].filter((k) => signals[k]);
15426
+ const detected = SUPPORTED_IDES.filter((k) => k !== "antigravity" && signals[k]);
15427
15427
  const initialValues = detected.length > 0 ? detected : ["claude"];
15428
15428
  const choices = await clack.multiselect({
15429
15429
  message: "\u{1F3AF} Which editor(s) will you use rcode with?",
@@ -16400,7 +16400,6 @@ ${BLOCK}`, { mode: 493 });
16400
16400
  console.error(`\u2716 Source tree not found at ${SOURCE_ROOT}. Running from wrong dir?`);
16401
16401
  return 1;
16402
16402
  }
16403
- const SUPPORTED_IDES = ["claude", "cursor", "gemini", "vscode", "antigravity"];
16404
16403
  const unsupported = opts.ides.filter((ide) => !SUPPORTED_IDES.includes(ide));
16405
16404
  if (unsupported.length > 0) {
16406
16405
  console.error(`\u2716 --ide ${unsupported.join(", ")} is not supported in v${readPackageVersion()}.`);
@@ -17204,6 +17203,7 @@ commit_planning: ${desired}
17204
17203
  module2.exports.parseArgs = parseArgs;
17205
17204
  module2.exports.buildInstallPlan = buildInstallPlan;
17206
17205
  module2.exports.install = install;
17206
+ module2.exports.SUPPORTED_IDES = SUPPORTED_IDES;
17207
17207
  }
17208
17208
  });
17209
17209
 
@@ -17703,6 +17703,8 @@ var require_update = __commonJS({
17703
17703
  }
17704
17704
  console.log();
17705
17705
  }
17706
+ module2.exports.parseArgs = parseArgs;
17707
+ module2.exports.detectInstalledEditors = detectInstalledEditors;
17706
17708
  }
17707
17709
  });
17708
17710
 
@@ -17746,6 +17748,9 @@ var require_uninstall = __commonJS({
17746
17748
  function isLocalOverride(name) {
17747
17749
  return /\.local\.(md|mdc|json|yaml|yml|toml|js|ts)$/.test(name);
17748
17750
  }
17751
+ function stripRihalGitignoreBlock(text) {
17752
+ return text.replace(/\n?# ===== rcode-managed gitignore block[\s\S]*?# ===== end rcode-managed gitignore block =====\n?/g, "\n").replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, "\n").replace(/\n{3,}/g, "\n\n");
17753
+ }
17749
17754
  function removeMatching(dir, predicate) {
17750
17755
  if (!fs2.existsSync(dir)) return 0;
17751
17756
  let count = 0;
@@ -17981,8 +17986,8 @@ var require_uninstall = __commonJS({
17981
17986
  async function runUninstall(args) {
17982
17987
  const opts = parseArgs(args);
17983
17988
  const cwd = process.cwd();
17984
- const SUPPORTED_EDITORS = ["claude", "cursor", "gemini", "vscode", "antigravity"];
17985
- const editors = opts.editor ? opts.editor === "all" ? SUPPORTED_EDITORS : [opts.editor] : SUPPORTED_EDITORS;
17989
+ const { SUPPORTED_IDES } = require_install();
17990
+ const editors = opts.editor ? opts.editor === "all" ? Array.from(SUPPORTED_IDES) : [opts.editor] : Array.from(SUPPORTED_IDES);
17986
17991
  console.log(`
17987
17992
  \u{1F54C} Rihal Code \u2014 Uninstall
17988
17993
  `);
@@ -18219,7 +18224,7 @@ var require_uninstall = __commonJS({
18219
18224
  if (fs2.existsSync(gitignorePath)) {
18220
18225
  try {
18221
18226
  const before = fs2.readFileSync(gitignorePath, "utf8");
18222
- const stripped = before.replace(/\n?# ===== rcode-managed gitignore block[\s\S]*?# ===== end rcode-managed gitignore block =====\n?/g, "\n").replace(/\n?# >>> rihal-code >>>[\s\S]*?# <<< rihal-code <<<\n?/g, "\n").replace(/\n{3,}/g, "\n\n");
18227
+ const stripped = stripRihalGitignoreBlock(before);
18223
18228
  if (stripped !== before) {
18224
18229
  fs2.writeFileSync(gitignorePath, stripped);
18225
18230
  console.log(` \u2713 stripped rcode block from .gitignore (--purge)`);
@@ -18248,6 +18253,10 @@ var require_uninstall = __commonJS({
18248
18253
  To reinstall later:`);
18249
18254
  console.log(` rcode install`);
18250
18255
  }
18256
+ module2.exports.isLocalOverride = isLocalOverride;
18257
+ module2.exports.planToPathList = planToPathList;
18258
+ module2.exports.discoverKnownActionSkills = discoverKnownActionSkills;
18259
+ module2.exports.stripRihalGitignoreBlock = stripRihalGitignoreBlock;
18251
18260
  if (require.main === module2) {
18252
18261
  module2.exports(process.argv.slice(2)).catch((err) => {
18253
18262
  if (err instanceof PromptAbortError) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzlaa/rcode",
3
- "version": "3.4.26",
3
+ "version": "3.4.28",
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": {