@1presence/bridge 0.28.0 → 0.30.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 +83 -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 ────────────────────────────────────────────────────────────────────
|
|
@@ -59,8 +88,26 @@ function spawnClaude(params) {
|
|
|
59
88
|
process.stderr.write(`[bridge:verbose] override md: ${(0, path_1.join)(BRIDGE_CWD, 'CLAUDE.md')}\n`);
|
|
60
89
|
process.stderr.write(`[bridge:verbose] system prompt: ${systemPromptPath}\n`);
|
|
61
90
|
process.stderr.write(`[bridge:verbose] mcp config: ${mcpConfigPath}\n`);
|
|
91
|
+
process.stderr.write(`[bridge:verbose] session id: ${presenceSessionId}\n`);
|
|
92
|
+
process.stderr.write(`[bridge:verbose] conversation: ${conversationId}\n`);
|
|
62
93
|
process.stderr.write(`[bridge:verbose] history turns: ${history.length}\n`);
|
|
63
94
|
}
|
|
95
|
+
// Debug transcript: lead with the user prompt for this turn (the clean
|
|
96
|
+
// message, before the gateway's ephemeral-context prefix), plus the session
|
|
97
|
+
// id (correlates with the chat URL / Firestore session doc) and a hint at
|
|
98
|
+
// how much prior context is being replayed.
|
|
99
|
+
if (debug) {
|
|
100
|
+
const histNote = history.length ? ` (replaying ${history.length} prior turn${history.length === 1 ? '' : 's'})` : '';
|
|
101
|
+
debugBlock(`user · session ${presenceSessionId}${histNote}`, DEBUG_COLORS.user, text);
|
|
102
|
+
}
|
|
103
|
+
else if (!verbose) {
|
|
104
|
+
// Default mode is quiet, but always surface the session id once per turn so
|
|
105
|
+
// it can be matched to the chat URL / Firestore session doc when debugging.
|
|
106
|
+
process.stderr.write(`[bridge] session ${presenceSessionId}\n`);
|
|
107
|
+
}
|
|
108
|
+
// tool_use_id → tool name, so a tool_result block (which only carries the id)
|
|
109
|
+
// can be labelled with the tool it answers in the debug transcript.
|
|
110
|
+
const toolNames = new Map();
|
|
64
111
|
// If a prior process is still running for this conversation (user sent a
|
|
65
112
|
// follow-up before the previous turn finished), supersede it. The latest
|
|
66
113
|
// user intent wins; the orphan would otherwise keep streaming events.
|
|
@@ -230,16 +277,25 @@ function spawnClaude(params) {
|
|
|
230
277
|
let wroteText = false;
|
|
231
278
|
for (const block of content) {
|
|
232
279
|
if (block['type'] === 'tool_use') {
|
|
233
|
-
if (wroteText) {
|
|
234
|
-
process.stderr.write('\n');
|
|
235
|
-
wroteText = false;
|
|
236
|
-
}
|
|
237
280
|
const toolName = block['name'];
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
281
|
+
const toolId = block['id'];
|
|
282
|
+
if (toolId)
|
|
283
|
+
toolNames.set(toolId, toolName);
|
|
284
|
+
if (debug) {
|
|
285
|
+
// Clean transcript: a single coloured block with the full input.
|
|
286
|
+
debugBlock(`tool → ${toolName}`, DEBUG_COLORS.input, formatPayload(block['input']));
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
if (wroteText) {
|
|
290
|
+
process.stderr.write('\n');
|
|
291
|
+
wroteText = false;
|
|
292
|
+
}
|
|
293
|
+
const prefix = toolName.startsWith('mcp__') ? '[mcp]' : '[tool]';
|
|
294
|
+
process.stderr.write(`[bridge] ${prefix} ${toolName}\n`);
|
|
295
|
+
if (verbose) {
|
|
296
|
+
const input = block['input'];
|
|
297
|
+
process.stderr.write(`[bridge:verbose] ─── input ${toolName} ───\n${formatPayload(input)}\n[bridge:verbose] ─── end input ───\n`);
|
|
298
|
+
}
|
|
243
299
|
}
|
|
244
300
|
// Defense-in-depth: CLI flags (--tools "", --allowedTools, --strict-mcp-config,
|
|
245
301
|
// --setting-sources "") are supposed to make this unreachable. If we see a
|
|
@@ -269,8 +325,14 @@ function spawnClaude(params) {
|
|
|
269
325
|
else if (block['type'] === 'text') {
|
|
270
326
|
const text = block['text'];
|
|
271
327
|
if (text) {
|
|
272
|
-
|
|
273
|
-
|
|
328
|
+
if (debug) {
|
|
329
|
+
// Full text, newlines intact — the readable transcript.
|
|
330
|
+
debugBlock('assistant', DEBUG_COLORS.assistant, text);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
process.stderr.write(text.replace(/\n+/g, ' '));
|
|
334
|
+
wroteText = true;
|
|
335
|
+
}
|
|
274
336
|
}
|
|
275
337
|
}
|
|
276
338
|
}
|
|
@@ -279,7 +341,7 @@ function spawnClaude(params) {
|
|
|
279
341
|
}
|
|
280
342
|
}
|
|
281
343
|
// Tool results stream back as `user` events with tool_result blocks.
|
|
282
|
-
if (verbose && type === 'user') {
|
|
344
|
+
if ((verbose || debug) && type === 'user') {
|
|
283
345
|
const msg = event['message'];
|
|
284
346
|
const content = msg?.['content'];
|
|
285
347
|
if (Array.isArray(content)) {
|
|
@@ -287,7 +349,14 @@ function spawnClaude(params) {
|
|
|
287
349
|
if (block['type'] === 'tool_result') {
|
|
288
350
|
const id = block['tool_use_id'] ?? '';
|
|
289
351
|
const out = block['content'];
|
|
290
|
-
|
|
352
|
+
if (debug) {
|
|
353
|
+
const name = toolNames.get(id) ?? id ?? 'result';
|
|
354
|
+
const errFlag = block['is_error'] ? ' [error]' : '';
|
|
355
|
+
debugBlock(`result ← ${name}${errFlag}`, DEBUG_COLORS.result, formatPayload(out));
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
process.stderr.write(`[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───\n`);
|
|
359
|
+
}
|
|
291
360
|
}
|
|
292
361
|
}
|
|
293
362
|
}
|
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
|