@imdeadpool/guardex 7.0.11 → 7.0.12
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/README.md +24 -17
- package/bin/multiagent-safety.js +171 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,24 +20,24 @@ I was running ~30 Codex agents in parallel and hit a wall: they kept working on
|
|
|
20
20
|
|
|
21
21
|
GitGuardex exists to stop that loop. Every agent gets its own worktree, claims the files it's touching, and can't clobber files another agent has claimed. Your local branch stays clean; agents stay in their lanes.
|
|
22
22
|
|
|
23
|
-

|
|
24
|
-
|
|
25
|
-
Coming soon: [recodee.com](https://recodee.com) — live account health, usage, routing, and capacity in one place.
|
|
26
|
-
|
|
27
23
|
```mermaid
|
|
28
24
|
flowchart LR
|
|
29
|
-
A[Agent A
|
|
30
|
-
B[Agent B
|
|
31
|
-
C[Agent C
|
|
32
|
-
D[Agent D
|
|
33
|
-
E[Agent E
|
|
34
|
-
S --> F[
|
|
35
|
-
F --> G[
|
|
36
|
-
G --> H[
|
|
37
|
-
H --> I[Regression risk
|
|
38
|
-
I -->
|
|
25
|
+
A[Agent A adds assertions in a shared test] --> S[Several agents touch the same files]
|
|
26
|
+
B[Agent B rewrites the same test flow] --> S
|
|
27
|
+
C[Agent C updates the shared helper] --> S
|
|
28
|
+
D[Agent D deletes lines Agent A just added] --> S
|
|
29
|
+
E[Agent E saves an older snapshot of the file] --> S
|
|
30
|
+
S --> F[One agent overwrites another agent's edits]
|
|
31
|
+
F --> G[Another agent deletes code the others just added]
|
|
32
|
+
G --> H[Lost work, rework, and review confusion]
|
|
33
|
+
H --> I[Regression risk and flaky fixes grow]
|
|
34
|
+
I --> S
|
|
39
35
|
```
|
|
40
36
|
|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
Coming soon: [recodee.com](https://recodee.com) — live account health, usage, routing, and capacity in one place.
|
|
40
|
+
|
|
41
41
|
---
|
|
42
42
|
|
|
43
43
|
## What it does
|
|
@@ -122,7 +122,7 @@ gx finish --all
|
|
|
122
122
|
|
|
123
123
|
This is the real Source Control shape Guardex is aiming for: isolated agent branches, clear OpenSpec artifacts, and no pile-up on one shared checkout.
|
|
124
124
|
|
|
125
|
-

|
|
126
126
|
|
|
127
127
|
---
|
|
128
128
|
|
|
@@ -237,7 +237,7 @@ A few things worth knowing up front:
|
|
|
237
237
|
|
|
238
238
|
- Running `gx` with no command opens the status/health view.
|
|
239
239
|
- `gx init` is just an alias for `gx setup`.
|
|
240
|
-
- Setup/doctor can install missing
|
|
240
|
+
- Setup/doctor can install missing companion tooling (OMC runtime, OpenSpec, cavemem, codex-auth, caveman, cavekit) — but only with explicit Y/N confirmation.
|
|
241
241
|
- Direct commits/pushes to protected branches are **blocked** by default. Agents must use the `agent/*` + PR flow.
|
|
242
242
|
- **Exception:** VS Code Source Control commits are allowed on protected branches that exist only locally (no upstream, no remote branch).
|
|
243
243
|
- On protected `main`, `gx doctor` auto-runs in a sandbox agent branch/worktree so it can't touch your real main.
|
|
@@ -255,13 +255,15 @@ git config multiagent.allowVscodeProtectedBranchWrites true
|
|
|
255
255
|
|
|
256
256
|
## Companion tools
|
|
257
257
|
|
|
258
|
-
GitGuardex is designed to work alongside these. All optional — but if you're running many agents, you probably want them. `gx status` reports the machine-detectable
|
|
258
|
+
GitGuardex is designed to work alongside these. All optional — but if you're running many agents, you probably want them. `gx status` reports the machine-detectable companion helpers, including local `caveman` / `cavekit` installs when their home-directory footprints are present.
|
|
259
259
|
|
|
260
260
|
```text
|
|
261
261
|
● oh-my-codex: active
|
|
262
262
|
● oh-my-claude-sisyphus: active
|
|
263
263
|
● @fission-ai/openspec: active
|
|
264
264
|
● cavemem: active
|
|
265
|
+
● cavekit: active
|
|
266
|
+
● caveman: active
|
|
265
267
|
● @imdeadpool/codex-account-switcher: active
|
|
266
268
|
● gh: active
|
|
267
269
|
```
|
|
@@ -488,6 +490,11 @@ npm pack --dry-run
|
|
|
488
490
|
<details>
|
|
489
491
|
<summary><strong>v7.x</strong></summary>
|
|
490
492
|
|
|
493
|
+
### v7.0.12
|
|
494
|
+
- Fixed the self-update handoff after `gx` installs a newer global package. When the on-disk install advances, GitGuardex now restarts into the installed CLI instead of continuing in the old process and printing the stale in-memory version.
|
|
495
|
+
- This removes the confusing `Updated to latest published version` followed by `CLI: ...7.0.10` mismatch that happened when `7.0.11` finished installing during the same `gx` invocation.
|
|
496
|
+
- Bumped `@imdeadpool/guardex` from `7.0.11` → `7.0.12`.
|
|
497
|
+
|
|
491
498
|
### v7.0.11
|
|
492
499
|
- Fixed the npm release workflow trigger so publishes run from `release.published` or explicit manual dispatch, instead of double-firing on both the tag push and the release event.
|
|
493
500
|
- This keeps the GitHub `npm` environment from collecting duplicate cancelled deploy cards for the same version and leaves one canonical release deployment to monitor.
|
package/bin/multiagent-safety.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
4
5
|
const path = require('node:path');
|
|
5
6
|
const cp = require('node:child_process');
|
|
6
7
|
|
|
@@ -13,6 +14,8 @@ const LEGACY_NAMES = ['guardex', 'multiagent-safety'];
|
|
|
13
14
|
const OPENSPEC_PACKAGE = '@fission-ai/openspec';
|
|
14
15
|
const OMC_PACKAGE = 'oh-my-claude-sisyphus';
|
|
15
16
|
const CAVEMEM_PACKAGE = 'cavemem';
|
|
17
|
+
const NPX_BIN = process.env.GUARDEX_NPX_BIN || 'npx';
|
|
18
|
+
const GUARDEX_HOME_DIR = path.resolve(process.env.GUARDEX_HOME_DIR || os.homedir());
|
|
16
19
|
const GLOBAL_TOOLCHAIN_PACKAGES = [
|
|
17
20
|
'oh-my-codex',
|
|
18
21
|
OMC_PACKAGE,
|
|
@@ -20,6 +23,26 @@ const GLOBAL_TOOLCHAIN_PACKAGES = [
|
|
|
20
23
|
CAVEMEM_PACKAGE,
|
|
21
24
|
'@imdeadpool/codex-account-switcher',
|
|
22
25
|
];
|
|
26
|
+
const OPTIONAL_LOCAL_COMPANION_TOOLS = [
|
|
27
|
+
{
|
|
28
|
+
name: 'cavekit',
|
|
29
|
+
candidatePaths: [
|
|
30
|
+
'.cavekit/plugin.json',
|
|
31
|
+
'.codex/local-marketplaces/cavekit/.agents/plugins/marketplace.json',
|
|
32
|
+
],
|
|
33
|
+
installCommand: `${NPX_BIN} skills add JuliusBrussee/cavekit`,
|
|
34
|
+
installArgs: ['skills', 'add', 'JuliusBrussee/cavekit'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'caveman',
|
|
38
|
+
candidatePaths: [
|
|
39
|
+
'.config/caveman/config.json',
|
|
40
|
+
'.cavekit/skills/caveman/SKILL.md',
|
|
41
|
+
],
|
|
42
|
+
installCommand: `${NPX_BIN} skills add JuliusBrussee/caveman`,
|
|
43
|
+
installArgs: ['skills', 'add', 'JuliusBrussee/caveman'],
|
|
44
|
+
},
|
|
45
|
+
];
|
|
23
46
|
const GH_BIN = process.env.GUARDEX_GH_BIN || 'gh';
|
|
24
47
|
const REQUIRED_SYSTEM_TOOLS = [
|
|
25
48
|
{
|
|
@@ -3393,9 +3416,15 @@ function maybeSelfUpdateBeforeStatus() {
|
|
|
3393
3416
|
}
|
|
3394
3417
|
|
|
3395
3418
|
console.log(`[${TOOL_NAME}] ✅ Updated to latest published version.`);
|
|
3419
|
+
restartIntoUpdatedGuardex(check.latest);
|
|
3396
3420
|
}
|
|
3397
3421
|
|
|
3398
3422
|
function readInstalledGuardexVersion() {
|
|
3423
|
+
const installInfo = readInstalledGuardexInstallInfo();
|
|
3424
|
+
return installInfo ? installInfo.version : null;
|
|
3425
|
+
}
|
|
3426
|
+
|
|
3427
|
+
function readInstalledGuardexInstallInfo() {
|
|
3399
3428
|
// Resolves the globally-installed package's on-disk version so we can
|
|
3400
3429
|
// verify npm actually wrote new bytes. Uses `npm root -g` to locate the
|
|
3401
3430
|
// global install root so we don't accidentally read the running source
|
|
@@ -3417,7 +3446,24 @@ function readInstalledGuardexVersion() {
|
|
|
3417
3446
|
}
|
|
3418
3447
|
const parsed = JSON.parse(fs.readFileSync(installedPkgPath, 'utf8'));
|
|
3419
3448
|
if (parsed && typeof parsed.version === 'string') {
|
|
3420
|
-
|
|
3449
|
+
let binRelative = null;
|
|
3450
|
+
if (typeof parsed.bin === 'string') {
|
|
3451
|
+
binRelative = parsed.bin;
|
|
3452
|
+
} else if (parsed.bin && typeof parsed.bin === 'object') {
|
|
3453
|
+
const invokedName = path.basename(process.argv[1] || '');
|
|
3454
|
+
binRelative =
|
|
3455
|
+
parsed.bin[invokedName] ||
|
|
3456
|
+
parsed.bin[SHORT_TOOL_NAME] ||
|
|
3457
|
+
Object.values(parsed.bin).find((value) => typeof value === 'string') ||
|
|
3458
|
+
null;
|
|
3459
|
+
}
|
|
3460
|
+
const packageRoot = path.dirname(installedPkgPath);
|
|
3461
|
+
const binPath = binRelative ? path.join(packageRoot, binRelative) : null;
|
|
3462
|
+
return {
|
|
3463
|
+
version: parsed.version,
|
|
3464
|
+
packageRoot,
|
|
3465
|
+
binPath,
|
|
3466
|
+
};
|
|
3421
3467
|
}
|
|
3422
3468
|
} catch (error) {
|
|
3423
3469
|
return null;
|
|
@@ -3425,6 +3471,38 @@ function readInstalledGuardexVersion() {
|
|
|
3425
3471
|
return null;
|
|
3426
3472
|
}
|
|
3427
3473
|
|
|
3474
|
+
function restartIntoUpdatedGuardex(expectedVersion) {
|
|
3475
|
+
const installInfo = readInstalledGuardexInstallInfo();
|
|
3476
|
+
if (!installInfo || installInfo.version !== expectedVersion || installInfo.version === packageJson.version) {
|
|
3477
|
+
return;
|
|
3478
|
+
}
|
|
3479
|
+
if (!installInfo.binPath || !fs.existsSync(installInfo.binPath)) {
|
|
3480
|
+
console.log(`[${TOOL_NAME}] Restart required to use ${installInfo.version}. Rerun ${SHORT_TOOL_NAME}.`);
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3484
|
+
console.log(`[${TOOL_NAME}] Restarting into ${installInfo.version}…`);
|
|
3485
|
+
const restartResult = cp.spawnSync(
|
|
3486
|
+
process.execPath,
|
|
3487
|
+
[installInfo.binPath, ...process.argv.slice(2)],
|
|
3488
|
+
{
|
|
3489
|
+
cwd: process.cwd(),
|
|
3490
|
+
env: {
|
|
3491
|
+
...process.env,
|
|
3492
|
+
GUARDEX_SKIP_UPDATE_CHECK: '1',
|
|
3493
|
+
},
|
|
3494
|
+
stdio: 'inherit',
|
|
3495
|
+
},
|
|
3496
|
+
);
|
|
3497
|
+
if (restartResult.error) {
|
|
3498
|
+
console.log(
|
|
3499
|
+
`[${TOOL_NAME}] Restart into ${installInfo.version} failed. Rerun ${SHORT_TOOL_NAME}.`,
|
|
3500
|
+
);
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
process.exit(restartResult.status == null ? 0 : restartResult.status);
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3428
3506
|
function checkForOpenSpecPackageUpdate() {
|
|
3429
3507
|
if (envFlagEnabled('GUARDEX_SKIP_OPENSPEC_UPDATE_CHECK')) {
|
|
3430
3508
|
return { checked: false, reason: 'disabled' };
|
|
@@ -3616,15 +3694,44 @@ function detectRequiredSystemTools() {
|
|
|
3616
3694
|
return services;
|
|
3617
3695
|
}
|
|
3618
3696
|
|
|
3697
|
+
function detectOptionalLocalCompanionTools() {
|
|
3698
|
+
return OPTIONAL_LOCAL_COMPANION_TOOLS.map((tool) => {
|
|
3699
|
+
const detectedPath = tool.candidatePaths
|
|
3700
|
+
.map((relativePath) => path.join(GUARDEX_HOME_DIR, relativePath))
|
|
3701
|
+
.find((candidatePath) => fs.existsSync(candidatePath));
|
|
3702
|
+
return {
|
|
3703
|
+
name: tool.name,
|
|
3704
|
+
displayName: tool.displayName || tool.name,
|
|
3705
|
+
installCommand: tool.installCommand,
|
|
3706
|
+
installArgs: [...tool.installArgs],
|
|
3707
|
+
status: detectedPath ? 'active' : 'inactive',
|
|
3708
|
+
detectedPath: detectedPath || null,
|
|
3709
|
+
};
|
|
3710
|
+
});
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
function describeCompanionInstallCommands(missingPackages, missingLocalTools) {
|
|
3714
|
+
const commands = [];
|
|
3715
|
+
if (missingPackages.length > 0) {
|
|
3716
|
+
commands.push(`${NPM_BIN} i -g ${missingPackages.join(' ')}`);
|
|
3717
|
+
}
|
|
3718
|
+
for (const tool of missingLocalTools) {
|
|
3719
|
+
commands.push(tool.installCommand);
|
|
3720
|
+
}
|
|
3721
|
+
return commands;
|
|
3722
|
+
}
|
|
3723
|
+
|
|
3619
3724
|
function askGlobalInstallForMissing(options, missingPackages) {
|
|
3620
3725
|
const approval = resolveGlobalInstallApproval(options);
|
|
3621
3726
|
if (!approval.approved) {
|
|
3622
3727
|
return approval;
|
|
3623
3728
|
}
|
|
3624
3729
|
|
|
3730
|
+
const missingLocalTools = detectOptionalLocalCompanionTools().filter((tool) => tool.status !== 'active');
|
|
3731
|
+
const installCommands = describeCompanionInstallCommands(missingPackages, missingLocalTools);
|
|
3625
3732
|
if (approval.source === 'prompt') {
|
|
3626
3733
|
const approved = promptYesNoStrict(
|
|
3627
|
-
`Install missing
|
|
3734
|
+
`Install missing companion tools now? (${installCommands.join(' && ')})`,
|
|
3628
3735
|
);
|
|
3629
3736
|
return { approved, source: 'prompt' };
|
|
3630
3737
|
}
|
|
@@ -3638,36 +3745,61 @@ function installGlobalToolchain(options) {
|
|
|
3638
3745
|
}
|
|
3639
3746
|
|
|
3640
3747
|
const detection = detectGlobalToolchainPackages();
|
|
3748
|
+
const localCompanionTools = detectOptionalLocalCompanionTools();
|
|
3641
3749
|
if (!detection.ok) {
|
|
3642
3750
|
console.log(`[${TOOL_NAME}] ⚠️ Could not detect global packages: ${detection.error}`);
|
|
3643
3751
|
} else {
|
|
3644
3752
|
if (detection.installed.length > 0) {
|
|
3645
3753
|
console.log(`[${TOOL_NAME}] Already installed globally: ${detection.installed.join(', ')}`);
|
|
3646
3754
|
}
|
|
3647
|
-
|
|
3755
|
+
const installedLocalTools = localCompanionTools
|
|
3756
|
+
.filter((tool) => tool.status === 'active')
|
|
3757
|
+
.map((tool) => tool.name);
|
|
3758
|
+
if (installedLocalTools.length > 0) {
|
|
3759
|
+
console.log(`[${TOOL_NAME}] Already installed locally: ${installedLocalTools.join(', ')}`);
|
|
3760
|
+
}
|
|
3761
|
+
if (detection.missing.length === 0 && localCompanionTools.every((tool) => tool.status === 'active')) {
|
|
3648
3762
|
return { status: 'already-installed' };
|
|
3649
3763
|
}
|
|
3650
3764
|
}
|
|
3651
3765
|
|
|
3652
3766
|
const missingPackages = detection.ok ? detection.missing : [...GLOBAL_TOOLCHAIN_PACKAGES];
|
|
3767
|
+
const missingLocalTools = localCompanionTools.filter((tool) => tool.status !== 'active');
|
|
3653
3768
|
const approval = askGlobalInstallForMissing(options, missingPackages);
|
|
3654
3769
|
if (!approval.approved) {
|
|
3655
3770
|
return { status: 'skipped', reason: approval.source };
|
|
3656
3771
|
}
|
|
3657
3772
|
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
const
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3773
|
+
const installed = [];
|
|
3774
|
+
if (missingPackages.length > 0) {
|
|
3775
|
+
console.log(
|
|
3776
|
+
`[${TOOL_NAME}] Installing global toolchain: npm i -g ${missingPackages.join(' ')}`,
|
|
3777
|
+
);
|
|
3778
|
+
const result = run(NPM_BIN, ['i', '-g', ...missingPackages], { stdio: 'inherit' });
|
|
3779
|
+
if (result.status !== 0) {
|
|
3780
|
+
const stderr = (result.stderr || '').trim();
|
|
3781
|
+
return {
|
|
3782
|
+
status: 'failed',
|
|
3783
|
+
reason: stderr || 'npm global install failed',
|
|
3784
|
+
};
|
|
3785
|
+
}
|
|
3786
|
+
installed.push(...missingPackages);
|
|
3668
3787
|
}
|
|
3669
3788
|
|
|
3670
|
-
|
|
3789
|
+
for (const tool of missingLocalTools) {
|
|
3790
|
+
console.log(`[${TOOL_NAME}] Installing local companion tool: ${tool.installCommand}`);
|
|
3791
|
+
const result = run(NPX_BIN, tool.installArgs, { stdio: 'inherit' });
|
|
3792
|
+
if (result.status !== 0) {
|
|
3793
|
+
const stderr = (result.stderr || '').trim();
|
|
3794
|
+
return {
|
|
3795
|
+
status: 'failed',
|
|
3796
|
+
reason: stderr || `${tool.name} install failed`,
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
installed.push(tool.name);
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3802
|
+
return { status: 'installed', packages: installed };
|
|
3671
3803
|
}
|
|
3672
3804
|
|
|
3673
3805
|
function gitRefExists(repoRoot, refName) {
|
|
@@ -4018,9 +4150,15 @@ function status(rawArgs) {
|
|
|
4018
4150
|
status: toolchain.installed.includes(pkg) ? 'active' : 'inactive',
|
|
4019
4151
|
};
|
|
4020
4152
|
});
|
|
4153
|
+
const localCompanionServices = detectOptionalLocalCompanionTools().map((tool) => ({
|
|
4154
|
+
name: tool.name,
|
|
4155
|
+
displayName: tool.displayName || tool.name,
|
|
4156
|
+
status: tool.status,
|
|
4157
|
+
}));
|
|
4021
4158
|
const requiredSystemTools = detectRequiredSystemTools();
|
|
4022
4159
|
const services = [
|
|
4023
4160
|
...npmServices,
|
|
4161
|
+
...localCompanionServices,
|
|
4024
4162
|
...requiredSystemTools.map((tool) => ({
|
|
4025
4163
|
name: tool.name,
|
|
4026
4164
|
displayName: tool.displayName || tool.name,
|
|
@@ -4079,6 +4217,17 @@ function status(rawArgs) {
|
|
|
4079
4217
|
const serviceLabel = service.displayName || service.name;
|
|
4080
4218
|
console.log(` - ${statusDot(service.status)} ${serviceLabel}: ${service.status}`);
|
|
4081
4219
|
}
|
|
4220
|
+
const inactiveOptionalCompanions = [...npmServices, ...localCompanionServices]
|
|
4221
|
+
.filter((service) => service.status !== 'active')
|
|
4222
|
+
.map((service) => service.displayName || service.name);
|
|
4223
|
+
if (inactiveOptionalCompanions.length > 0) {
|
|
4224
|
+
console.log(
|
|
4225
|
+
`[${TOOL_NAME}] Optional companion tools inactive: ${inactiveOptionalCompanions.join(', ')}`,
|
|
4226
|
+
);
|
|
4227
|
+
console.log(
|
|
4228
|
+
`[${TOOL_NAME}] Run '${SHORT_TOOL_NAME} setup' to install missing companions with an explicit Y/N prompt.`,
|
|
4229
|
+
);
|
|
4230
|
+
}
|
|
4082
4231
|
const missingSystemTools = requiredSystemTools.filter((tool) => tool.status !== 'active');
|
|
4083
4232
|
if (missingSystemTools.length > 0) {
|
|
4084
4233
|
const tools = missingSystemTools
|
|
@@ -4713,19 +4862,23 @@ function setup(rawArgs) {
|
|
|
4713
4862
|
const globalInstallStatus = installGlobalToolchain(options);
|
|
4714
4863
|
if (globalInstallStatus.status === 'installed') {
|
|
4715
4864
|
console.log(
|
|
4716
|
-
`[${TOOL_NAME}] ✅
|
|
4865
|
+
`[${TOOL_NAME}] ✅ Companion tools installed (${(globalInstallStatus.packages || []).join(', ')}).`,
|
|
4717
4866
|
);
|
|
4718
4867
|
} else if (globalInstallStatus.status === 'already-installed') {
|
|
4719
|
-
console.log(`[${TOOL_NAME}] ✅ Companion
|
|
4868
|
+
console.log(`[${TOOL_NAME}] ✅ Companion tools already installed. Skipping.`);
|
|
4720
4869
|
} else if (globalInstallStatus.status === 'failed') {
|
|
4870
|
+
const installCommands = describeCompanionInstallCommands(
|
|
4871
|
+
GLOBAL_TOOLCHAIN_PACKAGES,
|
|
4872
|
+
OPTIONAL_LOCAL_COMPANION_TOOLS,
|
|
4873
|
+
);
|
|
4721
4874
|
console.log(
|
|
4722
4875
|
`[${TOOL_NAME}] ⚠️ Global install failed: ${globalInstallStatus.reason}\n` +
|
|
4723
4876
|
`[${TOOL_NAME}] Continue with local safety setup. You can retry later with:\n` +
|
|
4724
|
-
` ${
|
|
4877
|
+
installCommands.map((command) => ` ${command}`).join('\n'),
|
|
4725
4878
|
);
|
|
4726
4879
|
} else if (globalInstallStatus.status === 'skipped' && globalInstallStatus.reason === 'non-interactive-default') {
|
|
4727
4880
|
console.log(
|
|
4728
|
-
`[${TOOL_NAME}] Skipping
|
|
4881
|
+
`[${TOOL_NAME}] Skipping companion installs (non-interactive mode). ` +
|
|
4729
4882
|
`Use --yes-global-install to force or run interactively for Y/N prompt.`,
|
|
4730
4883
|
);
|
|
4731
4884
|
}
|