Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ Install repo skills with `npx skills add recodee/gitguardex`; `npx skills add re
| [**cavekit**](https://github.com/JuliusBrussee/cavekit) — `npx skills add JuliusBrussee/cavekit` | Spec-driven build loop with `spec`, `build`, `check`, `caveman`, `backprop` skills bundled in. | [![stars](https://img.shields.io/github/stars/JuliusBrussee/cavekit?style=social)](https://github.com/JuliusBrussee/cavekit) |
| [**caveman**](https://github.com/JuliusBrussee/caveman) — `npx skills add JuliusBrussee/caveman` | Ultra-compressed response mode for Claude / Codex. Less output-token churn on long reviews and debug loops. | [![stars](https://img.shields.io/github/stars/JuliusBrussee/caveman?style=social)](https://github.com/JuliusBrussee/caveman) |
| [**codex-account-switcher**](https://github.com/recodeecom/codex-account-switcher-cli) — `npm i -g @imdeadpool/codex-account-switcher` | Multi-identity Codex account switcher. Auto-registers accounts on `codex login`; switch with one command. | [![stars](https://img.shields.io/github/stars/recodeecom/codex-account-switcher-cli?style=social)](https://github.com/recodeecom/codex-account-switcher-cli) |
| [**GitHub CLI (`gh`)**](https://github.com/cli/cli) — see [cli.github.com](https://cli.github.com/) | Required for PR / merge automation. `gx branch finish --via-pr --wait-for-merge` depends on it. | [![stars](https://img.shields.io/github/stars/cli/cli?style=social)](https://github.com/cli/cli) |
| [**GitHub CLI (`gh`)**](https://github.com/cli/cli) — see [cli.github.com](https://cli.github.com/) | Required for PR / merge automation. `gx branch finish --via-pr --wait-for-merge` depends on it. If `ghx` is on `PATH`, Guardex uses that GitHub CLI cache proxy automatically; set `GUARDEX_GH_BIN=gh` to force direct `gh`. | [![stars](https://img.shields.io/github/stars/cli/cli?style=social)](https://github.com/cli/cli) |

---

Expand Down
1 change: 1 addition & 0 deletions src/cli/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -1957,6 +1957,7 @@ function collectServicesSnapshot() {
...requiredSystemTools.map((tool) => ({
name: tool.name,
displayName: tool.displayName || tool.name,
command: tool.command,
status: tool.status,
})),
];
Expand Down
18 changes: 16 additions & 2 deletions src/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,24 @@ const OPTIONAL_LOCAL_COMPANION_TOOLS = [
installArgs: ['skills', 'add', 'JuliusBrussee/caveman'],
},
];
const GH_BIN = process.env.GUARDEX_GH_BIN || 'gh';
function commandAvailable(command) {
const result = cp.spawnSync(command, ['--version'], { stdio: 'ignore' });
return result.status === 0;
}

function resolveGithubCliBin(env = process.env) {
const explicit = String(env.GUARDEX_GH_BIN || '').trim();
if (explicit) {
return explicit;
}
return commandAvailable('ghx') ? 'ghx' : 'gh';
}

const GH_BIN = resolveGithubCliBin();
const REQUIRED_SYSTEM_TOOLS = [
{
name: 'gh',
displayName: 'GitHub (gh)',
displayName: GH_BIN === 'ghx' ? 'GitHub (ghx proxy)' : 'GitHub (gh)',
command: GH_BIN,
installHint: 'https://cli.github.com/',
},
Expand Down Expand Up @@ -698,6 +711,7 @@ module.exports = {
GLOBAL_TOOLCHAIN_SERVICES,
GLOBAL_TOOLCHAIN_PACKAGES,
OPTIONAL_LOCAL_COMPANION_TOOLS,
resolveGithubCliBin,
GH_BIN,
REQUIRED_SYSTEM_TOOLS,
MAINTAINER_RELEASE_REPO,
Expand Down
5 changes: 3 additions & 2 deletions src/doctor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const {
path,
TOOL_NAME,
SHORT_TOOL_NAME,
GH_BIN,
LOCK_FILE_RELATIVE,
REQUIRED_MANAGED_REPO_FILES,
OMX_SCAFFOLD_DIRECTORIES,
Expand Down Expand Up @@ -442,7 +443,7 @@ function finishDoctorSandboxBranch(blocked, metadata, options = {}) {
};
}

const ghBin = process.env.GUARDEX_GH_BIN || 'gh';
const ghBin = GH_BIN;
if (!isCommandAvailable(ghBin)) {
return {
status: 'skipped',
Expand Down Expand Up @@ -890,7 +891,7 @@ function autoFinishReadyAgentBranches(repoRoot, options = {}) {

const originAvailable = hasOriginRemote(repoRoot);
const explicitGhBin = Boolean(String(process.env.GUARDEX_GH_BIN || '').trim());
const ghBin = process.env.GUARDEX_GH_BIN || 'gh';
const ghBin = GH_BIN;
const ghAvailable =
originAvailable &&
(explicitGhBin || originRemoteLooksLikeGithub(repoRoot)) &&
Expand Down
29 changes: 27 additions & 2 deletions test/status.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,39 @@ echo "unexpected gh args: $*" >&2
exit 1
`);

const result = runNodeWithEnv([], repoDir, {
const result = runNodeWithEnv(['status', '--verbose'], repoDir, {
GUARDEX_GH_BIN: fakeGh.fakePath,
});
assert.equal(result.status, 0, result.stderr || result.stdout);
assert.match(result.stdout, /GitHub \(gh\): active/);
});


test('status prefers ghx as the GitHub CLI proxy when no explicit gh binary is set', () => {
const repoDir = initRepo();
const fakeGhx = createFakeBin('ghx', `
if [[ "$1" == "--version" ]]; then
echo "ghx version 1.0.0"
exit 0
fi
echo "unexpected ghx args: $*" >&2
exit 1
`);

const result = runNodeWithEnv(['status', '--target', repoDir, '--json'], repoDir, {
PATH: `${fakeGhx.fakeBin}:${process.env.PATH}`,
});

assert.equal(result.status, 0, result.stderr || result.stdout);
const payload = JSON.parse(result.stdout);
const ghService = payload.services.find((service) => service.name === 'gh');
assert.ok(ghService, 'GitHub CLI service should be included in status payload');
assert.equal(ghService.displayName, 'GitHub (ghx proxy)');
assert.equal(ghService.command, 'ghx');
assert.equal(ghService.status, 'active');
});


test('warning-only degraded status avoids zero-error wording and points humans at doctor', () => {
const repoDir = initRepo();

Expand Down Expand Up @@ -484,7 +509,7 @@ echo "unexpected npm args: $*" >&2
exit 1
`);

const result = runNodeWithEnv(['status', '--target', targetDir], targetDir, {
const result = runNodeWithEnv(['status', '--target', targetDir, '--verbose'], targetDir, {
GUARDEX_NPM_BIN: fakeNpm,
GUARDEX_HOME_DIR: fakeHome,
});
Expand Down
Loading