baychat 0.17.0 → 0.17.1
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/dist/connect.js +48 -1
- package/dist/relay/commands.js +8 -8
- package/dist/runtime-binary.js +18 -0
- package/package.json +1 -1
package/dist/connect.js
CHANGED
|
@@ -32,8 +32,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
32
32
|
};
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
34
|
exports.renderConnectMenu = renderConnectMenu;
|
|
35
|
+
exports.isClaudeConnectTarget = isClaudeConnectTarget;
|
|
35
36
|
exports.parseConnectClient = parseConnectClient;
|
|
36
37
|
exports.writeClientConfig = writeClientConfig;
|
|
38
|
+
exports.cmdConnectClaude = cmdConnectClaude;
|
|
37
39
|
exports.cmdConnect = cmdConnect;
|
|
38
40
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
39
41
|
const node_path_1 = __importDefault(require("node:path"));
|
|
@@ -61,14 +63,32 @@ function renderConnectMenu() {
|
|
|
61
63
|
"Connect this laptop to BayChat, once, and configure your client:",
|
|
62
64
|
"",
|
|
63
65
|
...rows,
|
|
66
|
+
" npx baychat connect claude → Claude Code (refreshes its skill)",
|
|
64
67
|
"",
|
|
65
68
|
"You approve a QR on your phone. After that, in any coding session:",
|
|
66
69
|
"",
|
|
67
70
|
" /baychat <name> join BayChat as a session called <name>",
|
|
68
71
|
"",
|
|
69
|
-
"Claude Code
|
|
72
|
+
"First-time Claude Code setup is `npx baychat login` — it registers the MCP",
|
|
73
|
+
"server AND writes the skill. After that, `connect claude` refreshes the skill",
|
|
74
|
+
"on its own: no QR, no re-pairing. Run it after every CLI upgrade.",
|
|
70
75
|
].join("\n");
|
|
71
76
|
}
|
|
77
|
+
/** Spellings of Claude Code accepted by `connect`. */
|
|
78
|
+
const CLAUDE_CONNECT_ALIASES = new Set(["claude", "claude-code", "claudecode"]);
|
|
79
|
+
/**
|
|
80
|
+
* Is this `connect` argument Claude Code?
|
|
81
|
+
*
|
|
82
|
+
* Claude Code is deliberately NOT in `MCP_CLIENTS`: that list is clients whose
|
|
83
|
+
* MCP config is a file we write, and Claude Code's is registered by
|
|
84
|
+
* `claude mcp add` instead. But refusing the word entirely made the runtime this
|
|
85
|
+
* product is mostly used from the only one you could not `connect` — and sent a
|
|
86
|
+
* user whose credential was perfectly valid to `login`, which opens a pairing QR,
|
|
87
|
+
* when all they needed was the skill file refreshed after a CLI upgrade.
|
|
88
|
+
*/
|
|
89
|
+
function isClaudeConnectTarget(value) {
|
|
90
|
+
return CLAUDE_CONNECT_ALIASES.has(value.trim().toLowerCase());
|
|
91
|
+
}
|
|
72
92
|
/**
|
|
73
93
|
* Narrow a client argument.
|
|
74
94
|
*
|
|
@@ -159,11 +179,38 @@ const realIo = {
|
|
|
159
179
|
*
|
|
160
180
|
* @returns 0 on success, 2 when the laptop login expired without approval.
|
|
161
181
|
*/
|
|
182
|
+
/**
|
|
183
|
+
* `baychat connect claude` — refresh Claude Code's skill.
|
|
184
|
+
*
|
|
185
|
+
* Deliberately does NOT touch the credential or the MCP registration. Both are
|
|
186
|
+
* `login`'s job, and re-doing them would put a device-pairing QR in front of
|
|
187
|
+
* somebody whose login is fine. Writing the skill needs no auth at all: it is
|
|
188
|
+
* generated locally from this CLI's own version, which is exactly why it goes
|
|
189
|
+
* stale on upgrade and exactly why this command has to exist.
|
|
190
|
+
*/
|
|
191
|
+
function cmdConnectClaude() {
|
|
192
|
+
try {
|
|
193
|
+
for (const line of (0, runtime_install_1.describeInstall)((0, runtime_install_1.installRuntimeCommand)("claude")))
|
|
194
|
+
console.log(` ${line}`);
|
|
195
|
+
console.log("");
|
|
196
|
+
console.log(" Restart Claude Code once so it picks the skill up.");
|
|
197
|
+
console.log(" Not logged in yet? `npx baychat login` — that registers the MCP server too.");
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
console.log(`Could not install the Claude Code skill: ${err instanceof Error ? err.message : String(err)}`);
|
|
202
|
+
return 1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
162
205
|
async function cmdConnect(clientArg, opts = {}) {
|
|
163
206
|
if (clientArg === undefined) {
|
|
164
207
|
console.log(renderConnectMenu());
|
|
165
208
|
return 0;
|
|
166
209
|
}
|
|
210
|
+
// Claude Code first: it is not an MCP-config client, so it must not reach
|
|
211
|
+
// `parseConnectClient`, which would reject it.
|
|
212
|
+
if (isClaudeConnectTarget(clientArg))
|
|
213
|
+
return cmdConnectClaude();
|
|
167
214
|
const client = parseConnectClient(clientArg);
|
|
168
215
|
const base = (opts.base || process.env.BAYCHAT_API_URL || config_1.DEFAULT_API_URL).replace(/\/$/, "");
|
|
169
216
|
const steps = (0, connect_plan_1.planConnect)({
|
package/dist/relay/commands.js
CHANGED
|
@@ -746,7 +746,7 @@ async function cmdRelayAttach(opts) {
|
|
|
746
746
|
* bare name, which is exactly the behaviour that shipped before this existed — a
|
|
747
747
|
* machine where PATH is fine keeps working, and one where it is not now works too.
|
|
748
748
|
*/
|
|
749
|
-
function resolveRuntimeBin(runtime) {
|
|
749
|
+
function resolveRuntimeBin(runtime, env = process.env, execPath = process.execPath) {
|
|
750
750
|
// Delegates to the prover rather than walking PATH itself. The hand-rolled
|
|
751
751
|
// walk this replaces had two Windows faults, and both produced a recorded
|
|
752
752
|
// path the daemon could never spawn:
|
|
@@ -763,7 +763,7 @@ function resolveRuntimeBin(runtime) {
|
|
|
763
763
|
// `resolveRuntimeBinary` tries the platform's real extension order and PROVES
|
|
764
764
|
// each candidate by running it, which is the same question this function was
|
|
765
765
|
// always asking — just answered correctly.
|
|
766
|
-
const decided = decideRuntimeBin(runtime);
|
|
766
|
+
const decided = decideRuntimeBin(runtime, env, execPath);
|
|
767
767
|
return decided.ok ? decided.bin : undefined;
|
|
768
768
|
}
|
|
769
769
|
/**
|
|
@@ -775,16 +775,16 @@ function resolveRuntimeBin(runtime) {
|
|
|
775
775
|
* then re-probed could still register `runtimeBin: undefined` — the exact state
|
|
776
776
|
* the guard exists to prevent, reached by way of the guard.
|
|
777
777
|
*/
|
|
778
|
-
function decideRuntimeBin(runtime) {
|
|
779
|
-
const override =
|
|
780
|
-
const resolved = (0, runtime_binary_1.resolveRuntimeBinary)(runtime, (0, runtime_binary_1.currentBinaryEnv)(override));
|
|
778
|
+
function decideRuntimeBin(runtime, env = process.env, execPath = process.execPath) {
|
|
779
|
+
const override = env[`BAYCHAT_${runtime.toUpperCase()}_BIN`];
|
|
780
|
+
const resolved = (0, runtime_binary_1.resolveRuntimeBinary)(runtime, (0, runtime_binary_1.currentBinaryEnv)(override, env, execPath));
|
|
781
781
|
if (!resolved.ok) {
|
|
782
782
|
// An explicit override is a user ASSERTION. If it cannot be proven, stop —
|
|
783
783
|
// see the guard in `cmdRelayAttach`. Absence of one is not an assertion, so
|
|
784
784
|
// a plain failed probe keeps the best-effort fallback.
|
|
785
785
|
if (override)
|
|
786
786
|
return { ok: false, reason: (0, runtime_binary_1.summarizeResolutionFailure)(resolved) };
|
|
787
|
-
return { ok: true, bin: managedRuntimeBin(runtime) };
|
|
787
|
+
return { ok: true, bin: managedRuntimeBin(runtime, env) };
|
|
788
788
|
}
|
|
789
789
|
try {
|
|
790
790
|
// Resolve symlinks: ~/.local/bin/claude is typically a link into a versioned
|
|
@@ -797,10 +797,10 @@ function decideRuntimeBin(runtime) {
|
|
|
797
797
|
return { ok: true, bin: resolved.path };
|
|
798
798
|
}
|
|
799
799
|
}
|
|
800
|
-
function managedRuntimeBin(runtime) {
|
|
800
|
+
function managedRuntimeBin(runtime, env = process.env) {
|
|
801
801
|
if (runtime !== "codex")
|
|
802
802
|
return undefined;
|
|
803
|
-
const root =
|
|
803
|
+
const root = env.CODEX_MANAGED_PACKAGE_ROOT?.trim();
|
|
804
804
|
if (!root)
|
|
805
805
|
return undefined;
|
|
806
806
|
const candidate = path.join(root, "bin", "codex.js");
|
package/dist/runtime-binary.js
CHANGED
|
@@ -273,6 +273,24 @@ function currentBinaryEnv(override, env = process.env, execPath = process.execPa
|
|
|
273
273
|
timeout: PROBE_TIMEOUT_MS,
|
|
274
274
|
encoding: "utf8",
|
|
275
275
|
shell: false,
|
|
276
|
+
// THE PROBE MUST BE ABLE TO START WHAT IT IS PROBING.
|
|
277
|
+
//
|
|
278
|
+
// An npm runtime is a `#!/usr/bin/env node` script, and a spawn inherits
|
|
279
|
+
// THIS process's environment — the daemon's, under systemd, with no node
|
|
280
|
+
// on it. So probing the real binary died with
|
|
281
|
+
// `/usr/bin/env: 'node': No such file or directory`, the candidate was
|
|
282
|
+
// rejected as broken rather than unstartable, and resolution fell through
|
|
283
|
+
// to `/snap/bin/codex`.
|
|
284
|
+
//
|
|
285
|
+
// Measured 2026-09-01 18:00 from the daemon's log, after the PATH search
|
|
286
|
+
// was already fixed: `codex resolved to /snap/bin/codex (codex-cli
|
|
287
|
+
// 0.114.0)`, then `queue did not deliver ... this codex build has no
|
|
288
|
+
// \`queue\` subcommand`. The snap is 0.114.0; `queue` landed in 0.149.0.
|
|
289
|
+
// So a probe that could not start a shebang script cost Codex the one
|
|
290
|
+
// rung a live session can answer on.
|
|
291
|
+
//
|
|
292
|
+
// Same environment the spawn will use, for the same reason.
|
|
293
|
+
env: (0, spawn_env_1.headlessSpawnEnv)(env, execPath),
|
|
276
294
|
});
|
|
277
295
|
return summarizeProbe({
|
|
278
296
|
status: run.status,
|