@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 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 prefix = toolName.startsWith('mcp__') ? '[mcp]' : '[tool]';
239
- process.stderr.write(`[bridge] ${prefix} ${toolName}\n`);
240
- if (verbose) {
241
- const input = block['input'];
242
- process.stderr.write(`[bridge:verbose] ─── input ${toolName} ───\n${formatPayload(input)}\n[bridge:verbose] ─── end input ───\n`);
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
- process.stderr.write(text.replace(/\n+/g, ' '));
273
- wroteText = true;
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
- process.stderr.write(`[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───\n`);
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "Run 1Presence on your Mac and use your Claude.ai Pro subscription from any device",
5
5
  "bin": {
6
6
  "1presence-bridge": "dist/index.js"