claude-bridge-cli 1.5.1 → 2.0.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/bin/cli.js +23 -15
- package/lib/bridge.js +33 -4
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -128,12 +128,11 @@ Options:
|
|
|
128
128
|
Relay options (connect to a remote relay server):
|
|
129
129
|
--relay-url <url> WebSocket URL of the relay server
|
|
130
130
|
--machine <name> Machine name for the relay
|
|
131
|
-
--token <bearer> Machine bearer (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
machines you don't want to leave any saved bearer on.
|
|
131
|
+
--token <bearer> Machine bearer (skips both auth.json and pair flow)
|
|
132
|
+
--save-auth Cache the bearer in ~/.claude-bridge/auth.json so the
|
|
133
|
+
next start reuses it. Required for unattended /
|
|
134
|
+
systemd-service installs. WITHOUT this flag the CLI
|
|
135
|
+
re-pairs (browser OTP) on every start — the default.
|
|
137
136
|
--cf-id <id> Cloudflare Access Client ID (optional)
|
|
138
137
|
--cf-secret <secret> Cloudflare Access Client Secret (optional)
|
|
139
138
|
|
|
@@ -141,7 +140,9 @@ Environment variables:
|
|
|
141
140
|
All options can be set via env vars with BRIDGE_ prefix:
|
|
142
141
|
BRIDGE_PORT, BRIDGE_HOST, BRIDGE_CWD, BRIDGE_TIMEOUT,
|
|
143
142
|
BRIDGE_RELAY_URL, BRIDGE_MACHINE_NAME, BRIDGE_MACHINE_TOKEN,
|
|
144
|
-
|
|
143
|
+
BRIDGE_SAVE_AUTH=1 (cache the bearer to ~/.claude-bridge/auth.json
|
|
144
|
+
for unattended restarts; default re-pairs every
|
|
145
|
+
start so nothing is persisted),
|
|
145
146
|
BRIDGE_CF_ID, BRIDGE_CF_SECRET
|
|
146
147
|
`;
|
|
147
148
|
|
|
@@ -169,7 +170,8 @@ function main() {
|
|
|
169
170
|
"relay-url": { type: "string", default: env("RELAY_URL", "") },
|
|
170
171
|
machine: { type: "string", default: env("MACHINE_NAME", "") },
|
|
171
172
|
token: { type: "string", default: env("MACHINE_TOKEN", "") },
|
|
172
|
-
|
|
173
|
+
"save-auth":{ type: "boolean", default: env("SAVE_AUTH", "") === "1" },
|
|
174
|
+
ephemeral: { type: "boolean", default: false }, // deprecated, now default behavior — kept as a no-op for compatibility
|
|
173
175
|
"cf-id": { type: "string", default: env("CF_ID", "") },
|
|
174
176
|
"cf-secret": { type: "string", default: env("CF_SECRET", "") },
|
|
175
177
|
},
|
|
@@ -186,7 +188,10 @@ function main() {
|
|
|
186
188
|
url: values["relay-url"],
|
|
187
189
|
machine: values.machine,
|
|
188
190
|
token: values.token,
|
|
189
|
-
ephemeral
|
|
191
|
+
// Default = ephemeral (pair on every start, never persist). Opt in
|
|
192
|
+
// to caching with --save-auth when running unattended / as a service.
|
|
193
|
+
// The legacy --ephemeral flag is a no-op (kept for back-compat).
|
|
194
|
+
saveAuth: !!values["save-auth"],
|
|
190
195
|
cfId: values["cf-id"],
|
|
191
196
|
cfSecret: values["cf-secret"],
|
|
192
197
|
} : null,
|
|
@@ -250,19 +255,22 @@ async function run(config) {
|
|
|
250
255
|
}
|
|
251
256
|
// Resolve a bearer:
|
|
252
257
|
// --token → use it directly (never look at auth.json)
|
|
253
|
-
// --
|
|
254
|
-
// default
|
|
258
|
+
// --save-auth → reuse saved auth.json; pair only if no entry exists
|
|
259
|
+
// default (no flags) → pair fresh on every start, never read or write
|
|
260
|
+
// auth.json (most secure; requires user at the
|
|
261
|
+
// keyboard for every launch)
|
|
255
262
|
if (!config.relay.token) {
|
|
256
|
-
const saved = config.relay.
|
|
257
|
-
?
|
|
258
|
-
:
|
|
263
|
+
const saved = config.relay.saveAuth
|
|
264
|
+
? lookupSavedBearer(config.relay.url, config.relay.machine)
|
|
265
|
+
: null;
|
|
259
266
|
if (saved) {
|
|
260
267
|
config.relay.token = saved;
|
|
261
268
|
console.log(`[bridge] Using saved bearer from ${authFilePath()}`);
|
|
262
269
|
} else {
|
|
263
270
|
try {
|
|
271
|
+
// ephemeral == NOT saveAuth: don't write back when pair completes.
|
|
264
272
|
config.relay.token = await pairInteractive(
|
|
265
|
-
config.relay.url, config.relay.machine, config.relay.
|
|
273
|
+
config.relay.url, config.relay.machine, /* ephemeral */ !config.relay.saveAuth
|
|
266
274
|
);
|
|
267
275
|
} catch (e) {
|
|
268
276
|
console.error(`[bridge] ERROR: ${e.message}`);
|
package/lib/bridge.js
CHANGED
|
@@ -290,15 +290,44 @@ const INTERNAL_USER_PATTERNS = [
|
|
|
290
290
|
function extractUserText(content) {
|
|
291
291
|
// Only extract type:"text" parts. tool_result records don't have a text
|
|
292
292
|
// part so they return empty string and get filtered out.
|
|
293
|
-
|
|
294
|
-
if (
|
|
293
|
+
let raw = "";
|
|
294
|
+
if (typeof content === "string") raw = content;
|
|
295
|
+
else if (Array.isArray(content)) {
|
|
295
296
|
for (const part of content) {
|
|
296
297
|
if (part && typeof part === "object" && part.type === "text") {
|
|
297
|
-
|
|
298
|
+
raw = part.text || "";
|
|
299
|
+
break;
|
|
298
300
|
}
|
|
299
301
|
}
|
|
300
302
|
}
|
|
301
|
-
return
|
|
303
|
+
return resolveAtFileRefs(raw);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// When the bridge sends a multi-line prompt to claude on Windows it writes
|
|
307
|
+
// the prompt to a temp file and passes "@C:\...\claude-prompt-NNN.txt" as
|
|
308
|
+
// the -p arg. claude records that literal @path in the session JSONL as
|
|
309
|
+
// the user message. When we read the session back we want to show the
|
|
310
|
+
// actual content, not the path — otherwise history looks like a wall of
|
|
311
|
+
// temp-file paths. If the file still exists on disk, inline its contents;
|
|
312
|
+
// otherwise leave the @path alone so the user at least sees something.
|
|
313
|
+
function resolveAtFileRefs(text) {
|
|
314
|
+
if (!text || typeof text !== "string") return text;
|
|
315
|
+
// Match a leading @<path> that points at a claude-prompt-*.txt temp file.
|
|
316
|
+
// Restrict to the temp-file pattern we generate ourselves — never inline
|
|
317
|
+
// arbitrary user-typed @file references (which are a real Claude Code
|
|
318
|
+
// feature that should remain as-is).
|
|
319
|
+
const trimmed = text.trim();
|
|
320
|
+
if (!trimmed.startsWith("@")) return text;
|
|
321
|
+
const m = trimmed.match(/^@(.+?claude-prompt-\d+-[a-z0-9]+\.txt)\s*$/i);
|
|
322
|
+
if (!m) return text;
|
|
323
|
+
const filePath = m[1];
|
|
324
|
+
try {
|
|
325
|
+
if (fs.existsSync(filePath)) {
|
|
326
|
+
const body = fs.readFileSync(filePath, "utf8");
|
|
327
|
+
if (body && body.length) return body;
|
|
328
|
+
}
|
|
329
|
+
} catch {}
|
|
330
|
+
return text;
|
|
302
331
|
}
|
|
303
332
|
|
|
304
333
|
function shouldSkipUserText(text) {
|
package/package.json
CHANGED