vibe-gate-mcp 0.1.6 → 0.1.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/CHANGELOG.md +21 -0
- package/dist/index.mjs +66 -31
- package/docs/CLI_PROVIDERS.md +2 -0
- package/docs/TROUBLESHOOTING.md +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.1.8] - 2026-09-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Resolve explicitly selected CLI names through Windows `PATH` and `PATHEXT` before spawning, including Cursor's `agent.cmd` and legacy `cursor-agent.cmd` shims.
|
|
15
|
+
- Launch Windows `.cmd` and `.bat` shims through `cmd.exe` while keeping native executables on the direct spawn path.
|
|
16
|
+
|
|
17
|
+
### Tests
|
|
18
|
+
|
|
19
|
+
- Cover Windows `PATHEXT` resolution for explicit `agent` and `cursor-agent` commands and safely quoted batch-shim invocation.
|
|
20
|
+
|
|
21
|
+
## [0.1.7] - 2026-09-24
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Detect and launch Windows `.cmd` and `.bat` CLI shims through `cmd.exe` while keeping native executables on the direct spawn path.
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
|
|
29
|
+
- Cover Windows `PATHEXT` shim resolution and safely quoted batch-shim invocation.
|
|
30
|
+
|
|
10
31
|
## [0.1.6] - 2026-09-24
|
|
11
32
|
|
|
12
33
|
### Added
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { basename, dirname, extname, isAbsolute, join, normalize, relative, resolve } from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { config } from "dotenv";
|
|
5
6
|
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
@@ -2477,6 +2478,65 @@ function createOpenCodeProvider(apiKey, model, plan = OPENCODE_PLANS.ZEN) {
|
|
|
2477
2478
|
} };
|
|
2478
2479
|
}
|
|
2479
2480
|
//#endregion
|
|
2481
|
+
//#region src/llm/cli-command.ts
|
|
2482
|
+
/** Platform-specific executable lookup and process invocation for local CLIs. */
|
|
2483
|
+
const WINDOWS_EXECUTABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
2484
|
+
".COM",
|
|
2485
|
+
".EXE",
|
|
2486
|
+
".BAT",
|
|
2487
|
+
".CMD"
|
|
2488
|
+
]);
|
|
2489
|
+
const WINDOWS_BATCH_EXTENSIONS = /* @__PURE__ */ new Set([".BAT", ".CMD"]);
|
|
2490
|
+
function executableExtensions(command, isWindows, pathExt = process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD") {
|
|
2491
|
+
const commandExtension = isWindows ? path.win32.extname(command) : extname(command);
|
|
2492
|
+
if (!isWindows || commandExtension) return [""];
|
|
2493
|
+
return pathExt.split(";").filter((extension) => WINDOWS_EXECUTABLE_EXTENSIONS.has(extension.toUpperCase()));
|
|
2494
|
+
}
|
|
2495
|
+
function executableCandidates(command, options = {}) {
|
|
2496
|
+
const isWindows = (options.platform ?? process.platform) === "win32";
|
|
2497
|
+
const pathApi = isWindows ? path.win32 : path;
|
|
2498
|
+
const hasDirectory = pathApi.isAbsolute(command) || command.includes("/") || command.includes("\\");
|
|
2499
|
+
const pathValue = options.pathValue ?? process.env.PATH ?? process.env.Path ?? "";
|
|
2500
|
+
const pathDelimiter = isWindows ? ";" : path.delimiter;
|
|
2501
|
+
const bases = hasDirectory ? [pathApi.resolve(command)] : pathValue.split(pathDelimiter).filter(Boolean).map((directory) => pathApi.join(directory, command));
|
|
2502
|
+
const extensions = executableExtensions(command, isWindows, options.pathExt);
|
|
2503
|
+
return bases.flatMap((base) => extensions.map((extension) => extension ? `${base}${extension}` : base));
|
|
2504
|
+
}
|
|
2505
|
+
function findExecutable(command, options = {}) {
|
|
2506
|
+
const isWindows = (options.platform ?? process.platform) === "win32";
|
|
2507
|
+
const canAccess = options.canAccess ?? ((candidate, windows) => {
|
|
2508
|
+
try {
|
|
2509
|
+
accessSync(candidate, windows ? constants.F_OK : constants.X_OK);
|
|
2510
|
+
return true;
|
|
2511
|
+
} catch {
|
|
2512
|
+
return false;
|
|
2513
|
+
}
|
|
2514
|
+
});
|
|
2515
|
+
for (const candidate of executableCandidates(command, options)) if (canAccess(candidate, isWindows)) return candidate;
|
|
2516
|
+
}
|
|
2517
|
+
function quoteCmdToken(value) {
|
|
2518
|
+
if (/[%"\0\r\n]/.test(value)) throw new Error("Windows CLI arguments cannot contain percent signs, quotes, or line breaks.");
|
|
2519
|
+
return `"${value}"`;
|
|
2520
|
+
}
|
|
2521
|
+
function buildCliSpawnTarget(command, args, platform = process.platform, comspec = process.env.ComSpec ?? process.env.COMSPEC ?? "cmd.exe") {
|
|
2522
|
+
const extension = extname(command).toUpperCase();
|
|
2523
|
+
if (platform !== "win32" || !WINDOWS_BATCH_EXTENSIONS.has(extension)) return {
|
|
2524
|
+
command,
|
|
2525
|
+
args
|
|
2526
|
+
};
|
|
2527
|
+
return {
|
|
2528
|
+
command: comspec,
|
|
2529
|
+
args: [
|
|
2530
|
+
"/d",
|
|
2531
|
+
"/s",
|
|
2532
|
+
"/v:off",
|
|
2533
|
+
"/c",
|
|
2534
|
+
`"${[command, ...args].map(quoteCmdToken).join(" ")}"`
|
|
2535
|
+
],
|
|
2536
|
+
windowsVerbatimArguments: true
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
//#endregion
|
|
2480
2540
|
//#region src/llm/cli.ts
|
|
2481
2541
|
/**
|
|
2482
2542
|
* Local authenticated CLI providers. These CLIs receive the complete review
|
|
@@ -2520,11 +2580,14 @@ function sanitizeStderr(stderr) {
|
|
|
2520
2580
|
}
|
|
2521
2581
|
function runCli({ command, args, cwd, input, timeoutMs, label, env, keepCredentialEnvKeys }) {
|
|
2522
2582
|
return new Promise((resolve, reject) => {
|
|
2523
|
-
const
|
|
2583
|
+
const childEnv = createChildEnv(env, keepCredentialEnvKeys);
|
|
2584
|
+
const target = buildCliSpawnTarget(findExecutable(command, { pathValue: childEnv.PATH ?? childEnv.Path }) ?? command, args);
|
|
2585
|
+
const child = spawn(target.command, target.args, {
|
|
2524
2586
|
cwd,
|
|
2525
|
-
env:
|
|
2587
|
+
env: childEnv,
|
|
2526
2588
|
shell: false,
|
|
2527
2589
|
windowsHide: true,
|
|
2590
|
+
...target.windowsVerbatimArguments ? { windowsVerbatimArguments: true } : {},
|
|
2528
2591
|
stdio: [
|
|
2529
2592
|
"pipe",
|
|
2530
2593
|
"pipe",
|
|
@@ -3003,9 +3066,6 @@ function createOpenCodeCliProvider(command, model, timeoutMs) {
|
|
|
3003
3066
|
}
|
|
3004
3067
|
//#endregion
|
|
3005
3068
|
//#region src/llm/index.ts
|
|
3006
|
-
/**
|
|
3007
|
-
* LLM provider factory and local CLI auto-detection.
|
|
3008
|
-
*/
|
|
3009
3069
|
const AUTO_DETECT_CLI_ORDER = [
|
|
3010
3070
|
PROVIDERS.CODEX_CLI,
|
|
3011
3071
|
PROVIDERS.CLAUDE_CODE,
|
|
@@ -3026,31 +3086,6 @@ function commandCandidates(id, config) {
|
|
|
3026
3086
|
if (id === PROVIDERS.CURSOR_AGENT) return [CLI_DEFAULT_COMMANDS[id], CURSOR_AGENT_LEGACY_COMMAND];
|
|
3027
3087
|
return [CLI_DEFAULT_COMMANDS[id]];
|
|
3028
3088
|
}
|
|
3029
|
-
function commandSearchBases(command) {
|
|
3030
|
-
if (isAbsolute(command) || command.includes("/") || command.includes("\\")) return [resolve(command)];
|
|
3031
|
-
return (process.env.PATH ?? process.env.Path ?? "").split(delimiter).filter(Boolean).map((dir) => join(dir, command));
|
|
3032
|
-
}
|
|
3033
|
-
function executableExtensions(command, isWindows) {
|
|
3034
|
-
if (!isWindows || extname(command)) return [""];
|
|
3035
|
-
return (process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter((extension) => [".COM", ".EXE"].includes(extension.toUpperCase()));
|
|
3036
|
-
}
|
|
3037
|
-
function canExecute(path, isWindows) {
|
|
3038
|
-
try {
|
|
3039
|
-
accessSync(path, isWindows ? constants.F_OK : constants.X_OK);
|
|
3040
|
-
return true;
|
|
3041
|
-
} catch {
|
|
3042
|
-
return false;
|
|
3043
|
-
}
|
|
3044
|
-
}
|
|
3045
|
-
function findExecutable(command) {
|
|
3046
|
-
const isWindows = process.platform === "win32";
|
|
3047
|
-
const bases = commandSearchBases(command);
|
|
3048
|
-
const extensions = executableExtensions(command, isWindows);
|
|
3049
|
-
for (const base of bases) for (const extension of extensions) {
|
|
3050
|
-
const candidate = extension ? `${base}${extension}` : base;
|
|
3051
|
-
if (canExecute(candidate, isWindows)) return candidate;
|
|
3052
|
-
}
|
|
3053
|
-
}
|
|
3054
3089
|
function hasOpenCodeModel(config) {
|
|
3055
3090
|
const model = config.criticModel;
|
|
3056
3091
|
const separator = model?.indexOf("/") ?? -1;
|
package/docs/CLI_PROVIDERS.md
CHANGED
|
@@ -8,6 +8,8 @@ The CLI is installed locally, but its model request still goes to the provider.
|
|
|
8
8
|
|
|
9
9
|
When `CRITIC_PROVIDER` is empty or unset, Vibe-Gate checks local CLI executables in this order: Codex (`codex`), Claude Code (`claude`), Cursor Agent (`agent`, then legacy `cursor-agent`), and OpenCode CLI (`opencode`). OpenCode CLI is considered only with a `provider/model` `CRITIC_MODEL`, and that model format moves it to the front of the default order. Configured `*_CLI_PATH` values are checked before default PATH names, using the same provider order. The first tool response reports the selected CLI in `providerNotice`. Detection checks whether the executable is available; it does not verify that the CLI is signed in. If the selected CLI needs login, Vibe-Gate returns its error and does not switch to another account or service. If no local CLI is found, Vibe-Gate retains its OpenAI default and requires `OPENAI_API_KEY`. Set `CRITIC_PROVIDER` to select a provider explicitly.
|
|
10
10
|
|
|
11
|
+
On Windows, command names are resolved through `PATH` and `PATHEXT` for `.COM`, `.EXE`, `.BAT`, and `.CMD` files whether `CRITIC_PROVIDER` is automatic or explicitly set. Batch shims (`.bat` and `.cmd`) run through `cmd.exe`; native executables run directly.
|
|
12
|
+
|
|
11
13
|
| `CRITIC_PROVIDER` | Command | Sign in | Model selection |
|
|
12
14
|
| ----------------- | ----------------------------------------- | ---------------------------------------------- | -------------------------------------------------- |
|
|
13
15
|
| `codex-cli` | `codex` | `codex login` | Optional `CRITIC_MODEL` |
|
package/docs/TROUBLESHOOTING.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
### Local CLI not found or not authenticated
|
|
18
18
|
|
|
19
|
-
**Cause:** IDE-launched MCP servers may have a shorter `PATH` than an interactive terminal, or the CLI may not have an account session for this OS user.
|
|
19
|
+
**Cause:** IDE-launched MCP servers may have a shorter `PATH` than an interactive terminal, or the CLI may not have an account session for this OS user. On Windows, the CLI shim may be a `.cmd` or `.bat` file listed in `PATHEXT`.
|
|
20
20
|
|
|
21
21
|
**Fix:** Run the CLI's login flow in a terminal as the same user running the IDE, then set its matching `*_CLI_PATH` to the absolute executable path if needed. For Cursor, `cursor-agent` remains the `CRITIC_PROVIDER` value, while the current executable is `agent`; `cursor-agent` is only a legacy fallback. For Claude Code, `claude auth login` defaults to Claude subscription sign-in; `--console` selects API billing. See [CLI_PROVIDERS.md](CLI_PROVIDERS.md) for provider-specific setup.
|
|
22
22
|
|