@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 +26 -20
- package/dist/index.js +19 -15
- package/package.json +1 -1
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
|
-
|
|
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' ?
|
|
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',
|
|
146
|
+
debugBlock('user · this turn', exports.SECTION_COLORS.user, text);
|
|
141
147
|
}
|
|
142
|
-
else
|
|
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}`,
|
|
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
|
|
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',
|
|
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}`,
|
|
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
|
|
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
|
-
|
|
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);
|