@hanzlaa/rcode 3.4.26 → 3.4.27
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 +20 -3
- package/cli/postinstall.js +40 -26
- package/cli/uninstall.js +34 -14
- package/cli/update.js +4 -0
- package/dist/rcode.js +16 -6
- package/package.json +1 -1
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
package/cli/postinstall.js
CHANGED
|
@@ -13,42 +13,52 @@
|
|
|
13
13
|
const os = require('os');
|
|
14
14
|
const path = require('path');
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
26
|
-
if (
|
|
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/,
|
|
33
|
-
/[/\\]lib[/\\]node_modules[/\\]/,
|
|
34
|
-
/\.nvm[/\\]versions[/\\]/,
|
|
35
|
-
/\.pnpm[/\\]/,
|
|
36
|
-
/\.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(
|
|
39
|
-
|
|
40
|
-
|
|
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
|
|
423
|
-
//
|
|
424
|
-
//
|
|
425
|
-
|
|
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' ?
|
|
430
|
-
:
|
|
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
|
@@ -15218,6 +15218,7 @@ var require_install = __commonJS({
|
|
|
15218
15218
|
var bold = (s) => pc.bold(s);
|
|
15219
15219
|
var PACKAGE_ROOT2 = path2.resolve(__dirname, "..");
|
|
15220
15220
|
var SOURCE_ROOT = path2.join(PACKAGE_ROOT2, "rihal");
|
|
15221
|
+
var SUPPORTED_IDES = Object.freeze(["claude", "cursor", "gemini", "vscode", "antigravity"]);
|
|
15221
15222
|
var ConfigSchema = z.object({
|
|
15222
15223
|
user_name: z.string().min(1),
|
|
15223
15224
|
project_name: z.string().min(1),
|
|
@@ -15419,11 +15420,11 @@ var require_install = __commonJS({
|
|
|
15419
15420
|
if (opts.noPrompt || opts.global) return ["claude"];
|
|
15420
15421
|
if (opts.yes || !process.stdin.isTTY) {
|
|
15421
15422
|
const signals2 = detectIdeSignals(opts.target);
|
|
15422
|
-
const detected2 =
|
|
15423
|
+
const detected2 = SUPPORTED_IDES.filter((k) => signals2[k]);
|
|
15423
15424
|
return detected2.length > 0 ? detected2 : ["claude"];
|
|
15424
15425
|
}
|
|
15425
15426
|
const signals = detectIdeSignals(opts.target);
|
|
15426
|
-
const detected =
|
|
15427
|
+
const detected = SUPPORTED_IDES.filter((k) => k !== "antigravity" && signals[k]);
|
|
15427
15428
|
const initialValues = detected.length > 0 ? detected : ["claude"];
|
|
15428
15429
|
const choices = await clack.multiselect({
|
|
15429
15430
|
message: "\u{1F3AF} Which editor(s) will you use rcode with?",
|
|
@@ -16400,7 +16401,6 @@ ${BLOCK}`, { mode: 493 });
|
|
|
16400
16401
|
console.error(`\u2716 Source tree not found at ${SOURCE_ROOT}. Running from wrong dir?`);
|
|
16401
16402
|
return 1;
|
|
16402
16403
|
}
|
|
16403
|
-
const SUPPORTED_IDES = ["claude", "cursor", "gemini", "vscode", "antigravity"];
|
|
16404
16404
|
const unsupported = opts.ides.filter((ide) => !SUPPORTED_IDES.includes(ide));
|
|
16405
16405
|
if (unsupported.length > 0) {
|
|
16406
16406
|
console.error(`\u2716 --ide ${unsupported.join(", ")} is not supported in v${readPackageVersion()}.`);
|
|
@@ -17204,6 +17204,7 @@ commit_planning: ${desired}
|
|
|
17204
17204
|
module2.exports.parseArgs = parseArgs;
|
|
17205
17205
|
module2.exports.buildInstallPlan = buildInstallPlan;
|
|
17206
17206
|
module2.exports.install = install;
|
|
17207
|
+
module2.exports.SUPPORTED_IDES = SUPPORTED_IDES;
|
|
17207
17208
|
}
|
|
17208
17209
|
});
|
|
17209
17210
|
|
|
@@ -17703,6 +17704,8 @@ var require_update = __commonJS({
|
|
|
17703
17704
|
}
|
|
17704
17705
|
console.log();
|
|
17705
17706
|
}
|
|
17707
|
+
module2.exports.parseArgs = parseArgs;
|
|
17708
|
+
module2.exports.detectInstalledEditors = detectInstalledEditors;
|
|
17706
17709
|
}
|
|
17707
17710
|
});
|
|
17708
17711
|
|
|
@@ -17746,6 +17749,9 @@ var require_uninstall = __commonJS({
|
|
|
17746
17749
|
function isLocalOverride(name) {
|
|
17747
17750
|
return /\.local\.(md|mdc|json|yaml|yml|toml|js|ts)$/.test(name);
|
|
17748
17751
|
}
|
|
17752
|
+
function stripRihalGitignoreBlock(text) {
|
|
17753
|
+
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");
|
|
17754
|
+
}
|
|
17749
17755
|
function removeMatching(dir, predicate) {
|
|
17750
17756
|
if (!fs2.existsSync(dir)) return 0;
|
|
17751
17757
|
let count = 0;
|
|
@@ -17981,8 +17987,8 @@ var require_uninstall = __commonJS({
|
|
|
17981
17987
|
async function runUninstall(args) {
|
|
17982
17988
|
const opts = parseArgs(args);
|
|
17983
17989
|
const cwd = process.cwd();
|
|
17984
|
-
const
|
|
17985
|
-
const editors = opts.editor ? opts.editor === "all" ?
|
|
17990
|
+
const { SUPPORTED_IDES } = require_install();
|
|
17991
|
+
const editors = opts.editor ? opts.editor === "all" ? Array.from(SUPPORTED_IDES) : [opts.editor] : Array.from(SUPPORTED_IDES);
|
|
17986
17992
|
console.log(`
|
|
17987
17993
|
\u{1F54C} Rihal Code \u2014 Uninstall
|
|
17988
17994
|
`);
|
|
@@ -18219,7 +18225,7 @@ var require_uninstall = __commonJS({
|
|
|
18219
18225
|
if (fs2.existsSync(gitignorePath)) {
|
|
18220
18226
|
try {
|
|
18221
18227
|
const before = fs2.readFileSync(gitignorePath, "utf8");
|
|
18222
|
-
const stripped = before
|
|
18228
|
+
const stripped = stripRihalGitignoreBlock(before);
|
|
18223
18229
|
if (stripped !== before) {
|
|
18224
18230
|
fs2.writeFileSync(gitignorePath, stripped);
|
|
18225
18231
|
console.log(` \u2713 stripped rcode block from .gitignore (--purge)`);
|
|
@@ -18248,6 +18254,10 @@ var require_uninstall = __commonJS({
|
|
|
18248
18254
|
To reinstall later:`);
|
|
18249
18255
|
console.log(` rcode install`);
|
|
18250
18256
|
}
|
|
18257
|
+
module2.exports.isLocalOverride = isLocalOverride;
|
|
18258
|
+
module2.exports.planToPathList = planToPathList;
|
|
18259
|
+
module2.exports.discoverKnownActionSkills = discoverKnownActionSkills;
|
|
18260
|
+
module2.exports.stripRihalGitignoreBlock = stripRihalGitignoreBlock;
|
|
18251
18261
|
if (require.main === module2) {
|
|
18252
18262
|
module2.exports(process.argv.slice(2)).catch((err) => {
|
|
18253
18263
|
if (err instanceof PromptAbortError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.27",
|
|
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": {
|