@1presence/bridge 0.28.0 → 0.29.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/README.md +5 -0
- package/dist/claude.js +75 -14
- package/dist/index.js +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,11 @@ npx @1presence/bridge
|
|
|
15
15
|
|
|
16
16
|
On first run, a browser window will open to sign in to your 1Presence account. Your credentials are cached in `~/.1presence/auth.json` so subsequent runs start immediately.
|
|
17
17
|
|
|
18
|
+
### Flags
|
|
19
|
+
|
|
20
|
+
- `--debug` (`-d`) — print a clean per-turn transcript: the user prompt, the assistant's text, and every tool call's input and output. This mirrors what an admin sees in the chat's debug view. Use this when you want to follow the conversation and inspect tool calls.
|
|
21
|
+
- `--verbose` (`-v`) — log tool inputs/outputs plus the full system prompt and setup paths on every turn. Use this when debugging the prompt itself; for following messages and tool calls without the prompt dump, prefer `--debug`.
|
|
22
|
+
|
|
18
23
|
Once connected, your 1Presence app on any device automatically routes to your local Claude Code session. When you stop the bridge, 1Presence falls back to platform mode.
|
|
19
24
|
|
|
20
25
|
## How it works
|
package/dist/claude.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.setVerbose = setVerbose;
|
|
4
|
+
exports.setDebug = setDebug;
|
|
4
5
|
exports.spawnClaude = spawnClaude;
|
|
5
6
|
exports.killAll = killAll;
|
|
6
7
|
const child_process_1 = require("child_process");
|
|
@@ -36,9 +37,17 @@ const config_1 = require("./config");
|
|
|
36
37
|
// Track whether we've already announced the model this process — printing it
|
|
37
38
|
// per-spawn is noisy; once on startup is what the user actually wants to see.
|
|
38
39
|
let modelAnnounced = false;
|
|
39
|
-
// Verbose flag — when set via --verbose, log full tool inputs and outputs
|
|
40
|
+
// Verbose flag — when set via --verbose, log full tool inputs and outputs
|
|
41
|
+
// PLUS the entire system prompt. Great for prompt debugging, noisy for
|
|
42
|
+
// message debugging (the prompt dump buries the conversation).
|
|
40
43
|
let verbose = false;
|
|
41
44
|
function setVerbose(v) { verbose = v; }
|
|
45
|
+
// Debug flag — when set via --debug, render a clean, sectioned transcript of
|
|
46
|
+
// the live turn: user prompt, assistant text, every tool input, every tool
|
|
47
|
+
// result. This is the bridge equivalent of the chat's admin debug view. It
|
|
48
|
+
// deliberately does NOT print the system prompt — that's what --verbose is for.
|
|
49
|
+
let debug = false;
|
|
50
|
+
function setDebug(v) { debug = v; }
|
|
42
51
|
function formatPayload(value) {
|
|
43
52
|
try {
|
|
44
53
|
return JSON.stringify(value, null, 2);
|
|
@@ -47,6 +56,26 @@ function formatPayload(value) {
|
|
|
47
56
|
return String(value);
|
|
48
57
|
}
|
|
49
58
|
}
|
|
59
|
+
// ─── Debug transcript rendering ─────────────────────────────────────────────
|
|
60
|
+
//
|
|
61
|
+
// A clean, scannable block per event — coloured header rule + body. Matches
|
|
62
|
+
// the shape of the chat's admin debug bubbles (user / assistant / tool input /
|
|
63
|
+
// tool result) so what you see locally mirrors what an admin sees in the app.
|
|
64
|
+
const USE_COLOR = process.stderr.isTTY === true && !process.env['NO_COLOR'];
|
|
65
|
+
function paint(code, s) {
|
|
66
|
+
return USE_COLOR ? `\x1b[${code}m${s}\x1b[0m` : s;
|
|
67
|
+
}
|
|
68
|
+
// ANSI colour codes per section, mirroring the admin debug palette.
|
|
69
|
+
const DEBUG_COLORS = {
|
|
70
|
+
user: '34', // blue
|
|
71
|
+
assistant: '32', // green
|
|
72
|
+
input: '36', // cyan
|
|
73
|
+
result: '33', // yellow
|
|
74
|
+
};
|
|
75
|
+
function debugBlock(label, colorCode, body) {
|
|
76
|
+
const rule = `── ${label} `.padEnd(64, '─');
|
|
77
|
+
process.stderr.write(`\n${paint(colorCode, rule)}\n${body.trimEnd()}\n`);
|
|
78
|
+
}
|
|
50
79
|
// ─── Active processes ─────────────────────────────────────────────────────────
|
|
51
80
|
const active = new Map();
|
|
52
81
|
// ─── Spawn ────────────────────────────────────────────────────────────────────
|
|
@@ -61,6 +90,16 @@ function spawnClaude(params) {
|
|
|
61
90
|
process.stderr.write(`[bridge:verbose] mcp config: ${mcpConfigPath}\n`);
|
|
62
91
|
process.stderr.write(`[bridge:verbose] history turns: ${history.length}\n`);
|
|
63
92
|
}
|
|
93
|
+
// Debug transcript: lead with the user prompt for this turn (the clean
|
|
94
|
+
// message, before the gateway's ephemeral-context prefix), plus a hint at
|
|
95
|
+
// how much prior context is being replayed.
|
|
96
|
+
if (debug) {
|
|
97
|
+
const histNote = history.length ? ` (replaying ${history.length} prior turn${history.length === 1 ? '' : 's'})` : '';
|
|
98
|
+
debugBlock(`user${histNote}`, DEBUG_COLORS.user, text);
|
|
99
|
+
}
|
|
100
|
+
// tool_use_id → tool name, so a tool_result block (which only carries the id)
|
|
101
|
+
// can be labelled with the tool it answers in the debug transcript.
|
|
102
|
+
const toolNames = new Map();
|
|
64
103
|
// If a prior process is still running for this conversation (user sent a
|
|
65
104
|
// follow-up before the previous turn finished), supersede it. The latest
|
|
66
105
|
// user intent wins; the orphan would otherwise keep streaming events.
|
|
@@ -230,16 +269,25 @@ function spawnClaude(params) {
|
|
|
230
269
|
let wroteText = false;
|
|
231
270
|
for (const block of content) {
|
|
232
271
|
if (block['type'] === 'tool_use') {
|
|
233
|
-
if (wroteText) {
|
|
234
|
-
process.stderr.write('\n');
|
|
235
|
-
wroteText = false;
|
|
236
|
-
}
|
|
237
272
|
const toolName = block['name'];
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
273
|
+
const toolId = block['id'];
|
|
274
|
+
if (toolId)
|
|
275
|
+
toolNames.set(toolId, toolName);
|
|
276
|
+
if (debug) {
|
|
277
|
+
// Clean transcript: a single coloured block with the full input.
|
|
278
|
+
debugBlock(`tool → ${toolName}`, DEBUG_COLORS.input, formatPayload(block['input']));
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
if (wroteText) {
|
|
282
|
+
process.stderr.write('\n');
|
|
283
|
+
wroteText = false;
|
|
284
|
+
}
|
|
285
|
+
const prefix = toolName.startsWith('mcp__') ? '[mcp]' : '[tool]';
|
|
286
|
+
process.stderr.write(`[bridge] ${prefix} ${toolName}\n`);
|
|
287
|
+
if (verbose) {
|
|
288
|
+
const input = block['input'];
|
|
289
|
+
process.stderr.write(`[bridge:verbose] ─── input ${toolName} ───\n${formatPayload(input)}\n[bridge:verbose] ─── end input ───\n`);
|
|
290
|
+
}
|
|
243
291
|
}
|
|
244
292
|
// Defense-in-depth: CLI flags (--tools "", --allowedTools, --strict-mcp-config,
|
|
245
293
|
// --setting-sources "") are supposed to make this unreachable. If we see a
|
|
@@ -269,8 +317,14 @@ function spawnClaude(params) {
|
|
|
269
317
|
else if (block['type'] === 'text') {
|
|
270
318
|
const text = block['text'];
|
|
271
319
|
if (text) {
|
|
272
|
-
|
|
273
|
-
|
|
320
|
+
if (debug) {
|
|
321
|
+
// Full text, newlines intact — the readable transcript.
|
|
322
|
+
debugBlock('assistant', DEBUG_COLORS.assistant, text);
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
process.stderr.write(text.replace(/\n+/g, ' '));
|
|
326
|
+
wroteText = true;
|
|
327
|
+
}
|
|
274
328
|
}
|
|
275
329
|
}
|
|
276
330
|
}
|
|
@@ -279,7 +333,7 @@ function spawnClaude(params) {
|
|
|
279
333
|
}
|
|
280
334
|
}
|
|
281
335
|
// Tool results stream back as `user` events with tool_result blocks.
|
|
282
|
-
if (verbose && type === 'user') {
|
|
336
|
+
if ((verbose || debug) && type === 'user') {
|
|
283
337
|
const msg = event['message'];
|
|
284
338
|
const content = msg?.['content'];
|
|
285
339
|
if (Array.isArray(content)) {
|
|
@@ -287,7 +341,14 @@ function spawnClaude(params) {
|
|
|
287
341
|
if (block['type'] === 'tool_result') {
|
|
288
342
|
const id = block['tool_use_id'] ?? '';
|
|
289
343
|
const out = block['content'];
|
|
290
|
-
|
|
344
|
+
if (debug) {
|
|
345
|
+
const name = toolNames.get(id) ?? id ?? 'result';
|
|
346
|
+
const errFlag = block['is_error'] ? ' [error]' : '';
|
|
347
|
+
debugBlock(`result ← ${name}${errFlag}`, DEBUG_COLORS.result, formatPayload(out));
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
process.stderr.write(`[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───\n`);
|
|
351
|
+
}
|
|
291
352
|
}
|
|
292
353
|
}
|
|
293
354
|
}
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,10 @@ if (__dirname.endsWith('dist')) {
|
|
|
31
31
|
}
|
|
32
32
|
// ─── CLI args ─────────────────────────────────────────────────────────────────
|
|
33
33
|
const VERBOSE = process.argv.includes('--verbose') || process.argv.includes('-v');
|
|
34
|
+
// --debug renders a clean per-turn transcript (user prompt, assistant text,
|
|
35
|
+
// tool inputs, tool outputs) — the bridge equivalent of the chat's admin
|
|
36
|
+
// debug view. Unlike --verbose it does NOT dump the system prompt.
|
|
37
|
+
const DEBUG = process.argv.includes('--debug') || process.argv.includes('-d');
|
|
34
38
|
// ─── Config ───────────────────────────────────────────────────────────────────
|
|
35
39
|
const GATEWAY_URL = process.env.BRIDGE_GATEWAY_URL ?? 'https://api.1presence.com';
|
|
36
40
|
const GATEWAY_WS = GATEWAY_URL.replace(/^https?:/, 'wss:').replace(/\/$/, '') + '/bridge';
|
|
@@ -424,6 +428,10 @@ async function main() {
|
|
|
424
428
|
(0, claude_1.setVerbose)(true);
|
|
425
429
|
console.log('[bridge:verbose] verbose logging enabled — system prompts, tool inputs, and tool outputs will be printed.\n');
|
|
426
430
|
}
|
|
431
|
+
if (DEBUG) {
|
|
432
|
+
(0, claude_1.setDebug)(true);
|
|
433
|
+
console.log('[bridge:debug] debug transcript enabled — user prompts, assistant text, tool inputs, and tool outputs will be printed (system prompt omitted; use --verbose for that).\n');
|
|
434
|
+
}
|
|
427
435
|
if (await (0, update_1.checkAndUpdate)())
|
|
428
436
|
return;
|
|
429
437
|
// Auth
|