@1presence/bridge 0.31.0 → 0.33.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/claude.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SECTION_COLORS = void 0;
3
4
  exports.setVerbose = setVerbose;
4
5
  exports.setDebug = setDebug;
6
+ exports.paint = paint;
5
7
  exports.spawnClaude = spawnClaude;
6
8
  exports.killAll = killAll;
7
9
  const child_process_1 = require("child_process");
@@ -65,8 +67,12 @@ const USE_COLOR = process.stderr.isTTY === true && !process.env['NO_COLOR'];
65
67
  function paint(code, s) {
66
68
  return USE_COLOR ? `\x1b[${code}m${s}\x1b[0m` : s;
67
69
  }
68
- // ANSI colour codes per section, mirroring the admin debug palette.
69
- const DEBUG_COLORS = {
70
+ // ANSI colour codes per section, mirroring the admin debug palette. Shared
71
+ // across all three console modes (debug / verbose / normal) so the same kind
72
+ // of content is always the same colour — system prompts magenta, user prompts
73
+ // blue, assistant text green, tool inputs cyan, tool results yellow.
74
+ exports.SECTION_COLORS = {
75
+ system: '35', // magenta
70
76
  user: '34', // blue
71
77
  assistant: '32', // green
72
78
  input: '36', // cyan
@@ -97,7 +103,7 @@ function summariseHistoryBlock(block) {
97
103
  // can tell user turns from assistant turns at a glance — the missing
98
104
  // distinction that made replayed context unreadable in --debug.
99
105
  function renderHistoryMessage(msg) {
100
- const color = msg.role === 'user' ? DEBUG_COLORS.user : DEBUG_COLORS.assistant;
106
+ const color = msg.role === 'user' ? exports.SECTION_COLORS.user : exports.SECTION_COLORS.assistant;
101
107
  const body = typeof msg.content === 'string'
102
108
  ? msg.content
103
109
  : msg.content.map(summariseHistoryBlock).join('\n');
@@ -111,19 +117,19 @@ function spawnClaude(params) {
111
117
  const systemPromptPath = (0, path_1.join)((0, os_1.tmpdir)(), `agent-${uid}.md`);
112
118
  const mcpConfigPath = (0, path_1.join)((0, os_1.tmpdir)(), `mcp-${uid}.json`);
113
119
  if (verbose) {
114
- process.stderr.write(`[bridge:verbose] cwd: ${BRIDGE_CWD}\n`);
115
- process.stderr.write(`[bridge:verbose] override md: ${(0, path_1.join)(BRIDGE_CWD, 'CLAUDE.md')}\n`);
116
- process.stderr.write(`[bridge:verbose] system prompt: ${systemPromptPath}\n`);
117
- process.stderr.write(`[bridge:verbose] mcp config: ${mcpConfigPath}\n`);
118
- process.stderr.write(`[bridge:verbose] session id: ${presenceSessionId}\n`);
119
- process.stderr.write(`[bridge:verbose] conversation: ${conversationId}\n`);
120
- process.stderr.write(`[bridge:verbose] history turns: ${history.length}\n`);
120
+ process.stderr.write(paint('90', `[bridge:verbose] cwd: ${BRIDGE_CWD}`) + '\n');
121
+ process.stderr.write(paint('90', `[bridge:verbose] override md: ${(0, path_1.join)(BRIDGE_CWD, 'CLAUDE.md')}`) + '\n');
122
+ process.stderr.write(paint('90', `[bridge:verbose] system prompt: ${systemPromptPath}`) + '\n');
123
+ process.stderr.write(paint('90', `[bridge:verbose] mcp config: ${mcpConfigPath}`) + '\n');
124
+ process.stderr.write(paint('90', `[bridge:verbose] session id: ${presenceSessionId}`) + '\n');
125
+ process.stderr.write(paint('90', `[bridge:verbose] conversation: ${conversationId}`) + '\n');
126
+ process.stderr.write(paint('90', `[bridge:verbose] history turns: ${history.length}`) + '\n');
121
127
  }
122
128
  // Debug transcript: lead with the user prompt for this turn (the clean
123
129
  // message, before the gateway's ephemeral-context prefix), plus the session
124
130
  // id (correlates with the chat URL / Firestore session doc) and a hint at
125
131
  // how much prior context is being replayed.
126
- if (debug) {
132
+ if (debug || verbose) {
127
133
  process.stderr.write(`\n${paint('1', `══ session ${presenceSessionId} ══`)}\n`);
128
134
  // `history` already ends with the new user prompt (gateway-appended). Render
129
135
  // every PRIOR message with its role colour so what the model saw as context
@@ -137,9 +143,9 @@ function spawnClaude(params) {
137
143
  for (const msg of prior)
138
144
  renderHistoryMessage(msg);
139
145
  }
140
- debugBlock('user · this turn', DEBUG_COLORS.user, text);
146
+ debugBlock('user · this turn', exports.SECTION_COLORS.user, text);
141
147
  }
142
- else if (!verbose) {
148
+ else {
143
149
  // Default mode is quiet, but always surface the session id once per turn so
144
150
  // it can be matched to the chat URL / Firestore session doc when debugging.
145
151
  process.stderr.write(`[bridge] session ${presenceSessionId}\n`);
@@ -322,7 +328,7 @@ function spawnClaude(params) {
322
328
  toolNames.set(toolId, toolName);
323
329
  if (debug) {
324
330
  // Clean transcript: a single coloured block with the full input.
325
- debugBlock(`tool → ${toolName}`, DEBUG_COLORS.input, formatPayload(block['input']));
331
+ debugBlock(`tool → ${toolName}`, exports.SECTION_COLORS.input, formatPayload(block['input']));
326
332
  }
327
333
  else {
328
334
  if (wroteText) {
@@ -330,10 +336,10 @@ function spawnClaude(params) {
330
336
  wroteText = false;
331
337
  }
332
338
  const prefix = toolName.startsWith('mcp__') ? '[mcp]' : '[tool]';
333
- process.stderr.write(`[bridge] ${prefix} ${toolName}\n`);
339
+ process.stderr.write(paint(exports.SECTION_COLORS.input, `[bridge] ${prefix} ${toolName}`) + '\n');
334
340
  if (verbose) {
335
341
  const input = block['input'];
336
- process.stderr.write(`[bridge:verbose] ─── input ${toolName} ───\n${formatPayload(input)}\n[bridge:verbose] ─── end input ───\n`);
342
+ process.stderr.write(paint(exports.SECTION_COLORS.input, `[bridge:verbose] ─── input ${toolName} ───\n${formatPayload(input)}\n[bridge:verbose] ─── end input ───`) + '\n');
337
343
  }
338
344
  }
339
345
  // Defense-in-depth: CLI flags (--tools "", --allowedTools, --strict-mcp-config,
@@ -366,10 +372,10 @@ function spawnClaude(params) {
366
372
  if (text) {
367
373
  if (debug) {
368
374
  // Full text, newlines intact — the readable transcript.
369
- debugBlock('assistant', DEBUG_COLORS.assistant, text);
375
+ debugBlock('assistant', exports.SECTION_COLORS.assistant, text);
370
376
  }
371
377
  else {
372
- process.stderr.write(text.replace(/\n+/g, ' '));
378
+ process.stderr.write(paint(exports.SECTION_COLORS.assistant, text.replace(/\n+/g, ' ')));
373
379
  wroteText = true;
374
380
  }
375
381
  }
@@ -391,10 +397,10 @@ function spawnClaude(params) {
391
397
  if (debug) {
392
398
  const name = toolNames.get(id) ?? id ?? 'result';
393
399
  const errFlag = block['is_error'] ? ' [error]' : '';
394
- debugBlock(`result ← ${name}${errFlag}`, DEBUG_COLORS.result, formatPayload(out));
400
+ debugBlock(`result ← ${name}${errFlag}`, exports.SECTION_COLORS.result, formatPayload(out));
395
401
  }
396
402
  else {
397
- process.stderr.write(`[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───\n`);
403
+ process.stderr.write(paint(exports.SECTION_COLORS.result, `[bridge:verbose] ─── output ${id} ───\n${formatPayload(out)}\n[bridge:verbose] ─── end output ───`) + '\n');
398
404
  }
399
405
  }
400
406
  }
package/dist/index.js CHANGED
@@ -52,9 +52,13 @@ let currentWs = null;
52
52
  // must surface the error, not silently degrade to a different prompt source
53
53
  // (which historically caused the "Skills section authoritative" rule to
54
54
  // vanish and the agent to vault-hunt for skills).
55
- async function fetchSystemPrompt(token) {
55
+ async function fetchSystemPrompt(token, agentSlug) {
56
56
  const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
57
- const url = `${GATEWAY_HTTP}/system-prompt-for-bridge?timezone=${encodeURIComponent(tz)}`;
57
+ // Pass the selected agent slug so agent-api resolves THIS agent (identity,
58
+ // granted connectors, scoped memory) rather than always falling back to the
59
+ // default 1Presence. Without it, every Local Mode turn was the generalist.
60
+ const agentParam = agentSlug ? `&agent=${encodeURIComponent(agentSlug)}` : '';
61
+ const url = `${GATEWAY_HTTP}/system-prompt-for-bridge?timezone=${encodeURIComponent(tz)}${agentParam}`;
58
62
  let res;
59
63
  try {
60
64
  res = await fetch(url, {
@@ -89,14 +93,14 @@ function tmpFile(name) {
89
93
  // connector status, palace, onboarding phase, skills) — call this per turn in
90
94
  // the bridge too, otherwise newly shipped skills and mid-session vault writes
91
95
  // never reach a long-running bridge. Throws on failure; caller must handle.
92
- async function writeSystemPrompt(auth) {
96
+ async function writeSystemPrompt(auth, agentSlug) {
93
97
  const { uid, token } = auth;
94
- const systemPrompt = await fetchSystemPrompt(token);
98
+ const systemPrompt = await fetchSystemPrompt(token, agentSlug);
95
99
  writeRestricted(tmpFile(`agent-${uid}.md`), systemPrompt);
96
100
  if (VERBOSE) {
97
- console.log('\n[bridge:verbose] ─── system prompt ───────────────────────');
98
- console.log(systemPrompt);
99
- console.log('[bridge:verbose] ─── end system prompt ───────────────────\n');
101
+ console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, '\n[bridge:verbose] ─── system prompt ───────────────────────'));
102
+ console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, systemPrompt));
103
+ console.log((0, claude_1.paint)(claude_1.SECTION_COLORS.system, '[bridge:verbose] ─── end system prompt ───────────────────\n'));
100
104
  }
101
105
  }
102
106
  function writeMcpConfig(auth) {
@@ -112,8 +116,8 @@ function writeMcpConfig(auth) {
112
116
  };
113
117
  writeRestricted(tmpFile(`mcp-${uid}.json`), JSON.stringify(mcpConfig, null, 2));
114
118
  }
115
- async function writeSetupFiles(auth) {
116
- await writeSystemPrompt(auth);
119
+ async function writeSetupFiles(auth, agentSlug) {
120
+ await writeSystemPrompt(auth, agentSlug);
117
121
  writeMcpConfig(auth);
118
122
  }
119
123
  // The MCP config embeds a Bearer JWT and the system prompt may contain vault
@@ -129,7 +133,7 @@ function isUuid(value) {
129
133
  return UUID_RE.test(value);
130
134
  }
131
135
  // ─── Handle a single incoming message (token refresh + spawn) ─────────────────
132
- async function handleMessage(conversationId, text, sessionId, history, auth, vaultFileOpen, clientCapabilities, syncedFolders) {
136
+ async function handleMessage(conversationId, text, sessionId, history, auth, vaultFileOpen, clientCapabilities, syncedFolders, agentSlug) {
133
137
  // Refresh JWT if <10 min remaining before spawning Claude
134
138
  let activeAuth = auth;
135
139
  try {
@@ -137,7 +141,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
137
141
  if (freshAuth.token !== auth.token) {
138
142
  currentAuth = freshAuth;
139
143
  activeAuth = freshAuth;
140
- await writeSetupFiles(freshAuth);
144
+ await writeSetupFiles(freshAuth, agentSlug);
141
145
  }
142
146
  }
143
147
  catch (err) {
@@ -161,7 +165,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
161
165
  // (e.g. agent vault-hunting for skills because the Skills authoritative
162
166
  // rule was missing from the previous snapshot).
163
167
  try {
164
- await writeSystemPrompt(activeAuth);
168
+ await writeSystemPrompt(activeAuth, agentSlug);
165
169
  }
166
170
  catch (err) {
167
171
  const message = `System prompt refresh failed: ${err.message}`;
@@ -376,11 +380,11 @@ function connect(auth, retryDelay = 1000) {
376
380
  }
377
381
  if (msg.type !== 'message' || !msg.conversationId || !msg.text)
378
382
  return;
379
- const { conversationId, text, sessionId, history, vaultFileOpen, clientCapabilities, syncedFolders } = msg;
383
+ const { conversationId, text, sessionId, history, vaultFileOpen, clientCapabilities, syncedFolders, agentSlug } = msg;
380
384
  const ts = new Date().toLocaleTimeString();
381
385
  const hist = Array.isArray(history) ? history : [];
382
386
  console.log(`[${ts}] ▶ ${text}${hist.length ? ` (history: ${hist.length} turn${hist.length === 1 ? '' : 's'})` : ''}`);
383
- handleMessage(conversationId, text, sessionId ?? null, hist, auth, vaultFileOpen, clientCapabilities, syncedFolders).catch((err) => {
387
+ handleMessage(conversationId, text, sessionId ?? null, hist, auth, vaultFileOpen, clientCapabilities, syncedFolders, agentSlug).catch((err) => {
384
388
  console.error(`[bridge] handleMessage error: ${err.message}`);
385
389
  });
386
390
  });
@@ -426,7 +430,7 @@ async function main() {
426
430
  console.log(`1Presence Bridge v${package_json_1.version}\n`);
427
431
  if (VERBOSE) {
428
432
  (0, claude_1.setVerbose)(true);
429
- console.log('[bridge:verbose] verbose logging enabled — system prompts, tool inputs, and tool outputs will be printed.\n');
433
+ console.log('[bridge:verbose] verbose logging enabled — system prompts (magenta), user prompts (blue), assistant text (green), tool inputs (cyan), and tool outputs (yellow) will be printed, colour-coded by kind.\n');
430
434
  }
431
435
  if (DEBUG) {
432
436
  (0, claude_1.setDebug)(true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1presence/bridge",
3
- "version": "0.31.0",
3
+ "version": "0.33.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"