@1presence/bridge 0.23.0 → 0.25.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/accumulator.js +20 -8
- package/dist/claude.js +12 -1
- package/dist/index.js +1 -0
- package/package.json +1 -1
package/dist/accumulator.js
CHANGED
|
@@ -7,15 +7,25 @@ function makeBridgeAccumulator() {
|
|
|
7
7
|
assistantText: '',
|
|
8
8
|
toolCalls: [],
|
|
9
9
|
toolResults: {},
|
|
10
|
+
turns: [],
|
|
10
11
|
};
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// Returns the current open API-turn bucket, creating one lazily if a text
|
|
13
|
+
// event arrives before any `{type:'assistant'}` event (shouldn't normally
|
|
14
|
+
// happen with Claude Code's stream-json, but keep it robust).
|
|
15
|
+
function currentTurn() {
|
|
16
|
+
if (state.turns.length === 0)
|
|
17
|
+
state.turns.push({ text: '', toolUseIds: [] });
|
|
18
|
+
return state.turns[state.turns.length - 1];
|
|
19
|
+
}
|
|
13
20
|
function appendText(text) {
|
|
14
|
-
|
|
21
|
+
const turn = currentTurn();
|
|
22
|
+
turn.text += text;
|
|
23
|
+
// Mirror to the flat string with `\n\n` between turns for convenience.
|
|
24
|
+
if (state.assistantText && state.turns.length > 1 && turn.text === text) {
|
|
25
|
+
// First text emission of a new turn — separate from prior turn.
|
|
15
26
|
state.assistantText += '\n\n';
|
|
27
|
+
}
|
|
16
28
|
state.assistantText += text;
|
|
17
|
-
turnTextEmitted = true;
|
|
18
|
-
textEmitted = true;
|
|
19
29
|
}
|
|
20
30
|
return {
|
|
21
31
|
consume(event) {
|
|
@@ -27,9 +37,9 @@ function makeBridgeAccumulator() {
|
|
|
27
37
|
return;
|
|
28
38
|
}
|
|
29
39
|
if (type === 'assistant') {
|
|
30
|
-
// New API turn —
|
|
31
|
-
//
|
|
32
|
-
|
|
40
|
+
// New API turn — open a fresh bucket. All text and tool_use blocks
|
|
41
|
+
// in this `assistant` event belong to this single API turn.
|
|
42
|
+
state.turns.push({ text: '', toolUseIds: [] });
|
|
33
43
|
const msg = event['message'];
|
|
34
44
|
const content = msg?.['content'];
|
|
35
45
|
if (!Array.isArray(content))
|
|
@@ -48,6 +58,7 @@ function makeBridgeAccumulator() {
|
|
|
48
58
|
continue;
|
|
49
59
|
const bareName = name.replace(/^mcp__1presence__/, '');
|
|
50
60
|
state.toolCalls.push({ id, name: bareName, input });
|
|
61
|
+
currentTurn().toolUseIds.push(id);
|
|
51
62
|
if (bareName === 'set_conversation_title') {
|
|
52
63
|
const raw = String(input['title'] ?? '').trim();
|
|
53
64
|
if (raw)
|
|
@@ -95,6 +106,7 @@ async function postSaveTurn(gatewayHttp, token, record) {
|
|
|
95
106
|
assistantText: record.assistantText,
|
|
96
107
|
toolCalls: record.toolCalls,
|
|
97
108
|
toolResults: record.toolResults,
|
|
109
|
+
...(record.apiTurns ? { apiTurns: record.apiTurns } : {}),
|
|
98
110
|
...(record.title ? { title: record.title } : {}),
|
|
99
111
|
...(record.usage ? { usage: record.usage } : {}),
|
|
100
112
|
}),
|
package/dist/claude.js
CHANGED
|
@@ -232,7 +232,18 @@ function spawnClaude(params) {
|
|
|
232
232
|
// --setting-sources "") are supposed to make this unreachable. If we see a
|
|
233
233
|
// non-1Presence tool here anyway, something has bypassed those guards — kill
|
|
234
234
|
// immediately so any side effect already in flight is the only damage done.
|
|
235
|
-
|
|
235
|
+
//
|
|
236
|
+
// Valid forms:
|
|
237
|
+
// mcp__1presence__<name> — namespaced MCP form
|
|
238
|
+
// <snake_case_name> — bare form; Claude Code may omit the prefix in
|
|
239
|
+
// stream-json output. Safe because --strict-mcp-config
|
|
240
|
+
// limits MCP to the 1presence server only.
|
|
241
|
+
// Invalid (real violations):
|
|
242
|
+
// PascalCase (Bash, Read, Write, …) — Claude Code built-ins
|
|
243
|
+
// mcp__<other>__* — tools from a different MCP server
|
|
244
|
+
const isMcp1presence = toolName.startsWith('mcp__1presence__');
|
|
245
|
+
const isBareName = /^[a-z][a-z0-9_]*$/.test(toolName);
|
|
246
|
+
if (!isMcp1presence && !isBareName) {
|
|
236
247
|
killedForViolation = true;
|
|
237
248
|
const violation = `bridge tool violation: ${toolName} is not allowed in Local Mode`;
|
|
238
249
|
process.stderr.write(`[bridge] FATAL ${violation} — killing\n`);
|
package/dist/index.js
CHANGED
|
@@ -188,6 +188,7 @@ async function handleMessage(conversationId, text, sessionId, history, auth, vau
|
|
|
188
188
|
assistantText: s.assistantText,
|
|
189
189
|
toolCalls: s.toolCalls,
|
|
190
190
|
toolResults: s.toolResults,
|
|
191
|
+
apiTurns: s.turns,
|
|
191
192
|
...(s.title ? { title: s.title } : {}),
|
|
192
193
|
usage: usage
|
|
193
194
|
? { ...usage, ...(model ? { model } : {}) }
|