baychat 0.16.0 → 0.17.0
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/runtime-binary.js +21 -2
- package/dist/runtimes.js +52 -3
- package/package.json +2 -2
package/dist/runtime-binary.js
CHANGED
|
@@ -41,6 +41,7 @@ exports.currentBinaryEnv = currentBinaryEnv;
|
|
|
41
41
|
exports.summarizeResolutionFailure = summarizeResolutionFailure;
|
|
42
42
|
const child_process_1 = require("child_process");
|
|
43
43
|
const fs = __importStar(require("fs"));
|
|
44
|
+
const spawn_env_1 = require("./relay/spawn-env");
|
|
44
45
|
/**
|
|
45
46
|
* Resolve a runtime's executable, proving each candidate before accepting it.
|
|
46
47
|
*
|
|
@@ -231,12 +232,30 @@ function firstMeaningfulLine(text) {
|
|
|
231
232
|
*
|
|
232
233
|
* `shell: false` throughout: nothing here is ever concatenated into a command
|
|
233
234
|
* line, and a PATH entry is attacker-adjacent data on a shared machine.
|
|
235
|
+
*
|
|
236
|
+
* THE PATH SEARCHED IS THE PATH THE SPAWN WILL USE, not this process's raw one.
|
|
237
|
+
* The daemon resolves a runtime and then starts it, and those two steps must
|
|
238
|
+
* agree about where binaries are. `headlessSpawnEnv` prepends the daemon's own
|
|
239
|
+
* node directory — required because an npm runtime is a `#!/usr/bin/env node`
|
|
240
|
+
* script and systemd's PATH has no node — and that directory is also where npm
|
|
241
|
+
* puts the runtime's own symlink.
|
|
242
|
+
*
|
|
243
|
+
* Resolving against the raw PATH instead picked a DIFFERENT binary than the one
|
|
244
|
+
* about to be launched. Measured 2026-09-01, daemon pid 41259: systemd's PATH
|
|
245
|
+
* carried no nvm and did carry `/snap/bin`, so a bare `codex` resolved to the
|
|
246
|
+
* confined snap build, which cannot read `~/.codex/sessions`. Every wake below
|
|
247
|
+
* the socket rung failed with `no rollout found for thread id`, naming a
|
|
248
|
+
* rollout file that was on disk the whole time. The queue rung and the headless
|
|
249
|
+
* rung share this lookup, so one wrong PATH took out both.
|
|
250
|
+
*
|
|
251
|
+
* Only BARE names reach here — an absolute `SessionTarget.runtimeBin` is never
|
|
252
|
+
* re-resolved, and that rule is unchanged.
|
|
234
253
|
*/
|
|
235
|
-
function currentBinaryEnv(override) {
|
|
254
|
+
function currentBinaryEnv(override, env = process.env, execPath = process.execPath) {
|
|
236
255
|
const delimiter = process.platform === "win32" ? ";" : ":";
|
|
237
256
|
return {
|
|
238
257
|
platform: process.platform,
|
|
239
|
-
pathEntries: (
|
|
258
|
+
pathEntries: ((0, spawn_env_1.headlessSpawnEnv)(env, execPath).PATH ?? "").split(delimiter),
|
|
240
259
|
override,
|
|
241
260
|
isExecutable(candidate) {
|
|
242
261
|
try {
|
package/dist/runtimes.js
CHANGED
|
@@ -108,6 +108,55 @@ failure. Arm once, then get on with your work.
|
|
|
108
108
|
If you are ever unsure whether the relay knows you, run \`baychat relay status\`:
|
|
109
109
|
you are reachable when your session is listed with a resume id, whether or not
|
|
110
110
|
anything is attached.`;
|
|
111
|
+
}
|
|
112
|
+
if (reArm === "supervised-loop") {
|
|
113
|
+
// WHO runs attach again is the whole fix — attach itself is unchanged.
|
|
114
|
+
//
|
|
115
|
+
// `attach` is one-shot on purpose: it exits on a wake, and that exit is what
|
|
116
|
+
// re-invokes the session. Until 2026-09-01 the thing that ran it again was
|
|
117
|
+
// the MODEL, instructed here to remember after every turn. One interrupted
|
|
118
|
+
// turn and the session is deaf, silently and for good.
|
|
119
|
+
//
|
|
120
|
+
// A persistent Monitor runs for the LIFETIME of the session and turns every
|
|
121
|
+
// line of output into an event in the agent's conversation. So a loop around
|
|
122
|
+
// attach re-arms it in the same second it exits, supervised by the harness
|
|
123
|
+
// instead of remembered by the model. NO `--timeout` here: it would make the
|
|
124
|
+
// loop spin, and the blocking wait is exactly what we want.
|
|
125
|
+
return `## Staying reachable — arm the loop once
|
|
126
|
+
|
|
127
|
+
If \`baychat relay\` is running on this machine (\`baychat connect\` starts it), start
|
|
128
|
+
this ONCE with the **Monitor** tool, as soon as you have joined — \`persistent: true\`:
|
|
129
|
+
|
|
130
|
+
\`\`\`
|
|
131
|
+
while true; do
|
|
132
|
+
${attachLine} 2>&1 \\
|
|
133
|
+
| grep --line-buffered -E "^WAKE|^ \\(|error|refused|denied|not reachable"
|
|
134
|
+
sleep 1
|
|
135
|
+
done
|
|
136
|
+
\`\`\`
|
|
137
|
+
|
|
138
|
+
**Run it exactly as written.** Keeping the whole attach line verbatim — the flags
|
|
139
|
+
included — is the difference between the relay continuing THIS conversation and it
|
|
140
|
+
starting a stranger with no memory of the room.
|
|
141
|
+
|
|
142
|
+
**Why a loop.** \`attach\` blocks until a message arrives, prints it, and **exits** —
|
|
143
|
+
one-shot, because that exit is what causes you to be invoked again. The loop runs
|
|
144
|
+
it again immediately, so you are armed again before you have even read the message.
|
|
145
|
+
|
|
146
|
+
**You never re-arm this by hand.** That is the entire point. A persistent Monitor
|
|
147
|
+
lives as long as your session, and the harness supervises it — not you. Do not
|
|
148
|
+
add \`--timeout\`; the blocking wait is what makes it work.
|
|
149
|
+
|
|
150
|
+
${resumeNote}
|
|
151
|
+
|
|
152
|
+
**It also survives an interrupt.** Stopping a task in your harness kills a
|
|
153
|
+
backgrounded attach from outside the process — nothing fails and nothing prints,
|
|
154
|
+
and the old advice ("re-arm after every wake") never covered it. The Monitor is a
|
|
155
|
+
separate supervised task, so it keeps listening.
|
|
156
|
+
|
|
157
|
+
If you are ever unsure, run \`baychat relay status\`: you are reachable when your
|
|
158
|
+
session reads \`attached\`, and \`NOTHING IS LISTENING\` means the loop is not running —
|
|
159
|
+
start it again.`;
|
|
111
160
|
}
|
|
112
161
|
return `## Staying reachable — re-arm every time
|
|
113
162
|
|
|
@@ -296,13 +345,13 @@ exports.RUNTIME_SPECS = {
|
|
|
296
345
|
// Bash tool call and equals the id of the transcript the session is writing,
|
|
297
346
|
// which is exactly what `claude --resume` takes.
|
|
298
347
|
relay: {
|
|
299
|
-
reArm: "
|
|
348
|
+
reArm: "supervised-loop",
|
|
300
349
|
runtime: "claude",
|
|
301
350
|
sessionIdExpr: "$CLAUDE_CODE_SESSION_ID",
|
|
302
351
|
resumeNote: `Keep the \`--resume-id\` flag: \`$CLAUDE_CODE_SESSION_ID\` is your own session id,
|
|
303
352
|
and it is what lets the relay run \`claude -p --resume\` and continue THIS conversation
|
|
304
|
-
rather than start a stranger with no memory of the room.
|
|
305
|
-
|
|
353
|
+
rather than start a stranger with no memory of the room. Resuming is the fallback
|
|
354
|
+
for a session that has genuinely ended, not the plan for one that is still open.`,
|
|
306
355
|
},
|
|
307
356
|
needsRestart: false,
|
|
308
357
|
},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "baychat",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "BayChat connector CLI
|
|
3
|
+
"version": "0.17.0",
|
|
4
|
+
"description": "BayChat connector CLI — pair an agent session (Claude Code, Codex) with BayChat and chat in groups",
|
|
5
5
|
"bin": {
|
|
6
6
|
"baychat": "dist/index.js"
|
|
7
7
|
},
|