@vanillagreen/pi-claude-bridge 1.9.0 → 2.0.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 +24 -11
- package/bundle/connector-inventory.js +10 -0
- package/bundle/index.js +2418 -1794
- package/package.json +6 -6
- package/src/assistant-stream.ts +313 -46
- package/src/auth-presence.ts +6 -50
- package/src/bridge-state.ts +43 -1
- package/src/connector-audit.ts +203 -0
- package/src/connector-cache.ts +118 -0
- package/src/connector-inventory.ts +52 -0
- package/src/connectors.ts +142 -1
- package/src/convert.ts +14 -0
- package/src/index.ts +330 -172
- package/src/native-provider.ts +89 -0
- package/src/query-state.ts +218 -9
- package/src/query-teardown.ts +45 -0
- package/src/rate-limit.ts +42 -10
- package/src/session-persistence.ts +7 -2
- package/src/tool-pairing-audit.ts +48 -0
- package/src/typebox-to-zod.ts +9 -3
package/bundle/index.js
CHANGED
|
@@ -8788,6 +8788,7 @@ function zO(e) {
|
|
|
8788
8788
|
}
|
|
8789
8789
|
var $O = typeof String.prototype.isWellFormed === "function" ? Function.prototype.call.bind(String.prototype.isWellFormed) : void 0;
|
|
8790
8790
|
var qUe = typeof String.prototype.toWellFormed === "function" ? Function.prototype.call.bind(String.prototype.toWellFormed) : void 0;
|
|
8791
|
+
var qO = ["You've hit your", "You've reached your", "You're out of usage credits", "Your org is out of usage \xB7 add funds to continue", "Your org is out of usage \xB7 contact your admin", "Your seat type doesn't include usage credits", "Your seat type doesn't include usage", "Your usage allocation has been disabled by your admin", "Your group's usage limit is set to $0", "Fable 5 requires usage credits", "You're out of extra usage", "Your seat type doesn't include extra usage"];
|
|
8791
8792
|
var It = class extends Error {
|
|
8792
8793
|
};
|
|
8793
8794
|
function Cs() {
|
|
@@ -26937,514 +26938,6 @@ function splitPrefixSuffix(input, options = {}) {
|
|
|
26937
26938
|
];
|
|
26938
26939
|
}
|
|
26939
26940
|
|
|
26940
|
-
// src/convert.ts
|
|
26941
|
-
var PROVIDER_ID = "claude-bridge";
|
|
26942
|
-
var PI_TO_SDK_TOOL_NAME = {
|
|
26943
|
-
read: "Read",
|
|
26944
|
-
write: "Write",
|
|
26945
|
-
edit: "Edit",
|
|
26946
|
-
bash: "Bash"
|
|
26947
|
-
};
|
|
26948
|
-
function sanitizeToolId(id, cache) {
|
|
26949
|
-
const existing = cache.get(id);
|
|
26950
|
-
if (existing) return existing;
|
|
26951
|
-
const clean = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
26952
|
-
cache.set(id, clean);
|
|
26953
|
-
return clean;
|
|
26954
|
-
}
|
|
26955
|
-
function mapPiToolNameToSdk(name, customToolNameToSdk) {
|
|
26956
|
-
if (!name) return "";
|
|
26957
|
-
const normalized = name.toLowerCase();
|
|
26958
|
-
if (customToolNameToSdk) {
|
|
26959
|
-
const mapped = customToolNameToSdk.get(name) ?? customToolNameToSdk.get(normalized);
|
|
26960
|
-
if (mapped) return mapped;
|
|
26961
|
-
}
|
|
26962
|
-
if (PI_TO_SDK_TOOL_NAME[normalized]) return PI_TO_SDK_TOOL_NAME[normalized];
|
|
26963
|
-
return pascalCase(name);
|
|
26964
|
-
}
|
|
26965
|
-
function messageContentToText(content) {
|
|
26966
|
-
if (typeof content === "string") return content;
|
|
26967
|
-
if (!Array.isArray(content)) return "";
|
|
26968
|
-
const parts = [];
|
|
26969
|
-
let hasText = false;
|
|
26970
|
-
for (const block of content) {
|
|
26971
|
-
if (block.type === "text" && block.text) {
|
|
26972
|
-
parts.push(block.text);
|
|
26973
|
-
hasText = true;
|
|
26974
|
-
} else if (block.type !== "text" && block.type !== "image") {
|
|
26975
|
-
parts.push(`[${block.type}]`);
|
|
26976
|
-
}
|
|
26977
|
-
}
|
|
26978
|
-
return hasText ? parts.join("\n") : "";
|
|
26979
|
-
}
|
|
26980
|
-
function imageBlockToAnthropic(block) {
|
|
26981
|
-
if (!block.data || !block.mimeType) return void 0;
|
|
26982
|
-
return { type: "image", source: { type: "base64", media_type: block.mimeType, data: block.data } };
|
|
26983
|
-
}
|
|
26984
|
-
function toolResultContentToAnthropic(content) {
|
|
26985
|
-
if (typeof content === "string") return content;
|
|
26986
|
-
if (!Array.isArray(content)) return "";
|
|
26987
|
-
const blocks = [];
|
|
26988
|
-
for (const block of content) {
|
|
26989
|
-
if (block.type === "text" && block.text) {
|
|
26990
|
-
blocks.push({ type: "text", text: block.text });
|
|
26991
|
-
} else if (block.type === "image") {
|
|
26992
|
-
const image = imageBlockToAnthropic(block);
|
|
26993
|
-
if (image) blocks.push(image);
|
|
26994
|
-
} else if (block.type) {
|
|
26995
|
-
blocks.push({ type: "text", text: `[${block.type}]` });
|
|
26996
|
-
}
|
|
26997
|
-
}
|
|
26998
|
-
if (blocks.length === 0) return "";
|
|
26999
|
-
if (blocks.every((block) => block.type === "text")) return blocks.map((block) => block.text).join("\n");
|
|
27000
|
-
return blocks;
|
|
27001
|
-
}
|
|
27002
|
-
function assistantProvenancePrefix(msg) {
|
|
27003
|
-
if (msg.role !== "assistant") return void 0;
|
|
27004
|
-
const provider = typeof msg.provider === "string" ? msg.provider : void 0;
|
|
27005
|
-
const model = typeof msg.model === "string" ? msg.model : void 0;
|
|
27006
|
-
const api = typeof msg.api === "string" ? msg.api : void 0;
|
|
27007
|
-
if (!provider && !model && !api) return void 0;
|
|
27008
|
-
if (provider === PROVIDER_ID || api === "anthropic") return void 0;
|
|
27009
|
-
return `[Prior Pi assistant response from ${provider ?? api ?? "unknown-provider"}${model ? `/${model}` : ""}]
|
|
27010
|
-
`;
|
|
27011
|
-
}
|
|
27012
|
-
function userMessageToAnthropic(msg) {
|
|
27013
|
-
if (typeof msg.content === "string") return { role: "user", content: msg.content || "[empty]" };
|
|
27014
|
-
if (Array.isArray(msg.content)) {
|
|
27015
|
-
const parts = [];
|
|
27016
|
-
for (const block of msg.content) {
|
|
27017
|
-
if (block.type === "text" && block.text) parts.push({ type: "text", text: block.text });
|
|
27018
|
-
else if (block.type === "image" && block.data && block.mimeType) parts.push(imageBlockToAnthropic(block));
|
|
27019
|
-
}
|
|
27020
|
-
const kept = parts.filter(Boolean);
|
|
27021
|
-
return { role: "user", content: kept.length ? kept : "[image]" };
|
|
27022
|
-
}
|
|
27023
|
-
return { role: "user", content: "[empty]" };
|
|
27024
|
-
}
|
|
27025
|
-
function toolResultToAnthropicBlock(msg, sanitizedIds) {
|
|
27026
|
-
const content = toolResultContentToAnthropic(msg.content);
|
|
27027
|
-
return {
|
|
27028
|
-
type: "tool_result",
|
|
27029
|
-
tool_use_id: sanitizeToolId(msg.toolCallId, sanitizedIds),
|
|
27030
|
-
content: content || "",
|
|
27031
|
-
is_error: msg.isError
|
|
27032
|
-
};
|
|
27033
|
-
}
|
|
27034
|
-
function hasToolUse(msg) {
|
|
27035
|
-
return msg.role === "assistant" && Array.isArray(msg.content) && msg.content.some((block) => block.type === "toolCall");
|
|
27036
|
-
}
|
|
27037
|
-
function convertPiMessages(messages, customToolNameToSdk) {
|
|
27038
|
-
const anthropicMessages = [];
|
|
27039
|
-
const sanitizedIds = /* @__PURE__ */ new Map();
|
|
27040
|
-
const pushToolResultGroup = (toolMessages) => {
|
|
27041
|
-
if (toolMessages.length === 0) return;
|
|
27042
|
-
anthropicMessages.push({
|
|
27043
|
-
role: "user",
|
|
27044
|
-
content: toolMessages.map((toolMsg) => {
|
|
27045
|
-
const content = toolResultContentToAnthropic(toolMsg.content);
|
|
27046
|
-
return {
|
|
27047
|
-
type: "tool_result",
|
|
27048
|
-
tool_use_id: sanitizeToolId(toolMsg.toolCallId, sanitizedIds),
|
|
27049
|
-
content: content || "",
|
|
27050
|
-
is_error: toolMsg.isError
|
|
27051
|
-
};
|
|
27052
|
-
})
|
|
27053
|
-
});
|
|
27054
|
-
};
|
|
27055
|
-
for (let i = 0; i < messages.length; i++) {
|
|
27056
|
-
const msg = messages[i];
|
|
27057
|
-
if (msg.role === "user") {
|
|
27058
|
-
anthropicMessages.push(userMessageToAnthropic(msg));
|
|
27059
|
-
} else if (msg.role === "assistant") {
|
|
27060
|
-
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
27061
|
-
const blocks = [];
|
|
27062
|
-
const provenance = assistantProvenancePrefix(msg);
|
|
27063
|
-
if (provenance) blocks.push({ type: "text", text: provenance });
|
|
27064
|
-
for (const block of content) {
|
|
27065
|
-
if (block.type === "text" && block.text) {
|
|
27066
|
-
blocks.push({ type: "text", text: block.text });
|
|
27067
|
-
} else if (block.type === "thinking") {
|
|
27068
|
-
const sig = block.thinkingSignature;
|
|
27069
|
-
const isAnthropicProvider = msg.provider === PROVIDER_ID || msg.api === "anthropic";
|
|
27070
|
-
if (isAnthropicProvider && sig) {
|
|
27071
|
-
blocks.push({ type: "thinking", thinking: block.thinking ?? "", signature: sig });
|
|
27072
|
-
}
|
|
27073
|
-
} else if (block.type === "toolCall") {
|
|
27074
|
-
const toolName = mapPiToolNameToSdk(block.name, customToolNameToSdk);
|
|
27075
|
-
blocks.push({ type: "tool_use", id: sanitizeToolId(block.id, sanitizedIds), name: toolName, input: block.arguments ?? {} });
|
|
27076
|
-
}
|
|
27077
|
-
}
|
|
27078
|
-
if (!blocks.length) blocks.push({ type: "text", text: "[incompatible content omitted]" });
|
|
27079
|
-
anthropicMessages.push({ role: "assistant", content: blocks });
|
|
27080
|
-
if (hasToolUse(msg)) {
|
|
27081
|
-
const toolMessages = [];
|
|
27082
|
-
const interleavedUsers = [];
|
|
27083
|
-
let j2 = i + 1;
|
|
27084
|
-
for (; j2 < messages.length; j2++) {
|
|
27085
|
-
const next = messages[j2];
|
|
27086
|
-
if (next.role === "assistant") break;
|
|
27087
|
-
if (next.role === "toolResult") toolMessages.push(next);
|
|
27088
|
-
else if (next.role === "user") interleavedUsers.push(next);
|
|
27089
|
-
else break;
|
|
27090
|
-
}
|
|
27091
|
-
if (toolMessages.length > 0) {
|
|
27092
|
-
pushToolResultGroup(toolMessages);
|
|
27093
|
-
for (const userMsg of interleavedUsers) anthropicMessages.push(userMessageToAnthropic(userMsg));
|
|
27094
|
-
i = j2 - 1;
|
|
27095
|
-
}
|
|
27096
|
-
}
|
|
27097
|
-
} else if (msg.role === "toolResult") {
|
|
27098
|
-
const blocks = [];
|
|
27099
|
-
for (; i < messages.length; i++) {
|
|
27100
|
-
const toolMsg = messages[i];
|
|
27101
|
-
if (toolMsg.role !== "toolResult") {
|
|
27102
|
-
i--;
|
|
27103
|
-
break;
|
|
27104
|
-
}
|
|
27105
|
-
blocks.push(toolResultToAnthropicBlock(toolMsg, sanitizedIds));
|
|
27106
|
-
}
|
|
27107
|
-
anthropicMessages.push({ role: "user", content: blocks });
|
|
27108
|
-
}
|
|
27109
|
-
}
|
|
27110
|
-
return { anthropicMessages, sanitizedIds };
|
|
27111
|
-
}
|
|
27112
|
-
|
|
27113
|
-
// src/models.ts
|
|
27114
|
-
var FABLE_MODEL_ID = "claude-fable-5";
|
|
27115
|
-
var FABLE_FALLBACK_MODEL_ID = "claude-opus-4-8";
|
|
27116
|
-
var OPUS_5_MODEL_ID = "claude-opus-5";
|
|
27117
|
-
var SONNET_5_MODEL_ID = "claude-sonnet-5";
|
|
27118
|
-
function fallbackModelForPrimaryModel(modelId) {
|
|
27119
|
-
return modelId === FABLE_MODEL_ID || modelId === OPUS_5_MODEL_ID ? FABLE_FALLBACK_MODEL_ID : void 0;
|
|
27120
|
-
}
|
|
27121
|
-
var MODEL_IDS_IN_ORDER = [
|
|
27122
|
-
FABLE_MODEL_ID,
|
|
27123
|
-
OPUS_5_MODEL_ID,
|
|
27124
|
-
FABLE_FALLBACK_MODEL_ID,
|
|
27125
|
-
"claude-opus-4-7",
|
|
27126
|
-
"claude-opus-4-6",
|
|
27127
|
-
SONNET_5_MODEL_ID,
|
|
27128
|
-
"claude-sonnet-4-6",
|
|
27129
|
-
"claude-haiku-4-5"
|
|
27130
|
-
];
|
|
27131
|
-
var FALLBACK_MODELS = {
|
|
27132
|
-
[FABLE_MODEL_ID]: {
|
|
27133
|
-
id: FABLE_MODEL_ID,
|
|
27134
|
-
name: "Claude Fable 5",
|
|
27135
|
-
reasoning: true,
|
|
27136
|
-
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27137
|
-
input: ["text", "image"],
|
|
27138
|
-
contextWindow: 1e6,
|
|
27139
|
-
maxTokens: 128e3
|
|
27140
|
-
},
|
|
27141
|
-
[OPUS_5_MODEL_ID]: {
|
|
27142
|
-
id: OPUS_5_MODEL_ID,
|
|
27143
|
-
name: "Claude Opus 5",
|
|
27144
|
-
reasoning: true,
|
|
27145
|
-
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27146
|
-
input: ["text", "image"],
|
|
27147
|
-
contextWindow: 1e6,
|
|
27148
|
-
maxTokens: 128e3
|
|
27149
|
-
},
|
|
27150
|
-
[FABLE_FALLBACK_MODEL_ID]: {
|
|
27151
|
-
id: FABLE_FALLBACK_MODEL_ID,
|
|
27152
|
-
name: "Claude Opus 4.8",
|
|
27153
|
-
reasoning: true,
|
|
27154
|
-
thinkingLevelMap: { xhigh: "xhigh" },
|
|
27155
|
-
input: ["text", "image"],
|
|
27156
|
-
contextWindow: 1e6,
|
|
27157
|
-
maxTokens: 128e3
|
|
27158
|
-
},
|
|
27159
|
-
[SONNET_5_MODEL_ID]: {
|
|
27160
|
-
id: SONNET_5_MODEL_ID,
|
|
27161
|
-
name: "Claude Sonnet 5",
|
|
27162
|
-
reasoning: true,
|
|
27163
|
-
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27164
|
-
input: ["text", "image"],
|
|
27165
|
-
contextWindow: 1e6,
|
|
27166
|
-
maxTokens: 128e3
|
|
27167
|
-
}
|
|
27168
|
-
};
|
|
27169
|
-
function modelDisplayName(modelId) {
|
|
27170
|
-
return FALLBACK_MODELS[modelId]?.name ?? modelId;
|
|
27171
|
-
}
|
|
27172
|
-
function buildModels(piAiModels) {
|
|
27173
|
-
return MODEL_IDS_IN_ORDER.map((id) => piAiModels.find((m) => m.id === id) ?? FALLBACK_MODELS[id]).filter((m) => m != null).map(({ id, name, reasoning, input, contextWindow, maxTokens, thinkingLevelMap }) => ({
|
|
27174
|
-
id,
|
|
27175
|
-
name,
|
|
27176
|
-
reasoning,
|
|
27177
|
-
input,
|
|
27178
|
-
contextWindow,
|
|
27179
|
-
maxTokens,
|
|
27180
|
-
thinkingLevelMap,
|
|
27181
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
27182
|
-
}));
|
|
27183
|
-
}
|
|
27184
|
-
|
|
27185
|
-
// src/skills.ts
|
|
27186
|
-
var MCP_SERVER_NAME = "custom-tools";
|
|
27187
|
-
var MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
27188
|
-
function extractSkillsBlock(systemPrompt) {
|
|
27189
|
-
if (!systemPrompt) return void 0;
|
|
27190
|
-
const startMarker = "The following skills provide specialized instructions for specific tasks.";
|
|
27191
|
-
const endMarker = "</available_skills>";
|
|
27192
|
-
const start = systemPrompt.indexOf(startMarker);
|
|
27193
|
-
if (start === -1) return void 0;
|
|
27194
|
-
const end = systemPrompt.indexOf(endMarker, start);
|
|
27195
|
-
if (end === -1) return void 0;
|
|
27196
|
-
return rewriteSkillsBlock(systemPrompt.slice(start, end + endMarker.length).trim());
|
|
27197
|
-
}
|
|
27198
|
-
function rewriteSkillsBlock(skillsBlock) {
|
|
27199
|
-
return skillsBlock.replace(
|
|
27200
|
-
"Use the read tool to load a skill's file",
|
|
27201
|
-
`Use the read tool (mcp__${MCP_SERVER_NAME}__read) to load a skill's file`
|
|
27202
|
-
);
|
|
27203
|
-
}
|
|
27204
|
-
|
|
27205
|
-
// src/extract-tool-results.ts
|
|
27206
|
-
function toolResultToMcpContent(content) {
|
|
27207
|
-
if (typeof content === "string") return [{ type: "text", text: content || "" }];
|
|
27208
|
-
if (!Array.isArray(content)) return [{ type: "text", text: "" }];
|
|
27209
|
-
const blocks = [];
|
|
27210
|
-
for (const block of content) {
|
|
27211
|
-
if (block.type === "text" && block.text) blocks.push({ type: "text", text: block.text });
|
|
27212
|
-
else if (block.type === "image" && block.data && block.mimeType) blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
|
|
27213
|
-
}
|
|
27214
|
-
return blocks.length ? blocks : [{ type: "text", text: "" }];
|
|
27215
|
-
}
|
|
27216
|
-
function extractAllToolResults(messages) {
|
|
27217
|
-
const results = [];
|
|
27218
|
-
let stopIdx = -1;
|
|
27219
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
27220
|
-
const msg = messages[i];
|
|
27221
|
-
if (msg.role === "toolResult") {
|
|
27222
|
-
results.unshift({ content: toolResultToMcpContent(msg.content), isError: msg.isError, toolCallId: msg.toolCallId });
|
|
27223
|
-
} else if (msg.role === "assistant") {
|
|
27224
|
-
stopIdx = i;
|
|
27225
|
-
break;
|
|
27226
|
-
}
|
|
27227
|
-
}
|
|
27228
|
-
return { results, stopIdx };
|
|
27229
|
-
}
|
|
27230
|
-
|
|
27231
|
-
// src/query-state.ts
|
|
27232
|
-
var DRAIN_CAUSE_TEXT = {
|
|
27233
|
-
"abort": "the turn was aborted",
|
|
27234
|
-
"stream-idle-timeout": "the Claude Code stream went idle and the turn timed out",
|
|
27235
|
-
"query-end": "the query ended"
|
|
27236
|
-
};
|
|
27237
|
-
function interruptedToolCallResult(cause) {
|
|
27238
|
-
return {
|
|
27239
|
-
content: [{ type: "text", text: `Claude bridge: ${DRAIN_CAUSE_TEXT[cause]} before this tool call's result was delivered. The call did not complete and produced no output.` }],
|
|
27240
|
-
isError: true
|
|
27241
|
-
};
|
|
27242
|
-
}
|
|
27243
|
-
function toolCallDrainCause(flags) {
|
|
27244
|
-
if (flags.wasAborted || flags.signalAborted) return "abort";
|
|
27245
|
-
if (flags.streamIdleTimedOut) return "stream-idle-timeout";
|
|
27246
|
-
return "query-end";
|
|
27247
|
-
}
|
|
27248
|
-
function drainPendingToolCalls(queryCtx, cause) {
|
|
27249
|
-
const drained = queryCtx.pendingToolCalls.size;
|
|
27250
|
-
if (drained === 0) return 0;
|
|
27251
|
-
const result = interruptedToolCallResult(cause);
|
|
27252
|
-
for (const pending of queryCtx.pendingToolCalls.values()) pending.resolve(result);
|
|
27253
|
-
queryCtx.pendingToolCalls.clear();
|
|
27254
|
-
return drained;
|
|
27255
|
-
}
|
|
27256
|
-
function normalizeForCompare(value) {
|
|
27257
|
-
if (Array.isArray(value)) return value.map(normalizeForCompare);
|
|
27258
|
-
if (value && typeof value === "object") {
|
|
27259
|
-
const out = {};
|
|
27260
|
-
for (const key of Object.keys(value).sort()) {
|
|
27261
|
-
const child = value[key];
|
|
27262
|
-
if (child !== void 0) out[key] = normalizeForCompare(child);
|
|
27263
|
-
}
|
|
27264
|
-
return out;
|
|
27265
|
-
}
|
|
27266
|
-
return value;
|
|
27267
|
-
}
|
|
27268
|
-
function argsKey(value) {
|
|
27269
|
-
return JSON.stringify(normalizeForCompare(value ?? {}));
|
|
27270
|
-
}
|
|
27271
|
-
function sameArgs(left, right) {
|
|
27272
|
-
return argsKey(left) === argsKey(right);
|
|
27273
|
-
}
|
|
27274
|
-
function hasRecordedArgs(args) {
|
|
27275
|
-
return Object.keys(args ?? {}).length > 0;
|
|
27276
|
-
}
|
|
27277
|
-
function unique(values) {
|
|
27278
|
-
const out = [];
|
|
27279
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27280
|
-
for (const value of values) {
|
|
27281
|
-
if (!value || seen.has(value)) continue;
|
|
27282
|
-
seen.add(value);
|
|
27283
|
-
out.push(value);
|
|
27284
|
-
}
|
|
27285
|
-
return out;
|
|
27286
|
-
}
|
|
27287
|
-
var QueryContext = class {
|
|
27288
|
-
// Query-scoped (fully isolated per query)
|
|
27289
|
-
activeQuery = null;
|
|
27290
|
-
currentPiStream = null;
|
|
27291
|
-
latestCursor = 0;
|
|
27292
|
-
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
27293
|
-
pendingResults = /* @__PURE__ */ new Map();
|
|
27294
|
-
turnToolCallIds = [];
|
|
27295
|
-
turnToolCalls = [];
|
|
27296
|
-
claimedToolCallIds = /* @__PURE__ */ new Set();
|
|
27297
|
-
deliveredToolResultIds = /* @__PURE__ */ new Set();
|
|
27298
|
-
resolvedToolResultIds = /* @__PURE__ */ new Set();
|
|
27299
|
-
unmatchedToolResultIds = /* @__PURE__ */ new Set();
|
|
27300
|
-
reportedToolResultMismatch = false;
|
|
27301
|
-
deferredUserMessages = [];
|
|
27302
|
-
handledTerminalError = false;
|
|
27303
|
-
// Per-turn (reset together)
|
|
27304
|
-
turnOutput = null;
|
|
27305
|
-
turnStarted = false;
|
|
27306
|
-
turnSawStreamEvent = false;
|
|
27307
|
-
turnSawToolCall = false;
|
|
27308
|
-
get turnBlocks() {
|
|
27309
|
-
if (!this.turnOutput) throw new Error("turnBlocks accessed before resetTurnState");
|
|
27310
|
-
return this.turnOutput.content;
|
|
27311
|
-
}
|
|
27312
|
-
resetTurnState(model) {
|
|
27313
|
-
this.turnOutput = {
|
|
27314
|
-
role: "assistant",
|
|
27315
|
-
content: [],
|
|
27316
|
-
api: model.api,
|
|
27317
|
-
provider: model.provider,
|
|
27318
|
-
model: model.id,
|
|
27319
|
-
usage: {
|
|
27320
|
-
input: 0,
|
|
27321
|
-
output: 0,
|
|
27322
|
-
cacheRead: 0,
|
|
27323
|
-
cacheWrite: 0,
|
|
27324
|
-
totalTokens: 0,
|
|
27325
|
-
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
27326
|
-
},
|
|
27327
|
-
stopReason: "stop",
|
|
27328
|
-
timestamp: Date.now()
|
|
27329
|
-
};
|
|
27330
|
-
this.turnStarted = false;
|
|
27331
|
-
this.turnSawStreamEvent = false;
|
|
27332
|
-
this.turnSawToolCall = false;
|
|
27333
|
-
this.handledTerminalError = false;
|
|
27334
|
-
}
|
|
27335
|
-
resetToolTracking() {
|
|
27336
|
-
this.turnToolCallIds = [];
|
|
27337
|
-
this.turnToolCalls = [];
|
|
27338
|
-
this.claimedToolCallIds.clear();
|
|
27339
|
-
this.deliveredToolResultIds.clear();
|
|
27340
|
-
this.resolvedToolResultIds.clear();
|
|
27341
|
-
this.unmatchedToolResultIds.clear();
|
|
27342
|
-
this.reportedToolResultMismatch = false;
|
|
27343
|
-
}
|
|
27344
|
-
recordToolCall(id, toolName, args = {}) {
|
|
27345
|
-
if (!id) return;
|
|
27346
|
-
if (!this.turnToolCallIds.includes(id)) this.turnToolCallIds.push(id);
|
|
27347
|
-
const existing = this.turnToolCalls.find((call) => call.id === id);
|
|
27348
|
-
if (existing) {
|
|
27349
|
-
existing.toolName = toolName;
|
|
27350
|
-
existing.arguments = args;
|
|
27351
|
-
return;
|
|
27352
|
-
}
|
|
27353
|
-
this.turnToolCalls.push({ id, toolName, arguments: args });
|
|
27354
|
-
}
|
|
27355
|
-
updateToolCallArgs(id, args) {
|
|
27356
|
-
if (!id) return;
|
|
27357
|
-
const existing = this.turnToolCalls.find((call) => call.id === id);
|
|
27358
|
-
if (existing) existing.arguments = args;
|
|
27359
|
-
}
|
|
27360
|
-
hasRecordedToolCall(id) {
|
|
27361
|
-
return Boolean(id && (this.turnToolCallIds.includes(id) || this.turnToolCalls.some((call) => call.id === id)));
|
|
27362
|
-
}
|
|
27363
|
-
claimToolCall(toolName, args = {}) {
|
|
27364
|
-
const unclaimed = this.turnToolCalls.filter((call) => !this.claimedToolCallIds.has(call.id));
|
|
27365
|
-
const byName = unclaimed.filter((call) => call.toolName === toolName);
|
|
27366
|
-
const exact = byName.filter((call) => sameArgs(call.arguments, args));
|
|
27367
|
-
let chosen;
|
|
27368
|
-
let match = "none";
|
|
27369
|
-
let ambiguous = false;
|
|
27370
|
-
if (exact.length > 0) {
|
|
27371
|
-
chosen = exact[0];
|
|
27372
|
-
match = "tool-args";
|
|
27373
|
-
ambiguous = exact.length > 1;
|
|
27374
|
-
} else if (byName.length === 1 && !hasRecordedArgs(byName[0].arguments)) {
|
|
27375
|
-
chosen = byName[0];
|
|
27376
|
-
match = "tool-name";
|
|
27377
|
-
}
|
|
27378
|
-
if (!chosen) return { match: "none", ambiguous: false, available: unclaimed.length };
|
|
27379
|
-
this.claimedToolCallIds.add(chosen.id);
|
|
27380
|
-
return { toolCallId: chosen.id, match, ambiguous, available: unclaimed.length };
|
|
27381
|
-
}
|
|
27382
|
-
markToolResultDelivered(id) {
|
|
27383
|
-
if (id) this.deliveredToolResultIds.add(id);
|
|
27384
|
-
}
|
|
27385
|
-
markToolResultResolved(id) {
|
|
27386
|
-
if (id) this.resolvedToolResultIds.add(id);
|
|
27387
|
-
}
|
|
27388
|
-
markToolResultUnmatched(id) {
|
|
27389
|
-
if (id) this.unmatchedToolResultIds.add(id);
|
|
27390
|
-
}
|
|
27391
|
-
toolResultProgress() {
|
|
27392
|
-
const expectedIds = unique([
|
|
27393
|
-
...this.turnToolCalls.map((call) => call.id),
|
|
27394
|
-
...this.turnToolCallIds
|
|
27395
|
-
]);
|
|
27396
|
-
const deliveredIds = unique(this.deliveredToolResultIds);
|
|
27397
|
-
const resolvedIds = unique(this.resolvedToolResultIds);
|
|
27398
|
-
const waitingIds = unique(this.pendingToolCalls.keys());
|
|
27399
|
-
const queuedIds = unique(this.pendingResults.keys());
|
|
27400
|
-
const unmatchedResultIds = unique(this.unmatchedToolResultIds);
|
|
27401
|
-
const missingDeliveredIds = expectedIds.filter((id) => !this.deliveredToolResultIds.has(id));
|
|
27402
|
-
const unresolvedIds = expectedIds.filter((id) => !this.resolvedToolResultIds.has(id));
|
|
27403
|
-
const affectedIds = /* @__PURE__ */ new Set([...missingDeliveredIds, ...unresolvedIds, ...waitingIds, ...queuedIds, ...unmatchedResultIds]);
|
|
27404
|
-
const counts = /* @__PURE__ */ new Map();
|
|
27405
|
-
for (const call of this.turnToolCalls) {
|
|
27406
|
-
if (affectedIds.size > 0 && !affectedIds.has(call.id)) continue;
|
|
27407
|
-
counts.set(call.toolName, (counts.get(call.toolName) ?? 0) + 1);
|
|
27408
|
-
}
|
|
27409
|
-
return {
|
|
27410
|
-
expectedIds,
|
|
27411
|
-
deliveredIds,
|
|
27412
|
-
resolvedIds,
|
|
27413
|
-
waitingIds,
|
|
27414
|
-
queuedIds,
|
|
27415
|
-
unmatchedResultIds,
|
|
27416
|
-
missingDeliveredIds,
|
|
27417
|
-
unresolvedIds,
|
|
27418
|
-
toolNames: [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name, count]) => ({ name, count })),
|
|
27419
|
-
expectedCount: expectedIds.length,
|
|
27420
|
-
deliveredCount: deliveredIds.length,
|
|
27421
|
-
resolvedCount: resolvedIds.length,
|
|
27422
|
-
waitingCount: waitingIds.length,
|
|
27423
|
-
queuedCount: queuedIds.length,
|
|
27424
|
-
unmatchedResultCount: unmatchedResultIds.length
|
|
27425
|
-
};
|
|
27426
|
-
}
|
|
27427
|
-
};
|
|
27428
|
-
var _ctx = new QueryContext();
|
|
27429
|
-
var contextStack = [];
|
|
27430
|
-
function ctx() {
|
|
27431
|
-
return _ctx;
|
|
27432
|
-
}
|
|
27433
|
-
function stackDepth() {
|
|
27434
|
-
return contextStack.length;
|
|
27435
|
-
}
|
|
27436
|
-
function pushContext() {
|
|
27437
|
-
if (!_ctx.activeQuery) throw new Error("pushContext() called with no active query");
|
|
27438
|
-
contextStack.push(_ctx);
|
|
27439
|
-
_ctx = new QueryContext();
|
|
27440
|
-
}
|
|
27441
|
-
function popContext() {
|
|
27442
|
-
if (contextStack.length === 0) throw new Error("popContext() called with empty stack");
|
|
27443
|
-
const parent = contextStack[contextStack.length - 1];
|
|
27444
|
-
parent.deferredUserMessages.push(..._ctx.deferredUserMessages);
|
|
27445
|
-
_ctx = contextStack.pop();
|
|
27446
|
-
}
|
|
27447
|
-
|
|
27448
26941
|
// src/config.ts
|
|
27449
26942
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
27450
26943
|
import { homedir } from "os";
|
|
@@ -27649,187 +27142,1646 @@ function loadConfig(cwd) {
|
|
|
27649
27142
|
};
|
|
27650
27143
|
}
|
|
27651
27144
|
|
|
27652
|
-
// src/
|
|
27653
|
-
|
|
27654
|
-
|
|
27655
|
-
|
|
27656
|
-
|
|
27657
|
-
const
|
|
27658
|
-
|
|
27659
|
-
|
|
27660
|
-
|
|
27661
|
-
|
|
27662
|
-
|
|
27145
|
+
// src/skills.ts
|
|
27146
|
+
var MCP_SERVER_NAME = "custom-tools";
|
|
27147
|
+
var MCP_TOOL_PREFIX = `mcp__${MCP_SERVER_NAME}__`;
|
|
27148
|
+
function extractSkillsBlock(systemPrompt) {
|
|
27149
|
+
if (!systemPrompt) return void 0;
|
|
27150
|
+
const startMarker = "The following skills provide specialized instructions for specific tasks.";
|
|
27151
|
+
const endMarker = "</available_skills>";
|
|
27152
|
+
const start = systemPrompt.indexOf(startMarker);
|
|
27153
|
+
if (start === -1) return void 0;
|
|
27154
|
+
const end = systemPrompt.indexOf(endMarker, start);
|
|
27155
|
+
if (end === -1) return void 0;
|
|
27156
|
+
return rewriteSkillsBlock(systemPrompt.slice(start, end + endMarker.length).trim());
|
|
27663
27157
|
}
|
|
27664
|
-
function
|
|
27665
|
-
|
|
27666
|
-
|
|
27158
|
+
function rewriteSkillsBlock(skillsBlock) {
|
|
27159
|
+
return skillsBlock.replace(
|
|
27160
|
+
"Use the read tool to load a skill's file",
|
|
27161
|
+
`Use the read tool (mcp__${MCP_SERVER_NAME}__read) to load a skill's file`
|
|
27162
|
+
);
|
|
27667
27163
|
}
|
|
27668
|
-
|
|
27669
|
-
|
|
27670
|
-
|
|
27671
|
-
|
|
27672
|
-
|
|
27673
|
-
|
|
27674
|
-
|
|
27675
|
-
|
|
27164
|
+
|
|
27165
|
+
// src/connector-inventory.ts
|
|
27166
|
+
var CONNECTOR_NS_PREFIX = "mcp__claude_ai_";
|
|
27167
|
+
var DEFAULT_API_BASE = "https://api.anthropic.com";
|
|
27168
|
+
var DEFAULT_PROXY_BASE = "https://mcp-proxy.anthropic.com/v1/mcp";
|
|
27169
|
+
var OAUTH_BETA_HEADER = "oauth-2025-04-20";
|
|
27170
|
+
function connectorServerName(connectorName) {
|
|
27171
|
+
return `claude.ai ${connectorName.trim()}`;
|
|
27172
|
+
}
|
|
27173
|
+
function connectorProxyUrl(installedServerId, proxyBase = DEFAULT_PROXY_BASE) {
|
|
27174
|
+
return `${trimTrailingSlashes(proxyBase)}/${encodeURIComponent(installedServerId)}`;
|
|
27175
|
+
}
|
|
27176
|
+
function connectorServerNamespace(connectorName) {
|
|
27177
|
+
return `${CONNECTOR_NS_PREFIX}${connectorName.trim().replace(/\s+/g, "_")}__`;
|
|
27178
|
+
}
|
|
27179
|
+
function credentialCandidatePaths(env = process.env) {
|
|
27180
|
+
const roots = [];
|
|
27181
|
+
const configDir = env.CLAUDE_CONFIG_DIR?.trim();
|
|
27182
|
+
if (configDir) roots.push(configDir);
|
|
27183
|
+
const home = env.HOME?.trim();
|
|
27184
|
+
if (home) roots.push(`${home}/.claude`, home);
|
|
27185
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27186
|
+
const paths = [];
|
|
27187
|
+
for (const root of roots) {
|
|
27188
|
+
for (const name of [".credentials.json", ".claude.json"]) {
|
|
27189
|
+
const p2 = `${root}/${name}`;
|
|
27190
|
+
if (!seen.has(p2)) {
|
|
27191
|
+
seen.add(p2);
|
|
27192
|
+
paths.push(p2);
|
|
27193
|
+
}
|
|
27194
|
+
}
|
|
27676
27195
|
}
|
|
27196
|
+
return paths;
|
|
27677
27197
|
}
|
|
27678
|
-
function
|
|
27679
|
-
|
|
27680
|
-
|
|
27681
|
-
|
|
27682
|
-
|
|
27683
|
-
|
|
27684
|
-
|
|
27685
|
-
|
|
27686
|
-
|
|
27687
|
-
|
|
27688
|
-
|
|
27689
|
-
|
|
27690
|
-
|
|
27691
|
-
|
|
27198
|
+
function resolveClaudeOAuth(readFile, env = process.env) {
|
|
27199
|
+
let accessToken;
|
|
27200
|
+
let organizationUuid;
|
|
27201
|
+
for (const path of credentialCandidatePaths(env)) {
|
|
27202
|
+
const raw = readFile(path);
|
|
27203
|
+
if (!raw) continue;
|
|
27204
|
+
let parsed;
|
|
27205
|
+
try {
|
|
27206
|
+
parsed = JSON.parse(raw);
|
|
27207
|
+
} catch {
|
|
27208
|
+
continue;
|
|
27209
|
+
}
|
|
27210
|
+
accessToken ??= nonEmptyString(parsed?.claudeAiOauth?.accessToken);
|
|
27211
|
+
organizationUuid ??= nonEmptyString(parsed?.oauthAccount?.organizationUuid);
|
|
27212
|
+
if (accessToken && organizationUuid) break;
|
|
27213
|
+
}
|
|
27214
|
+
if (!accessToken || !organizationUuid) return void 0;
|
|
27215
|
+
return { accessToken, organizationUuid };
|
|
27692
27216
|
}
|
|
27693
|
-
function
|
|
27694
|
-
|
|
27695
|
-
if (state.credentialed) return state.registered ? "noop" : "register";
|
|
27696
|
-
return "unregister";
|
|
27217
|
+
function nonEmptyString(value) {
|
|
27218
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
27697
27219
|
}
|
|
27698
|
-
|
|
27699
|
-
|
|
27700
|
-
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
27701
|
-
import { dirname as dirname2, join as join4, resolve as resolve3 } from "path";
|
|
27702
|
-
function globalAgentsPath() {
|
|
27703
|
-
return join4(piUserDir(), "AGENTS.md");
|
|
27220
|
+
function connectorsListUrl(organizationUuid, apiBase = DEFAULT_API_BASE) {
|
|
27221
|
+
return `${trimTrailingSlashes(apiBase)}/api/oauth/organizations/${encodeURIComponent(organizationUuid)}/mcp/connectors/list`;
|
|
27704
27222
|
}
|
|
27705
|
-
function
|
|
27706
|
-
|
|
27707
|
-
|
|
27708
|
-
|
|
27709
|
-
const globalPath = globalAgentsPath();
|
|
27710
|
-
if (existsSync4(globalPath)) return globalPath;
|
|
27711
|
-
return void 0;
|
|
27223
|
+
function trimTrailingSlashes(value) {
|
|
27224
|
+
let end = value.length;
|
|
27225
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
27226
|
+
return value.slice(0, end);
|
|
27712
27227
|
}
|
|
27713
|
-
function
|
|
27714
|
-
|
|
27715
|
-
|
|
27716
|
-
|
|
27717
|
-
|
|
27718
|
-
|
|
27719
|
-
|
|
27720
|
-
|
|
27228
|
+
async function listAccountConnectors(deps) {
|
|
27229
|
+
const { credentials, apiBase, signal } = deps;
|
|
27230
|
+
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
27231
|
+
const url2 = connectorsListUrl(credentials.organizationUuid, apiBase);
|
|
27232
|
+
const fail = (reason) => ({ ok: false, complete: false, reason: redactSecret(reason, credentials.accessToken) });
|
|
27233
|
+
let response;
|
|
27234
|
+
try {
|
|
27235
|
+
response = await fetchImpl(url2, {
|
|
27236
|
+
method: "POST",
|
|
27237
|
+
headers: {
|
|
27238
|
+
"Authorization": `Bearer ${credentials.accessToken}`,
|
|
27239
|
+
"anthropic-beta": OAUTH_BETA_HEADER,
|
|
27240
|
+
"Content-Type": "application/json"
|
|
27241
|
+
},
|
|
27242
|
+
body: "{}",
|
|
27243
|
+
signal
|
|
27244
|
+
});
|
|
27245
|
+
} catch (error51) {
|
|
27246
|
+
return fail(`connector list request failed: ${errorText(error51)}`);
|
|
27721
27247
|
}
|
|
27722
|
-
|
|
27723
|
-
}
|
|
27724
|
-
function extractAgentsAppend() {
|
|
27725
|
-
const agentsPath = resolveAgentsMdPath();
|
|
27726
|
-
if (!agentsPath) return void 0;
|
|
27248
|
+
let bodyText;
|
|
27727
27249
|
try {
|
|
27728
|
-
|
|
27729
|
-
|
|
27730
|
-
|
|
27731
|
-
|
|
27732
|
-
|
|
27733
|
-
${
|
|
27250
|
+
bodyText = await response.text();
|
|
27251
|
+
} catch (error51) {
|
|
27252
|
+
return fail(`connector list response unreadable: ${errorText(error51)}`);
|
|
27253
|
+
}
|
|
27254
|
+
if (!response.ok) {
|
|
27255
|
+
return fail(`connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
|
|
27256
|
+
}
|
|
27257
|
+
let parsed;
|
|
27258
|
+
try {
|
|
27259
|
+
parsed = JSON.parse(bodyText);
|
|
27734
27260
|
} catch {
|
|
27735
|
-
return
|
|
27261
|
+
return fail("connector list returned a non-JSON body");
|
|
27736
27262
|
}
|
|
27263
|
+
if (!Array.isArray(parsed?.results)) {
|
|
27264
|
+
return fail("connector list response had no results array");
|
|
27265
|
+
}
|
|
27266
|
+
const connectors = [];
|
|
27267
|
+
for (const raw of parsed.results) {
|
|
27268
|
+
const entry = raw;
|
|
27269
|
+
const name = nonEmptyString(entry?.name);
|
|
27270
|
+
if (!name) {
|
|
27271
|
+
return fail("connector list contained an entry with no name");
|
|
27272
|
+
}
|
|
27273
|
+
connectors.push({
|
|
27274
|
+
name,
|
|
27275
|
+
installedServerId: nonEmptyString(entry?.installedServerId),
|
|
27276
|
+
directoryUuid: nonEmptyString(entry?.directoryUuid),
|
|
27277
|
+
installState: nonEmptyString(entry?.installState),
|
|
27278
|
+
description: nonEmptyString(entry?.description),
|
|
27279
|
+
isAuthless: typeof entry?.isAuthless === "boolean" ? entry.isAuthless : void 0
|
|
27280
|
+
});
|
|
27281
|
+
}
|
|
27282
|
+
return { ok: true, complete: true, connectors };
|
|
27737
27283
|
}
|
|
27738
|
-
function
|
|
27739
|
-
let sanitized = content;
|
|
27740
|
-
sanitized = sanitized.replace(/~\/\.pi\b/gi, "~/.claude");
|
|
27741
|
-
sanitized = sanitized.replace(/(^|[\s'"`])\.pi\//g, "$1.claude/");
|
|
27742
|
-
sanitized = sanitized.replace(/\b\.pi\b/gi, ".claude");
|
|
27743
|
-
sanitized = sanitized.replace(/\bpi\b/gi, "environment");
|
|
27744
|
-
return sanitized;
|
|
27745
|
-
}
|
|
27746
|
-
|
|
27747
|
-
// src/prompt-context.ts
|
|
27748
|
-
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
27749
|
-
import { dirname as dirname3, join as join5, resolve as resolve4 } from "path";
|
|
27750
|
-
function readTrimmed(path) {
|
|
27284
|
+
function apiErrorSuffix(bodyText) {
|
|
27751
27285
|
try {
|
|
27752
|
-
|
|
27753
|
-
|
|
27754
|
-
return content.length > 0 ? content : void 0;
|
|
27286
|
+
const message = JSON.parse(bodyText)?.error?.message;
|
|
27287
|
+
return typeof message === "string" && message.trim() ? ` (${message.trim()})` : "";
|
|
27755
27288
|
} catch {
|
|
27756
|
-
return
|
|
27289
|
+
return "";
|
|
27757
27290
|
}
|
|
27758
27291
|
}
|
|
27759
|
-
function
|
|
27760
|
-
|
|
27761
|
-
|
|
27762
|
-
|
|
27763
|
-
|
|
27764
|
-
const parent = dirname3(current);
|
|
27765
|
-
if (parent === current) break;
|
|
27766
|
-
current = parent;
|
|
27292
|
+
function redactSecret(text, secret) {
|
|
27293
|
+
if (!secret || secret.length < 8) return text;
|
|
27294
|
+
let out = text;
|
|
27295
|
+
for (const form of /* @__PURE__ */ new Set([secret, encodeURIComponent(secret)])) {
|
|
27296
|
+
out = out.split(form).join("[redacted]");
|
|
27767
27297
|
}
|
|
27768
|
-
return
|
|
27298
|
+
return out;
|
|
27769
27299
|
}
|
|
27770
|
-
function
|
|
27771
|
-
|
|
27772
|
-
{ label: "global APPEND_SYSTEM.md", path: join5(piUserDir(), "APPEND_SYSTEM.md") }
|
|
27773
|
-
];
|
|
27774
|
-
const projectPath = isolatedFromEnv() ? void 0 : findProjectAppendSystem(cwd);
|
|
27775
|
-
if (projectPath) files.push({ label: "project .pi/APPEND_SYSTEM.md", path: projectPath });
|
|
27776
|
-
const seen = /* @__PURE__ */ new Set();
|
|
27777
|
-
const output = [];
|
|
27778
|
-
for (const file2 of files) {
|
|
27779
|
-
if (seen.has(file2.path)) continue;
|
|
27780
|
-
seen.add(file2.path);
|
|
27781
|
-
const content = readTrimmed(file2.path);
|
|
27782
|
-
if (content) output.push({ label: file2.label, content });
|
|
27783
|
-
}
|
|
27784
|
-
return output;
|
|
27300
|
+
function errorText(error51) {
|
|
27301
|
+
return error51 instanceof Error ? error51.message : String(error51);
|
|
27785
27302
|
}
|
|
27786
|
-
|
|
27787
|
-
|
|
27303
|
+
|
|
27304
|
+
// src/connectors.ts
|
|
27305
|
+
var DISALLOWED_BUILTIN_TOOLS = [
|
|
27306
|
+
"Read",
|
|
27307
|
+
"Write",
|
|
27308
|
+
"Edit",
|
|
27309
|
+
"MultiEdit",
|
|
27310
|
+
"Glob",
|
|
27311
|
+
"Grep",
|
|
27312
|
+
"Bash",
|
|
27313
|
+
"Agent",
|
|
27314
|
+
"Task",
|
|
27315
|
+
"NotebookEdit",
|
|
27316
|
+
"EnterWorktree",
|
|
27317
|
+
"ExitWorktree",
|
|
27318
|
+
"CronList",
|
|
27319
|
+
"CronCreate",
|
|
27320
|
+
"CronDelete",
|
|
27321
|
+
"TeamCreate",
|
|
27322
|
+
"TeamDelete",
|
|
27323
|
+
"TaskOutput",
|
|
27324
|
+
"TaskStop",
|
|
27325
|
+
"SendMessage",
|
|
27326
|
+
"Skill",
|
|
27327
|
+
"TodoRead",
|
|
27328
|
+
"TodoWrite",
|
|
27329
|
+
"ListMcpResources",
|
|
27330
|
+
"ReadMcpResource",
|
|
27331
|
+
"WebFetch",
|
|
27332
|
+
"WebSearch",
|
|
27333
|
+
"AskUserQuestion",
|
|
27334
|
+
"EnterPlanMode",
|
|
27335
|
+
"ExitPlanMode",
|
|
27336
|
+
"ToolSearch",
|
|
27337
|
+
"ScheduleWakeup"
|
|
27338
|
+
];
|
|
27339
|
+
var CLAUDE_BRIDGE_TOOL_ISOLATION = {
|
|
27340
|
+
tools: [],
|
|
27341
|
+
disallowedTools: DISALLOWED_BUILTIN_TOOLS,
|
|
27342
|
+
allowedTools: [`mcp__${MCP_SERVER_NAME}__*`]
|
|
27343
|
+
};
|
|
27344
|
+
function connectorsEnabledFromEnv() {
|
|
27345
|
+
const v2 = (process.env.CLAUDE_BRIDGE_ENABLE_CONNECTORS ?? "").trim().toLowerCase();
|
|
27346
|
+
return v2 === "1" || v2 === "true" || v2 === "yes" || v2 === "on";
|
|
27788
27347
|
}
|
|
27789
|
-
function
|
|
27790
|
-
|
|
27791
|
-
let start = -1;
|
|
27792
|
-
for (const heading of headings) {
|
|
27793
|
-
const index = systemPrompt.indexOf(heading);
|
|
27794
|
-
if (index >= 0 && (start < 0 || index < start)) start = index;
|
|
27795
|
-
}
|
|
27796
|
-
if (start < 0) return void 0;
|
|
27797
|
-
const rest = systemPrompt.slice(start).trim();
|
|
27798
|
-
const endCandidates = [
|
|
27799
|
-
rest.slice(1).search(/\n##\s+/),
|
|
27800
|
-
rest.search(/\n<\/project_instructions>/),
|
|
27801
|
-
rest.search(/\n<\/project_context>/)
|
|
27802
|
-
].map((index, offset) => index >= 0 && offset === 0 ? index + 1 : index).filter((index) => index >= 0);
|
|
27803
|
-
const end = endCandidates.length > 0 ? Math.min(...endCandidates) : -1;
|
|
27804
|
-
return (end >= 0 ? rest.slice(0, end) : rest).trim();
|
|
27348
|
+
function connectorsEnabledFor(config2) {
|
|
27349
|
+
return connectorsEnabledFromEnv() || config2?.provider?.enableConnectors === true;
|
|
27805
27350
|
}
|
|
27806
|
-
|
|
27807
|
-
|
|
27808
|
-
|
|
27809
|
-
|
|
27351
|
+
var CLAUDE_AI_CONNECTOR_TOOL_PATTERNS = [
|
|
27352
|
+
"mcp__claude_ai_Gmail__*",
|
|
27353
|
+
"mcp__claude_ai_Google_Calendar__*",
|
|
27354
|
+
"mcp__claude_ai_Google_Drive__*",
|
|
27355
|
+
"mcp__claude_ai_Slack__*",
|
|
27356
|
+
"mcp__claude_ai_Atlassian__*"
|
|
27357
|
+
];
|
|
27358
|
+
var CONNECTOR_DISCOVERY_TOOLS = ["ToolSearch", "ListMcpResources", "ReadMcpResource"];
|
|
27359
|
+
var CONNECTOR_NS_PREFIX2 = "mcp__claude_ai_";
|
|
27360
|
+
var CONNECTOR_NS_GMAIL = `${CONNECTOR_NS_PREFIX2}Gmail__`;
|
|
27361
|
+
var CONNECTOR_NS_CALENDAR = `${CONNECTOR_NS_PREFIX2}Google_Calendar__`;
|
|
27362
|
+
var CONNECTOR_NS_DRIVE = `${CONNECTOR_NS_PREFIX2}Google_Drive__`;
|
|
27363
|
+
var CONNECTOR_NS_SLACK = `${CONNECTOR_NS_PREFIX2}Slack__`;
|
|
27364
|
+
var CONNECTOR_NS_ATLASSIAN = `${CONNECTOR_NS_PREFIX2}Atlassian__`;
|
|
27365
|
+
var CONNECTOR_READ_VERBS = /* @__PURE__ */ new Set([
|
|
27366
|
+
"list",
|
|
27367
|
+
"search",
|
|
27368
|
+
"get",
|
|
27369
|
+
"read",
|
|
27370
|
+
"fetch",
|
|
27371
|
+
"find",
|
|
27372
|
+
"download",
|
|
27373
|
+
"describe",
|
|
27374
|
+
"query",
|
|
27375
|
+
"count",
|
|
27376
|
+
"view",
|
|
27377
|
+
"lookup",
|
|
27378
|
+
"whoami"
|
|
27379
|
+
]);
|
|
27380
|
+
var CONNECTOR_MUTATION_WORDS = /* @__PURE__ */ new Set([
|
|
27381
|
+
"create",
|
|
27382
|
+
"update",
|
|
27383
|
+
"delete",
|
|
27384
|
+
"remove",
|
|
27385
|
+
"add",
|
|
27386
|
+
"edit",
|
|
27387
|
+
"send",
|
|
27388
|
+
"post",
|
|
27389
|
+
"write",
|
|
27390
|
+
"upload",
|
|
27391
|
+
"publish",
|
|
27392
|
+
"schedule",
|
|
27393
|
+
"transition",
|
|
27394
|
+
"archive",
|
|
27395
|
+
"move",
|
|
27396
|
+
"copy",
|
|
27397
|
+
"revoke",
|
|
27398
|
+
"assign",
|
|
27399
|
+
"invite",
|
|
27400
|
+
"share",
|
|
27401
|
+
"rename",
|
|
27402
|
+
"replace",
|
|
27403
|
+
"set",
|
|
27404
|
+
"merge",
|
|
27405
|
+
"resolve",
|
|
27406
|
+
"lock",
|
|
27407
|
+
"unlock",
|
|
27408
|
+
"acknowledge",
|
|
27409
|
+
"ack",
|
|
27410
|
+
"book",
|
|
27411
|
+
"start",
|
|
27412
|
+
"stop",
|
|
27413
|
+
"terminate",
|
|
27414
|
+
"restart",
|
|
27415
|
+
"join",
|
|
27416
|
+
"leave",
|
|
27417
|
+
"star",
|
|
27418
|
+
"unstar",
|
|
27419
|
+
"forward",
|
|
27420
|
+
"sync",
|
|
27421
|
+
"approve",
|
|
27422
|
+
"reject",
|
|
27423
|
+
"close",
|
|
27424
|
+
"reopen",
|
|
27425
|
+
"cancel",
|
|
27426
|
+
"enable",
|
|
27427
|
+
"disable",
|
|
27428
|
+
"grant",
|
|
27429
|
+
"trigger",
|
|
27430
|
+
"execute",
|
|
27431
|
+
"apply",
|
|
27432
|
+
"submit",
|
|
27433
|
+
"pin",
|
|
27434
|
+
"unpin",
|
|
27435
|
+
"mute",
|
|
27436
|
+
"unmute",
|
|
27437
|
+
"subscribe",
|
|
27438
|
+
"unsubscribe",
|
|
27439
|
+
"follow",
|
|
27440
|
+
"unfollow",
|
|
27441
|
+
"clear",
|
|
27442
|
+
"purge",
|
|
27443
|
+
"reset",
|
|
27444
|
+
"rotate",
|
|
27445
|
+
"deploy",
|
|
27446
|
+
"install",
|
|
27447
|
+
"uninstall",
|
|
27448
|
+
"save",
|
|
27449
|
+
"store",
|
|
27450
|
+
"put",
|
|
27451
|
+
"patch",
|
|
27452
|
+
"insert",
|
|
27453
|
+
"append",
|
|
27454
|
+
"prepend",
|
|
27455
|
+
"duplicate",
|
|
27456
|
+
"restore",
|
|
27457
|
+
"revert",
|
|
27458
|
+
"import",
|
|
27459
|
+
"export",
|
|
27460
|
+
"upsert",
|
|
27461
|
+
"sign",
|
|
27462
|
+
"complete",
|
|
27463
|
+
"claim",
|
|
27464
|
+
"release",
|
|
27465
|
+
"promote",
|
|
27466
|
+
"demote",
|
|
27467
|
+
"escalate",
|
|
27468
|
+
"resend",
|
|
27469
|
+
"retry",
|
|
27470
|
+
"react",
|
|
27471
|
+
"vote"
|
|
27472
|
+
]);
|
|
27473
|
+
function connectorNameWords(segment) {
|
|
27474
|
+
return segment.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => word.toLowerCase());
|
|
27475
|
+
}
|
|
27476
|
+
var CONNECTOR_WRITE_TOOLS = [
|
|
27477
|
+
`${CONNECTOR_NS_GMAIL}create_draft`,
|
|
27478
|
+
`${CONNECTOR_NS_GMAIL}create_label`,
|
|
27479
|
+
`${CONNECTOR_NS_GMAIL}label_message`,
|
|
27480
|
+
`${CONNECTOR_NS_GMAIL}label_thread`,
|
|
27481
|
+
`${CONNECTOR_NS_GMAIL}unlabel_message`,
|
|
27482
|
+
`${CONNECTOR_NS_GMAIL}unlabel_thread`,
|
|
27483
|
+
`${CONNECTOR_NS_GMAIL}apply_sensitive_label`,
|
|
27484
|
+
`${CONNECTOR_NS_GMAIL}remove_sensitive_label`,
|
|
27485
|
+
`${CONNECTOR_NS_CALENDAR}create_event`,
|
|
27486
|
+
`${CONNECTOR_NS_CALENDAR}update_event`,
|
|
27487
|
+
`${CONNECTOR_NS_CALENDAR}delete_event`,
|
|
27488
|
+
`${CONNECTOR_NS_CALENDAR}respond_to_event`,
|
|
27489
|
+
`${CONNECTOR_NS_DRIVE}create_file`,
|
|
27490
|
+
`${CONNECTOR_NS_DRIVE}copy_file`,
|
|
27491
|
+
// Slack + Atlassian writes, taken from a live enumeration of an account with
|
|
27492
|
+
// both connectors attached. The PreToolUse hook already denies these by verb;
|
|
27493
|
+
// listing them by id also removes them from the model's context in a
|
|
27494
|
+
// read-only session (the CLI matcher needs exact ids). Additive only — an id
|
|
27495
|
+
// missing here is still denied at call time.
|
|
27496
|
+
`${CONNECTOR_NS_SLACK}slack_send_message`,
|
|
27497
|
+
`${CONNECTOR_NS_SLACK}slack_send_message_draft`,
|
|
27498
|
+
`${CONNECTOR_NS_SLACK}slack_schedule_message`,
|
|
27499
|
+
`${CONNECTOR_NS_SLACK}slack_create_canvas`,
|
|
27500
|
+
`${CONNECTOR_NS_SLACK}slack_update_canvas`,
|
|
27501
|
+
`${CONNECTOR_NS_ATLASSIAN}createJiraIssue`,
|
|
27502
|
+
`${CONNECTOR_NS_ATLASSIAN}editJiraIssue`,
|
|
27503
|
+
`${CONNECTOR_NS_ATLASSIAN}transitionJiraIssue`,
|
|
27504
|
+
`${CONNECTOR_NS_ATLASSIAN}addCommentToJiraIssue`,
|
|
27505
|
+
`${CONNECTOR_NS_ATLASSIAN}addWorklogToJiraIssue`,
|
|
27506
|
+
`${CONNECTOR_NS_ATLASSIAN}createIssueLink`,
|
|
27507
|
+
`${CONNECTOR_NS_ATLASSIAN}createConfluencePage`,
|
|
27508
|
+
`${CONNECTOR_NS_ATLASSIAN}updateConfluencePage`,
|
|
27509
|
+
`${CONNECTOR_NS_ATLASSIAN}createConfluenceFooterComment`,
|
|
27510
|
+
`${CONNECTOR_NS_ATLASSIAN}createConfluenceInlineComment`,
|
|
27511
|
+
`${CONNECTOR_NS_ATLASSIAN}createCompassComponent`,
|
|
27512
|
+
`${CONNECTOR_NS_ATLASSIAN}createCompassComponentRelationship`,
|
|
27513
|
+
`${CONNECTOR_NS_ATLASSIAN}createCompassCustomFieldDefinition`
|
|
27514
|
+
];
|
|
27515
|
+
function isChildExecutedTool(name) {
|
|
27516
|
+
return typeof name === "string" && name.startsWith(CONNECTOR_NS_PREFIX2);
|
|
27517
|
+
}
|
|
27518
|
+
function isConnectorWriteTool(name) {
|
|
27519
|
+
if (!name.startsWith(CONNECTOR_NS_PREFIX2)) return false;
|
|
27520
|
+
const sep2 = name.indexOf("__", CONNECTOR_NS_PREFIX2.length);
|
|
27521
|
+
if (sep2 <= CONNECTOR_NS_PREFIX2.length) return true;
|
|
27522
|
+
const server = name.slice(CONNECTOR_NS_PREFIX2.length, sep2);
|
|
27523
|
+
const words = connectorNameWords(name.slice(sep2 + "__".length));
|
|
27524
|
+
const serverWords = connectorNameWords(server);
|
|
27525
|
+
let skipped = 0;
|
|
27526
|
+
while (skipped < serverWords.length && words[skipped] === serverWords[skipped] && !CONNECTOR_MUTATION_WORDS.has(words[skipped])) skipped++;
|
|
27527
|
+
const rest = words.slice(skipped);
|
|
27528
|
+
if (rest.length === 0) return true;
|
|
27529
|
+
if (!CONNECTOR_READ_VERBS.has(rest[0])) return true;
|
|
27530
|
+
return rest.some((word) => CONNECTOR_MUTATION_WORDS.has(word));
|
|
27531
|
+
}
|
|
27532
|
+
function connectorWriteModeFromEnv() {
|
|
27533
|
+
const v2 = (process.env.CLAUDE_BRIDGE_CONNECTOR_WRITE ?? "").trim().toLowerCase();
|
|
27534
|
+
if (v2 === "allow") return "allow";
|
|
27535
|
+
if (v2 === "deny") return "deny";
|
|
27810
27536
|
return void 0;
|
|
27811
27537
|
}
|
|
27812
|
-
function
|
|
27813
|
-
const
|
|
27814
|
-
|
|
27815
|
-
|
|
27816
|
-
|
|
27817
|
-
|
|
27818
|
-
|
|
27538
|
+
function connectorWriteModeFor(config2) {
|
|
27539
|
+
const resolved = connectorWriteModeFromEnv() ?? normalizeConnectorWriteMode(config2?.provider?.connectorWriteMode);
|
|
27540
|
+
return resolved === "allow" ? "allow" : "deny";
|
|
27541
|
+
}
|
|
27542
|
+
function connectorWriteDenyHook() {
|
|
27543
|
+
return async (input) => {
|
|
27544
|
+
try {
|
|
27545
|
+
if (input.hook_event_name !== "PreToolUse") return { continue: true };
|
|
27546
|
+
if (!isConnectorWriteTool(input.tool_name)) return { continue: true };
|
|
27547
|
+
return connectorWriteDenyOutput(String(input.tool_name));
|
|
27548
|
+
} catch {
|
|
27549
|
+
const toolName = typeof input?.tool_name === "string" ? input.tool_name : "<unknown>";
|
|
27550
|
+
return connectorWriteDenyOutput(toolName);
|
|
27819
27551
|
}
|
|
27820
|
-
}
|
|
27821
|
-
|
|
27822
|
-
|
|
27823
|
-
|
|
27824
|
-
|
|
27825
|
-
|
|
27552
|
+
};
|
|
27553
|
+
}
|
|
27554
|
+
function connectorWriteDenyOutput(toolName) {
|
|
27555
|
+
return {
|
|
27556
|
+
hookSpecificOutput: {
|
|
27557
|
+
hookEventName: "PreToolUse",
|
|
27558
|
+
permissionDecision: "deny",
|
|
27559
|
+
permissionDecisionReason: `Connector write tool "${toolName}" is blocked in read-only connector mode. Connector writes must go through the host application's gated approval flow.`
|
|
27826
27560
|
}
|
|
27827
|
-
}
|
|
27828
|
-
|
|
27829
|
-
|
|
27830
|
-
|
|
27831
|
-
|
|
27832
|
-
|
|
27561
|
+
};
|
|
27562
|
+
}
|
|
27563
|
+
function connectorQueryOptions(connectorsEnabled, writeMode = "deny") {
|
|
27564
|
+
const isolation = toolIsolationForQuery(connectorsEnabled, writeMode);
|
|
27565
|
+
if (!connectorsEnabled || writeMode === "allow") return isolation;
|
|
27566
|
+
return { ...isolation, hooks: { PreToolUse: [{ hooks: [connectorWriteDenyHook()] }] } };
|
|
27567
|
+
}
|
|
27568
|
+
function toolIsolationForQuery(connectorsEnabled, writeMode = "deny") {
|
|
27569
|
+
if (!connectorsEnabled) return CLAUDE_BRIDGE_TOOL_ISOLATION;
|
|
27570
|
+
const disallowedTools = DISALLOWED_BUILTIN_TOOLS.filter((t) => !CONNECTOR_DISCOVERY_TOOLS.includes(t));
|
|
27571
|
+
if (writeMode !== "allow") disallowedTools.push(...CONNECTOR_WRITE_TOOLS);
|
|
27572
|
+
return {
|
|
27573
|
+
disallowedTools,
|
|
27574
|
+
allowedTools: [...CLAUDE_BRIDGE_TOOL_ISOLATION.allowedTools, ...CLAUDE_AI_CONNECTOR_TOOL_PATTERNS]
|
|
27575
|
+
};
|
|
27576
|
+
}
|
|
27577
|
+
function connectorMcpServers(inventory) {
|
|
27578
|
+
if (!inventory.ok) return {};
|
|
27579
|
+
if (connectorDeclarationsDisabled()) return {};
|
|
27580
|
+
const servers = {};
|
|
27581
|
+
for (const entry of inventory.connectors) {
|
|
27582
|
+
if (entry.installState !== "connected") continue;
|
|
27583
|
+
if (!entry.installedServerId) continue;
|
|
27584
|
+
servers[connectorServerName(entry.name)] = {
|
|
27585
|
+
type: "claudeai-proxy",
|
|
27586
|
+
url: connectorProxyUrl(entry.installedServerId),
|
|
27587
|
+
id: entry.installedServerId,
|
|
27588
|
+
alwaysLoad: true
|
|
27589
|
+
};
|
|
27590
|
+
}
|
|
27591
|
+
return servers;
|
|
27592
|
+
}
|
|
27593
|
+
function connectorDeclarationsDisabled(env = process.env) {
|
|
27594
|
+
const v2 = (env.CLAUDE_BRIDGE_CONNECTOR_DECLARE ?? "").trim().toLowerCase();
|
|
27595
|
+
return v2 === "off" || v2 === "0" || v2 === "false" || v2 === "no";
|
|
27596
|
+
}
|
|
27597
|
+
|
|
27598
|
+
// src/convert.ts
|
|
27599
|
+
var PROVIDER_ID = "claude-bridge";
|
|
27600
|
+
var PI_TO_SDK_TOOL_NAME = {
|
|
27601
|
+
read: "Read",
|
|
27602
|
+
write: "Write",
|
|
27603
|
+
edit: "Edit",
|
|
27604
|
+
bash: "Bash"
|
|
27605
|
+
};
|
|
27606
|
+
function sanitizeToolId(id, cache) {
|
|
27607
|
+
const existing = cache.get(id);
|
|
27608
|
+
if (existing) return existing;
|
|
27609
|
+
const clean = id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
27610
|
+
cache.set(id, clean);
|
|
27611
|
+
return clean;
|
|
27612
|
+
}
|
|
27613
|
+
function mapPiToolNameToSdk(name, customToolNameToSdk) {
|
|
27614
|
+
if (!name) return "";
|
|
27615
|
+
if (isChildExecutedTool(name)) return name;
|
|
27616
|
+
const normalized = name.toLowerCase();
|
|
27617
|
+
if (customToolNameToSdk) {
|
|
27618
|
+
const mapped = customToolNameToSdk.get(name) ?? customToolNameToSdk.get(normalized);
|
|
27619
|
+
if (mapped) return mapped;
|
|
27620
|
+
}
|
|
27621
|
+
if (PI_TO_SDK_TOOL_NAME[normalized]) return PI_TO_SDK_TOOL_NAME[normalized];
|
|
27622
|
+
return pascalCase(name);
|
|
27623
|
+
}
|
|
27624
|
+
function messageContentToText(content) {
|
|
27625
|
+
if (typeof content === "string") return content;
|
|
27626
|
+
if (!Array.isArray(content)) return "";
|
|
27627
|
+
const parts = [];
|
|
27628
|
+
let hasText = false;
|
|
27629
|
+
for (const block of content) {
|
|
27630
|
+
if (block.type === "text" && block.text) {
|
|
27631
|
+
parts.push(block.text);
|
|
27632
|
+
hasText = true;
|
|
27633
|
+
} else if (block.type !== "text" && block.type !== "image") {
|
|
27634
|
+
parts.push(`[${block.type}]`);
|
|
27635
|
+
}
|
|
27636
|
+
}
|
|
27637
|
+
return hasText ? parts.join("\n") : "";
|
|
27638
|
+
}
|
|
27639
|
+
function imageBlockToAnthropic(block) {
|
|
27640
|
+
if (!block.data || !block.mimeType) return void 0;
|
|
27641
|
+
return { type: "image", source: { type: "base64", media_type: block.mimeType, data: block.data } };
|
|
27642
|
+
}
|
|
27643
|
+
function toolResultContentToAnthropic(content) {
|
|
27644
|
+
if (typeof content === "string") return content;
|
|
27645
|
+
if (!Array.isArray(content)) return "";
|
|
27646
|
+
const blocks = [];
|
|
27647
|
+
for (const block of content) {
|
|
27648
|
+
if (block.type === "text" && block.text) {
|
|
27649
|
+
blocks.push({ type: "text", text: block.text });
|
|
27650
|
+
} else if (block.type === "image") {
|
|
27651
|
+
const image = imageBlockToAnthropic(block);
|
|
27652
|
+
if (image) blocks.push(image);
|
|
27653
|
+
} else if (block.type) {
|
|
27654
|
+
blocks.push({ type: "text", text: `[${block.type}]` });
|
|
27655
|
+
}
|
|
27656
|
+
}
|
|
27657
|
+
if (blocks.length === 0) return "";
|
|
27658
|
+
if (blocks.every((block) => block.type === "text")) return blocks.map((block) => block.text).join("\n");
|
|
27659
|
+
return blocks;
|
|
27660
|
+
}
|
|
27661
|
+
function assistantProvenancePrefix(msg) {
|
|
27662
|
+
if (msg.role !== "assistant") return void 0;
|
|
27663
|
+
const provider = typeof msg.provider === "string" ? msg.provider : void 0;
|
|
27664
|
+
const model = typeof msg.model === "string" ? msg.model : void 0;
|
|
27665
|
+
const api = typeof msg.api === "string" ? msg.api : void 0;
|
|
27666
|
+
if (!provider && !model && !api) return void 0;
|
|
27667
|
+
if (provider === PROVIDER_ID || api === "anthropic") return void 0;
|
|
27668
|
+
return `[Prior Pi assistant response from ${provider ?? api ?? "unknown-provider"}${model ? `/${model}` : ""}]
|
|
27669
|
+
`;
|
|
27670
|
+
}
|
|
27671
|
+
function userMessageToAnthropic(msg) {
|
|
27672
|
+
if (typeof msg.content === "string") return { role: "user", content: msg.content || "[empty]" };
|
|
27673
|
+
if (Array.isArray(msg.content)) {
|
|
27674
|
+
const parts = [];
|
|
27675
|
+
for (const block of msg.content) {
|
|
27676
|
+
if (block.type === "text" && block.text) parts.push({ type: "text", text: block.text });
|
|
27677
|
+
else if (block.type === "image" && block.data && block.mimeType) parts.push(imageBlockToAnthropic(block));
|
|
27678
|
+
}
|
|
27679
|
+
const kept = parts.filter(Boolean);
|
|
27680
|
+
return { role: "user", content: kept.length ? kept : "[image]" };
|
|
27681
|
+
}
|
|
27682
|
+
return { role: "user", content: "[empty]" };
|
|
27683
|
+
}
|
|
27684
|
+
function toolResultToAnthropicBlock(msg, sanitizedIds) {
|
|
27685
|
+
const content = toolResultContentToAnthropic(msg.content);
|
|
27686
|
+
return {
|
|
27687
|
+
type: "tool_result",
|
|
27688
|
+
tool_use_id: sanitizeToolId(msg.toolCallId, sanitizedIds),
|
|
27689
|
+
content: content || "",
|
|
27690
|
+
is_error: msg.isError
|
|
27691
|
+
};
|
|
27692
|
+
}
|
|
27693
|
+
function hasToolUse(msg) {
|
|
27694
|
+
return msg.role === "assistant" && Array.isArray(msg.content) && msg.content.some((block) => block.type === "toolCall");
|
|
27695
|
+
}
|
|
27696
|
+
function convertPiMessages(messages, customToolNameToSdk) {
|
|
27697
|
+
const anthropicMessages = [];
|
|
27698
|
+
const sanitizedIds = /* @__PURE__ */ new Map();
|
|
27699
|
+
const pushToolResultGroup = (toolMessages) => {
|
|
27700
|
+
if (toolMessages.length === 0) return;
|
|
27701
|
+
anthropicMessages.push({
|
|
27702
|
+
role: "user",
|
|
27703
|
+
content: toolMessages.map((toolMsg) => {
|
|
27704
|
+
const content = toolResultContentToAnthropic(toolMsg.content);
|
|
27705
|
+
return {
|
|
27706
|
+
type: "tool_result",
|
|
27707
|
+
tool_use_id: sanitizeToolId(toolMsg.toolCallId, sanitizedIds),
|
|
27708
|
+
content: content || "",
|
|
27709
|
+
is_error: toolMsg.isError
|
|
27710
|
+
};
|
|
27711
|
+
})
|
|
27712
|
+
});
|
|
27713
|
+
};
|
|
27714
|
+
for (let i = 0; i < messages.length; i++) {
|
|
27715
|
+
const msg = messages[i];
|
|
27716
|
+
if (msg.role === "user") {
|
|
27717
|
+
anthropicMessages.push(userMessageToAnthropic(msg));
|
|
27718
|
+
} else if (msg.role === "assistant") {
|
|
27719
|
+
const content = Array.isArray(msg.content) ? msg.content : [];
|
|
27720
|
+
const blocks = [];
|
|
27721
|
+
const provenance = assistantProvenancePrefix(msg);
|
|
27722
|
+
if (provenance) blocks.push({ type: "text", text: provenance });
|
|
27723
|
+
for (const block of content) {
|
|
27724
|
+
if (block.type === "text" && block.text) {
|
|
27725
|
+
blocks.push({ type: "text", text: block.text });
|
|
27726
|
+
} else if (block.type === "thinking") {
|
|
27727
|
+
const sig = block.thinkingSignature;
|
|
27728
|
+
const isAnthropicProvider = msg.provider === PROVIDER_ID || msg.api === "anthropic";
|
|
27729
|
+
if (isAnthropicProvider && sig) {
|
|
27730
|
+
blocks.push({ type: "thinking", thinking: block.thinking ?? "", signature: sig });
|
|
27731
|
+
}
|
|
27732
|
+
} else if (block.type === "toolCall") {
|
|
27733
|
+
const toolName = mapPiToolNameToSdk(block.name, customToolNameToSdk);
|
|
27734
|
+
blocks.push({ type: "tool_use", id: sanitizeToolId(block.id, sanitizedIds), name: toolName, input: block.arguments ?? {} });
|
|
27735
|
+
}
|
|
27736
|
+
}
|
|
27737
|
+
if (!blocks.length) blocks.push({ type: "text", text: "[incompatible content omitted]" });
|
|
27738
|
+
anthropicMessages.push({ role: "assistant", content: blocks });
|
|
27739
|
+
if (hasToolUse(msg)) {
|
|
27740
|
+
const toolMessages = [];
|
|
27741
|
+
const interleavedUsers = [];
|
|
27742
|
+
let j2 = i + 1;
|
|
27743
|
+
for (; j2 < messages.length; j2++) {
|
|
27744
|
+
const next = messages[j2];
|
|
27745
|
+
if (next.role === "assistant") break;
|
|
27746
|
+
if (next.role === "toolResult") toolMessages.push(next);
|
|
27747
|
+
else if (next.role === "user") interleavedUsers.push(next);
|
|
27748
|
+
else break;
|
|
27749
|
+
}
|
|
27750
|
+
if (toolMessages.length > 0) {
|
|
27751
|
+
pushToolResultGroup(toolMessages);
|
|
27752
|
+
for (const userMsg of interleavedUsers) anthropicMessages.push(userMessageToAnthropic(userMsg));
|
|
27753
|
+
i = j2 - 1;
|
|
27754
|
+
}
|
|
27755
|
+
}
|
|
27756
|
+
} else if (msg.role === "toolResult") {
|
|
27757
|
+
const blocks = [];
|
|
27758
|
+
for (; i < messages.length; i++) {
|
|
27759
|
+
const toolMsg = messages[i];
|
|
27760
|
+
if (toolMsg.role !== "toolResult") {
|
|
27761
|
+
i--;
|
|
27762
|
+
break;
|
|
27763
|
+
}
|
|
27764
|
+
blocks.push(toolResultToAnthropicBlock(toolMsg, sanitizedIds));
|
|
27765
|
+
}
|
|
27766
|
+
anthropicMessages.push({ role: "user", content: blocks });
|
|
27767
|
+
}
|
|
27768
|
+
}
|
|
27769
|
+
return { anthropicMessages, sanitizedIds };
|
|
27770
|
+
}
|
|
27771
|
+
|
|
27772
|
+
// src/models.ts
|
|
27773
|
+
var FABLE_MODEL_ID = "claude-fable-5";
|
|
27774
|
+
var FABLE_FALLBACK_MODEL_ID = "claude-opus-4-8";
|
|
27775
|
+
var OPUS_5_MODEL_ID = "claude-opus-5";
|
|
27776
|
+
var SONNET_5_MODEL_ID = "claude-sonnet-5";
|
|
27777
|
+
function fallbackModelForPrimaryModel(modelId) {
|
|
27778
|
+
return modelId === FABLE_MODEL_ID || modelId === OPUS_5_MODEL_ID ? FABLE_FALLBACK_MODEL_ID : void 0;
|
|
27779
|
+
}
|
|
27780
|
+
var MODEL_IDS_IN_ORDER = [
|
|
27781
|
+
FABLE_MODEL_ID,
|
|
27782
|
+
OPUS_5_MODEL_ID,
|
|
27783
|
+
FABLE_FALLBACK_MODEL_ID,
|
|
27784
|
+
"claude-opus-4-7",
|
|
27785
|
+
"claude-opus-4-6",
|
|
27786
|
+
SONNET_5_MODEL_ID,
|
|
27787
|
+
"claude-sonnet-4-6",
|
|
27788
|
+
"claude-haiku-4-5"
|
|
27789
|
+
];
|
|
27790
|
+
var FALLBACK_MODELS = {
|
|
27791
|
+
[FABLE_MODEL_ID]: {
|
|
27792
|
+
id: FABLE_MODEL_ID,
|
|
27793
|
+
name: "Claude Fable 5",
|
|
27794
|
+
reasoning: true,
|
|
27795
|
+
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27796
|
+
input: ["text", "image"],
|
|
27797
|
+
contextWindow: 1e6,
|
|
27798
|
+
maxTokens: 128e3
|
|
27799
|
+
},
|
|
27800
|
+
[OPUS_5_MODEL_ID]: {
|
|
27801
|
+
id: OPUS_5_MODEL_ID,
|
|
27802
|
+
name: "Claude Opus 5",
|
|
27803
|
+
reasoning: true,
|
|
27804
|
+
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27805
|
+
input: ["text", "image"],
|
|
27806
|
+
contextWindow: 1e6,
|
|
27807
|
+
maxTokens: 128e3
|
|
27808
|
+
},
|
|
27809
|
+
[FABLE_FALLBACK_MODEL_ID]: {
|
|
27810
|
+
id: FABLE_FALLBACK_MODEL_ID,
|
|
27811
|
+
name: "Claude Opus 4.8",
|
|
27812
|
+
reasoning: true,
|
|
27813
|
+
thinkingLevelMap: { xhigh: "xhigh" },
|
|
27814
|
+
input: ["text", "image"],
|
|
27815
|
+
contextWindow: 1e6,
|
|
27816
|
+
maxTokens: 128e3
|
|
27817
|
+
},
|
|
27818
|
+
[SONNET_5_MODEL_ID]: {
|
|
27819
|
+
id: SONNET_5_MODEL_ID,
|
|
27820
|
+
name: "Claude Sonnet 5",
|
|
27821
|
+
reasoning: true,
|
|
27822
|
+
thinkingLevelMap: { xhigh: "xhigh", max: "max" },
|
|
27823
|
+
input: ["text", "image"],
|
|
27824
|
+
contextWindow: 1e6,
|
|
27825
|
+
maxTokens: 128e3
|
|
27826
|
+
}
|
|
27827
|
+
};
|
|
27828
|
+
function modelDisplayName(modelId) {
|
|
27829
|
+
return FALLBACK_MODELS[modelId]?.name ?? modelId;
|
|
27830
|
+
}
|
|
27831
|
+
function buildModels(piAiModels) {
|
|
27832
|
+
return MODEL_IDS_IN_ORDER.map((id) => piAiModels.find((m) => m.id === id) ?? FALLBACK_MODELS[id]).filter((m) => m != null).map(({ id, name, reasoning, input, contextWindow, maxTokens, thinkingLevelMap }) => ({
|
|
27833
|
+
id,
|
|
27834
|
+
name,
|
|
27835
|
+
reasoning,
|
|
27836
|
+
input,
|
|
27837
|
+
contextWindow,
|
|
27838
|
+
maxTokens,
|
|
27839
|
+
thinkingLevelMap,
|
|
27840
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
|
|
27841
|
+
}));
|
|
27842
|
+
}
|
|
27843
|
+
|
|
27844
|
+
// src/extract-tool-results.ts
|
|
27845
|
+
function toolResultToMcpContent(content) {
|
|
27846
|
+
if (typeof content === "string") return [{ type: "text", text: content || "" }];
|
|
27847
|
+
if (!Array.isArray(content)) return [{ type: "text", text: "" }];
|
|
27848
|
+
const blocks = [];
|
|
27849
|
+
for (const block of content) {
|
|
27850
|
+
if (block.type === "text" && block.text) blocks.push({ type: "text", text: block.text });
|
|
27851
|
+
else if (block.type === "image" && block.data && block.mimeType) blocks.push({ type: "image", data: block.data, mimeType: block.mimeType });
|
|
27852
|
+
}
|
|
27853
|
+
return blocks.length ? blocks : [{ type: "text", text: "" }];
|
|
27854
|
+
}
|
|
27855
|
+
function extractAllToolResults(messages) {
|
|
27856
|
+
const results = [];
|
|
27857
|
+
let stopIdx = -1;
|
|
27858
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
27859
|
+
const msg = messages[i];
|
|
27860
|
+
if (msg.role === "toolResult") {
|
|
27861
|
+
results.unshift({ content: toolResultToMcpContent(msg.content), isError: msg.isError, toolCallId: msg.toolCallId });
|
|
27862
|
+
} else if (msg.role === "assistant") {
|
|
27863
|
+
stopIdx = i;
|
|
27864
|
+
break;
|
|
27865
|
+
}
|
|
27866
|
+
}
|
|
27867
|
+
return { results, stopIdx };
|
|
27868
|
+
}
|
|
27869
|
+
|
|
27870
|
+
// src/query-state.ts
|
|
27871
|
+
var DRAIN_CAUSE_TEXT = {
|
|
27872
|
+
"abort": "the turn was aborted",
|
|
27873
|
+
"stream-idle-timeout": "the Claude Code stream went idle and the turn timed out",
|
|
27874
|
+
"query-end": "the query ended"
|
|
27875
|
+
};
|
|
27876
|
+
function interruptedToolCallResult(cause) {
|
|
27877
|
+
return {
|
|
27878
|
+
content: [{ type: "text", text: `Claude bridge: ${DRAIN_CAUSE_TEXT[cause]} before this tool call's result was delivered. The call did not complete and produced no output.` }],
|
|
27879
|
+
isError: true
|
|
27880
|
+
};
|
|
27881
|
+
}
|
|
27882
|
+
function toolCallDrainCause(flags) {
|
|
27883
|
+
if (flags.wasAborted || flags.signalAborted) return "abort";
|
|
27884
|
+
if (flags.streamIdleTimedOut) return "stream-idle-timeout";
|
|
27885
|
+
return "query-end";
|
|
27886
|
+
}
|
|
27887
|
+
function drainPendingToolCalls(queryCtx, cause) {
|
|
27888
|
+
const drained = queryCtx.pendingToolCalls.size;
|
|
27889
|
+
if (drained === 0) return 0;
|
|
27890
|
+
const result = interruptedToolCallResult(cause);
|
|
27891
|
+
for (const pending of queryCtx.pendingToolCalls.values()) pending.resolve(result);
|
|
27892
|
+
queryCtx.pendingToolCalls.clear();
|
|
27893
|
+
return drained;
|
|
27894
|
+
}
|
|
27895
|
+
function normalizeForCompare(value) {
|
|
27896
|
+
if (Array.isArray(value)) return value.map(normalizeForCompare);
|
|
27897
|
+
if (value && typeof value === "object") {
|
|
27898
|
+
const out = {};
|
|
27899
|
+
for (const key of Object.keys(value).sort()) {
|
|
27900
|
+
const child = value[key];
|
|
27901
|
+
if (child !== void 0) out[key] = normalizeForCompare(child);
|
|
27902
|
+
}
|
|
27903
|
+
return out;
|
|
27904
|
+
}
|
|
27905
|
+
return value;
|
|
27906
|
+
}
|
|
27907
|
+
function argsKey(value) {
|
|
27908
|
+
return JSON.stringify(normalizeForCompare(value ?? {}));
|
|
27909
|
+
}
|
|
27910
|
+
function sameArgs(left, right) {
|
|
27911
|
+
return argsKey(left) === argsKey(right);
|
|
27912
|
+
}
|
|
27913
|
+
function hasRecordedArgs(args) {
|
|
27914
|
+
return Object.keys(args ?? {}).length > 0;
|
|
27915
|
+
}
|
|
27916
|
+
function unique(values) {
|
|
27917
|
+
const out = [];
|
|
27918
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27919
|
+
for (const value of values) {
|
|
27920
|
+
if (!value || seen.has(value)) continue;
|
|
27921
|
+
seen.add(value);
|
|
27922
|
+
out.push(value);
|
|
27923
|
+
}
|
|
27924
|
+
return out;
|
|
27925
|
+
}
|
|
27926
|
+
var QueryContext = class {
|
|
27927
|
+
// Query-scoped (fully isolated per query)
|
|
27928
|
+
activeQuery = null;
|
|
27929
|
+
currentPiStream = null;
|
|
27930
|
+
latestCursor = 0;
|
|
27931
|
+
pendingToolCalls = /* @__PURE__ */ new Map();
|
|
27932
|
+
pendingResults = /* @__PURE__ */ new Map();
|
|
27933
|
+
turnToolCallIds = [];
|
|
27934
|
+
turnToolCalls = [];
|
|
27935
|
+
/**
|
|
27936
|
+
* id → Pi tool name for every tool call this QUERY recorded, across all child
|
|
27937
|
+
* messages. Deliberately NOT cleared by resetToolTracking: per-message tracking
|
|
27938
|
+
* resets at every message boundary, but `pendingResults` is query-scoped, so a
|
|
27939
|
+
* result stranded there outlives the message that named it. Without this map a
|
|
27940
|
+
* teardown report can only say "1 queued" with empty toolNames and 0/0
|
|
27941
|
+
* counters — which is exactly the unactionable record the 2026-07-28 diag log
|
|
27942
|
+
* showed. Bounded by the number of tool calls in one query.
|
|
27943
|
+
*/
|
|
27944
|
+
queryToolNames = /* @__PURE__ */ new Map();
|
|
27945
|
+
claimedToolCallIds = /* @__PURE__ */ new Set();
|
|
27946
|
+
deliveredToolResultIds = /* @__PURE__ */ new Set();
|
|
27947
|
+
resolvedToolResultIds = /* @__PURE__ */ new Set();
|
|
27948
|
+
unmatchedToolResultIds = /* @__PURE__ */ new Set();
|
|
27949
|
+
reportedToolResultMismatch = false;
|
|
27950
|
+
deferredUserMessages = [];
|
|
27951
|
+
handledTerminalError = false;
|
|
27952
|
+
/** Armed grace timer for ending a tool_use turn whose terminal stream events
|
|
27953
|
+
* (message_delta/message_stop) never arrive. The normal path ends the turn at
|
|
27954
|
+
* message_stop, AFTER message_delta delivered the real output-token count;
|
|
27955
|
+
* this is the deadlock backstop for streams that go silent instead. Managed
|
|
27956
|
+
* by schedule/cancelToolUseTurnEnd in assistant-stream.ts. */
|
|
27957
|
+
scheduledToolUseEnd = null;
|
|
27958
|
+
// Tool calls the CHILD executes itself (claude.ai connectors — see
|
|
27959
|
+
// isChildExecutedTool). Deliberately NOT in turnToolCalls/turnToolCallIds:
|
|
27960
|
+
// those track calls Pi owes a result for, and Pi owes nothing here. Kept only
|
|
27961
|
+
// so the child's real result can be recognized when it comes back on the SDK's
|
|
27962
|
+
// `user` message, and so the streamed block's deltas can be skipped silently
|
|
27963
|
+
// instead of logging as "unmatched" (which reads like a bug).
|
|
27964
|
+
/** tool_use id → raw SDK tool name. */
|
|
27965
|
+
childExecutedToolCalls = /* @__PURE__ */ new Map();
|
|
27966
|
+
/**
|
|
27967
|
+
* The same calls, for the connector-call audit trail (see connector-audit.ts).
|
|
27968
|
+
*
|
|
27969
|
+
* Query-scoped and deliberately NOT cleared by resetToolTracking: that runs at
|
|
27970
|
+
* every child message boundary, and a call issued in one child message is only
|
|
27971
|
+
* reconciled after that message ends. Clearing it there would make an abandoned
|
|
27972
|
+
* call unrecordable at teardown — which is the one case the trail exists for.
|
|
27973
|
+
*/
|
|
27974
|
+
connectorCallAudit = /* @__PURE__ */ new Map();
|
|
27975
|
+
/** Claude Code session id for this query, from the SDK's `system` init message.
|
|
27976
|
+
* Undefined until it arrives; the audit trail omits the field rather than
|
|
27977
|
+
* guessing. */
|
|
27978
|
+
childSessionId;
|
|
27979
|
+
/** Anthropic content-block indexes of the current assistant message that carry
|
|
27980
|
+
* a child-executed tool_use. Scoped to one message: cleared at message_start,
|
|
27981
|
+
* and an index is released as soon as a new block starts there. */
|
|
27982
|
+
childExecutedStreamIndexes = /* @__PURE__ */ new Set();
|
|
27983
|
+
// Usage accounting for a Pi turn that spans SEVERAL child assistant messages.
|
|
27984
|
+
//
|
|
27985
|
+
// Every child message is a separate billed API call, and each reports its own
|
|
27986
|
+
// counters — `message_start`/`message_delta` REPLACE rather than accumulate. A
|
|
27987
|
+
// Pi turn used to end at the first tool call, so one Pi message meant one child
|
|
27988
|
+
// message and replacing was right. A turn containing a child-executed connector
|
|
27989
|
+
// call now keeps running across the child's follow-up messages, so replacing
|
|
27990
|
+
// would silently drop everything the earlier ones billed (measured: 55,685
|
|
27991
|
+
// cache-write tokens lost on a single connector turn).
|
|
27992
|
+
//
|
|
27993
|
+
// So: `turnUsageCarry` holds the totals of the child messages already COMPLETE
|
|
27994
|
+
// in this Pi turn, `currentMessageUsage` holds the one in flight, and the Pi
|
|
27995
|
+
// message reports their sum. Summing is the correct model for input and cache
|
|
27996
|
+
// too — each call bills its own.
|
|
27997
|
+
turnUsageCarry = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
27998
|
+
currentMessageUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
27999
|
+
/** Anthropic id of the child message `currentMessageUsage` describes. */
|
|
28000
|
+
currentMessageId;
|
|
28001
|
+
/**
|
|
28002
|
+
* Declare which child message the following usage belongs to, banking the
|
|
28003
|
+
* previous one's counters into the turn total.
|
|
28004
|
+
*
|
|
28005
|
+
* Keyed on the MESSAGE ID rather than on the call site, because both paths
|
|
28006
|
+
* that see a message boundary can fire for the SAME message: `message_start`
|
|
28007
|
+
* arrives on the stream, and the SDK then yields that message again in
|
|
28008
|
+
* completed form. Banking per call site double-counted whenever the completed
|
|
28009
|
+
* copy took the no-stream-events branch — which it does whenever a message
|
|
28010
|
+
* produced no content blocks, since `turnSawStreamEvent` only tracks those.
|
|
28011
|
+
*
|
|
28012
|
+
* With no id on either side (older/streamless shapes) this degrades to
|
|
28013
|
+
* banking on every call, which is what each caller means when it cannot
|
|
28014
|
+
* prove otherwise.
|
|
28015
|
+
*/
|
|
28016
|
+
beginChildMessage(messageId) {
|
|
28017
|
+
const id = typeof messageId === "string" && messageId.length > 0 ? messageId : void 0;
|
|
28018
|
+
if (id !== void 0 && id === this.currentMessageId) return;
|
|
28019
|
+
this.turnUsageCarry.input += this.currentMessageUsage.input;
|
|
28020
|
+
this.turnUsageCarry.output += this.currentMessageUsage.output;
|
|
28021
|
+
this.turnUsageCarry.cacheRead += this.currentMessageUsage.cacheRead;
|
|
28022
|
+
this.turnUsageCarry.cacheWrite += this.currentMessageUsage.cacheWrite;
|
|
28023
|
+
this.currentMessageUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
28024
|
+
this.currentMessageId = id;
|
|
28025
|
+
}
|
|
28026
|
+
// Per-turn (reset together)
|
|
28027
|
+
turnOutput = null;
|
|
28028
|
+
turnStarted = false;
|
|
28029
|
+
turnSawStreamEvent = false;
|
|
28030
|
+
turnSawToolCall = false;
|
|
28031
|
+
get turnBlocks() {
|
|
28032
|
+
if (!this.turnOutput) throw new Error("turnBlocks accessed before resetTurnState");
|
|
28033
|
+
return this.turnOutput.content;
|
|
28034
|
+
}
|
|
28035
|
+
resetTurnState(model) {
|
|
28036
|
+
this.turnOutput = {
|
|
28037
|
+
role: "assistant",
|
|
28038
|
+
content: [],
|
|
28039
|
+
api: model.api,
|
|
28040
|
+
provider: model.provider,
|
|
28041
|
+
model: model.id,
|
|
28042
|
+
usage: {
|
|
28043
|
+
input: 0,
|
|
28044
|
+
output: 0,
|
|
28045
|
+
cacheRead: 0,
|
|
28046
|
+
cacheWrite: 0,
|
|
28047
|
+
totalTokens: 0,
|
|
28048
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
|
|
28049
|
+
},
|
|
28050
|
+
stopReason: "stop",
|
|
28051
|
+
timestamp: Date.now()
|
|
28052
|
+
};
|
|
28053
|
+
this.turnStarted = false;
|
|
28054
|
+
this.turnSawStreamEvent = false;
|
|
28055
|
+
this.turnSawToolCall = false;
|
|
28056
|
+
this.handledTerminalError = false;
|
|
28057
|
+
if (this.scheduledToolUseEnd) {
|
|
28058
|
+
clearTimeout(this.scheduledToolUseEnd.timer);
|
|
28059
|
+
this.scheduledToolUseEnd = null;
|
|
28060
|
+
}
|
|
28061
|
+
this.turnUsageCarry = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
28062
|
+
this.currentMessageUsage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
|
|
28063
|
+
this.currentMessageId = void 0;
|
|
28064
|
+
}
|
|
28065
|
+
resetToolTracking() {
|
|
28066
|
+
this.turnToolCallIds = [];
|
|
28067
|
+
this.turnToolCalls = [];
|
|
28068
|
+
this.claimedToolCallIds.clear();
|
|
28069
|
+
this.deliveredToolResultIds.clear();
|
|
28070
|
+
this.resolvedToolResultIds.clear();
|
|
28071
|
+
this.unmatchedToolResultIds.clear();
|
|
28072
|
+
this.reportedToolResultMismatch = false;
|
|
28073
|
+
this.childExecutedToolCalls.clear();
|
|
28074
|
+
this.childExecutedStreamIndexes.clear();
|
|
28075
|
+
}
|
|
28076
|
+
/** Note a tool_use the child runs itself. `streamIndex` is present only on the
|
|
28077
|
+
* streamed path, where later deltas/stops for that block must be skipped. */
|
|
28078
|
+
noteChildExecutedToolCall(id, rawName, streamIndex) {
|
|
28079
|
+
if (id) {
|
|
28080
|
+
this.childExecutedToolCalls.set(id, rawName);
|
|
28081
|
+
if (!this.connectorCallAudit.has(id)) {
|
|
28082
|
+
this.connectorCallAudit.set(id, {
|
|
28083
|
+
name: rawName,
|
|
28084
|
+
...this.childSessionId ? { childSessionId: this.childSessionId } : {},
|
|
28085
|
+
recorded: false
|
|
28086
|
+
});
|
|
28087
|
+
}
|
|
28088
|
+
}
|
|
28089
|
+
if (typeof streamIndex === "number") this.childExecutedStreamIndexes.add(streamIndex);
|
|
28090
|
+
}
|
|
28091
|
+
recordToolCall(id, toolName, args = {}) {
|
|
28092
|
+
if (!id) return;
|
|
28093
|
+
this.queryToolNames.set(id, toolName);
|
|
28094
|
+
if (!this.turnToolCallIds.includes(id)) this.turnToolCallIds.push(id);
|
|
28095
|
+
const existing = this.turnToolCalls.find((call) => call.id === id);
|
|
28096
|
+
if (existing) {
|
|
28097
|
+
existing.toolName = toolName;
|
|
28098
|
+
existing.arguments = args;
|
|
28099
|
+
return;
|
|
28100
|
+
}
|
|
28101
|
+
this.turnToolCalls.push({ id, toolName, arguments: args });
|
|
28102
|
+
}
|
|
28103
|
+
updateToolCallArgs(id, args) {
|
|
28104
|
+
if (!id) return;
|
|
28105
|
+
const existing = this.turnToolCalls.find((call) => call.id === id);
|
|
28106
|
+
if (existing) existing.arguments = args;
|
|
28107
|
+
}
|
|
28108
|
+
hasRecordedToolCall(id) {
|
|
28109
|
+
return Boolean(id && (this.turnToolCallIds.includes(id) || this.turnToolCalls.some((call) => call.id === id)));
|
|
28110
|
+
}
|
|
28111
|
+
claimToolCall(toolName, args = {}) {
|
|
28112
|
+
const unclaimed = this.turnToolCalls.filter((call) => !this.claimedToolCallIds.has(call.id));
|
|
28113
|
+
const byName = unclaimed.filter((call) => call.toolName === toolName);
|
|
28114
|
+
const exact = byName.filter((call) => sameArgs(call.arguments, args));
|
|
28115
|
+
let chosen;
|
|
28116
|
+
let match = "none";
|
|
28117
|
+
let ambiguous = false;
|
|
28118
|
+
let argsMismatch = false;
|
|
28119
|
+
if (exact.length > 0) {
|
|
28120
|
+
chosen = exact[0];
|
|
28121
|
+
match = "tool-args";
|
|
28122
|
+
ambiguous = exact.length > 1;
|
|
28123
|
+
} else if (byName.length === 1) {
|
|
28124
|
+
chosen = byName[0];
|
|
28125
|
+
match = "tool-name";
|
|
28126
|
+
argsMismatch = hasRecordedArgs(byName[0].arguments);
|
|
28127
|
+
}
|
|
28128
|
+
if (!chosen) return { match: "none", ambiguous: false, available: unclaimed.length };
|
|
28129
|
+
this.claimedToolCallIds.add(chosen.id);
|
|
28130
|
+
return { toolCallId: chosen.id, match, ambiguous, available: unclaimed.length, ...argsMismatch ? { argsMismatch } : {} };
|
|
28131
|
+
}
|
|
28132
|
+
/**
|
|
28133
|
+
* Drain results still queued in `pendingResults` and report what was dropped.
|
|
28134
|
+
*
|
|
28135
|
+
* Called at a child MESSAGE boundary (message_start / the no-stream-events
|
|
28136
|
+
* assistant fallback): by then the child has necessarily received every tool
|
|
28137
|
+
* result for the previous message — a handler that matched resolved its result
|
|
28138
|
+
* directly or from this queue, and one that never matched already returned an
|
|
28139
|
+
* error. Whatever is still queued therefore belongs to a call whose handler
|
|
28140
|
+
* gave up, and no consumer will ever come for it. Left in place, each entry
|
|
28141
|
+
* poisons every later mismatch report for the whole query (queued>0 with 0/0
|
|
28142
|
+
* counters and no tool names) and forces a session rebuild per turn.
|
|
28143
|
+
*/
|
|
28144
|
+
takeStaleQueuedResults() {
|
|
28145
|
+
if (this.pendingResults.size === 0) return [];
|
|
28146
|
+
const stale = [...this.pendingResults.keys()].map((id) => ({
|
|
28147
|
+
id,
|
|
28148
|
+
toolName: this.queryToolNames.get(id) ?? "unknown"
|
|
28149
|
+
}));
|
|
28150
|
+
this.pendingResults.clear();
|
|
28151
|
+
return stale;
|
|
28152
|
+
}
|
|
28153
|
+
markToolResultDelivered(id) {
|
|
28154
|
+
if (id) this.deliveredToolResultIds.add(id);
|
|
28155
|
+
}
|
|
28156
|
+
markToolResultResolved(id) {
|
|
28157
|
+
if (id) this.resolvedToolResultIds.add(id);
|
|
28158
|
+
}
|
|
28159
|
+
markToolResultUnmatched(id) {
|
|
28160
|
+
if (id) this.unmatchedToolResultIds.add(id);
|
|
28161
|
+
}
|
|
28162
|
+
toolResultProgress() {
|
|
28163
|
+
const expectedIds = unique([
|
|
28164
|
+
...this.turnToolCalls.map((call) => call.id),
|
|
28165
|
+
...this.turnToolCallIds
|
|
28166
|
+
]);
|
|
28167
|
+
const deliveredIds = unique(this.deliveredToolResultIds);
|
|
28168
|
+
const resolvedIds = unique(this.resolvedToolResultIds);
|
|
28169
|
+
const waitingIds = unique(this.pendingToolCalls.keys());
|
|
28170
|
+
const queuedIds = unique(this.pendingResults.keys());
|
|
28171
|
+
const unmatchedResultIds = unique(this.unmatchedToolResultIds);
|
|
28172
|
+
const missingDeliveredIds = expectedIds.filter((id) => !this.deliveredToolResultIds.has(id));
|
|
28173
|
+
const unresolvedIds = expectedIds.filter((id) => !this.resolvedToolResultIds.has(id));
|
|
28174
|
+
const affectedIds = /* @__PURE__ */ new Set([...missingDeliveredIds, ...unresolvedIds, ...waitingIds, ...queuedIds, ...unmatchedResultIds]);
|
|
28175
|
+
const counts = /* @__PURE__ */ new Map();
|
|
28176
|
+
if (affectedIds.size > 0) {
|
|
28177
|
+
for (const id of affectedIds) {
|
|
28178
|
+
const name = this.queryToolNames.get(id) ?? this.turnToolCalls.find((call) => call.id === id)?.toolName ?? "unknown";
|
|
28179
|
+
counts.set(name, (counts.get(name) ?? 0) + 1);
|
|
28180
|
+
}
|
|
28181
|
+
} else {
|
|
28182
|
+
for (const call of this.turnToolCalls) {
|
|
28183
|
+
counts.set(call.toolName, (counts.get(call.toolName) ?? 0) + 1);
|
|
28184
|
+
}
|
|
28185
|
+
}
|
|
28186
|
+
return {
|
|
28187
|
+
expectedIds,
|
|
28188
|
+
deliveredIds,
|
|
28189
|
+
resolvedIds,
|
|
28190
|
+
waitingIds,
|
|
28191
|
+
queuedIds,
|
|
28192
|
+
unmatchedResultIds,
|
|
28193
|
+
missingDeliveredIds,
|
|
28194
|
+
unresolvedIds,
|
|
28195
|
+
toolNames: [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name, count]) => ({ name, count })),
|
|
28196
|
+
expectedCount: expectedIds.length,
|
|
28197
|
+
deliveredCount: deliveredIds.length,
|
|
28198
|
+
resolvedCount: resolvedIds.length,
|
|
28199
|
+
waitingCount: waitingIds.length,
|
|
28200
|
+
queuedCount: queuedIds.length,
|
|
28201
|
+
unmatchedResultCount: unmatchedResultIds.length
|
|
28202
|
+
};
|
|
28203
|
+
}
|
|
28204
|
+
};
|
|
28205
|
+
var _ctx = new QueryContext();
|
|
28206
|
+
var contextStack = [];
|
|
28207
|
+
function ctx() {
|
|
28208
|
+
return _ctx;
|
|
28209
|
+
}
|
|
28210
|
+
function stackDepth() {
|
|
28211
|
+
return contextStack.length;
|
|
28212
|
+
}
|
|
28213
|
+
function pushContext() {
|
|
28214
|
+
if (!_ctx.activeQuery) throw new Error("pushContext() called with no active query");
|
|
28215
|
+
contextStack.push(_ctx);
|
|
28216
|
+
_ctx = new QueryContext();
|
|
28217
|
+
}
|
|
28218
|
+
function popContext() {
|
|
28219
|
+
if (contextStack.length === 0) throw new Error("popContext() called with empty stack");
|
|
28220
|
+
const parent = contextStack[contextStack.length - 1];
|
|
28221
|
+
parent.deferredUserMessages.push(..._ctx.deferredUserMessages);
|
|
28222
|
+
_ctx = contextStack.pop();
|
|
28223
|
+
}
|
|
28224
|
+
function popContextFor(target) {
|
|
28225
|
+
if (_ctx === target) {
|
|
28226
|
+
popContext();
|
|
28227
|
+
return true;
|
|
28228
|
+
}
|
|
28229
|
+
const idx = contextStack.indexOf(target);
|
|
28230
|
+
if (idx < 0) return false;
|
|
28231
|
+
const parent = idx > 0 ? contextStack[idx - 1] : void 0;
|
|
28232
|
+
parent?.deferredUserMessages.push(...target.deferredUserMessages);
|
|
28233
|
+
contextStack.splice(idx, 1);
|
|
28234
|
+
return true;
|
|
28235
|
+
}
|
|
28236
|
+
|
|
28237
|
+
// src/debug.ts
|
|
28238
|
+
import { appendFileSync as appendFileSync2, chmodSync, mkdirSync as mkdirSync2 } from "fs";
|
|
28239
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
28240
|
+
var DEBUG = process.env.CLAUDE_BRIDGE_DEBUG === "1";
|
|
28241
|
+
var DEBUG_LOG_PATH = process.env.CLAUDE_BRIDGE_DEBUG_PATH || join3(piUserDir(), "claude-bridge.log");
|
|
28242
|
+
function diagLogPath() {
|
|
28243
|
+
return process.env.CLAUDE_BRIDGE_DIAG_PATH || join3(piUserDir(), "claude-bridge-diag.log");
|
|
28244
|
+
}
|
|
28245
|
+
if (DEBUG) {
|
|
28246
|
+
try {
|
|
28247
|
+
mkdirSync2(dirname2(DEBUG_LOG_PATH), { recursive: true });
|
|
28248
|
+
mkdirSync2(dirname2(diagLogPath()), { recursive: true, mode: 448 });
|
|
28249
|
+
} catch {
|
|
28250
|
+
}
|
|
28251
|
+
}
|
|
28252
|
+
var moduleInstanceId = Math.random().toString(36).slice(2, 8);
|
|
28253
|
+
function debug(...args) {
|
|
28254
|
+
if (!DEBUG) return;
|
|
28255
|
+
const ts2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
28256
|
+
const fmt = (a) => {
|
|
28257
|
+
if (typeof a === "string") return a;
|
|
28258
|
+
if (a instanceof Error) return `${a.name}: ${a.message}${a.stack ? "\n" + a.stack : ""}`;
|
|
28259
|
+
return JSON.stringify(a);
|
|
28260
|
+
};
|
|
28261
|
+
const msg = args.map(fmt).join(" ");
|
|
28262
|
+
try {
|
|
28263
|
+
appendFileSync2(DEBUG_LOG_PATH, `[${ts2}] [${moduleInstanceId}] ${msg}
|
|
28264
|
+
`);
|
|
28265
|
+
} catch {
|
|
28266
|
+
}
|
|
28267
|
+
}
|
|
28268
|
+
var nextCliDebugSeq = 1;
|
|
28269
|
+
function makeCliDebugOptions(tag) {
|
|
28270
|
+
if (!DEBUG) return {};
|
|
28271
|
+
const seq = nextCliDebugSeq++;
|
|
28272
|
+
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
28273
|
+
const logDir = join3(dirname2(DEBUG_LOG_PATH), "cc-cli-logs");
|
|
28274
|
+
try {
|
|
28275
|
+
mkdirSync2(logDir, { recursive: true });
|
|
28276
|
+
} catch {
|
|
28277
|
+
}
|
|
28278
|
+
const debugFile = join3(logDir, `${ts2}-${tag}-${seq}.log`);
|
|
28279
|
+
debug(`cli-debug: ${tag} #${seq} \u2192 ${debugFile}`);
|
|
28280
|
+
return {
|
|
28281
|
+
debug: true,
|
|
28282
|
+
debugFile,
|
|
28283
|
+
stderr: (data) => {
|
|
28284
|
+
for (const line of data.split(/\r?\n/)) {
|
|
28285
|
+
if (line) debug(`[cli-stderr ${tag}#${seq}] ${line}`);
|
|
28286
|
+
}
|
|
28287
|
+
}
|
|
28288
|
+
};
|
|
28289
|
+
}
|
|
28290
|
+
function diagDump(label, data) {
|
|
28291
|
+
try {
|
|
28292
|
+
const ts2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
28293
|
+
const entry = { ts: ts2, moduleInstanceId, label, ...data };
|
|
28294
|
+
const path = diagLogPath();
|
|
28295
|
+
try {
|
|
28296
|
+
mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
|
|
28297
|
+
} catch {
|
|
28298
|
+
}
|
|
28299
|
+
appendFileSync2(path, JSON.stringify(entry) + "\n", { mode: 384 });
|
|
28300
|
+
try {
|
|
28301
|
+
chmodSync(path, 384);
|
|
28302
|
+
} catch {
|
|
28303
|
+
}
|
|
28304
|
+
debug(`DIAG: ${label} (see ${path})`);
|
|
28305
|
+
} catch (error51) {
|
|
28306
|
+
debug(`DIAG FAILED: ${label}`, error51);
|
|
28307
|
+
}
|
|
28308
|
+
}
|
|
28309
|
+
|
|
28310
|
+
// src/tool-pairing-audit.ts
|
|
28311
|
+
function contentBlocks(content) {
|
|
28312
|
+
return Array.isArray(content) ? content.filter((block) => Boolean(block && typeof block === "object")) : [];
|
|
28313
|
+
}
|
|
28314
|
+
function toolUses(content) {
|
|
28315
|
+
return contentBlocks(content).filter((block) => block.type === "tool_use" && typeof block.id === "string").map((block) => ({ id: block.id, name: typeof block.name === "string" && block.name ? block.name : "unknown" }));
|
|
28316
|
+
}
|
|
28317
|
+
function toolResultIds(content) {
|
|
28318
|
+
const ids = /* @__PURE__ */ new Set();
|
|
28319
|
+
for (const block of contentBlocks(content)) {
|
|
28320
|
+
if (block.type === "tool_result" && typeof block.tool_use_id === "string") ids.add(block.tool_use_id);
|
|
28321
|
+
}
|
|
28322
|
+
return ids;
|
|
28323
|
+
}
|
|
28324
|
+
function findUnpairedToolUses(messages) {
|
|
28325
|
+
const missing = [];
|
|
28326
|
+
for (let i = 0; i < messages.length; i++) {
|
|
28327
|
+
const msg = messages[i];
|
|
28328
|
+
if (msg?.role !== "assistant") continue;
|
|
28329
|
+
const uses = toolUses(msg.content);
|
|
28330
|
+
if (uses.length === 0) continue;
|
|
28331
|
+
const next = messages[i + 1];
|
|
28332
|
+
const nextUserIndex = next?.role === "user" ? i + 1 : null;
|
|
28333
|
+
const resultIds = nextUserIndex == null ? /* @__PURE__ */ new Set() : toolResultIds(next.content);
|
|
28334
|
+
for (const use2 of uses) {
|
|
28335
|
+
if (!resultIds.has(use2.id)) {
|
|
28336
|
+
missing.push({ id: use2.id, toolName: use2.name, assistantIndex: i, userIndex: nextUserIndex });
|
|
28337
|
+
}
|
|
28338
|
+
}
|
|
28339
|
+
}
|
|
28340
|
+
return missing;
|
|
28341
|
+
}
|
|
28342
|
+
var LOST_TOOL_RESULT_TEXT = "Claude bridge: the result of this tool call was lost before the session was rebuilt (the turn was interrupted). Treat the call as failed \u2014 it may or may not have executed. Re-run the tool if its output is still needed.";
|
|
28343
|
+
function insertLostToolResultPlaceholders(messages, missing) {
|
|
28344
|
+
const block = (id) => ({ type: "tool_result", tool_use_id: id, content: LOST_TOOL_RESULT_TEXT, is_error: true });
|
|
28345
|
+
const byAssistant = /* @__PURE__ */ new Map();
|
|
28346
|
+
for (const item of missing) {
|
|
28347
|
+
const group = byAssistant.get(item.assistantIndex) ?? [];
|
|
28348
|
+
group.push(item);
|
|
28349
|
+
byAssistant.set(item.assistantIndex, group);
|
|
28350
|
+
}
|
|
28351
|
+
for (const assistantIndex of [...byAssistant.keys()].sort((a, b) => b - a)) {
|
|
28352
|
+
const group = byAssistant.get(assistantIndex);
|
|
28353
|
+
const blocks = group.map((item) => block(item.id));
|
|
28354
|
+
const userIndex = group[0].userIndex;
|
|
28355
|
+
if (userIndex != null && messages[userIndex]?.role === "user") {
|
|
28356
|
+
const user = messages[userIndex];
|
|
28357
|
+
const existing = typeof user.content === "string" ? user.content ? [{ type: "text", text: user.content }] : [] : Array.isArray(user.content) ? user.content : [];
|
|
28358
|
+
user.content = [...blocks, ...existing];
|
|
28359
|
+
} else {
|
|
28360
|
+
messages.splice(assistantIndex + 1, 0, { role: "user", content: blocks });
|
|
28361
|
+
}
|
|
28362
|
+
}
|
|
28363
|
+
}
|
|
28364
|
+
function summarizeMissingToolNames(missing) {
|
|
28365
|
+
const counts = /* @__PURE__ */ new Map();
|
|
28366
|
+
for (const item of missing) counts.set(item.toolName, (counts.get(item.toolName) ?? 0) + 1);
|
|
28367
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name, count]) => ({ name, count }));
|
|
28368
|
+
}
|
|
28369
|
+
|
|
28370
|
+
// src/bridge-state.ts
|
|
28371
|
+
var sharedSession = null;
|
|
28372
|
+
var extensionApi;
|
|
28373
|
+
var piUI;
|
|
28374
|
+
function setSharedSession(next) {
|
|
28375
|
+
sharedSession = next;
|
|
28376
|
+
}
|
|
28377
|
+
function setExtensionApi(next) {
|
|
28378
|
+
extensionApi = next;
|
|
28379
|
+
}
|
|
28380
|
+
function setPiUI(next) {
|
|
28381
|
+
piUI = next;
|
|
28382
|
+
}
|
|
28383
|
+
function safeNotify(message, level = "warning") {
|
|
28384
|
+
try {
|
|
28385
|
+
piUI?.notify(message, level);
|
|
28386
|
+
} catch (error51) {
|
|
28387
|
+
debug("notify failed:", error51);
|
|
28388
|
+
}
|
|
28389
|
+
}
|
|
28390
|
+
function argKeys(args) {
|
|
28391
|
+
return Object.keys(args ?? {}).sort();
|
|
28392
|
+
}
|
|
28393
|
+
function safeToolCallSummary(calls) {
|
|
28394
|
+
return calls.map((call) => ({ id: call.id, toolName: call.toolName, argKeys: argKeys(call.arguments) }));
|
|
28395
|
+
}
|
|
28396
|
+
var INTEGRITY_CUSTOM_TYPE = "claude-bridge-integrity";
|
|
28397
|
+
function appendIntegrityEntry(label, data) {
|
|
28398
|
+
try {
|
|
28399
|
+
if (!extensionApi) return false;
|
|
28400
|
+
extensionApi.appendEntry(INTEGRITY_CUSTOM_TYPE, { label, at: (/* @__PURE__ */ new Date()).toISOString(), ...data });
|
|
28401
|
+
return true;
|
|
28402
|
+
} catch (error51) {
|
|
28403
|
+
debug("appendIntegrityEntry failed:", error51);
|
|
28404
|
+
return false;
|
|
28405
|
+
}
|
|
28406
|
+
}
|
|
28407
|
+
function compactToolNameSummary(names, limit = 12) {
|
|
28408
|
+
const shown = names.slice(0, limit).map(({ name, count }) => count > 1 ? `${name}\xD7${count}` : name);
|
|
28409
|
+
if (names.length > limit) shown.push(`+${names.length - limit} more`);
|
|
28410
|
+
return shown;
|
|
28411
|
+
}
|
|
28412
|
+
function reportSyntheticToolResultRepair(missing, context) {
|
|
28413
|
+
try {
|
|
28414
|
+
if (missing.length === 0) return;
|
|
28415
|
+
const toolNames = summarizeMissingToolNames(missing);
|
|
28416
|
+
const toolNameSummary = compactToolNameSummary(toolNames);
|
|
28417
|
+
const sampledToolCallIds = missing.slice(0, 50).map((item) => item.id);
|
|
28418
|
+
diagDump("repair_tool_pairing_synthetic_results", {
|
|
28419
|
+
count: missing.length,
|
|
28420
|
+
toolNames,
|
|
28421
|
+
sampledToolCallIds,
|
|
28422
|
+
missing: missing.slice(0, 50),
|
|
28423
|
+
...context
|
|
28424
|
+
});
|
|
28425
|
+
appendIntegrityEntry("repair_tool_pairing_synthetic_results", {
|
|
28426
|
+
count: missing.length,
|
|
28427
|
+
toolNames,
|
|
28428
|
+
sampledToolCallIds: sampledToolCallIds.slice(0, 12)
|
|
28429
|
+
});
|
|
28430
|
+
safeNotify(
|
|
28431
|
+
`Claude bridge: ${missing.length} missing tool result(s) repaired with an explicit error placeholder${toolNameSummary.length ? ` for ${toolNameSummary.join(", ")}` : ""}. Real tool output was lost before Claude session import; see ${diagLogPath()}.`,
|
|
28432
|
+
"error"
|
|
28433
|
+
);
|
|
28434
|
+
} catch (error51) {
|
|
28435
|
+
debug("reportSyntheticToolResultRepair failed:", error51);
|
|
28436
|
+
}
|
|
28437
|
+
}
|
|
28438
|
+
function reportToolResultMismatch(queryCtx, reason, cwd, opts = {}) {
|
|
28439
|
+
try {
|
|
28440
|
+
if (queryCtx.reportedToolResultMismatch) return false;
|
|
28441
|
+
const progress = queryCtx.toolResultProgress();
|
|
28442
|
+
const hasMismatch = progress.expectedCount > 0 ? progress.unresolvedIds.length > 0 || progress.waitingCount > 0 || progress.queuedCount > 0 || progress.unmatchedResultCount > 0 : progress.waitingCount > 0 || progress.queuedCount > 0 || progress.unmatchedResultCount > 0;
|
|
28443
|
+
if (!hasMismatch) return false;
|
|
28444
|
+
queryCtx.reportedToolResultMismatch = true;
|
|
28445
|
+
if (sharedSession) {
|
|
28446
|
+
sharedSession = { ...sharedSession, needsRebuild: true, ...opts.forceRotate ? { forceRotate: true } : {} };
|
|
28447
|
+
}
|
|
28448
|
+
const toolNameSummary = compactToolNameSummary(progress.toolNames);
|
|
28449
|
+
diagDump("tool_result_delivery_mismatch", {
|
|
28450
|
+
reason,
|
|
28451
|
+
cwd,
|
|
28452
|
+
progress,
|
|
28453
|
+
activeQueryExists: queryCtx.activeQuery !== null,
|
|
28454
|
+
sharedSession: sharedSession ? {
|
|
28455
|
+
sessionId: sharedSession.sessionId.slice(0, 8),
|
|
28456
|
+
cursor: sharedSession.cursor,
|
|
28457
|
+
needsRebuild: sharedSession.needsRebuild === true,
|
|
28458
|
+
forceRotate: sharedSession.forceRotate === true
|
|
28459
|
+
} : null
|
|
28460
|
+
});
|
|
28461
|
+
appendIntegrityEntry("tool_result_delivery_mismatch", {
|
|
28462
|
+
reason,
|
|
28463
|
+
toolNames: progress.toolNames,
|
|
28464
|
+
expectedCount: progress.expectedCount,
|
|
28465
|
+
deliveredCount: progress.deliveredCount,
|
|
28466
|
+
resolvedCount: progress.resolvedCount,
|
|
28467
|
+
waitingIds: progress.waitingIds,
|
|
28468
|
+
queuedIds: progress.queuedIds,
|
|
28469
|
+
unmatchedResultIds: progress.unmatchedResultIds
|
|
28470
|
+
});
|
|
28471
|
+
safeNotify(
|
|
28472
|
+
`Claude bridge: tool result delivery interrupted during ${reason}; delivered ${progress.deliveredCount}/${progress.expectedCount}, resolved ${progress.resolvedCount}/${progress.expectedCount}, waiting=${progress.waitingCount}, queued=${progress.queuedCount}, unmatched=${progress.unmatchedResultCount}${toolNameSummary.length ? `, tools=${toolNameSummary.join(", ")}` : ""}. Claude session will rebuild before the next turn; see ${diagLogPath()}.`,
|
|
28473
|
+
"error"
|
|
28474
|
+
);
|
|
28475
|
+
return true;
|
|
28476
|
+
} catch (error51) {
|
|
28477
|
+
debug("reportToolResultMismatch failed:", error51);
|
|
28478
|
+
return false;
|
|
28479
|
+
}
|
|
28480
|
+
}
|
|
28481
|
+
function __testSetBridgeIntegrityState(state) {
|
|
28482
|
+
if ("ui" in state) piUI = state.ui;
|
|
28483
|
+
if ("sharedSession" in state) sharedSession = state.sharedSession ?? null;
|
|
28484
|
+
}
|
|
28485
|
+
function __testGetBridgeIntegrityState() {
|
|
28486
|
+
return { sharedSession };
|
|
28487
|
+
}
|
|
28488
|
+
|
|
28489
|
+
// src/connector-audit.ts
|
|
28490
|
+
var CONNECTOR_CALL_CUSTOM_TYPE = "claude-bridge-connector-call";
|
|
28491
|
+
function connectorResultByteSize(content) {
|
|
28492
|
+
if (content === void 0 || content === null) return void 0;
|
|
28493
|
+
if (typeof content === "string") return Buffer.byteLength(content, "utf8");
|
|
28494
|
+
try {
|
|
28495
|
+
const json2 = JSON.stringify(content);
|
|
28496
|
+
return typeof json2 === "string" ? Buffer.byteLength(json2, "utf8") : void 0;
|
|
28497
|
+
} catch {
|
|
28498
|
+
return void 0;
|
|
28499
|
+
}
|
|
28500
|
+
}
|
|
28501
|
+
var auditSink;
|
|
28502
|
+
function setConnectorCallAuditSink(sink) {
|
|
28503
|
+
auditSink = sink;
|
|
28504
|
+
}
|
|
28505
|
+
function appendConnectorCallAudit(data) {
|
|
28506
|
+
let delivered = false;
|
|
28507
|
+
if (extensionApi) {
|
|
28508
|
+
try {
|
|
28509
|
+
extensionApi.appendEntry(CONNECTOR_CALL_CUSTOM_TYPE, data);
|
|
28510
|
+
delivered = true;
|
|
28511
|
+
} catch (error51) {
|
|
28512
|
+
debug("appendConnectorCallAudit failed:", error51);
|
|
28513
|
+
}
|
|
28514
|
+
}
|
|
28515
|
+
if (auditSink) {
|
|
28516
|
+
try {
|
|
28517
|
+
auditSink({ ...data });
|
|
28518
|
+
delivered = true;
|
|
28519
|
+
} catch (error51) {
|
|
28520
|
+
debug("connector call audit sink failed:", error51);
|
|
28521
|
+
}
|
|
28522
|
+
}
|
|
28523
|
+
return delivered;
|
|
28524
|
+
}
|
|
28525
|
+
function recordConnectorCallResult(queryCtx, toolUseId, name, isError, byteSize) {
|
|
28526
|
+
const pending = queryCtx.connectorCallAudit.get(toolUseId);
|
|
28527
|
+
if (pending?.recorded) return false;
|
|
28528
|
+
const childSessionId = pending?.childSessionId ?? queryCtx.childSessionId;
|
|
28529
|
+
queryCtx.connectorCallAudit.set(toolUseId, { ...pending, name, childSessionId, recorded: true });
|
|
28530
|
+
return appendConnectorCallAudit({
|
|
28531
|
+
name,
|
|
28532
|
+
toolUseId,
|
|
28533
|
+
outcome: isError ? "error" : "ok",
|
|
28534
|
+
...byteSize !== void 0 ? { byteSize } : {},
|
|
28535
|
+
...childSessionId ? { childSessionId } : {}
|
|
28536
|
+
});
|
|
28537
|
+
}
|
|
28538
|
+
function flushConnectorCallAudit(queryCtx, reason) {
|
|
28539
|
+
let appended = 0;
|
|
28540
|
+
for (const [toolUseId, state] of queryCtx.connectorCallAudit) {
|
|
28541
|
+
if (state.recorded) continue;
|
|
28542
|
+
queryCtx.connectorCallAudit.set(toolUseId, { ...state, recorded: true });
|
|
28543
|
+
const childSessionId = state.childSessionId ?? queryCtx.childSessionId;
|
|
28544
|
+
if (appendConnectorCallAudit({
|
|
28545
|
+
name: state.name,
|
|
28546
|
+
toolUseId,
|
|
28547
|
+
outcome: "unobserved",
|
|
28548
|
+
reason,
|
|
28549
|
+
...childSessionId ? { childSessionId } : {}
|
|
28550
|
+
})) appended++;
|
|
28551
|
+
}
|
|
28552
|
+
return appended;
|
|
28553
|
+
}
|
|
28554
|
+
|
|
28555
|
+
// src/query-teardown.ts
|
|
28556
|
+
function teardownQuery(queryCtx, sdkQuery, cause, cwd, isReentrant) {
|
|
28557
|
+
if (queryCtx.activeQuery !== sdkQuery) return false;
|
|
28558
|
+
reportToolResultMismatch(queryCtx, "query teardown", cwd, { forceRotate: cause !== "query-end" });
|
|
28559
|
+
const drained = drainPendingToolCalls(queryCtx, cause);
|
|
28560
|
+
if (drained > 0) debug(`provider: query teardown drained ${drained} waiting MCP handler(s) as errors (cause=${cause})`);
|
|
28561
|
+
queryCtx.pendingResults.clear();
|
|
28562
|
+
const unobserved = flushConnectorCallAudit(queryCtx, cause);
|
|
28563
|
+
if (unobserved > 0) debug(`provider: query teardown recorded ${unobserved} connector call(s) with no observed result (cause=${cause})`);
|
|
28564
|
+
if (isReentrant) {
|
|
28565
|
+
if (!popContextFor(queryCtx)) debug("provider: query teardown found context already popped; skipping pop");
|
|
28566
|
+
} else {
|
|
28567
|
+
queryCtx.activeQuery = null;
|
|
28568
|
+
}
|
|
28569
|
+
return true;
|
|
28570
|
+
}
|
|
28571
|
+
|
|
28572
|
+
// src/auth-presence.ts
|
|
28573
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
28574
|
+
import { homedir as homedir2, platform as osPlatform } from "os";
|
|
28575
|
+
import { join as join4 } from "path";
|
|
28576
|
+
function resolveClaudeConfigDir(env = process.env) {
|
|
28577
|
+
const configured = env.CLAUDE_CONFIG_DIR;
|
|
28578
|
+
if (typeof configured === "string" && configured.trim().length > 0) return configured.trim();
|
|
28579
|
+
return join4(homedir2(), ".claude");
|
|
28580
|
+
}
|
|
28581
|
+
function nonEmptyEnv(value) {
|
|
28582
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
28583
|
+
}
|
|
28584
|
+
function envTruthy(value) {
|
|
28585
|
+
const v2 = value?.trim().toLowerCase();
|
|
28586
|
+
return v2 === "1" || v2 === "true";
|
|
28587
|
+
}
|
|
28588
|
+
function hasApiKeyHelper(configDir) {
|
|
28589
|
+
try {
|
|
28590
|
+
const settingsPath = join4(configDir, "settings.json");
|
|
28591
|
+
if (!existsSync3(settingsPath)) return false;
|
|
28592
|
+
const parsed = JSON.parse(readFileSync3(settingsPath, "utf8"));
|
|
28593
|
+
return typeof parsed?.apiKeyHelper === "string" && parsed.apiKeyHelper.trim().length > 0;
|
|
28594
|
+
} catch {
|
|
28595
|
+
return false;
|
|
28596
|
+
}
|
|
28597
|
+
}
|
|
28598
|
+
function hasClaudeCredentials(env = process.env, platform = osPlatform()) {
|
|
28599
|
+
if (nonEmptyEnv(env.CLAUDE_CODE_OAUTH_TOKEN)) return true;
|
|
28600
|
+
if (nonEmptyEnv(env.ANTHROPIC_API_KEY)) return true;
|
|
28601
|
+
if (nonEmptyEnv(env.ANTHROPIC_AUTH_TOKEN)) return true;
|
|
28602
|
+
if (envTruthy(env.CLAUDE_CODE_USE_BEDROCK)) return true;
|
|
28603
|
+
if (envTruthy(env.CLAUDE_CODE_USE_VERTEX)) return true;
|
|
28604
|
+
if (envTruthy(env.CLAUDE_CODE_USE_FOUNDRY)) return true;
|
|
28605
|
+
if (envTruthy(env.CLAUDE_CODE_USE_ANTHROPIC_AWS)) return true;
|
|
28606
|
+
if (envTruthy(env.CLAUDE_CODE_USE_MANTLE)) return true;
|
|
28607
|
+
const configDir = resolveClaudeConfigDir(env);
|
|
28608
|
+
if (existsSync3(join4(configDir, ".credentials.json"))) return true;
|
|
28609
|
+
if (hasApiKeyHelper(configDir)) return true;
|
|
28610
|
+
if (platform === "darwin") return true;
|
|
28611
|
+
return false;
|
|
28612
|
+
}
|
|
28613
|
+
|
|
28614
|
+
// src/native-provider.ts
|
|
28615
|
+
var NATIVE_PROVIDER_UNSUPPORTED_MESSAGE = "Claude bridge 2.x requires pi >= 0.81 (native provider API). Upgrade the host pi, or pin @vanillagreen/pi-claude-bridge@1.x.";
|
|
28616
|
+
function supportsNativeProvider(piAi2) {
|
|
28617
|
+
return typeof piAi2?.createProvider === "function";
|
|
28618
|
+
}
|
|
28619
|
+
function claudeAuthSourceLabel(env = process.env) {
|
|
28620
|
+
if (env.CLAUDE_CODE_OAUTH_TOKEN?.trim()) return "CLAUDE_CODE_OAUTH_TOKEN";
|
|
28621
|
+
if (env.ANTHROPIC_API_KEY?.trim()) return "ANTHROPIC_API_KEY";
|
|
28622
|
+
if (env.ANTHROPIC_AUTH_TOKEN?.trim()) return "ANTHROPIC_AUTH_TOKEN";
|
|
28623
|
+
return "Claude Code login";
|
|
28624
|
+
}
|
|
28625
|
+
function buildNativeProvider(piAi2, models, streamSimple, env = process.env) {
|
|
28626
|
+
if (!supportsNativeProvider(piAi2)) throw new Error(NATIVE_PROVIDER_UNSUPPORTED_MESSAGE);
|
|
28627
|
+
const stamped = models.map((model) => ({ api: "claude-bridge", baseUrl: "claude-bridge", provider: PROVIDER_ID, ...model }));
|
|
28628
|
+
const streams = {
|
|
28629
|
+
stream: streamSimple,
|
|
28630
|
+
streamSimple
|
|
28631
|
+
};
|
|
28632
|
+
return piAi2.createProvider({
|
|
28633
|
+
id: PROVIDER_ID,
|
|
28634
|
+
name: "Claude (Claude Code)",
|
|
28635
|
+
baseUrl: "claude-bridge",
|
|
28636
|
+
auth: {
|
|
28637
|
+
apiKey: {
|
|
28638
|
+
name: "Claude Code credentials",
|
|
28639
|
+
// check() exists so pi's availability pass never has to call
|
|
28640
|
+
// resolve(): both are existence-only, but check is the documented
|
|
28641
|
+
// side-effect-free probe.
|
|
28642
|
+
check: async () => hasClaudeCredentials(env) ? { type: "api_key", source: claudeAuthSourceLabel(env) } : void 0,
|
|
28643
|
+
resolve: async () => hasClaudeCredentials(env) ? { auth: { apiKey: "not-used" }, source: claudeAuthSourceLabel(env) } : void 0
|
|
28644
|
+
}
|
|
28645
|
+
},
|
|
28646
|
+
models: stamped,
|
|
28647
|
+
api: streams
|
|
28648
|
+
});
|
|
28649
|
+
}
|
|
28650
|
+
|
|
28651
|
+
// src/agents-md.ts
|
|
28652
|
+
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
28653
|
+
import { dirname as dirname3, join as join5, resolve as resolve3 } from "path";
|
|
28654
|
+
function globalAgentsPath() {
|
|
28655
|
+
return join5(piUserDir(), "AGENTS.md");
|
|
28656
|
+
}
|
|
28657
|
+
function resolveAgentsMdPath() {
|
|
28658
|
+
if (isolatedFromEnv()) return void 0;
|
|
28659
|
+
const fromCwd = findAgentsMdInParents(process.cwd());
|
|
28660
|
+
if (fromCwd) return fromCwd;
|
|
28661
|
+
const globalPath = globalAgentsPath();
|
|
28662
|
+
if (existsSync4(globalPath)) return globalPath;
|
|
28663
|
+
return void 0;
|
|
28664
|
+
}
|
|
28665
|
+
function findAgentsMdInParents(startDir) {
|
|
28666
|
+
let current = resolve3(startDir);
|
|
28667
|
+
while (true) {
|
|
28668
|
+
const candidate = join5(current, "AGENTS.md");
|
|
28669
|
+
if (existsSync4(candidate)) return candidate;
|
|
28670
|
+
const parent = dirname3(current);
|
|
28671
|
+
if (parent === current) break;
|
|
28672
|
+
current = parent;
|
|
28673
|
+
}
|
|
28674
|
+
return void 0;
|
|
28675
|
+
}
|
|
28676
|
+
function extractAgentsAppend() {
|
|
28677
|
+
const agentsPath = resolveAgentsMdPath();
|
|
28678
|
+
if (!agentsPath) return void 0;
|
|
28679
|
+
try {
|
|
28680
|
+
const content = readFileSync4(agentsPath, "utf-8").trim();
|
|
28681
|
+
if (!content) return void 0;
|
|
28682
|
+
const sanitized = sanitizeAgentsContent(content);
|
|
28683
|
+
return sanitized.length > 0 ? `# CLAUDE.md
|
|
28684
|
+
|
|
28685
|
+
${sanitized}` : void 0;
|
|
28686
|
+
} catch {
|
|
28687
|
+
return void 0;
|
|
28688
|
+
}
|
|
28689
|
+
}
|
|
28690
|
+
function sanitizeAgentsContent(content) {
|
|
28691
|
+
let sanitized = content;
|
|
28692
|
+
sanitized = sanitized.replace(/~\/\.pi\b/gi, "~/.claude");
|
|
28693
|
+
sanitized = sanitized.replace(/(^|[\s'"`])\.pi\//g, "$1.claude/");
|
|
28694
|
+
sanitized = sanitized.replace(/\b\.pi\b/gi, ".claude");
|
|
28695
|
+
sanitized = sanitized.replace(/\bpi\b/gi, "environment");
|
|
28696
|
+
return sanitized;
|
|
28697
|
+
}
|
|
28698
|
+
|
|
28699
|
+
// src/prompt-context.ts
|
|
28700
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
28701
|
+
import { dirname as dirname4, join as join6, resolve as resolve4 } from "path";
|
|
28702
|
+
function readTrimmed(path) {
|
|
28703
|
+
try {
|
|
28704
|
+
if (!existsSync5(path)) return void 0;
|
|
28705
|
+
const content = readFileSync5(path, "utf8").trim();
|
|
28706
|
+
return content.length > 0 ? content : void 0;
|
|
28707
|
+
} catch {
|
|
28708
|
+
return void 0;
|
|
28709
|
+
}
|
|
28710
|
+
}
|
|
28711
|
+
function findProjectAppendSystem(startDir) {
|
|
28712
|
+
let current = resolve4(startDir);
|
|
28713
|
+
while (true) {
|
|
28714
|
+
const candidate = join6(current, ".pi", "APPEND_SYSTEM.md");
|
|
28715
|
+
if (existsSync5(candidate)) return candidate;
|
|
28716
|
+
const parent = dirname4(current);
|
|
28717
|
+
if (parent === current) break;
|
|
28718
|
+
current = parent;
|
|
28719
|
+
}
|
|
28720
|
+
return void 0;
|
|
28721
|
+
}
|
|
28722
|
+
function readAppendSystemPromptFiles(cwd) {
|
|
28723
|
+
const files = [
|
|
28724
|
+
{ label: "global APPEND_SYSTEM.md", path: join6(piUserDir(), "APPEND_SYSTEM.md") }
|
|
28725
|
+
];
|
|
28726
|
+
const projectPath = isolatedFromEnv() ? void 0 : findProjectAppendSystem(cwd);
|
|
28727
|
+
if (projectPath) files.push({ label: "project .pi/APPEND_SYSTEM.md", path: projectPath });
|
|
28728
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28729
|
+
const output = [];
|
|
28730
|
+
for (const file2 of files) {
|
|
28731
|
+
if (seen.has(file2.path)) continue;
|
|
28732
|
+
seen.add(file2.path);
|
|
28733
|
+
const content = readTrimmed(file2.path);
|
|
28734
|
+
if (content) output.push({ label: file2.label, content });
|
|
28735
|
+
}
|
|
28736
|
+
return output;
|
|
28737
|
+
}
|
|
28738
|
+
function splitPromptBlocks(systemPrompt) {
|
|
28739
|
+
return (systemPrompt ?? "").split(/\n{2,}/).map((block) => block.trim()).filter(Boolean);
|
|
28740
|
+
}
|
|
28741
|
+
function extractHeadingSection(systemPrompt, headings) {
|
|
28742
|
+
if (!systemPrompt) return void 0;
|
|
28743
|
+
let start = -1;
|
|
28744
|
+
for (const heading of headings) {
|
|
28745
|
+
const index = systemPrompt.indexOf(heading);
|
|
28746
|
+
if (index >= 0 && (start < 0 || index < start)) start = index;
|
|
28747
|
+
}
|
|
28748
|
+
if (start < 0) return void 0;
|
|
28749
|
+
const rest = systemPrompt.slice(start).trim();
|
|
28750
|
+
const endCandidates = [
|
|
28751
|
+
rest.slice(1).search(/\n##\s+/),
|
|
28752
|
+
rest.search(/\n<\/project_instructions>/),
|
|
28753
|
+
rest.search(/\n<\/project_context>/)
|
|
28754
|
+
].map((index, offset) => index >= 0 && offset === 0 ? index + 1 : index).filter((index) => index >= 0);
|
|
28755
|
+
const end = endCandidates.length > 0 ? Math.min(...endCandidates) : -1;
|
|
28756
|
+
return (end >= 0 ? rest.slice(0, end) : rest).trim();
|
|
28757
|
+
}
|
|
28758
|
+
function extractBlockByMarkers(systemPrompt, markers) {
|
|
28759
|
+
for (const block of splitPromptBlocks(systemPrompt)) {
|
|
28760
|
+
if (markers.some((marker) => marker.test(block))) return block;
|
|
28761
|
+
}
|
|
28762
|
+
return void 0;
|
|
28763
|
+
}
|
|
28764
|
+
function buildPromptContextAppend(systemPrompt, cwd, settings) {
|
|
28765
|
+
const parts = [];
|
|
28766
|
+
const labels = [];
|
|
28767
|
+
if (settings.includeAppendSystemPromptMd) {
|
|
28768
|
+
for (const file2 of readAppendSystemPromptFiles(cwd)) {
|
|
28769
|
+
parts.push(xmlBlock("append_system_prompt", { label: file2.label }, file2.content));
|
|
28770
|
+
labels.push(file2.label);
|
|
28771
|
+
}
|
|
28772
|
+
}
|
|
28773
|
+
if (settings.includeProjectAgentsHook) {
|
|
28774
|
+
const projectAgents = extractHeadingSection(systemPrompt, ["## Project Agents", "## Project Subagents"]);
|
|
28775
|
+
if (projectAgents) {
|
|
28776
|
+
parts.push(xmlBlock("before_agent_start", { source: "project-agents" }, projectAgents));
|
|
28777
|
+
labels.push("project agents hook");
|
|
28778
|
+
}
|
|
28779
|
+
}
|
|
28780
|
+
if (settings.includeTaskPanelHook) {
|
|
28781
|
+
const taskReminder = extractBlockByMarkers(systemPrompt, [/^Task workflow reminder:/]);
|
|
28782
|
+
if (taskReminder) {
|
|
28783
|
+
parts.push(xmlBlock("before_agent_start", { source: "task-panel" }, taskReminder));
|
|
28784
|
+
labels.push("task panel hook");
|
|
27833
28785
|
}
|
|
27834
28786
|
}
|
|
27835
28787
|
if (settings.includeCavemanHook) {
|
|
@@ -42258,1026 +43210,471 @@ function convertBaseSchema(schema, ctx2) {
|
|
|
42258
43210
|
}
|
|
42259
43211
|
zodSchema = arraySchema;
|
|
42260
43212
|
} else {
|
|
42261
|
-
zodSchema = z2.array(z2.any());
|
|
42262
|
-
}
|
|
42263
|
-
break;
|
|
42264
|
-
}
|
|
42265
|
-
default:
|
|
42266
|
-
throw new Error(`Unsupported type: ${type}`);
|
|
42267
|
-
}
|
|
42268
|
-
return zodSchema;
|
|
42269
|
-
}
|
|
42270
|
-
function convertSchema(schema, ctx2) {
|
|
42271
|
-
if (typeof schema === "boolean") {
|
|
42272
|
-
return schema ? z2.any() : z2.never();
|
|
42273
|
-
}
|
|
42274
|
-
let baseSchema = convertBaseSchema(schema, ctx2);
|
|
42275
|
-
const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
|
|
42276
|
-
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
42277
|
-
const options = schema.anyOf.map((s) => convertSchema(s, ctx2));
|
|
42278
|
-
const anyOfUnion = z2.union(options);
|
|
42279
|
-
baseSchema = hasExplicitType ? z2.intersection(baseSchema, anyOfUnion) : anyOfUnion;
|
|
42280
|
-
}
|
|
42281
|
-
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
42282
|
-
const options = schema.oneOf.map((s) => convertSchema(s, ctx2));
|
|
42283
|
-
const oneOfUnion = z2.xor(options);
|
|
42284
|
-
baseSchema = hasExplicitType ? z2.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
|
42285
|
-
}
|
|
42286
|
-
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
42287
|
-
if (schema.allOf.length === 0) {
|
|
42288
|
-
baseSchema = hasExplicitType ? baseSchema : z2.any();
|
|
42289
|
-
} else {
|
|
42290
|
-
let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx2);
|
|
42291
|
-
const startIdx = hasExplicitType ? 0 : 1;
|
|
42292
|
-
for (let i = startIdx; i < schema.allOf.length; i++) {
|
|
42293
|
-
result = z2.intersection(result, convertSchema(schema.allOf[i], ctx2));
|
|
42294
|
-
}
|
|
42295
|
-
baseSchema = result;
|
|
42296
|
-
}
|
|
42297
|
-
}
|
|
42298
|
-
if (schema.nullable === true && ctx2.version === "openapi-3.0") {
|
|
42299
|
-
baseSchema = z2.nullable(baseSchema);
|
|
42300
|
-
}
|
|
42301
|
-
if (schema.readOnly === true) {
|
|
42302
|
-
baseSchema = z2.readonly(baseSchema);
|
|
42303
|
-
}
|
|
42304
|
-
if (schema.default !== void 0) {
|
|
42305
|
-
baseSchema = baseSchema.default(schema.default);
|
|
42306
|
-
}
|
|
42307
|
-
const extraMeta = {};
|
|
42308
|
-
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
|
42309
|
-
for (const key of coreMetadataKeys) {
|
|
42310
|
-
if (key in schema) {
|
|
42311
|
-
extraMeta[key] = schema[key];
|
|
42312
|
-
}
|
|
42313
|
-
}
|
|
42314
|
-
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
|
42315
|
-
for (const key of contentMetadataKeys) {
|
|
42316
|
-
if (key in schema) {
|
|
42317
|
-
extraMeta[key] = schema[key];
|
|
42318
|
-
}
|
|
42319
|
-
}
|
|
42320
|
-
for (const key of Object.keys(schema)) {
|
|
42321
|
-
if (!RECOGNIZED_KEYS.has(key)) {
|
|
42322
|
-
extraMeta[key] = schema[key];
|
|
42323
|
-
}
|
|
42324
|
-
}
|
|
42325
|
-
if (Object.keys(extraMeta).length > 0) {
|
|
42326
|
-
ctx2.registry.add(baseSchema, extraMeta);
|
|
42327
|
-
}
|
|
42328
|
-
if (schema.description) {
|
|
42329
|
-
baseSchema = baseSchema.describe(schema.description);
|
|
42330
|
-
}
|
|
42331
|
-
return baseSchema;
|
|
42332
|
-
}
|
|
42333
|
-
function fromJSONSchema(schema, params) {
|
|
42334
|
-
if (typeof schema === "boolean") {
|
|
42335
|
-
return schema ? z2.any() : z2.never();
|
|
42336
|
-
}
|
|
42337
|
-
let normalized;
|
|
42338
|
-
try {
|
|
42339
|
-
normalized = JSON.parse(JSON.stringify(schema));
|
|
42340
|
-
} catch {
|
|
42341
|
-
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
|
42342
|
-
}
|
|
42343
|
-
const version2 = detectVersion(normalized, params?.defaultTarget);
|
|
42344
|
-
const defs = normalized.$defs || normalized.definitions || {};
|
|
42345
|
-
const ctx2 = {
|
|
42346
|
-
version: version2,
|
|
42347
|
-
defs,
|
|
42348
|
-
refs: /* @__PURE__ */ new Map(),
|
|
42349
|
-
processing: /* @__PURE__ */ new Set(),
|
|
42350
|
-
rootSchema: normalized,
|
|
42351
|
-
registry: params?.registry ?? globalRegistry
|
|
42352
|
-
};
|
|
42353
|
-
return convertSchema(normalized, ctx2);
|
|
42354
|
-
}
|
|
42355
|
-
|
|
42356
|
-
// node_modules/zod/v4/classic/coerce.js
|
|
42357
|
-
var coerce_exports = {};
|
|
42358
|
-
__export(coerce_exports, {
|
|
42359
|
-
bigint: () => bigint3,
|
|
42360
|
-
boolean: () => boolean3,
|
|
42361
|
-
date: () => date4,
|
|
42362
|
-
number: () => number3,
|
|
42363
|
-
string: () => string3
|
|
42364
|
-
});
|
|
42365
|
-
function string3(params) {
|
|
42366
|
-
return _coercedString(ZodString, params);
|
|
42367
|
-
}
|
|
42368
|
-
function number3(params) {
|
|
42369
|
-
return _coercedNumber(ZodNumber, params);
|
|
42370
|
-
}
|
|
42371
|
-
function boolean3(params) {
|
|
42372
|
-
return _coercedBoolean(ZodBoolean, params);
|
|
42373
|
-
}
|
|
42374
|
-
function bigint3(params) {
|
|
42375
|
-
return _coercedBigint(ZodBigInt, params);
|
|
42376
|
-
}
|
|
42377
|
-
function date4(params) {
|
|
42378
|
-
return _coercedDate(ZodDate, params);
|
|
42379
|
-
}
|
|
42380
|
-
|
|
42381
|
-
// node_modules/zod/v4/classic/external.js
|
|
42382
|
-
config(en_default());
|
|
42383
|
-
|
|
42384
|
-
// src/typebox-to-zod.ts
|
|
42385
|
-
function jsonSchemaPropertyToZod(prop) {
|
|
42386
|
-
let base;
|
|
42387
|
-
if (Array.isArray(prop.enum) && prop.enum.length > 0) base = external_exports.enum(prop.enum);
|
|
42388
|
-
else switch (prop.type) {
|
|
42389
|
-
case "string":
|
|
42390
|
-
base = external_exports.string();
|
|
42391
|
-
break;
|
|
42392
|
-
case "number":
|
|
42393
|
-
case "integer":
|
|
42394
|
-
base = external_exports.number();
|
|
42395
|
-
break;
|
|
42396
|
-
case "boolean":
|
|
42397
|
-
base = external_exports.boolean();
|
|
42398
|
-
break;
|
|
42399
|
-
case "array": {
|
|
42400
|
-
base = prop.items ? external_exports.array(jsonSchemaPropertyToZod(prop.items)) : external_exports.array(external_exports.unknown());
|
|
42401
|
-
const minItems = typeof prop.minItems === "number" ? prop.minItems : void 0;
|
|
42402
|
-
if (minItems !== void 0) base = base.min(minItems);
|
|
42403
|
-
break;
|
|
42404
|
-
}
|
|
42405
|
-
case "object": {
|
|
42406
|
-
if (prop.properties && typeof prop.properties === "object" && !Array.isArray(prop.properties)) {
|
|
42407
|
-
base = external_exports.object(jsonSchemaToZodShape(prop));
|
|
42408
|
-
if (prop.additionalProperties === false) base = base.strict();
|
|
42409
|
-
else if (prop.additionalProperties === true) base = base.passthrough();
|
|
42410
|
-
} else {
|
|
42411
|
-
base = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
42412
|
-
}
|
|
42413
|
-
break;
|
|
42414
|
-
}
|
|
42415
|
-
default:
|
|
42416
|
-
base = external_exports.unknown();
|
|
42417
|
-
}
|
|
42418
|
-
if (typeof prop.description === "string") base = base.describe(prop.description);
|
|
42419
|
-
return base;
|
|
42420
|
-
}
|
|
42421
|
-
function jsonSchemaToZodShape(schema) {
|
|
42422
|
-
const s = schema;
|
|
42423
|
-
if (!s || s.type !== "object" || !s.properties) return {};
|
|
42424
|
-
const props = s.properties;
|
|
42425
|
-
const required2 = new Set(Array.isArray(s.required) ? s.required : []);
|
|
42426
|
-
const shape = {};
|
|
42427
|
-
for (const [key, prop] of Object.entries(props)) {
|
|
42428
|
-
const zodProp = jsonSchemaPropertyToZod(prop);
|
|
42429
|
-
shape[key] = required2.has(key) ? zodProp : zodProp.optional();
|
|
42430
|
-
}
|
|
42431
|
-
return shape;
|
|
42432
|
-
}
|
|
42433
|
-
|
|
42434
|
-
// src/index.ts
|
|
42435
|
-
import { readFileSync as nodeReadFileSync } from "node:fs";
|
|
42436
|
-
|
|
42437
|
-
// src/pi-ai-compat.ts
|
|
42438
|
-
var dynamicImport = (specifier) => import(specifier);
|
|
42439
|
-
async function resolveGetModels(root, loadCompat = () => dynamicImport("@earendil-works/pi-ai/compat")) {
|
|
42440
|
-
if (typeof root?.getModels === "function") return root.getModels;
|
|
42441
|
-
const compat = await loadCompat();
|
|
42442
|
-
if (typeof compat?.getModels !== "function") throw new Error("pi-ai getModels API is unavailable");
|
|
42443
|
-
return compat.getModels;
|
|
42444
|
-
}
|
|
42445
|
-
|
|
42446
|
-
// src/connector-inventory.ts
|
|
42447
|
-
var CONNECTOR_NS_PREFIX = "mcp__claude_ai_";
|
|
42448
|
-
var DEFAULT_API_BASE = "https://api.anthropic.com";
|
|
42449
|
-
var OAUTH_BETA_HEADER = "oauth-2025-04-20";
|
|
42450
|
-
function connectorServerNamespace(connectorName) {
|
|
42451
|
-
return `${CONNECTOR_NS_PREFIX}${connectorName.trim().replace(/\s+/g, "_")}__`;
|
|
42452
|
-
}
|
|
42453
|
-
function credentialCandidatePaths(env = process.env) {
|
|
42454
|
-
const roots = [];
|
|
42455
|
-
const configDir = env.CLAUDE_CONFIG_DIR?.trim();
|
|
42456
|
-
if (configDir) roots.push(configDir);
|
|
42457
|
-
const home = env.HOME?.trim();
|
|
42458
|
-
if (home) roots.push(`${home}/.claude`, home);
|
|
42459
|
-
const seen = /* @__PURE__ */ new Set();
|
|
42460
|
-
const paths = [];
|
|
42461
|
-
for (const root of roots) {
|
|
42462
|
-
for (const name of [".credentials.json", ".claude.json"]) {
|
|
42463
|
-
const p2 = `${root}/${name}`;
|
|
42464
|
-
if (!seen.has(p2)) {
|
|
42465
|
-
seen.add(p2);
|
|
42466
|
-
paths.push(p2);
|
|
42467
|
-
}
|
|
42468
|
-
}
|
|
42469
|
-
}
|
|
42470
|
-
return paths;
|
|
42471
|
-
}
|
|
42472
|
-
function resolveClaudeOAuth(readFile, env = process.env) {
|
|
42473
|
-
let accessToken;
|
|
42474
|
-
let organizationUuid;
|
|
42475
|
-
for (const path of credentialCandidatePaths(env)) {
|
|
42476
|
-
const raw = readFile(path);
|
|
42477
|
-
if (!raw) continue;
|
|
42478
|
-
let parsed;
|
|
42479
|
-
try {
|
|
42480
|
-
parsed = JSON.parse(raw);
|
|
42481
|
-
} catch {
|
|
42482
|
-
continue;
|
|
42483
|
-
}
|
|
42484
|
-
accessToken ??= nonEmptyString(parsed?.claudeAiOauth?.accessToken);
|
|
42485
|
-
organizationUuid ??= nonEmptyString(parsed?.oauthAccount?.organizationUuid);
|
|
42486
|
-
if (accessToken && organizationUuid) break;
|
|
42487
|
-
}
|
|
42488
|
-
if (!accessToken || !organizationUuid) return void 0;
|
|
42489
|
-
return { accessToken, organizationUuid };
|
|
42490
|
-
}
|
|
42491
|
-
function nonEmptyString(value) {
|
|
42492
|
-
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
42493
|
-
}
|
|
42494
|
-
function connectorsListUrl(organizationUuid, apiBase = DEFAULT_API_BASE) {
|
|
42495
|
-
return `${trimTrailingSlashes(apiBase)}/api/oauth/organizations/${encodeURIComponent(organizationUuid)}/mcp/connectors/list`;
|
|
42496
|
-
}
|
|
42497
|
-
function trimTrailingSlashes(value) {
|
|
42498
|
-
let end = value.length;
|
|
42499
|
-
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
42500
|
-
return value.slice(0, end);
|
|
42501
|
-
}
|
|
42502
|
-
async function listAccountConnectors(deps) {
|
|
42503
|
-
const { credentials, apiBase, signal } = deps;
|
|
42504
|
-
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
42505
|
-
const url2 = connectorsListUrl(credentials.organizationUuid, apiBase);
|
|
42506
|
-
const fail = (reason) => ({ ok: false, complete: false, reason: redactSecret(reason, credentials.accessToken) });
|
|
42507
|
-
let response;
|
|
42508
|
-
try {
|
|
42509
|
-
response = await fetchImpl(url2, {
|
|
42510
|
-
method: "POST",
|
|
42511
|
-
headers: {
|
|
42512
|
-
"Authorization": `Bearer ${credentials.accessToken}`,
|
|
42513
|
-
"anthropic-beta": OAUTH_BETA_HEADER,
|
|
42514
|
-
"Content-Type": "application/json"
|
|
42515
|
-
},
|
|
42516
|
-
body: "{}",
|
|
42517
|
-
signal
|
|
42518
|
-
});
|
|
42519
|
-
} catch (error51) {
|
|
42520
|
-
return fail(`connector list request failed: ${errorText(error51)}`);
|
|
42521
|
-
}
|
|
42522
|
-
let bodyText;
|
|
42523
|
-
try {
|
|
42524
|
-
bodyText = await response.text();
|
|
42525
|
-
} catch (error51) {
|
|
42526
|
-
return fail(`connector list response unreadable: ${errorText(error51)}`);
|
|
42527
|
-
}
|
|
42528
|
-
if (!response.ok) {
|
|
42529
|
-
return fail(`connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
|
|
42530
|
-
}
|
|
42531
|
-
let parsed;
|
|
42532
|
-
try {
|
|
42533
|
-
parsed = JSON.parse(bodyText);
|
|
42534
|
-
} catch {
|
|
42535
|
-
return fail("connector list returned a non-JSON body");
|
|
42536
|
-
}
|
|
42537
|
-
if (!Array.isArray(parsed?.results)) {
|
|
42538
|
-
return fail("connector list response had no results array");
|
|
42539
|
-
}
|
|
42540
|
-
const connectors = [];
|
|
42541
|
-
for (const raw of parsed.results) {
|
|
42542
|
-
const entry = raw;
|
|
42543
|
-
const name = nonEmptyString(entry?.name);
|
|
42544
|
-
if (!name) {
|
|
42545
|
-
return fail("connector list contained an entry with no name");
|
|
42546
|
-
}
|
|
42547
|
-
connectors.push({
|
|
42548
|
-
name,
|
|
42549
|
-
installedServerId: nonEmptyString(entry?.installedServerId),
|
|
42550
|
-
directoryUuid: nonEmptyString(entry?.directoryUuid),
|
|
42551
|
-
description: nonEmptyString(entry?.description),
|
|
42552
|
-
isAuthless: typeof entry?.isAuthless === "boolean" ? entry.isAuthless : void 0
|
|
42553
|
-
});
|
|
42554
|
-
}
|
|
42555
|
-
return { ok: true, complete: true, connectors };
|
|
42556
|
-
}
|
|
42557
|
-
function apiErrorSuffix(bodyText) {
|
|
42558
|
-
try {
|
|
42559
|
-
const message = JSON.parse(bodyText)?.error?.message;
|
|
42560
|
-
return typeof message === "string" && message.trim() ? ` (${message.trim()})` : "";
|
|
42561
|
-
} catch {
|
|
42562
|
-
return "";
|
|
42563
|
-
}
|
|
42564
|
-
}
|
|
42565
|
-
function redactSecret(text, secret) {
|
|
42566
|
-
if (!secret || secret.length < 8) return text;
|
|
42567
|
-
let out = text;
|
|
42568
|
-
for (const form of /* @__PURE__ */ new Set([secret, encodeURIComponent(secret)])) {
|
|
42569
|
-
out = out.split(form).join("[redacted]");
|
|
42570
|
-
}
|
|
42571
|
-
return out;
|
|
42572
|
-
}
|
|
42573
|
-
function errorText(error51) {
|
|
42574
|
-
return error51 instanceof Error ? error51.message : String(error51);
|
|
42575
|
-
}
|
|
42576
|
-
|
|
42577
|
-
// src/debug.ts
|
|
42578
|
-
import { appendFileSync as appendFileSync2, chmodSync, mkdirSync as mkdirSync2 } from "fs";
|
|
42579
|
-
import { dirname as dirname4, join as join6 } from "path";
|
|
42580
|
-
var DEBUG = process.env.CLAUDE_BRIDGE_DEBUG === "1";
|
|
42581
|
-
var DEBUG_LOG_PATH = process.env.CLAUDE_BRIDGE_DEBUG_PATH || join6(piUserDir(), "claude-bridge.log");
|
|
42582
|
-
function diagLogPath() {
|
|
42583
|
-
return process.env.CLAUDE_BRIDGE_DIAG_PATH || join6(piUserDir(), "claude-bridge-diag.log");
|
|
42584
|
-
}
|
|
42585
|
-
if (DEBUG) {
|
|
42586
|
-
try {
|
|
42587
|
-
mkdirSync2(dirname4(DEBUG_LOG_PATH), { recursive: true });
|
|
42588
|
-
mkdirSync2(dirname4(diagLogPath()), { recursive: true, mode: 448 });
|
|
42589
|
-
} catch {
|
|
42590
|
-
}
|
|
42591
|
-
}
|
|
42592
|
-
var moduleInstanceId = Math.random().toString(36).slice(2, 8);
|
|
42593
|
-
function debug(...args) {
|
|
42594
|
-
if (!DEBUG) return;
|
|
42595
|
-
const ts2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
42596
|
-
const fmt = (a) => {
|
|
42597
|
-
if (typeof a === "string") return a;
|
|
42598
|
-
if (a instanceof Error) return `${a.name}: ${a.message}${a.stack ? "\n" + a.stack : ""}`;
|
|
42599
|
-
return JSON.stringify(a);
|
|
42600
|
-
};
|
|
42601
|
-
const msg = args.map(fmt).join(" ");
|
|
42602
|
-
try {
|
|
42603
|
-
appendFileSync2(DEBUG_LOG_PATH, `[${ts2}] [${moduleInstanceId}] ${msg}
|
|
42604
|
-
`);
|
|
42605
|
-
} catch {
|
|
42606
|
-
}
|
|
42607
|
-
}
|
|
42608
|
-
var nextCliDebugSeq = 1;
|
|
42609
|
-
function makeCliDebugOptions(tag) {
|
|
42610
|
-
if (!DEBUG) return {};
|
|
42611
|
-
const seq = nextCliDebugSeq++;
|
|
42612
|
-
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
42613
|
-
const logDir = join6(dirname4(DEBUG_LOG_PATH), "cc-cli-logs");
|
|
42614
|
-
try {
|
|
42615
|
-
mkdirSync2(logDir, { recursive: true });
|
|
42616
|
-
} catch {
|
|
42617
|
-
}
|
|
42618
|
-
const debugFile = join6(logDir, `${ts2}-${tag}-${seq}.log`);
|
|
42619
|
-
debug(`cli-debug: ${tag} #${seq} \u2192 ${debugFile}`);
|
|
42620
|
-
return {
|
|
42621
|
-
debug: true,
|
|
42622
|
-
debugFile,
|
|
42623
|
-
stderr: (data) => {
|
|
42624
|
-
for (const line of data.split(/\r?\n/)) {
|
|
42625
|
-
if (line) debug(`[cli-stderr ${tag}#${seq}] ${line}`);
|
|
42626
|
-
}
|
|
42627
|
-
}
|
|
42628
|
-
};
|
|
42629
|
-
}
|
|
42630
|
-
function diagDump(label, data) {
|
|
42631
|
-
try {
|
|
42632
|
-
const ts2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
42633
|
-
const entry = { ts: ts2, moduleInstanceId, label, ...data };
|
|
42634
|
-
const path = diagLogPath();
|
|
42635
|
-
try {
|
|
42636
|
-
mkdirSync2(dirname4(path), { recursive: true, mode: 448 });
|
|
42637
|
-
} catch {
|
|
42638
|
-
}
|
|
42639
|
-
appendFileSync2(path, JSON.stringify(entry) + "\n", { mode: 384 });
|
|
42640
|
-
try {
|
|
42641
|
-
chmodSync(path, 384);
|
|
42642
|
-
} catch {
|
|
42643
|
-
}
|
|
42644
|
-
debug(`DIAG: ${label} (see ${path})`);
|
|
42645
|
-
} catch (error51) {
|
|
42646
|
-
debug(`DIAG FAILED: ${label}`, error51);
|
|
42647
|
-
}
|
|
42648
|
-
}
|
|
42649
|
-
|
|
42650
|
-
// src/claude-executable.ts
|
|
42651
|
-
import { spawn as spawnProcess } from "child_process";
|
|
42652
|
-
import { accessSync, constants as fsConstants, readFileSync as readFileSync6, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
|
|
42653
|
-
import { delimiter, join as join7 } from "path";
|
|
42654
|
-
function executableFromPath(name) {
|
|
42655
|
-
const paths = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
42656
|
-
for (const dir of paths) {
|
|
42657
|
-
const candidate = join7(dir, name);
|
|
42658
|
-
try {
|
|
42659
|
-
accessSync(candidate, fsConstants.X_OK);
|
|
42660
|
-
return candidate;
|
|
42661
|
-
} catch {
|
|
42662
|
-
}
|
|
42663
|
-
}
|
|
42664
|
-
return void 0;
|
|
42665
|
-
}
|
|
42666
|
-
function resolveClaudeExecutable(configured) {
|
|
42667
|
-
const trimmed = configured?.trim();
|
|
42668
|
-
if (trimmed) return trimmed;
|
|
42669
|
-
if (isolatedFromEnv()) return void 0;
|
|
42670
|
-
return executableFromPath("claude") ?? executableFromPath("claude-code");
|
|
42671
|
-
}
|
|
42672
|
-
function errnoValue(err) {
|
|
42673
|
-
return typeof err?.errno === "number" ? err.errno : void 0;
|
|
42674
|
-
}
|
|
42675
|
-
function syscallValue(err) {
|
|
42676
|
-
return typeof err?.syscall === "string" ? err.syscall : void 0;
|
|
42677
|
-
}
|
|
42678
|
-
function pathValue(err) {
|
|
42679
|
-
const value = err?.path;
|
|
42680
|
-
return typeof value === "string" ? value : void 0;
|
|
42681
|
-
}
|
|
42682
|
-
function codeValue(err, fallback) {
|
|
42683
|
-
const value = err?.code;
|
|
42684
|
-
return typeof value === "string" ? value : fallback;
|
|
42685
|
-
}
|
|
42686
|
-
function displayValue(value) {
|
|
42687
|
-
return value === void 0 || value === null || value === "" ? "<none>" : String(value);
|
|
42688
|
-
}
|
|
42689
|
-
function makeClaudePreflightError(summary, details) {
|
|
42690
|
-
const detail = [
|
|
42691
|
-
`code=${details.code}`,
|
|
42692
|
-
`errno=${displayValue(details.errno)}`,
|
|
42693
|
-
`syscall=${displayValue(details.syscall)}`,
|
|
42694
|
-
`path=${details.path}`,
|
|
42695
|
-
`cwd=${details.cwd}`,
|
|
42696
|
-
...details.fileType ? [`fileType=${details.fileType}`] : [],
|
|
42697
|
-
...details.realPath ? [`realPath=${details.realPath}`] : []
|
|
42698
|
-
].join(" ");
|
|
42699
|
-
const error51 = new Error(`${summary} (${detail})`);
|
|
42700
|
-
error51.name = "ClaudeExecutablePreflightError";
|
|
42701
|
-
error51.code = details.code;
|
|
42702
|
-
if (details.errno !== void 0) error51.errno = typeof details.errno === "number" ? details.errno : Number(details.errno);
|
|
42703
|
-
if (details.syscall) error51.syscall = details.syscall;
|
|
42704
|
-
error51.path = details.path;
|
|
42705
|
-
error51.cwd = details.cwd;
|
|
42706
|
-
if (details.fileType) error51.fileType = details.fileType;
|
|
42707
|
-
if (details.realPath) error51.realPath = details.realPath;
|
|
42708
|
-
if (details.cause !== void 0) error51.cause = details.cause;
|
|
42709
|
-
return error51;
|
|
42710
|
-
}
|
|
42711
|
-
function classifyClaudeExecutableBytes(bytes) {
|
|
42712
|
-
if (bytes.length === 0) return "empty";
|
|
42713
|
-
if (bytes.length >= 2 && bytes[0] === 35 && bytes[1] === 33) return "shebang-script";
|
|
42714
|
-
if (bytes.length >= 4 && bytes[0] === 127 && bytes[1] === 69 && bytes[2] === 76 && bytes[3] === 70) return "elf";
|
|
42715
|
-
if (bytes.length >= 2 && bytes[0] === 77 && bytes[1] === 90) return "pe";
|
|
42716
|
-
if (bytes.length >= 4) {
|
|
42717
|
-
const magic = bytes[0] * 16777216 + bytes[1] * 65536 + bytes[2] * 256 + bytes[3];
|
|
42718
|
-
if (magic === 4277009102 || magic === 4277009103 || magic === 3472551422 || magic === 3489328638 || magic === 3405691582 || magic === 3199925962) return "mach-o";
|
|
43213
|
+
zodSchema = z2.array(z2.any());
|
|
43214
|
+
}
|
|
43215
|
+
break;
|
|
43216
|
+
}
|
|
43217
|
+
default:
|
|
43218
|
+
throw new Error(`Unsupported type: ${type}`);
|
|
42719
43219
|
}
|
|
42720
|
-
return
|
|
43220
|
+
return zodSchema;
|
|
42721
43221
|
}
|
|
42722
|
-
function
|
|
42723
|
-
|
|
42724
|
-
|
|
42725
|
-
const cwdStat = statSync2(cwd);
|
|
42726
|
-
if (!cwdStat.isDirectory()) {
|
|
42727
|
-
throw makeClaudePreflightError("Claude Code spawn cwd preflight failed: cwd is not a directory.", {
|
|
42728
|
-
code: "ENOTDIR",
|
|
42729
|
-
syscall: "chdir",
|
|
42730
|
-
path: cwd,
|
|
42731
|
-
cwd
|
|
42732
|
-
});
|
|
42733
|
-
}
|
|
42734
|
-
accessSync(cwd, fsConstants.X_OK);
|
|
42735
|
-
realCwd = realpathSync2(cwd);
|
|
42736
|
-
} catch (err) {
|
|
42737
|
-
if (err.name === "ClaudeExecutablePreflightError") throw err;
|
|
42738
|
-
throw makeClaudePreflightError("Claude Code spawn cwd preflight failed: cwd is not reachable before spawning Claude Code.", {
|
|
42739
|
-
code: codeValue(err, "EACCES"),
|
|
42740
|
-
errno: errnoValue(err),
|
|
42741
|
-
syscall: syscallValue(err),
|
|
42742
|
-
path: pathValue(err) ?? cwd,
|
|
42743
|
-
cwd,
|
|
42744
|
-
cause: err
|
|
42745
|
-
});
|
|
43222
|
+
function convertSchema(schema, ctx2) {
|
|
43223
|
+
if (typeof schema === "boolean") {
|
|
43224
|
+
return schema ? z2.any() : z2.never();
|
|
42746
43225
|
}
|
|
42747
|
-
let
|
|
42748
|
-
|
|
42749
|
-
|
|
42750
|
-
|
|
42751
|
-
|
|
42752
|
-
|
|
42753
|
-
|
|
42754
|
-
|
|
42755
|
-
|
|
42756
|
-
|
|
43226
|
+
let baseSchema = convertBaseSchema(schema, ctx2);
|
|
43227
|
+
const hasExplicitType = schema.type || schema.enum !== void 0 || schema.const !== void 0;
|
|
43228
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
43229
|
+
const options = schema.anyOf.map((s) => convertSchema(s, ctx2));
|
|
43230
|
+
const anyOfUnion = z2.union(options);
|
|
43231
|
+
baseSchema = hasExplicitType ? z2.intersection(baseSchema, anyOfUnion) : anyOfUnion;
|
|
43232
|
+
}
|
|
43233
|
+
if (schema.oneOf && Array.isArray(schema.oneOf)) {
|
|
43234
|
+
const options = schema.oneOf.map((s) => convertSchema(s, ctx2));
|
|
43235
|
+
const oneOfUnion = z2.xor(options);
|
|
43236
|
+
baseSchema = hasExplicitType ? z2.intersection(baseSchema, oneOfUnion) : oneOfUnion;
|
|
43237
|
+
}
|
|
43238
|
+
if (schema.allOf && Array.isArray(schema.allOf)) {
|
|
43239
|
+
if (schema.allOf.length === 0) {
|
|
43240
|
+
baseSchema = hasExplicitType ? baseSchema : z2.any();
|
|
43241
|
+
} else {
|
|
43242
|
+
let result = hasExplicitType ? baseSchema : convertSchema(schema.allOf[0], ctx2);
|
|
43243
|
+
const startIdx = hasExplicitType ? 0 : 1;
|
|
43244
|
+
for (let i = startIdx; i < schema.allOf.length; i++) {
|
|
43245
|
+
result = z2.intersection(result, convertSchema(schema.allOf[i], ctx2));
|
|
43246
|
+
}
|
|
43247
|
+
baseSchema = result;
|
|
42757
43248
|
}
|
|
42758
|
-
accessSync(path, fsConstants.X_OK);
|
|
42759
|
-
realPath = realpathSync2(path);
|
|
42760
|
-
} catch (err) {
|
|
42761
|
-
if (err.name === "ClaudeExecutablePreflightError") throw err;
|
|
42762
|
-
throw makeClaudePreflightError("Claude Code executable preflight failed: cannot access resolved executable before spawning Claude Code.", {
|
|
42763
|
-
code: codeValue(err, "ENOENT"),
|
|
42764
|
-
errno: errnoValue(err),
|
|
42765
|
-
syscall: syscallValue(err),
|
|
42766
|
-
path: pathValue(err) ?? path,
|
|
42767
|
-
cwd,
|
|
42768
|
-
cause: err
|
|
42769
|
-
});
|
|
42770
43249
|
}
|
|
42771
|
-
|
|
42772
|
-
|
|
42773
|
-
fileType = classifyClaudeExecutableBytes(readFileSync6(realPath).subarray(0, 16));
|
|
42774
|
-
} catch (err) {
|
|
42775
|
-
throw makeClaudePreflightError("Claude Code executable preflight failed: cannot read executable header before spawning Claude Code.", {
|
|
42776
|
-
code: codeValue(err, "EACCES"),
|
|
42777
|
-
errno: errnoValue(err),
|
|
42778
|
-
syscall: syscallValue(err),
|
|
42779
|
-
path: pathValue(err) ?? realPath,
|
|
42780
|
-
cwd,
|
|
42781
|
-
realPath,
|
|
42782
|
-
cause: err
|
|
42783
|
-
});
|
|
43250
|
+
if (schema.nullable === true && ctx2.version === "openapi-3.0") {
|
|
43251
|
+
baseSchema = z2.nullable(baseSchema);
|
|
42784
43252
|
}
|
|
42785
|
-
if (
|
|
42786
|
-
|
|
42787
|
-
code: "ENOEXEC",
|
|
42788
|
-
syscall: "exec",
|
|
42789
|
-
path,
|
|
42790
|
-
cwd,
|
|
42791
|
-
fileType,
|
|
42792
|
-
realPath
|
|
42793
|
-
});
|
|
43253
|
+
if (schema.readOnly === true) {
|
|
43254
|
+
baseSchema = z2.readonly(baseSchema);
|
|
42794
43255
|
}
|
|
42795
|
-
|
|
42796
|
-
|
|
42797
|
-
function envFlagEnabled(value) {
|
|
42798
|
-
return value === "1" || value?.toLowerCase() === "true";
|
|
42799
|
-
}
|
|
42800
|
-
function wrapClaudeSpawnErrorForSdk(err, options) {
|
|
42801
|
-
const originalCode = codeValue(err, "SPAWN_ERROR");
|
|
42802
|
-
const originalMessage = err.message;
|
|
42803
|
-
const spawnPath = pathValue(err) ?? options.command;
|
|
42804
|
-
const cwd = options.cwd ?? process.cwd();
|
|
42805
|
-
const detail = [
|
|
42806
|
-
`code=${originalCode}`,
|
|
42807
|
-
`errno=${displayValue(errnoValue(err))}`,
|
|
42808
|
-
`syscall=${displayValue(syscallValue(err))}`,
|
|
42809
|
-
`path=${spawnPath}`,
|
|
42810
|
-
`cwd=${cwd}`,
|
|
42811
|
-
`command=${options.command}`
|
|
42812
|
-
].join(" ");
|
|
42813
|
-
const wrapped = new Error(`Claude Code spawn failed: ${originalMessage} (${detail})`);
|
|
42814
|
-
wrapped.name = "ClaudeSpawnDiagnosticError";
|
|
42815
|
-
wrapped.code = originalCode === "ENOENT" ? "CLAUDE_BRIDGE_SPAWN_FAILED" : originalCode;
|
|
42816
|
-
wrapped.originalCode = originalCode;
|
|
42817
|
-
wrapped.originalMessage = originalMessage;
|
|
42818
|
-
const errno = errnoValue(err);
|
|
42819
|
-
if (errno !== void 0) wrapped.errno = typeof errno === "number" ? errno : Number(errno);
|
|
42820
|
-
const syscall = syscallValue(err);
|
|
42821
|
-
if (syscall) wrapped.syscall = syscall;
|
|
42822
|
-
wrapped.path = spawnPath;
|
|
42823
|
-
wrapped.cwd = cwd;
|
|
42824
|
-
return wrapped;
|
|
42825
|
-
}
|
|
42826
|
-
function spawnClaudeCodeWithDiagnostics(options) {
|
|
42827
|
-
const pipeStderr = DEBUG || envFlagEnabled(options.env.DEBUG_CLAUDE_AGENT_SDK);
|
|
42828
|
-
const child = spawnProcess(options.command, options.args, {
|
|
42829
|
-
cwd: options.cwd,
|
|
42830
|
-
env: options.env,
|
|
42831
|
-
signal: options.signal,
|
|
42832
|
-
stdio: ["pipe", "pipe", pipeStderr ? "pipe" : "ignore"],
|
|
42833
|
-
windowsHide: true
|
|
42834
|
-
});
|
|
42835
|
-
if (pipeStderr) {
|
|
42836
|
-
child.stderr?.on("data", (data) => {
|
|
42837
|
-
for (const line of data.toString().split(/\r?\n/)) {
|
|
42838
|
-
if (line) debug(`[cli-stderr spawn] ${line}`);
|
|
42839
|
-
}
|
|
42840
|
-
});
|
|
43256
|
+
if (schema.default !== void 0) {
|
|
43257
|
+
baseSchema = baseSchema.default(schema.default);
|
|
42841
43258
|
}
|
|
42842
|
-
|
|
42843
|
-
|
|
42844
|
-
|
|
42845
|
-
|
|
42846
|
-
|
|
42847
|
-
|
|
42848
|
-
if (originalStack) err.stack = originalStack;
|
|
42849
|
-
});
|
|
42850
|
-
return {
|
|
42851
|
-
stdin: child.stdin,
|
|
42852
|
-
stdout: child.stdout,
|
|
42853
|
-
get killed() {
|
|
42854
|
-
return child.killed;
|
|
42855
|
-
},
|
|
42856
|
-
get exitCode() {
|
|
42857
|
-
return child.exitCode;
|
|
42858
|
-
},
|
|
42859
|
-
kill: child.kill.bind(child),
|
|
42860
|
-
on: child.on.bind(child),
|
|
42861
|
-
once: child.once.bind(child),
|
|
42862
|
-
off: child.off.bind(child)
|
|
42863
|
-
};
|
|
42864
|
-
}
|
|
42865
|
-
|
|
42866
|
-
// src/tool-pairing-audit.ts
|
|
42867
|
-
function contentBlocks(content) {
|
|
42868
|
-
return Array.isArray(content) ? content.filter((block) => Boolean(block && typeof block === "object")) : [];
|
|
42869
|
-
}
|
|
42870
|
-
function toolUses(content) {
|
|
42871
|
-
return contentBlocks(content).filter((block) => block.type === "tool_use" && typeof block.id === "string").map((block) => ({ id: block.id, name: typeof block.name === "string" && block.name ? block.name : "unknown" }));
|
|
42872
|
-
}
|
|
42873
|
-
function toolResultIds(content) {
|
|
42874
|
-
const ids = /* @__PURE__ */ new Set();
|
|
42875
|
-
for (const block of contentBlocks(content)) {
|
|
42876
|
-
if (block.type === "tool_result" && typeof block.tool_use_id === "string") ids.add(block.tool_use_id);
|
|
43259
|
+
const extraMeta = {};
|
|
43260
|
+
const coreMetadataKeys = ["$id", "id", "$comment", "$anchor", "$vocabulary", "$dynamicRef", "$dynamicAnchor"];
|
|
43261
|
+
for (const key of coreMetadataKeys) {
|
|
43262
|
+
if (key in schema) {
|
|
43263
|
+
extraMeta[key] = schema[key];
|
|
43264
|
+
}
|
|
42877
43265
|
}
|
|
42878
|
-
|
|
42879
|
-
|
|
42880
|
-
|
|
42881
|
-
|
|
42882
|
-
for (let i = 0; i < messages.length; i++) {
|
|
42883
|
-
const msg = messages[i];
|
|
42884
|
-
if (msg?.role !== "assistant") continue;
|
|
42885
|
-
const uses = toolUses(msg.content);
|
|
42886
|
-
if (uses.length === 0) continue;
|
|
42887
|
-
const next = messages[i + 1];
|
|
42888
|
-
const nextUserIndex = next?.role === "user" ? i + 1 : null;
|
|
42889
|
-
const resultIds = nextUserIndex == null ? /* @__PURE__ */ new Set() : toolResultIds(next.content);
|
|
42890
|
-
for (const use2 of uses) {
|
|
42891
|
-
if (!resultIds.has(use2.id)) {
|
|
42892
|
-
missing.push({ id: use2.id, toolName: use2.name, assistantIndex: i, userIndex: nextUserIndex });
|
|
42893
|
-
}
|
|
43266
|
+
const contentMetadataKeys = ["contentEncoding", "contentMediaType", "contentSchema"];
|
|
43267
|
+
for (const key of contentMetadataKeys) {
|
|
43268
|
+
if (key in schema) {
|
|
43269
|
+
extraMeta[key] = schema[key];
|
|
42894
43270
|
}
|
|
42895
43271
|
}
|
|
42896
|
-
|
|
42897
|
-
|
|
42898
|
-
|
|
42899
|
-
|
|
42900
|
-
for (const item of missing) counts.set(item.toolName, (counts.get(item.toolName) ?? 0) + 1);
|
|
42901
|
-
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([name, count]) => ({ name, count }));
|
|
42902
|
-
}
|
|
42903
|
-
|
|
42904
|
-
// src/bridge-state.ts
|
|
42905
|
-
var sharedSession = null;
|
|
42906
|
-
var extensionApi;
|
|
42907
|
-
var piUI;
|
|
42908
|
-
function setSharedSession(next) {
|
|
42909
|
-
sharedSession = next;
|
|
42910
|
-
}
|
|
42911
|
-
function setExtensionApi(next) {
|
|
42912
|
-
extensionApi = next;
|
|
42913
|
-
}
|
|
42914
|
-
function setPiUI(next) {
|
|
42915
|
-
piUI = next;
|
|
42916
|
-
}
|
|
42917
|
-
function safeNotify(message, level = "warning") {
|
|
42918
|
-
try {
|
|
42919
|
-
piUI?.notify(message, level);
|
|
42920
|
-
} catch (error51) {
|
|
42921
|
-
debug("notify failed:", error51);
|
|
43272
|
+
for (const key of Object.keys(schema)) {
|
|
43273
|
+
if (!RECOGNIZED_KEYS.has(key)) {
|
|
43274
|
+
extraMeta[key] = schema[key];
|
|
43275
|
+
}
|
|
42922
43276
|
}
|
|
42923
|
-
|
|
42924
|
-
|
|
42925
|
-
|
|
42926
|
-
|
|
42927
|
-
|
|
42928
|
-
return calls.map((call) => ({ id: call.id, toolName: call.toolName, argKeys: argKeys(call.arguments) }));
|
|
42929
|
-
}
|
|
42930
|
-
function compactToolNameSummary(names, limit = 12) {
|
|
42931
|
-
const shown = names.slice(0, limit).map(({ name, count }) => count > 1 ? `${name}\xD7${count}` : name);
|
|
42932
|
-
if (names.length > limit) shown.push(`+${names.length - limit} more`);
|
|
42933
|
-
return shown;
|
|
42934
|
-
}
|
|
42935
|
-
function reportSyntheticToolResultRepair(missing, context) {
|
|
42936
|
-
try {
|
|
42937
|
-
if (missing.length === 0) return;
|
|
42938
|
-
const toolNames = summarizeMissingToolNames(missing);
|
|
42939
|
-
const toolNameSummary = compactToolNameSummary(toolNames);
|
|
42940
|
-
const sampledToolCallIds = missing.slice(0, 50).map((item) => item.id);
|
|
42941
|
-
diagDump("repair_tool_pairing_synthetic_results", {
|
|
42942
|
-
count: missing.length,
|
|
42943
|
-
toolNames,
|
|
42944
|
-
sampledToolCallIds,
|
|
42945
|
-
missing: missing.slice(0, 50),
|
|
42946
|
-
...context
|
|
42947
|
-
});
|
|
42948
|
-
safeNotify(
|
|
42949
|
-
`Claude bridge: ${missing.length} missing tool result(s) repaired with "[no tool result recorded]"${toolNameSummary.length ? ` for ${toolNameSummary.join(", ")}` : ""}. Real tool output was lost before Claude session import; see ${diagLogPath()}.`,
|
|
42950
|
-
"error"
|
|
42951
|
-
);
|
|
42952
|
-
} catch (error51) {
|
|
42953
|
-
debug("reportSyntheticToolResultRepair failed:", error51);
|
|
43277
|
+
if (Object.keys(extraMeta).length > 0) {
|
|
43278
|
+
ctx2.registry.add(baseSchema, extraMeta);
|
|
43279
|
+
}
|
|
43280
|
+
if (schema.description) {
|
|
43281
|
+
baseSchema = baseSchema.describe(schema.description);
|
|
42954
43282
|
}
|
|
43283
|
+
return baseSchema;
|
|
42955
43284
|
}
|
|
42956
|
-
function
|
|
43285
|
+
function fromJSONSchema(schema, params) {
|
|
43286
|
+
if (typeof schema === "boolean") {
|
|
43287
|
+
return schema ? z2.any() : z2.never();
|
|
43288
|
+
}
|
|
43289
|
+
let normalized;
|
|
42957
43290
|
try {
|
|
42958
|
-
|
|
42959
|
-
|
|
42960
|
-
|
|
42961
|
-
if (!hasMismatch) return false;
|
|
42962
|
-
queryCtx.reportedToolResultMismatch = true;
|
|
42963
|
-
if (sharedSession) {
|
|
42964
|
-
sharedSession = { ...sharedSession, needsRebuild: true, ...opts.forceRotate ? { forceRotate: true } : {} };
|
|
42965
|
-
}
|
|
42966
|
-
const toolNameSummary = compactToolNameSummary(progress.toolNames);
|
|
42967
|
-
diagDump("tool_result_delivery_mismatch", {
|
|
42968
|
-
reason,
|
|
42969
|
-
cwd,
|
|
42970
|
-
progress,
|
|
42971
|
-
activeQueryExists: queryCtx.activeQuery !== null,
|
|
42972
|
-
sharedSession: sharedSession ? {
|
|
42973
|
-
sessionId: sharedSession.sessionId.slice(0, 8),
|
|
42974
|
-
cursor: sharedSession.cursor,
|
|
42975
|
-
needsRebuild: sharedSession.needsRebuild === true,
|
|
42976
|
-
forceRotate: sharedSession.forceRotate === true
|
|
42977
|
-
} : null
|
|
42978
|
-
});
|
|
42979
|
-
safeNotify(
|
|
42980
|
-
`Claude bridge: tool result delivery interrupted during ${reason}; delivered ${progress.deliveredCount}/${progress.expectedCount}, resolved ${progress.resolvedCount}/${progress.expectedCount}, waiting=${progress.waitingCount}, queued=${progress.queuedCount}, unmatched=${progress.unmatchedResultCount}${toolNameSummary.length ? `, tools=${toolNameSummary.join(", ")}` : ""}. Claude session will rebuild before the next turn; see ${diagLogPath()}.`,
|
|
42981
|
-
"error"
|
|
42982
|
-
);
|
|
42983
|
-
return true;
|
|
42984
|
-
} catch (error51) {
|
|
42985
|
-
debug("reportToolResultMismatch failed:", error51);
|
|
42986
|
-
return false;
|
|
43291
|
+
normalized = JSON.parse(JSON.stringify(schema));
|
|
43292
|
+
} catch {
|
|
43293
|
+
throw new Error("fromJSONSchema input is not valid JSON (possibly cyclic); use $defs/$ref for recursive schemas");
|
|
42987
43294
|
}
|
|
42988
|
-
|
|
42989
|
-
|
|
42990
|
-
|
|
42991
|
-
|
|
42992
|
-
|
|
42993
|
-
|
|
42994
|
-
|
|
43295
|
+
const version2 = detectVersion(normalized, params?.defaultTarget);
|
|
43296
|
+
const defs = normalized.$defs || normalized.definitions || {};
|
|
43297
|
+
const ctx2 = {
|
|
43298
|
+
version: version2,
|
|
43299
|
+
defs,
|
|
43300
|
+
refs: /* @__PURE__ */ new Map(),
|
|
43301
|
+
processing: /* @__PURE__ */ new Set(),
|
|
43302
|
+
rootSchema: normalized,
|
|
43303
|
+
registry: params?.registry ?? globalRegistry
|
|
43304
|
+
};
|
|
43305
|
+
return convertSchema(normalized, ctx2);
|
|
42995
43306
|
}
|
|
42996
43307
|
|
|
42997
|
-
//
|
|
42998
|
-
var
|
|
42999
|
-
|
|
43000
|
-
|
|
43001
|
-
|
|
43002
|
-
|
|
43003
|
-
|
|
43004
|
-
|
|
43005
|
-
|
|
43006
|
-
|
|
43007
|
-
|
|
43008
|
-
"NotebookEdit",
|
|
43009
|
-
"EnterWorktree",
|
|
43010
|
-
"ExitWorktree",
|
|
43011
|
-
"CronList",
|
|
43012
|
-
"CronCreate",
|
|
43013
|
-
"CronDelete",
|
|
43014
|
-
"TeamCreate",
|
|
43015
|
-
"TeamDelete",
|
|
43016
|
-
"TaskOutput",
|
|
43017
|
-
"TaskStop",
|
|
43018
|
-
"SendMessage",
|
|
43019
|
-
"Skill",
|
|
43020
|
-
"TodoRead",
|
|
43021
|
-
"TodoWrite",
|
|
43022
|
-
"ListMcpResources",
|
|
43023
|
-
"ReadMcpResource",
|
|
43024
|
-
"WebFetch",
|
|
43025
|
-
"WebSearch",
|
|
43026
|
-
"AskUserQuestion",
|
|
43027
|
-
"EnterPlanMode",
|
|
43028
|
-
"ExitPlanMode",
|
|
43029
|
-
"ToolSearch",
|
|
43030
|
-
"ScheduleWakeup"
|
|
43031
|
-
];
|
|
43032
|
-
var CLAUDE_BRIDGE_TOOL_ISOLATION = {
|
|
43033
|
-
tools: [],
|
|
43034
|
-
disallowedTools: DISALLOWED_BUILTIN_TOOLS,
|
|
43035
|
-
allowedTools: [`mcp__${MCP_SERVER_NAME}__*`]
|
|
43036
|
-
};
|
|
43037
|
-
function connectorsEnabledFromEnv() {
|
|
43038
|
-
const v2 = (process.env.CLAUDE_BRIDGE_ENABLE_CONNECTORS ?? "").trim().toLowerCase();
|
|
43039
|
-
return v2 === "1" || v2 === "true" || v2 === "yes" || v2 === "on";
|
|
43040
|
-
}
|
|
43041
|
-
function connectorsEnabledFor(config2) {
|
|
43042
|
-
return connectorsEnabledFromEnv() || config2?.provider?.enableConnectors === true;
|
|
43043
|
-
}
|
|
43044
|
-
var CLAUDE_AI_CONNECTOR_TOOL_PATTERNS = [
|
|
43045
|
-
"mcp__claude_ai_Gmail__*",
|
|
43046
|
-
"mcp__claude_ai_Google_Calendar__*",
|
|
43047
|
-
"mcp__claude_ai_Google_Drive__*",
|
|
43048
|
-
"mcp__claude_ai_Slack__*",
|
|
43049
|
-
"mcp__claude_ai_Atlassian__*"
|
|
43050
|
-
];
|
|
43051
|
-
var CONNECTOR_DISCOVERY_TOOLS = ["ToolSearch", "ListMcpResources", "ReadMcpResource"];
|
|
43052
|
-
var CONNECTOR_NS_PREFIX2 = "mcp__claude_ai_";
|
|
43053
|
-
var CONNECTOR_NS_GMAIL = `${CONNECTOR_NS_PREFIX2}Gmail__`;
|
|
43054
|
-
var CONNECTOR_NS_CALENDAR = `${CONNECTOR_NS_PREFIX2}Google_Calendar__`;
|
|
43055
|
-
var CONNECTOR_NS_DRIVE = `${CONNECTOR_NS_PREFIX2}Google_Drive__`;
|
|
43056
|
-
var CONNECTOR_NS_SLACK = `${CONNECTOR_NS_PREFIX2}Slack__`;
|
|
43057
|
-
var CONNECTOR_NS_ATLASSIAN = `${CONNECTOR_NS_PREFIX2}Atlassian__`;
|
|
43058
|
-
var CONNECTOR_READ_VERBS = /* @__PURE__ */ new Set([
|
|
43059
|
-
"list",
|
|
43060
|
-
"search",
|
|
43061
|
-
"get",
|
|
43062
|
-
"read",
|
|
43063
|
-
"fetch",
|
|
43064
|
-
"find",
|
|
43065
|
-
"download",
|
|
43066
|
-
"describe",
|
|
43067
|
-
"query",
|
|
43068
|
-
"count",
|
|
43069
|
-
"view",
|
|
43070
|
-
"lookup",
|
|
43071
|
-
"whoami"
|
|
43072
|
-
]);
|
|
43073
|
-
var CONNECTOR_MUTATION_WORDS = /* @__PURE__ */ new Set([
|
|
43074
|
-
"create",
|
|
43075
|
-
"update",
|
|
43076
|
-
"delete",
|
|
43077
|
-
"remove",
|
|
43078
|
-
"add",
|
|
43079
|
-
"edit",
|
|
43080
|
-
"send",
|
|
43081
|
-
"post",
|
|
43082
|
-
"write",
|
|
43083
|
-
"upload",
|
|
43084
|
-
"publish",
|
|
43085
|
-
"schedule",
|
|
43086
|
-
"transition",
|
|
43087
|
-
"archive",
|
|
43088
|
-
"move",
|
|
43089
|
-
"copy",
|
|
43090
|
-
"revoke",
|
|
43091
|
-
"assign",
|
|
43092
|
-
"invite",
|
|
43093
|
-
"share",
|
|
43094
|
-
"rename",
|
|
43095
|
-
"replace",
|
|
43096
|
-
"set",
|
|
43097
|
-
"merge",
|
|
43098
|
-
"resolve",
|
|
43099
|
-
"lock",
|
|
43100
|
-
"unlock",
|
|
43101
|
-
"acknowledge",
|
|
43102
|
-
"ack",
|
|
43103
|
-
"book",
|
|
43104
|
-
"start",
|
|
43105
|
-
"stop",
|
|
43106
|
-
"terminate",
|
|
43107
|
-
"restart",
|
|
43108
|
-
"join",
|
|
43109
|
-
"leave",
|
|
43110
|
-
"star",
|
|
43111
|
-
"unstar",
|
|
43112
|
-
"forward",
|
|
43113
|
-
"sync",
|
|
43114
|
-
"approve",
|
|
43115
|
-
"reject",
|
|
43116
|
-
"close",
|
|
43117
|
-
"reopen",
|
|
43118
|
-
"cancel",
|
|
43119
|
-
"enable",
|
|
43120
|
-
"disable",
|
|
43121
|
-
"grant",
|
|
43122
|
-
"trigger",
|
|
43123
|
-
"execute",
|
|
43124
|
-
"apply",
|
|
43125
|
-
"submit",
|
|
43126
|
-
"pin",
|
|
43127
|
-
"unpin",
|
|
43128
|
-
"mute",
|
|
43129
|
-
"unmute",
|
|
43130
|
-
"subscribe",
|
|
43131
|
-
"unsubscribe",
|
|
43132
|
-
"follow",
|
|
43133
|
-
"unfollow",
|
|
43134
|
-
"clear",
|
|
43135
|
-
"purge",
|
|
43136
|
-
"reset",
|
|
43137
|
-
"rotate",
|
|
43138
|
-
"deploy",
|
|
43139
|
-
"install",
|
|
43140
|
-
"uninstall",
|
|
43141
|
-
"save",
|
|
43142
|
-
"store",
|
|
43143
|
-
"put",
|
|
43144
|
-
"patch",
|
|
43145
|
-
"insert",
|
|
43146
|
-
"append",
|
|
43147
|
-
"prepend",
|
|
43148
|
-
"duplicate",
|
|
43149
|
-
"restore",
|
|
43150
|
-
"revert",
|
|
43151
|
-
"import",
|
|
43152
|
-
"export",
|
|
43153
|
-
"upsert",
|
|
43154
|
-
"sign",
|
|
43155
|
-
"complete",
|
|
43156
|
-
"claim",
|
|
43157
|
-
"release",
|
|
43158
|
-
"promote",
|
|
43159
|
-
"demote",
|
|
43160
|
-
"escalate",
|
|
43161
|
-
"resend",
|
|
43162
|
-
"retry",
|
|
43163
|
-
"react",
|
|
43164
|
-
"vote"
|
|
43165
|
-
]);
|
|
43166
|
-
function connectorNameWords(segment) {
|
|
43167
|
-
return segment.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => word.toLowerCase());
|
|
43308
|
+
// node_modules/zod/v4/classic/coerce.js
|
|
43309
|
+
var coerce_exports = {};
|
|
43310
|
+
__export(coerce_exports, {
|
|
43311
|
+
bigint: () => bigint3,
|
|
43312
|
+
boolean: () => boolean3,
|
|
43313
|
+
date: () => date4,
|
|
43314
|
+
number: () => number3,
|
|
43315
|
+
string: () => string3
|
|
43316
|
+
});
|
|
43317
|
+
function string3(params) {
|
|
43318
|
+
return _coercedString(ZodString, params);
|
|
43168
43319
|
}
|
|
43169
|
-
|
|
43170
|
-
|
|
43171
|
-
`${CONNECTOR_NS_GMAIL}create_label`,
|
|
43172
|
-
`${CONNECTOR_NS_GMAIL}label_message`,
|
|
43173
|
-
`${CONNECTOR_NS_GMAIL}label_thread`,
|
|
43174
|
-
`${CONNECTOR_NS_GMAIL}unlabel_message`,
|
|
43175
|
-
`${CONNECTOR_NS_GMAIL}unlabel_thread`,
|
|
43176
|
-
`${CONNECTOR_NS_GMAIL}apply_sensitive_label`,
|
|
43177
|
-
`${CONNECTOR_NS_GMAIL}remove_sensitive_label`,
|
|
43178
|
-
`${CONNECTOR_NS_CALENDAR}create_event`,
|
|
43179
|
-
`${CONNECTOR_NS_CALENDAR}update_event`,
|
|
43180
|
-
`${CONNECTOR_NS_CALENDAR}delete_event`,
|
|
43181
|
-
`${CONNECTOR_NS_CALENDAR}respond_to_event`,
|
|
43182
|
-
`${CONNECTOR_NS_DRIVE}create_file`,
|
|
43183
|
-
`${CONNECTOR_NS_DRIVE}copy_file`,
|
|
43184
|
-
// Slack + Atlassian writes, taken from a live enumeration of an account with
|
|
43185
|
-
// both connectors attached. The PreToolUse hook already denies these by verb;
|
|
43186
|
-
// listing them by id also removes them from the model's context in a
|
|
43187
|
-
// read-only session (the CLI matcher needs exact ids). Additive only — an id
|
|
43188
|
-
// missing here is still denied at call time.
|
|
43189
|
-
`${CONNECTOR_NS_SLACK}slack_send_message`,
|
|
43190
|
-
`${CONNECTOR_NS_SLACK}slack_send_message_draft`,
|
|
43191
|
-
`${CONNECTOR_NS_SLACK}slack_schedule_message`,
|
|
43192
|
-
`${CONNECTOR_NS_SLACK}slack_create_canvas`,
|
|
43193
|
-
`${CONNECTOR_NS_SLACK}slack_update_canvas`,
|
|
43194
|
-
`${CONNECTOR_NS_ATLASSIAN}createJiraIssue`,
|
|
43195
|
-
`${CONNECTOR_NS_ATLASSIAN}editJiraIssue`,
|
|
43196
|
-
`${CONNECTOR_NS_ATLASSIAN}transitionJiraIssue`,
|
|
43197
|
-
`${CONNECTOR_NS_ATLASSIAN}addCommentToJiraIssue`,
|
|
43198
|
-
`${CONNECTOR_NS_ATLASSIAN}addWorklogToJiraIssue`,
|
|
43199
|
-
`${CONNECTOR_NS_ATLASSIAN}createIssueLink`,
|
|
43200
|
-
`${CONNECTOR_NS_ATLASSIAN}createConfluencePage`,
|
|
43201
|
-
`${CONNECTOR_NS_ATLASSIAN}updateConfluencePage`,
|
|
43202
|
-
`${CONNECTOR_NS_ATLASSIAN}createConfluenceFooterComment`,
|
|
43203
|
-
`${CONNECTOR_NS_ATLASSIAN}createConfluenceInlineComment`,
|
|
43204
|
-
`${CONNECTOR_NS_ATLASSIAN}createCompassComponent`,
|
|
43205
|
-
`${CONNECTOR_NS_ATLASSIAN}createCompassComponentRelationship`,
|
|
43206
|
-
`${CONNECTOR_NS_ATLASSIAN}createCompassCustomFieldDefinition`
|
|
43207
|
-
];
|
|
43208
|
-
function isConnectorWriteTool(name) {
|
|
43209
|
-
if (!name.startsWith(CONNECTOR_NS_PREFIX2)) return false;
|
|
43210
|
-
const sep2 = name.indexOf("__", CONNECTOR_NS_PREFIX2.length);
|
|
43211
|
-
if (sep2 <= CONNECTOR_NS_PREFIX2.length) return true;
|
|
43212
|
-
const server = name.slice(CONNECTOR_NS_PREFIX2.length, sep2);
|
|
43213
|
-
const words = connectorNameWords(name.slice(sep2 + "__".length));
|
|
43214
|
-
const serverWords = connectorNameWords(server);
|
|
43215
|
-
let skipped = 0;
|
|
43216
|
-
while (skipped < serverWords.length && words[skipped] === serverWords[skipped] && !CONNECTOR_MUTATION_WORDS.has(words[skipped])) skipped++;
|
|
43217
|
-
const rest = words.slice(skipped);
|
|
43218
|
-
if (rest.length === 0) return true;
|
|
43219
|
-
if (!CONNECTOR_READ_VERBS.has(rest[0])) return true;
|
|
43220
|
-
return rest.some((word) => CONNECTOR_MUTATION_WORDS.has(word));
|
|
43320
|
+
function number3(params) {
|
|
43321
|
+
return _coercedNumber(ZodNumber, params);
|
|
43221
43322
|
}
|
|
43222
|
-
function
|
|
43223
|
-
|
|
43224
|
-
if (v2 === "allow") return "allow";
|
|
43225
|
-
if (v2 === "deny") return "deny";
|
|
43226
|
-
return void 0;
|
|
43323
|
+
function boolean3(params) {
|
|
43324
|
+
return _coercedBoolean(ZodBoolean, params);
|
|
43227
43325
|
}
|
|
43228
|
-
function
|
|
43229
|
-
|
|
43230
|
-
return resolved === "allow" ? "allow" : "deny";
|
|
43326
|
+
function bigint3(params) {
|
|
43327
|
+
return _coercedBigint(ZodBigInt, params);
|
|
43231
43328
|
}
|
|
43232
|
-
function
|
|
43233
|
-
return
|
|
43329
|
+
function date4(params) {
|
|
43330
|
+
return _coercedDate(ZodDate, params);
|
|
43331
|
+
}
|
|
43332
|
+
|
|
43333
|
+
// node_modules/zod/v4/classic/external.js
|
|
43334
|
+
config(en_default());
|
|
43335
|
+
|
|
43336
|
+
// src/typebox-to-zod.ts
|
|
43337
|
+
function jsonSchemaPropertyToZod(prop) {
|
|
43338
|
+
let base;
|
|
43339
|
+
if (Array.isArray(prop.enum) && prop.enum.length > 0) base = external_exports.enum(prop.enum);
|
|
43340
|
+
else switch (prop.type) {
|
|
43341
|
+
case "string":
|
|
43342
|
+
base = external_exports.string();
|
|
43343
|
+
break;
|
|
43344
|
+
case "number":
|
|
43345
|
+
case "integer":
|
|
43346
|
+
base = external_exports.number();
|
|
43347
|
+
break;
|
|
43348
|
+
case "boolean":
|
|
43349
|
+
base = external_exports.boolean();
|
|
43350
|
+
break;
|
|
43351
|
+
case "array": {
|
|
43352
|
+
base = prop.items ? external_exports.array(jsonSchemaPropertyToZod(prop.items)) : external_exports.array(external_exports.unknown());
|
|
43353
|
+
const minItems = typeof prop.minItems === "number" ? prop.minItems : void 0;
|
|
43354
|
+
if (minItems !== void 0) base = base.min(minItems);
|
|
43355
|
+
break;
|
|
43356
|
+
}
|
|
43357
|
+
case "object": {
|
|
43358
|
+
if (prop.properties && typeof prop.properties === "object" && !Array.isArray(prop.properties)) {
|
|
43359
|
+
const obj = external_exports.object(jsonSchemaToZodShape(prop));
|
|
43360
|
+
base = prop.additionalProperties === false ? obj.strict() : obj.passthrough();
|
|
43361
|
+
} else {
|
|
43362
|
+
base = external_exports.record(external_exports.string(), external_exports.unknown());
|
|
43363
|
+
}
|
|
43364
|
+
break;
|
|
43365
|
+
}
|
|
43366
|
+
default:
|
|
43367
|
+
base = external_exports.unknown();
|
|
43368
|
+
}
|
|
43369
|
+
if (typeof prop.description === "string") base = base.describe(prop.description);
|
|
43370
|
+
return base;
|
|
43371
|
+
}
|
|
43372
|
+
function jsonSchemaToZodShape(schema) {
|
|
43373
|
+
const s = schema;
|
|
43374
|
+
if (!s || s.type !== "object" || !s.properties) return {};
|
|
43375
|
+
const props = s.properties;
|
|
43376
|
+
const required2 = new Set(Array.isArray(s.required) ? s.required : []);
|
|
43377
|
+
const shape = {};
|
|
43378
|
+
for (const [key, prop] of Object.entries(props)) {
|
|
43379
|
+
const zodProp = jsonSchemaPropertyToZod(prop);
|
|
43380
|
+
shape[key] = required2.has(key) ? zodProp : zodProp.optional();
|
|
43381
|
+
}
|
|
43382
|
+
return shape;
|
|
43383
|
+
}
|
|
43384
|
+
|
|
43385
|
+
// src/index.ts
|
|
43386
|
+
import { readFileSync as nodeReadFileSync } from "node:fs";
|
|
43387
|
+
|
|
43388
|
+
// src/pi-ai-compat.ts
|
|
43389
|
+
var dynamicImport = (specifier) => import(specifier);
|
|
43390
|
+
async function resolveGetModels(root, loadCompat = () => dynamicImport("@earendil-works/pi-ai/compat")) {
|
|
43391
|
+
if (typeof root?.getModels === "function") return root.getModels;
|
|
43392
|
+
const compat = await loadCompat();
|
|
43393
|
+
if (typeof compat?.getModels !== "function") throw new Error("pi-ai getModels API is unavailable");
|
|
43394
|
+
return compat.getModels;
|
|
43395
|
+
}
|
|
43396
|
+
|
|
43397
|
+
// src/connector-cache.ts
|
|
43398
|
+
import { createHash } from "node:crypto";
|
|
43399
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync } from "node:fs";
|
|
43400
|
+
import { dirname as dirname5, join as join7 } from "node:path";
|
|
43401
|
+
var CACHE_VERSION = 1;
|
|
43402
|
+
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
43403
|
+
function connectorCacheScopeKey(env = process.env) {
|
|
43404
|
+
return env.CLAUDE_CONFIG_DIR?.trim() || "<default>";
|
|
43405
|
+
}
|
|
43406
|
+
function connectorCachePath(scopeKey = connectorCacheScopeKey()) {
|
|
43407
|
+
const digest = createHash("sha256").update(scopeKey).digest("hex").slice(0, 16);
|
|
43408
|
+
return join7(piUserDir(), "connector-cache", `${digest}.json`);
|
|
43409
|
+
}
|
|
43410
|
+
function readCachedConnectors(scopeKey = connectorCacheScopeKey(), now = Date.now()) {
|
|
43411
|
+
let raw;
|
|
43412
|
+
try {
|
|
43413
|
+
raw = readFileSync6(connectorCachePath(scopeKey), "utf8");
|
|
43414
|
+
} catch {
|
|
43415
|
+
return void 0;
|
|
43416
|
+
}
|
|
43417
|
+
let parsed;
|
|
43418
|
+
try {
|
|
43419
|
+
parsed = JSON.parse(raw);
|
|
43420
|
+
} catch {
|
|
43421
|
+
return void 0;
|
|
43422
|
+
}
|
|
43423
|
+
if (parsed?.version !== CACHE_VERSION) return void 0;
|
|
43424
|
+
if (parsed?.scope !== scopeKey) return void 0;
|
|
43425
|
+
const savedAt = typeof parsed?.savedAt === "number" ? parsed.savedAt : 0;
|
|
43426
|
+
if (!savedAt || now - savedAt > MAX_AGE_MS || savedAt > now) return void 0;
|
|
43427
|
+
if (!Array.isArray(parsed?.connectors)) return void 0;
|
|
43428
|
+
const connectors = parsed.connectors.filter(
|
|
43429
|
+
(entry) => entry && typeof entry.name === "string" && entry.name.trim()
|
|
43430
|
+
);
|
|
43431
|
+
return connectors.length > 0 ? connectors : void 0;
|
|
43432
|
+
}
|
|
43433
|
+
function writeCachedConnectors(connectors, scopeKey = connectorCacheScopeKey(), now = Date.now()) {
|
|
43434
|
+
if (!Array.isArray(connectors) || connectors.length === 0) return false;
|
|
43435
|
+
const path = connectorCachePath(scopeKey);
|
|
43436
|
+
try {
|
|
43437
|
+
mkdirSync3(dirname5(path), { recursive: true, mode: 448 });
|
|
43438
|
+
writeFileSync(
|
|
43439
|
+
path,
|
|
43440
|
+
JSON.stringify({ version: CACHE_VERSION, scope: scopeKey, savedAt: now, connectors }),
|
|
43441
|
+
{ mode: 384 }
|
|
43442
|
+
);
|
|
43443
|
+
return true;
|
|
43444
|
+
} catch {
|
|
43445
|
+
return false;
|
|
43446
|
+
}
|
|
43447
|
+
}
|
|
43448
|
+
|
|
43449
|
+
// src/claude-executable.ts
|
|
43450
|
+
import { spawn as spawnProcess } from "child_process";
|
|
43451
|
+
import { accessSync, constants as fsConstants, readFileSync as readFileSync7, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
|
|
43452
|
+
import { delimiter, join as join8 } from "path";
|
|
43453
|
+
function executableFromPath(name) {
|
|
43454
|
+
const paths = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
43455
|
+
for (const dir of paths) {
|
|
43456
|
+
const candidate = join8(dir, name);
|
|
43234
43457
|
try {
|
|
43235
|
-
|
|
43236
|
-
|
|
43237
|
-
return connectorWriteDenyOutput(String(input.tool_name));
|
|
43458
|
+
accessSync(candidate, fsConstants.X_OK);
|
|
43459
|
+
return candidate;
|
|
43238
43460
|
} catch {
|
|
43239
|
-
const toolName = typeof input?.tool_name === "string" ? input.tool_name : "<unknown>";
|
|
43240
|
-
return connectorWriteDenyOutput(toolName);
|
|
43241
43461
|
}
|
|
43242
|
-
}
|
|
43462
|
+
}
|
|
43463
|
+
return void 0;
|
|
43243
43464
|
}
|
|
43244
|
-
function
|
|
43245
|
-
|
|
43246
|
-
|
|
43247
|
-
|
|
43248
|
-
|
|
43249
|
-
|
|
43465
|
+
function resolveClaudeExecutable(configured) {
|
|
43466
|
+
const trimmed = configured?.trim();
|
|
43467
|
+
if (trimmed) return trimmed;
|
|
43468
|
+
if (isolatedFromEnv()) return void 0;
|
|
43469
|
+
return executableFromPath("claude") ?? executableFromPath("claude-code");
|
|
43470
|
+
}
|
|
43471
|
+
function errnoValue(err) {
|
|
43472
|
+
return typeof err?.errno === "number" ? err.errno : void 0;
|
|
43473
|
+
}
|
|
43474
|
+
function syscallValue(err) {
|
|
43475
|
+
return typeof err?.syscall === "string" ? err.syscall : void 0;
|
|
43476
|
+
}
|
|
43477
|
+
function pathValue(err) {
|
|
43478
|
+
const value = err?.path;
|
|
43479
|
+
return typeof value === "string" ? value : void 0;
|
|
43480
|
+
}
|
|
43481
|
+
function codeValue(err, fallback) {
|
|
43482
|
+
const value = err?.code;
|
|
43483
|
+
return typeof value === "string" ? value : fallback;
|
|
43484
|
+
}
|
|
43485
|
+
function displayValue(value) {
|
|
43486
|
+
return value === void 0 || value === null || value === "" ? "<none>" : String(value);
|
|
43487
|
+
}
|
|
43488
|
+
function makeClaudePreflightError(summary, details) {
|
|
43489
|
+
const detail = [
|
|
43490
|
+
`code=${details.code}`,
|
|
43491
|
+
`errno=${displayValue(details.errno)}`,
|
|
43492
|
+
`syscall=${displayValue(details.syscall)}`,
|
|
43493
|
+
`path=${details.path}`,
|
|
43494
|
+
`cwd=${details.cwd}`,
|
|
43495
|
+
...details.fileType ? [`fileType=${details.fileType}`] : [],
|
|
43496
|
+
...details.realPath ? [`realPath=${details.realPath}`] : []
|
|
43497
|
+
].join(" ");
|
|
43498
|
+
const error51 = new Error(`${summary} (${detail})`);
|
|
43499
|
+
error51.name = "ClaudeExecutablePreflightError";
|
|
43500
|
+
error51.code = details.code;
|
|
43501
|
+
if (details.errno !== void 0) error51.errno = typeof details.errno === "number" ? details.errno : Number(details.errno);
|
|
43502
|
+
if (details.syscall) error51.syscall = details.syscall;
|
|
43503
|
+
error51.path = details.path;
|
|
43504
|
+
error51.cwd = details.cwd;
|
|
43505
|
+
if (details.fileType) error51.fileType = details.fileType;
|
|
43506
|
+
if (details.realPath) error51.realPath = details.realPath;
|
|
43507
|
+
if (details.cause !== void 0) error51.cause = details.cause;
|
|
43508
|
+
return error51;
|
|
43509
|
+
}
|
|
43510
|
+
function classifyClaudeExecutableBytes(bytes) {
|
|
43511
|
+
if (bytes.length === 0) return "empty";
|
|
43512
|
+
if (bytes.length >= 2 && bytes[0] === 35 && bytes[1] === 33) return "shebang-script";
|
|
43513
|
+
if (bytes.length >= 4 && bytes[0] === 127 && bytes[1] === 69 && bytes[2] === 76 && bytes[3] === 70) return "elf";
|
|
43514
|
+
if (bytes.length >= 2 && bytes[0] === 77 && bytes[1] === 90) return "pe";
|
|
43515
|
+
if (bytes.length >= 4) {
|
|
43516
|
+
const magic = bytes[0] * 16777216 + bytes[1] * 65536 + bytes[2] * 256 + bytes[3];
|
|
43517
|
+
if (magic === 4277009102 || magic === 4277009103 || magic === 3472551422 || magic === 3489328638 || magic === 3405691582 || magic === 3199925962) return "mach-o";
|
|
43518
|
+
}
|
|
43519
|
+
return "unknown";
|
|
43520
|
+
}
|
|
43521
|
+
function preflightClaudeExecutable(path, cwd) {
|
|
43522
|
+
let realCwd;
|
|
43523
|
+
try {
|
|
43524
|
+
const cwdStat = statSync2(cwd);
|
|
43525
|
+
if (!cwdStat.isDirectory()) {
|
|
43526
|
+
throw makeClaudePreflightError("Claude Code spawn cwd preflight failed: cwd is not a directory.", {
|
|
43527
|
+
code: "ENOTDIR",
|
|
43528
|
+
syscall: "chdir",
|
|
43529
|
+
path: cwd,
|
|
43530
|
+
cwd
|
|
43531
|
+
});
|
|
43250
43532
|
}
|
|
43251
|
-
|
|
43533
|
+
accessSync(cwd, fsConstants.X_OK);
|
|
43534
|
+
realCwd = realpathSync2(cwd);
|
|
43535
|
+
} catch (err) {
|
|
43536
|
+
if (err.name === "ClaudeExecutablePreflightError") throw err;
|
|
43537
|
+
throw makeClaudePreflightError("Claude Code spawn cwd preflight failed: cwd is not reachable before spawning Claude Code.", {
|
|
43538
|
+
code: codeValue(err, "EACCES"),
|
|
43539
|
+
errno: errnoValue(err),
|
|
43540
|
+
syscall: syscallValue(err),
|
|
43541
|
+
path: pathValue(err) ?? cwd,
|
|
43542
|
+
cwd,
|
|
43543
|
+
cause: err
|
|
43544
|
+
});
|
|
43545
|
+
}
|
|
43546
|
+
let realPath;
|
|
43547
|
+
try {
|
|
43548
|
+
const stat = statSync2(path);
|
|
43549
|
+
if (!stat.isFile()) {
|
|
43550
|
+
throw makeClaudePreflightError("Claude Code executable preflight failed: resolved path is not a file.", {
|
|
43551
|
+
code: "EACCES",
|
|
43552
|
+
syscall: "exec",
|
|
43553
|
+
path,
|
|
43554
|
+
cwd
|
|
43555
|
+
});
|
|
43556
|
+
}
|
|
43557
|
+
accessSync(path, fsConstants.X_OK);
|
|
43558
|
+
realPath = realpathSync2(path);
|
|
43559
|
+
} catch (err) {
|
|
43560
|
+
if (err.name === "ClaudeExecutablePreflightError") throw err;
|
|
43561
|
+
throw makeClaudePreflightError("Claude Code executable preflight failed: cannot access resolved executable before spawning Claude Code.", {
|
|
43562
|
+
code: codeValue(err, "ENOENT"),
|
|
43563
|
+
errno: errnoValue(err),
|
|
43564
|
+
syscall: syscallValue(err),
|
|
43565
|
+
path: pathValue(err) ?? path,
|
|
43566
|
+
cwd,
|
|
43567
|
+
cause: err
|
|
43568
|
+
});
|
|
43569
|
+
}
|
|
43570
|
+
let fileType;
|
|
43571
|
+
try {
|
|
43572
|
+
fileType = classifyClaudeExecutableBytes(readFileSync7(realPath).subarray(0, 16));
|
|
43573
|
+
} catch (err) {
|
|
43574
|
+
throw makeClaudePreflightError("Claude Code executable preflight failed: cannot read executable header before spawning Claude Code.", {
|
|
43575
|
+
code: codeValue(err, "EACCES"),
|
|
43576
|
+
errno: errnoValue(err),
|
|
43577
|
+
syscall: syscallValue(err),
|
|
43578
|
+
path: pathValue(err) ?? realPath,
|
|
43579
|
+
cwd,
|
|
43580
|
+
realPath,
|
|
43581
|
+
cause: err
|
|
43582
|
+
});
|
|
43583
|
+
}
|
|
43584
|
+
if (!["elf", "mach-o", "pe", "shebang-script"].includes(fileType)) {
|
|
43585
|
+
throw makeClaudePreflightError("Claude Code executable preflight failed: executable header is not an ELF, Mach-O, PE, or shebang script.", {
|
|
43586
|
+
code: "ENOEXEC",
|
|
43587
|
+
syscall: "exec",
|
|
43588
|
+
path,
|
|
43589
|
+
cwd,
|
|
43590
|
+
fileType,
|
|
43591
|
+
realPath
|
|
43592
|
+
});
|
|
43593
|
+
}
|
|
43594
|
+
return { path, realPath, cwd, realCwd, fileType };
|
|
43252
43595
|
}
|
|
43253
|
-
function
|
|
43254
|
-
|
|
43255
|
-
if (!connectorsEnabled || writeMode === "allow") return isolation;
|
|
43256
|
-
return { ...isolation, hooks: { PreToolUse: [{ hooks: [connectorWriteDenyHook()] }] } };
|
|
43596
|
+
function envFlagEnabled(value) {
|
|
43597
|
+
return value === "1" || value?.toLowerCase() === "true";
|
|
43257
43598
|
}
|
|
43258
|
-
function
|
|
43259
|
-
|
|
43260
|
-
const
|
|
43261
|
-
|
|
43599
|
+
function wrapClaudeSpawnErrorForSdk(err, options) {
|
|
43600
|
+
const originalCode = codeValue(err, "SPAWN_ERROR");
|
|
43601
|
+
const originalMessage = err.message;
|
|
43602
|
+
const spawnPath = pathValue(err) ?? options.command;
|
|
43603
|
+
const cwd = options.cwd ?? process.cwd();
|
|
43604
|
+
const detail = [
|
|
43605
|
+
`code=${originalCode}`,
|
|
43606
|
+
`errno=${displayValue(errnoValue(err))}`,
|
|
43607
|
+
`syscall=${displayValue(syscallValue(err))}`,
|
|
43608
|
+
`path=${spawnPath}`,
|
|
43609
|
+
`cwd=${cwd}`,
|
|
43610
|
+
`command=${options.command}`
|
|
43611
|
+
].join(" ");
|
|
43612
|
+
const wrapped = new Error(`Claude Code spawn failed: ${originalMessage} (${detail})`);
|
|
43613
|
+
wrapped.name = "ClaudeSpawnDiagnosticError";
|
|
43614
|
+
wrapped.code = originalCode === "ENOENT" ? "CLAUDE_BRIDGE_SPAWN_FAILED" : originalCode;
|
|
43615
|
+
wrapped.originalCode = originalCode;
|
|
43616
|
+
wrapped.originalMessage = originalMessage;
|
|
43617
|
+
const errno = errnoValue(err);
|
|
43618
|
+
if (errno !== void 0) wrapped.errno = typeof errno === "number" ? errno : Number(errno);
|
|
43619
|
+
const syscall = syscallValue(err);
|
|
43620
|
+
if (syscall) wrapped.syscall = syscall;
|
|
43621
|
+
wrapped.path = spawnPath;
|
|
43622
|
+
wrapped.cwd = cwd;
|
|
43623
|
+
return wrapped;
|
|
43624
|
+
}
|
|
43625
|
+
function spawnClaudeCodeWithDiagnostics(options) {
|
|
43626
|
+
const pipeStderr = DEBUG || envFlagEnabled(options.env.DEBUG_CLAUDE_AGENT_SDK);
|
|
43627
|
+
const child = spawnProcess(options.command, options.args, {
|
|
43628
|
+
cwd: options.cwd,
|
|
43629
|
+
env: options.env,
|
|
43630
|
+
signal: options.signal,
|
|
43631
|
+
stdio: ["pipe", "pipe", pipeStderr ? "pipe" : "ignore"],
|
|
43632
|
+
windowsHide: true
|
|
43633
|
+
});
|
|
43634
|
+
if (pipeStderr) {
|
|
43635
|
+
child.stderr?.on("data", (data) => {
|
|
43636
|
+
for (const line of data.toString().split(/\r?\n/)) {
|
|
43637
|
+
if (line) debug(`[cli-stderr spawn] ${line}`);
|
|
43638
|
+
}
|
|
43639
|
+
});
|
|
43640
|
+
}
|
|
43641
|
+
child.prependListener("error", (err) => {
|
|
43642
|
+
const originalStack = err.stack;
|
|
43643
|
+
const wrapped = wrapClaudeSpawnErrorForSdk(err, options);
|
|
43644
|
+
Object.assign(err, wrapped);
|
|
43645
|
+
err.name = wrapped.name;
|
|
43646
|
+
err.message = wrapped.message;
|
|
43647
|
+
if (originalStack) err.stack = originalStack;
|
|
43648
|
+
});
|
|
43262
43649
|
return {
|
|
43263
|
-
|
|
43264
|
-
|
|
43650
|
+
stdin: child.stdin,
|
|
43651
|
+
stdout: child.stdout,
|
|
43652
|
+
get killed() {
|
|
43653
|
+
return child.killed;
|
|
43654
|
+
},
|
|
43655
|
+
get exitCode() {
|
|
43656
|
+
return child.exitCode;
|
|
43657
|
+
},
|
|
43658
|
+
kill: child.kill.bind(child),
|
|
43659
|
+
on: child.on.bind(child),
|
|
43660
|
+
once: child.once.bind(child),
|
|
43661
|
+
off: child.off.bind(child)
|
|
43265
43662
|
};
|
|
43266
43663
|
}
|
|
43267
43664
|
|
|
43268
43665
|
// node_modules/cc-session-io/dist/chunk-D6EZBJOC.js
|
|
43269
43666
|
import { randomUUID } from "crypto";
|
|
43270
|
-
import { mkdirSync as
|
|
43271
|
-
import { dirname as
|
|
43272
|
-
import { readFileSync as
|
|
43667
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync2, appendFileSync as appendFileSync3, existsSync as existsSync6, rmSync as rmSync2 } from "fs";
|
|
43668
|
+
import { dirname as dirname6 } from "path";
|
|
43669
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
43273
43670
|
import { realpathSync as realpathSync3 } from "fs";
|
|
43274
43671
|
import { homedir as homedir3 } from "os";
|
|
43275
|
-
import { join as
|
|
43672
|
+
import { join as join9 } from "path";
|
|
43276
43673
|
function parseJsonl(content) {
|
|
43277
43674
|
return content.split("\n").filter((line) => line.trim()).map(parseRecord);
|
|
43278
43675
|
}
|
|
43279
43676
|
function parseJsonlFile(path) {
|
|
43280
|
-
return parseJsonl(
|
|
43677
|
+
return parseJsonl(readFileSync8(path, "utf-8"));
|
|
43281
43678
|
}
|
|
43282
43679
|
function parseRecord(line) {
|
|
43283
43680
|
const raw = JSON.parse(line);
|
|
@@ -43290,7 +43687,7 @@ function serializeRecord(record2) {
|
|
|
43290
43687
|
}
|
|
43291
43688
|
var MAX_SANITIZED_LENGTH = 200;
|
|
43292
43689
|
function getClaudeDir(claudeDir) {
|
|
43293
|
-
return claudeDir ?? process.env.CLAUDE_CONFIG_DIR ??
|
|
43690
|
+
return claudeDir ?? process.env.CLAUDE_CONFIG_DIR ?? join9(homedir3(), ".claude");
|
|
43294
43691
|
}
|
|
43295
43692
|
function normalizeProjectPath(projectPath) {
|
|
43296
43693
|
try {
|
|
@@ -43308,10 +43705,10 @@ function projectPathToHash(projectPath) {
|
|
|
43308
43705
|
return `${sanitized.slice(0, MAX_SANITIZED_LENGTH)}-${Math.abs(h).toString(36)}`;
|
|
43309
43706
|
}
|
|
43310
43707
|
function getProjectDir(projectPath, claudeDir) {
|
|
43311
|
-
return
|
|
43708
|
+
return join9(getClaudeDir(claudeDir), "projects", projectPathToHash(normalizeProjectPath(projectPath)));
|
|
43312
43709
|
}
|
|
43313
43710
|
function getSessionPath(sessionId, projectPath, claudeDir) {
|
|
43314
|
-
return
|
|
43711
|
+
return join9(getProjectDir(projectPath, claudeDir), `${sessionId}.jsonl`);
|
|
43315
43712
|
}
|
|
43316
43713
|
function repairToolPairing(messages) {
|
|
43317
43714
|
const result = [];
|
|
@@ -43646,15 +44043,15 @@ var Session = class {
|
|
|
43646
44043
|
/** Write pending records to disk. Creates the file/directory if needed. */
|
|
43647
44044
|
save() {
|
|
43648
44045
|
if (this._pendingRecords.length === 0) return;
|
|
43649
|
-
const dir =
|
|
44046
|
+
const dir = dirname6(this.jsonlPath);
|
|
43650
44047
|
if (!existsSync6(dir)) {
|
|
43651
|
-
|
|
44048
|
+
mkdirSync4(dir, { recursive: true });
|
|
43652
44049
|
}
|
|
43653
44050
|
const data = this._pendingRecords.map((r) => serializeRecord(r) + "\n").join("");
|
|
43654
44051
|
if (this._fileExists) {
|
|
43655
44052
|
appendFileSync3(this.jsonlPath, data, "utf-8");
|
|
43656
44053
|
} else {
|
|
43657
|
-
|
|
44054
|
+
writeFileSync2(this.jsonlPath, data, "utf-8");
|
|
43658
44055
|
this._fileExists = true;
|
|
43659
44056
|
}
|
|
43660
44057
|
this._records.push(...this._pendingRecords);
|
|
@@ -43709,7 +44106,7 @@ function readSession(jsonlPath, projectPath) {
|
|
|
43709
44106
|
}
|
|
43710
44107
|
|
|
43711
44108
|
// src/session-persistence.ts
|
|
43712
|
-
import { createHash } from "crypto";
|
|
44109
|
+
import { createHash as createHash2 } from "crypto";
|
|
43713
44110
|
import { realpathSync as realpathSync4, statSync as statSync4 } from "fs";
|
|
43714
44111
|
import { resolve as pathResolve } from "path";
|
|
43715
44112
|
|
|
@@ -43800,7 +44197,7 @@ function fingerprintMessages(messages) {
|
|
|
43800
44197
|
}
|
|
43801
44198
|
return message;
|
|
43802
44199
|
});
|
|
43803
|
-
return
|
|
44200
|
+
return createHash2("sha256").update(JSON.stringify(normalized)).digest("hex");
|
|
43804
44201
|
}
|
|
43805
44202
|
function readBuiltSessionContext(sessionManager) {
|
|
43806
44203
|
const built = typeof sessionManager?.buildSessionContext === "function" ? sessionManager.buildSessionContext() : void 0;
|
|
@@ -43909,6 +44306,7 @@ function convertAndImportMessages(session, messages, customToolNameToSdk, cwd) {
|
|
|
43909
44306
|
);
|
|
43910
44307
|
}
|
|
43911
44308
|
const missingToolResults = findUnpairedToolUses(anthropicMessages);
|
|
44309
|
+
if (missingToolResults.length > 0) insertLostToolResultPlaceholders(anthropicMessages, missingToolResults);
|
|
43912
44310
|
const repaired = repairToolPairing(anthropicMessages);
|
|
43913
44311
|
if (missingToolResults.length > 0) {
|
|
43914
44312
|
reportSyntheticToolResultRepair(missingToolResults, {
|
|
@@ -44097,18 +44495,22 @@ function createStreamIdleWatchdog({
|
|
|
44097
44495
|
// src/rate-limit.ts
|
|
44098
44496
|
var RATE_LIMIT_AUTO_RESUME_EVENT = "vstack:rate-limit";
|
|
44099
44497
|
var RATE_LIMIT_TOKEN = "\x1B[31m[rate-limit]\x1B[39m";
|
|
44100
|
-
|
|
44101
|
-
|
|
44102
|
-
if (typeof value === "string")
|
|
44103
|
-
|
|
44104
|
-
|
|
44105
|
-
|
|
44106
|
-
|
|
44107
|
-
|
|
44108
|
-
text = String(value);
|
|
44109
|
-
}
|
|
44498
|
+
var USAGE_LIMIT_PREFIXES = Array.isArray(qO) ? qO : [];
|
|
44499
|
+
function coerceMessageText(value) {
|
|
44500
|
+
if (typeof value === "string") return value;
|
|
44501
|
+
if (value instanceof Error) return value.message;
|
|
44502
|
+
try {
|
|
44503
|
+
return JSON.stringify(value ?? "");
|
|
44504
|
+
} catch {
|
|
44505
|
+
return String(value);
|
|
44110
44506
|
}
|
|
44111
|
-
|
|
44507
|
+
}
|
|
44508
|
+
function isExtraUsageRequiredMessage(value) {
|
|
44509
|
+
return /extra[-\s]?usage|overage|extra usage billing|extra usage credits|1M context/i.test(coerceMessageText(value));
|
|
44510
|
+
}
|
|
44511
|
+
function isUsageLimitMessage(value) {
|
|
44512
|
+
const text = coerceMessageText(value);
|
|
44513
|
+
return USAGE_LIMIT_PREFIXES.some((prefix) => text.includes(prefix));
|
|
44112
44514
|
}
|
|
44113
44515
|
function uniqueNonEmptyLines(values) {
|
|
44114
44516
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -44121,9 +44523,15 @@ function uniqueNonEmptyLines(values) {
|
|
|
44121
44523
|
}
|
|
44122
44524
|
return out;
|
|
44123
44525
|
}
|
|
44526
|
+
function resetTimestampMs(value) {
|
|
44527
|
+
let parsed = typeof value === "number" ? value : typeof value === "string" ? Date.parse(value) : Number.NaN;
|
|
44528
|
+
if (!Number.isFinite(parsed)) return void 0;
|
|
44529
|
+
if (typeof value === "number" && Math.abs(parsed) < 1e12) parsed *= 1e3;
|
|
44530
|
+
return parsed;
|
|
44531
|
+
}
|
|
44124
44532
|
function formatResetTimestamp(value) {
|
|
44125
|
-
const parsed =
|
|
44126
|
-
if (
|
|
44533
|
+
const parsed = resetTimestampMs(value);
|
|
44534
|
+
if (parsed === void 0) return "unknown";
|
|
44127
44535
|
return new Date(parsed).toLocaleString(void 0, {
|
|
44128
44536
|
day: "numeric",
|
|
44129
44537
|
hour: "numeric",
|
|
@@ -44200,10 +44608,17 @@ function mapToolArgs(toolName, args) {
|
|
|
44200
44608
|
// src/assistant-stream.ts
|
|
44201
44609
|
import { calculateCost } from "@earendil-works/pi-ai";
|
|
44202
44610
|
function updateUsage(output, usage, model) {
|
|
44203
|
-
|
|
44204
|
-
|
|
44205
|
-
|
|
44206
|
-
if (usage.
|
|
44611
|
+
const c = ctx();
|
|
44612
|
+
const current = c.currentMessageUsage;
|
|
44613
|
+
const carry = c.turnUsageCarry;
|
|
44614
|
+
if (usage.input_tokens != null) current.input = usage.input_tokens;
|
|
44615
|
+
if (usage.output_tokens != null) current.output = usage.output_tokens;
|
|
44616
|
+
if (usage.cache_read_input_tokens != null) current.cacheRead = usage.cache_read_input_tokens;
|
|
44617
|
+
if (usage.cache_creation_input_tokens != null) current.cacheWrite = usage.cache_creation_input_tokens;
|
|
44618
|
+
output.usage.input = carry.input + current.input;
|
|
44619
|
+
output.usage.output = carry.output + current.output;
|
|
44620
|
+
output.usage.cacheRead = carry.cacheRead + current.cacheRead;
|
|
44621
|
+
output.usage.cacheWrite = carry.cacheWrite + current.cacheWrite;
|
|
44207
44622
|
output.usage.totalTokens = output.usage.input + output.usage.output + output.usage.cacheRead + output.usage.cacheWrite;
|
|
44208
44623
|
calculateCost(model, output.usage);
|
|
44209
44624
|
const promptTokens = output.usage.input + output.usage.cacheRead + output.usage.cacheWrite;
|
|
@@ -44229,20 +44644,60 @@ function parsePartialJson(input, fallback) {
|
|
|
44229
44644
|
return fallback;
|
|
44230
44645
|
}
|
|
44231
44646
|
}
|
|
44232
|
-
function ensureTurnStarted() {
|
|
44233
|
-
if (!
|
|
44234
|
-
|
|
44235
|
-
|
|
44647
|
+
function ensureTurnStarted(c = ctx()) {
|
|
44648
|
+
if (!c.turnStarted && c.currentPiStream && c.turnOutput) {
|
|
44649
|
+
c.currentPiStream.push({ type: "start", partial: c.turnOutput });
|
|
44650
|
+
c.turnStarted = true;
|
|
44236
44651
|
}
|
|
44237
44652
|
}
|
|
44238
|
-
function finalizeCurrentStream(stopReason) {
|
|
44239
|
-
if (!
|
|
44240
|
-
debug(`provider: finalizeCurrentStream called, stopReason=${stopReason}, turnOutput=${JSON.stringify({ stopReason:
|
|
44241
|
-
if (!
|
|
44653
|
+
function finalizeCurrentStream(stopReason, c = ctx()) {
|
|
44654
|
+
if (!c.currentPiStream || !c.turnOutput) return;
|
|
44655
|
+
debug(`provider: finalizeCurrentStream called, stopReason=${stopReason}, turnOutput=${JSON.stringify({ stopReason: c.turnOutput.stopReason, error: c.turnOutput.errorMessage })}`);
|
|
44656
|
+
if (!c.turnStarted) ensureTurnStarted(c);
|
|
44242
44657
|
const reason = stopReason === "length" ? "length" : "stop";
|
|
44243
|
-
|
|
44244
|
-
|
|
44245
|
-
|
|
44658
|
+
c.currentPiStream.push({ type: "done", reason, message: c.turnOutput });
|
|
44659
|
+
c.currentPiStream.end();
|
|
44660
|
+
c.currentPiStream = null;
|
|
44661
|
+
}
|
|
44662
|
+
var TOOL_USE_END_GRACE_MS = 1500;
|
|
44663
|
+
function endToolUseTurn(c) {
|
|
44664
|
+
if (!c.currentPiStream || !c.turnOutput) return;
|
|
44665
|
+
cancelScheduledToolUseEnd(c);
|
|
44666
|
+
c.turnOutput.stopReason = "toolUse";
|
|
44667
|
+
c.currentPiStream.push({ type: "done", reason: "toolUse", message: c.turnOutput });
|
|
44668
|
+
c.currentPiStream.end();
|
|
44669
|
+
c.currentPiStream = null;
|
|
44670
|
+
}
|
|
44671
|
+
function cancelScheduledToolUseEnd(c) {
|
|
44672
|
+
if (!c.scheduledToolUseEnd) return;
|
|
44673
|
+
clearTimeout(c.scheduledToolUseEnd.timer);
|
|
44674
|
+
c.scheduledToolUseEnd = null;
|
|
44675
|
+
}
|
|
44676
|
+
function scheduleToolUseTurnEnd(c, action, source) {
|
|
44677
|
+
if (!c.currentPiStream || !c.turnOutput) return;
|
|
44678
|
+
if (c.scheduledToolUseEnd?.stream === c.currentPiStream) return;
|
|
44679
|
+
cancelScheduledToolUseEnd(c);
|
|
44680
|
+
const stream = c.currentPiStream;
|
|
44681
|
+
const timer = setTimeout(() => {
|
|
44682
|
+
if (c.currentPiStream !== stream) return;
|
|
44683
|
+
debug(`scheduleToolUseTurnEnd: no terminal stream event within ${TOOL_USE_END_GRACE_MS}ms (${source}) \u2014 force-ending tool_use turn`);
|
|
44684
|
+
c.scheduledToolUseEnd = null;
|
|
44685
|
+
action();
|
|
44686
|
+
}, TOOL_USE_END_GRACE_MS);
|
|
44687
|
+
timer.unref?.();
|
|
44688
|
+
c.scheduledToolUseEnd = { stream, timer };
|
|
44689
|
+
}
|
|
44690
|
+
function reapStaleQueuedResults(c) {
|
|
44691
|
+
const stale = c.takeStaleQueuedResults();
|
|
44692
|
+
if (stale.length === 0) return;
|
|
44693
|
+
const names = stale.map((entry) => entry.toolName);
|
|
44694
|
+
debug(`reapStaleQueuedResults: dropping ${stale.length} queued tool result(s) with no possible consumer:`, names.join(", "));
|
|
44695
|
+
diagDump("stale_queued_tool_results_dropped", { count: stale.length, stale });
|
|
44696
|
+
appendIntegrityEntry("stale_queued_tool_results_dropped", { count: stale.length, stale });
|
|
44697
|
+
safeNotify(
|
|
44698
|
+
`Claude bridge: dropped ${stale.length} tool result(s) whose handler never matched (${names.slice(0, 6).join(", ")}${names.length > 6 ? ", \u2026" : ""}). The model saw an error for these calls and may retry them.`,
|
|
44699
|
+
"warning"
|
|
44700
|
+
);
|
|
44246
44701
|
}
|
|
44247
44702
|
function updateTurnOutputModel(modelId) {
|
|
44248
44703
|
const c = ctx();
|
|
@@ -44251,6 +44706,29 @@ function updateTurnOutputModel(modelId) {
|
|
|
44251
44706
|
debug(`provider: active Claude model changed ${c.turnOutput.model} -> ${modelId}`);
|
|
44252
44707
|
c.turnOutput.model = modelId;
|
|
44253
44708
|
}
|
|
44709
|
+
function finalizeToolUseTurnFromMcpInvocation(queryCtx, toolCallId, toolName, mappedArgs) {
|
|
44710
|
+
if (!queryCtx.currentPiStream || !queryCtx.turnOutput) return;
|
|
44711
|
+
let idx = queryCtx.turnBlocks.findIndex((b) => b.type === "toolCall" && b.id === toolCallId);
|
|
44712
|
+
if (idx >= 0) {
|
|
44713
|
+
const block = queryCtx.turnBlocks[idx];
|
|
44714
|
+
if ("partialJson" in block) {
|
|
44715
|
+
block.arguments = mapToolArgs(block.name, parsePartialJson(block.partialJson, block.arguments));
|
|
44716
|
+
queryCtx.updateToolCallArgs(block.id, block.arguments);
|
|
44717
|
+
delete block.partialJson;
|
|
44718
|
+
delete block.index;
|
|
44719
|
+
queryCtx.currentPiStream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: queryCtx.turnOutput });
|
|
44720
|
+
}
|
|
44721
|
+
} else {
|
|
44722
|
+
queryCtx.turnBlocks.push({ type: "toolCall", id: toolCallId, name: toolName, arguments: mappedArgs });
|
|
44723
|
+
idx = queryCtx.turnBlocks.length - 1;
|
|
44724
|
+
const block = queryCtx.turnBlocks[idx];
|
|
44725
|
+
queryCtx.currentPiStream.push({ type: "toolcall_start", contentIndex: idx, partial: queryCtx.turnOutput });
|
|
44726
|
+
queryCtx.currentPiStream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: queryCtx.turnOutput });
|
|
44727
|
+
}
|
|
44728
|
+
queryCtx.turnSawToolCall = true;
|
|
44729
|
+
debug(`mcp handler: finalizing tool_use turn from MCP invocation [${toolCallId}] (${toolName}) \u2014 terminal stream events never arrived`);
|
|
44730
|
+
endToolUseTurn(queryCtx);
|
|
44731
|
+
}
|
|
44254
44732
|
function processStreamEvent(message, customToolNameToPi, model) {
|
|
44255
44733
|
const c = ctx();
|
|
44256
44734
|
if (!c.currentPiStream || !c.turnOutput) return;
|
|
@@ -44261,7 +44739,9 @@ function processStreamEvent(message, customToolNameToPi, model) {
|
|
|
44261
44739
|
return;
|
|
44262
44740
|
}
|
|
44263
44741
|
if (event?.type === "message_start") {
|
|
44742
|
+
reapStaleQueuedResults(c);
|
|
44264
44743
|
c.resetToolTracking();
|
|
44744
|
+
c.beginChildMessage(event.message?.id);
|
|
44265
44745
|
updateTurnOutputModel(event.message?.model);
|
|
44266
44746
|
if (event.message?.usage) updateUsage(c.turnOutput, event.message.usage, model);
|
|
44267
44747
|
return;
|
|
@@ -44269,6 +44749,12 @@ function processStreamEvent(message, customToolNameToPi, model) {
|
|
|
44269
44749
|
if (event?.type === "content_block_start") {
|
|
44270
44750
|
c.turnSawStreamEvent = true;
|
|
44271
44751
|
ensureTurnStarted();
|
|
44752
|
+
c.childExecutedStreamIndexes.delete(event.index);
|
|
44753
|
+
if (event.content_block?.type === "tool_use" && isChildExecutedTool(event.content_block.name)) {
|
|
44754
|
+
c.noteChildExecutedToolCall(event.content_block.id, event.content_block.name, event.index);
|
|
44755
|
+
debug(`processStreamEvent: child-executed tool ${event.content_block.name} [${event.content_block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
44756
|
+
return;
|
|
44757
|
+
}
|
|
44272
44758
|
if (event.content_block?.type === "text") {
|
|
44273
44759
|
c.turnBlocks.push({ type: "text", text: "", index: event.index });
|
|
44274
44760
|
c.currentPiStream.push({ type: "text_start", contentIndex: c.turnBlocks.length - 1, partial: c.turnOutput });
|
|
@@ -44294,6 +44780,10 @@ function processStreamEvent(message, customToolNameToPi, model) {
|
|
|
44294
44780
|
return;
|
|
44295
44781
|
}
|
|
44296
44782
|
if (event?.type === "content_block_delta") {
|
|
44783
|
+
if (c.childExecutedStreamIndexes.has(event.index)) {
|
|
44784
|
+
c.turnSawStreamEvent = true;
|
|
44785
|
+
return;
|
|
44786
|
+
}
|
|
44297
44787
|
const index = c.turnBlocks.findIndex((b) => b.index === event.index);
|
|
44298
44788
|
const block = c.turnBlocks[index];
|
|
44299
44789
|
if (!block) {
|
|
@@ -44319,6 +44809,10 @@ function processStreamEvent(message, customToolNameToPi, model) {
|
|
|
44319
44809
|
return;
|
|
44320
44810
|
}
|
|
44321
44811
|
if (event?.type === "content_block_stop") {
|
|
44812
|
+
if (c.childExecutedStreamIndexes.has(event.index)) {
|
|
44813
|
+
c.turnSawStreamEvent = true;
|
|
44814
|
+
return;
|
|
44815
|
+
}
|
|
44322
44816
|
const index = c.turnBlocks.findIndex((b) => b.index === event.index);
|
|
44323
44817
|
const block = c.turnBlocks[index];
|
|
44324
44818
|
if (!block) {
|
|
@@ -44349,10 +44843,7 @@ function processStreamEvent(message, customToolNameToPi, model) {
|
|
|
44349
44843
|
return;
|
|
44350
44844
|
}
|
|
44351
44845
|
if (event?.type === "message_stop" && c.turnSawToolCall) {
|
|
44352
|
-
c
|
|
44353
|
-
c.currentPiStream.push({ type: "done", reason: "toolUse", message: c.turnOutput });
|
|
44354
|
-
c.currentPiStream.end();
|
|
44355
|
-
c.currentPiStream = null;
|
|
44846
|
+
endToolUseTurn(c);
|
|
44356
44847
|
return;
|
|
44357
44848
|
}
|
|
44358
44849
|
if (event?.type !== "message_stop" && event?.type !== "ping") {
|
|
@@ -44365,6 +44856,11 @@ function appendMissingToolUsesFromAssistant(assistantMsg, model, customToolNameT
|
|
|
44365
44856
|
let sawToolUse = false;
|
|
44366
44857
|
for (const block of assistantMsg.content) {
|
|
44367
44858
|
if (block.type !== "tool_use") continue;
|
|
44859
|
+
if (isChildExecutedTool(block.name)) {
|
|
44860
|
+
c.noteChildExecutedToolCall(block.id, block.name);
|
|
44861
|
+
debug(`assistant message: child-executed tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
44862
|
+
continue;
|
|
44863
|
+
}
|
|
44368
44864
|
sawToolUse = true;
|
|
44369
44865
|
const existingIdx = c.turnBlocks.findIndex((b) => b.type === "toolCall" && b.id === block.id);
|
|
44370
44866
|
const name = mapToolName(block.name, customToolNameToPi);
|
|
@@ -44394,9 +44890,24 @@ function appendMissingToolUsesFromAssistant(assistantMsg, model, customToolNameT
|
|
|
44394
44890
|
c.currentPiStream?.push({ type: "toolcall_start", contentIndex: idx, partial: c.turnOutput });
|
|
44395
44891
|
c.currentPiStream?.push({ type: "toolcall_end", contentIndex: idx, toolCall: toolBlock, partial: c.turnOutput });
|
|
44396
44892
|
}
|
|
44397
|
-
if (assistantMsg.usage && c.turnOutput) updateUsage(c.turnOutput, assistantMsg.usage, model);
|
|
44893
|
+
if (assistantMsg.usage && c.turnOutput && c.currentPiStream) updateUsage(c.turnOutput, assistantMsg.usage, model);
|
|
44398
44894
|
return sawToolUse;
|
|
44399
44895
|
}
|
|
44896
|
+
function noteChildExecutedToolResults(message) {
|
|
44897
|
+
const c = ctx();
|
|
44898
|
+
if (c.childExecutedToolCalls.size === 0) return;
|
|
44899
|
+
const content = message.message?.content;
|
|
44900
|
+
if (!Array.isArray(content)) return;
|
|
44901
|
+
for (const block of content) {
|
|
44902
|
+
if (block?.type !== "tool_result") continue;
|
|
44903
|
+
const name = c.childExecutedToolCalls.get(block.tool_use_id);
|
|
44904
|
+
if (!name) continue;
|
|
44905
|
+
const isError = block.is_error === true;
|
|
44906
|
+
const byteSize = connectorResultByteSize(block.content);
|
|
44907
|
+
const audited = recordConnectorCallResult(c, block.tool_use_id, name, isError, byteSize);
|
|
44908
|
+
debug(`child-executed tool result: ${name} [${block.tool_use_id}] isError=${isError} byteSize=${byteSize ?? "unknown"} audited=${audited}`);
|
|
44909
|
+
}
|
|
44910
|
+
}
|
|
44400
44911
|
function processAssistantMessage(message, model, customToolNameToPi) {
|
|
44401
44912
|
const c = ctx();
|
|
44402
44913
|
const assistantMsg = message.message;
|
|
@@ -44405,20 +44916,21 @@ function processAssistantMessage(message, model, customToolNameToPi) {
|
|
|
44405
44916
|
if (c.turnSawStreamEvent) {
|
|
44406
44917
|
if (appendMissingToolUsesFromAssistant(assistantMsg, model, customToolNameToPi)) {
|
|
44407
44918
|
c.turnSawToolCall = true;
|
|
44408
|
-
|
|
44409
|
-
c.turnOutput.stopReason = "toolUse";
|
|
44410
|
-
c.currentPiStream.push({ type: "done", reason: "toolUse", message: c.turnOutput });
|
|
44411
|
-
c.currentPiStream.end();
|
|
44412
|
-
c.currentPiStream = null;
|
|
44413
|
-
debug("processAssistantMessage boundary: ended streamed tool_use turn from assistant message");
|
|
44414
|
-
}
|
|
44919
|
+
scheduleToolUseTurnEnd(c, () => endToolUseTurn(c), "assistant-boundary");
|
|
44415
44920
|
}
|
|
44416
44921
|
return;
|
|
44417
44922
|
}
|
|
44418
|
-
c.
|
|
44419
|
-
|
|
44923
|
+
const sameMessage = typeof assistantMsg.id === "string" && assistantMsg.id.length > 0 && assistantMsg.id === c.currentMessageId;
|
|
44924
|
+
if (!sameMessage) {
|
|
44925
|
+
reapStaleQueuedResults(c);
|
|
44926
|
+
c.resetToolTracking();
|
|
44927
|
+
}
|
|
44928
|
+
c.beginChildMessage(assistantMsg.id);
|
|
44929
|
+
debug(`processAssistantMessage fallback: ${assistantMsg.content.length} blocks, types=${assistantMsg.content.map((b) => b.type).join(",")}${sameMessage ? " (same message re-yield)" : ""}`);
|
|
44930
|
+
const alreadyRendered = (type, content) => c.turnBlocks.some((b) => b.type === type && (type === "text" ? b.text : b.thinking) === content);
|
|
44420
44931
|
for (const block of assistantMsg.content) {
|
|
44421
44932
|
if (block.type === "text" && block.text) {
|
|
44933
|
+
if (alreadyRendered("text", block.text)) continue;
|
|
44422
44934
|
ensureTurnStarted();
|
|
44423
44935
|
c.turnBlocks.push({ type: "text", text: block.text });
|
|
44424
44936
|
const idx = c.turnBlocks.length - 1;
|
|
@@ -44426,6 +44938,7 @@ function processAssistantMessage(message, model, customToolNameToPi) {
|
|
|
44426
44938
|
c.currentPiStream?.push({ type: "text_delta", contentIndex: idx, delta: block.text, partial: c.turnOutput });
|
|
44427
44939
|
c.currentPiStream?.push({ type: "text_end", contentIndex: idx, content: block.text, partial: c.turnOutput });
|
|
44428
44940
|
} else if (block.type === "thinking") {
|
|
44941
|
+
if (alreadyRendered("thinking", block.thinking ?? "")) continue;
|
|
44429
44942
|
ensureTurnStarted();
|
|
44430
44943
|
c.turnBlocks.push({ type: "thinking", thinking: block.thinking ?? "", thinkingSignature: block.signature ?? "" });
|
|
44431
44944
|
const idx = c.turnBlocks.length - 1;
|
|
@@ -44433,11 +44946,24 @@ function processAssistantMessage(message, model, customToolNameToPi) {
|
|
|
44433
44946
|
if (block.thinking) c.currentPiStream?.push({ type: "thinking_delta", contentIndex: idx, delta: block.thinking, partial: c.turnOutput });
|
|
44434
44947
|
c.currentPiStream?.push({ type: "thinking_end", contentIndex: idx, content: block.thinking ?? "", partial: c.turnOutput });
|
|
44435
44948
|
} else if (block.type === "tool_use") {
|
|
44949
|
+
if (isChildExecutedTool(block.name)) {
|
|
44950
|
+
c.noteChildExecutedToolCall(block.id, block.name);
|
|
44951
|
+
debug(`processAssistantMessage fallback: child-executed tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
|
|
44952
|
+
continue;
|
|
44953
|
+
}
|
|
44436
44954
|
ensureTurnStarted();
|
|
44437
44955
|
c.turnSawToolCall = true;
|
|
44438
44956
|
const mappedName = mapToolName(block.name, customToolNameToPi);
|
|
44439
44957
|
const mappedArgs = mapToolArgs(mappedName, block.input);
|
|
44440
44958
|
c.recordToolCall(block.id, mappedName, mappedArgs);
|
|
44959
|
+
const existingIdx = c.turnBlocks.findIndex((b) => b.type === "toolCall" && b.id === block.id);
|
|
44960
|
+
if (existingIdx >= 0) {
|
|
44961
|
+
const existing = c.turnBlocks[existingIdx];
|
|
44962
|
+
existing.name = mappedName;
|
|
44963
|
+
existing.arguments = mappedArgs;
|
|
44964
|
+
c.updateToolCallArgs(block.id, mappedArgs);
|
|
44965
|
+
continue;
|
|
44966
|
+
}
|
|
44441
44967
|
c.turnBlocks.push({
|
|
44442
44968
|
type: "toolCall",
|
|
44443
44969
|
id: block.id,
|
|
@@ -44456,10 +44982,7 @@ function processAssistantMessage(message, model, customToolNameToPi) {
|
|
|
44456
44982
|
}
|
|
44457
44983
|
if (assistantMsg.usage && c.turnOutput) updateUsage(c.turnOutput, assistantMsg.usage, model);
|
|
44458
44984
|
if (c.turnSawToolCall && c.currentPiStream && c.turnOutput) {
|
|
44459
|
-
c
|
|
44460
|
-
c.currentPiStream.push({ type: "done", reason: "toolUse", message: c.turnOutput });
|
|
44461
|
-
c.currentPiStream.end();
|
|
44462
|
-
c.currentPiStream = null;
|
|
44985
|
+
endToolUseTurn(c);
|
|
44463
44986
|
}
|
|
44464
44987
|
}
|
|
44465
44988
|
|
|
@@ -44481,6 +45004,27 @@ function emitRateLimitEvent(payload) {
|
|
|
44481
45004
|
function extraUsageAllowed(config2) {
|
|
44482
45005
|
return config2.provider?.allowExtraUsage === true;
|
|
44483
45006
|
}
|
|
45007
|
+
var lastFastModeDisabledNoticeReason = null;
|
|
45008
|
+
var FAST_MODE_DISABLED_REASON_TEXT = {
|
|
45009
|
+
disabled_by_env: "disabled by an environment variable",
|
|
45010
|
+
extra_usage_disabled: "extra usage is disabled for this account",
|
|
45011
|
+
free: "not available on the free plan",
|
|
45012
|
+
model_not_allowed: "not available for this model",
|
|
45013
|
+
network_error: "the eligibility check hit a network error",
|
|
45014
|
+
not_first_party: "not available for this account type",
|
|
45015
|
+
preference: "disabled by a Claude Code preference",
|
|
45016
|
+
sdk_opt_in_required: "the SDK opt-in is missing",
|
|
45017
|
+
unknown: "unavailable for an unknown reason"
|
|
45018
|
+
};
|
|
45019
|
+
function noteFastModeDisabledReason(message, bridgeConfig) {
|
|
45020
|
+
if (bridgeConfig.provider?.fastMode !== true) return;
|
|
45021
|
+
const reason = message.fast_mode_disabled_reason;
|
|
45022
|
+
if (typeof reason !== "string" || reason === "pending") return;
|
|
45023
|
+
if (reason === lastFastModeDisabledNoticeReason) return;
|
|
45024
|
+
lastFastModeDisabledNoticeReason = reason;
|
|
45025
|
+
const text = FAST_MODE_DISABLED_REASON_TEXT[reason] ?? `unavailable (${reason})`;
|
|
45026
|
+
safeNotify(`Claude bridge: fast mode is enabled in settings but Claude Code declined it \u2014 ${text}.`, "warning");
|
|
45027
|
+
}
|
|
44484
45028
|
function sdkTextFromMessage(message) {
|
|
44485
45029
|
if (message.type === "result") return message.result;
|
|
44486
45030
|
if (message.type === "assistant") {
|
|
@@ -44594,41 +45138,24 @@ function resolveMcpTools(context, excludeToolName) {
|
|
|
44594
45138
|
if (!context.tools) return { mcpTools, customToolNameToSdk, customToolNameToPi };
|
|
44595
45139
|
for (const tool of context.tools) {
|
|
44596
45140
|
if (tool.name === excludeToolName) continue;
|
|
45141
|
+
if (isChildExecutedTool(tool.name)) {
|
|
45142
|
+
debug(`resolveMcpTools: not re-offering child-native tool ${tool.name}`);
|
|
45143
|
+
continue;
|
|
45144
|
+
}
|
|
44597
45145
|
const sdkName = `${MCP_TOOL_PREFIX}${tool.name}`;
|
|
44598
45146
|
mcpTools.push(tool);
|
|
45147
|
+
const lowerName = tool.name.toLowerCase();
|
|
45148
|
+
const collision = customToolNameToSdk.get(lowerName);
|
|
45149
|
+
if (collision !== void 0 && collision !== sdkName) {
|
|
45150
|
+
debug(`WARNING: resolveMcpTools lowercase alias collision: ${tool.name} overwrites mapping previously held by ${collision}`);
|
|
45151
|
+
}
|
|
44599
45152
|
customToolNameToSdk.set(tool.name, sdkName);
|
|
44600
|
-
customToolNameToSdk.set(
|
|
45153
|
+
customToolNameToSdk.set(lowerName, sdkName);
|
|
44601
45154
|
customToolNameToPi.set(sdkName, tool.name);
|
|
44602
45155
|
customToolNameToPi.set(sdkName.toLowerCase(), tool.name);
|
|
44603
45156
|
}
|
|
44604
45157
|
return { mcpTools, customToolNameToSdk, customToolNameToPi };
|
|
44605
45158
|
}
|
|
44606
|
-
function finalizeToolUseTurnFromMcpInvocation(queryCtx, toolCallId, toolName, mappedArgs) {
|
|
44607
|
-
if (!queryCtx.currentPiStream || !queryCtx.turnOutput) return;
|
|
44608
|
-
let idx = queryCtx.turnBlocks.findIndex((b) => b.type === "toolCall" && b.id === toolCallId);
|
|
44609
|
-
if (idx >= 0) {
|
|
44610
|
-
const block = queryCtx.turnBlocks[idx];
|
|
44611
|
-
if ("partialJson" in block) {
|
|
44612
|
-
block.arguments = mapToolArgs(block.name, parsePartialJson(block.partialJson, block.arguments));
|
|
44613
|
-
queryCtx.updateToolCallArgs(block.id, block.arguments);
|
|
44614
|
-
delete block.partialJson;
|
|
44615
|
-
delete block.index;
|
|
44616
|
-
queryCtx.currentPiStream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: queryCtx.turnOutput });
|
|
44617
|
-
}
|
|
44618
|
-
} else {
|
|
44619
|
-
queryCtx.turnBlocks.push({ type: "toolCall", id: toolCallId, name: toolName, arguments: mappedArgs });
|
|
44620
|
-
idx = queryCtx.turnBlocks.length - 1;
|
|
44621
|
-
const block = queryCtx.turnBlocks[idx];
|
|
44622
|
-
queryCtx.currentPiStream.push({ type: "toolcall_start", contentIndex: idx, partial: queryCtx.turnOutput });
|
|
44623
|
-
queryCtx.currentPiStream.push({ type: "toolcall_end", contentIndex: idx, toolCall: block, partial: queryCtx.turnOutput });
|
|
44624
|
-
}
|
|
44625
|
-
queryCtx.turnSawToolCall = true;
|
|
44626
|
-
queryCtx.turnOutput.stopReason = "toolUse";
|
|
44627
|
-
debug(`mcp handler: finalizing tool_use turn from MCP invocation [${toolCallId}] (${toolName}) \u2014 SDK invoked the tool before message_stop/assistant message`);
|
|
44628
|
-
queryCtx.currentPiStream.push({ type: "done", reason: "toolUse", message: queryCtx.turnOutput });
|
|
44629
|
-
queryCtx.currentPiStream.end();
|
|
44630
|
-
queryCtx.currentPiStream = null;
|
|
44631
|
-
}
|
|
44632
45159
|
function buildMcpServers(tools, queryCtx) {
|
|
44633
45160
|
if (!tools.length) return void 0;
|
|
44634
45161
|
const mcpTools = tools.map((tool) => ({
|
|
@@ -44648,9 +45175,23 @@ function buildMcpServers(tools, queryCtx) {
|
|
|
44648
45175
|
turnToolCallIds: queryCtx.turnToolCallIds,
|
|
44649
45176
|
turnToolCalls: safeToolCallSummary(queryCtx.turnToolCalls)
|
|
44650
45177
|
});
|
|
45178
|
+
appendIntegrityEntry("tool_handler_unmatched", {
|
|
45179
|
+
toolName: tool.name,
|
|
45180
|
+
argKeys: argKeys(mappedArgs),
|
|
45181
|
+
available: claim.available,
|
|
45182
|
+
turnToolCallIds: queryCtx.turnToolCallIds
|
|
45183
|
+
});
|
|
44651
45184
|
return { content: [{ type: "text", text: `Claude bridge internal error: no matching tool_call id for ${tool.name}` }], isError: true };
|
|
44652
45185
|
}
|
|
44653
|
-
if (claim.
|
|
45186
|
+
if (claim.argsMismatch) {
|
|
45187
|
+
debug(`mcp handler: ${tool.name} [${toolCallId}] claimed sole same-name call despite args mismatch`);
|
|
45188
|
+
diagDump("tool_claim_args_mismatch", {
|
|
45189
|
+
toolName: tool.name,
|
|
45190
|
+
toolCallId,
|
|
45191
|
+
handlerArgKeys: argKeys(mappedArgs),
|
|
45192
|
+
recordedArgKeys: argKeys(queryCtx.turnToolCalls.find((call) => call.id === toolCallId)?.arguments)
|
|
45193
|
+
});
|
|
45194
|
+
} else if (claim.match !== "tool-args" || claim.ambiguous) {
|
|
44654
45195
|
debug(`mcp handler: ${tool.name} [${toolCallId}] claimed by ${claim.match}${claim.ambiguous ? " (ambiguous)" : ""}`);
|
|
44655
45196
|
}
|
|
44656
45197
|
if (toolCallId && queryCtx.pendingResults.has(toolCallId)) {
|
|
@@ -44661,7 +45202,11 @@ function buildMcpServers(tools, queryCtx) {
|
|
|
44661
45202
|
return result;
|
|
44662
45203
|
}
|
|
44663
45204
|
debug(`mcp handler: ${tool.name} [${toolCallId}] \u2192 waiting`);
|
|
44664
|
-
|
|
45205
|
+
scheduleToolUseTurnEnd(
|
|
45206
|
+
queryCtx,
|
|
45207
|
+
() => finalizeToolUseTurnFromMcpInvocation(queryCtx, toolCallId, tool.name, mappedArgs),
|
|
45208
|
+
`mcp-invocation:${tool.name}`
|
|
45209
|
+
);
|
|
44665
45210
|
return new Promise((resolve5) => {
|
|
44666
45211
|
queryCtx.pendingToolCalls.set(toolCallId, {
|
|
44667
45212
|
toolName: tool.name,
|
|
@@ -44715,20 +45260,26 @@ async function consumeQuery(sdkQuery, customToolNameToPi, model, cwd, bridgeConf
|
|
|
44715
45260
|
break;
|
|
44716
45261
|
case "result":
|
|
44717
45262
|
if (!ctx().turnSawStreamEvent && message.subtype === "success") {
|
|
44718
|
-
ensureTurnStarted();
|
|
44719
45263
|
const text = message.result || "";
|
|
45264
|
+
if (ctx().turnBlocks.some((b) => b.type === "text" && b.text === text)) {
|
|
45265
|
+
debug("consumeQuery: result text already rendered by assistant fallback; skipping duplicate");
|
|
45266
|
+
break;
|
|
45267
|
+
}
|
|
45268
|
+
ensureTurnStarted();
|
|
44720
45269
|
ctx().turnBlocks.push({ type: "text", text });
|
|
44721
45270
|
const idx = ctx().turnBlocks.length - 1;
|
|
44722
45271
|
ctx().currentPiStream?.push({ type: "text_start", contentIndex: idx, partial: ctx().turnOutput });
|
|
44723
45272
|
ctx().currentPiStream?.push({ type: "text_delta", contentIndex: idx, delta: text, partial: ctx().turnOutput });
|
|
44724
45273
|
ctx().currentPiStream?.push({ type: "text_end", contentIndex: idx, content: text, partial: ctx().turnOutput });
|
|
44725
|
-
} else if (message.subtype !== "success" && isExtraUsageRequiredMessage(message)) {
|
|
45274
|
+
} else if (message.subtype !== "success" && (isExtraUsageRequiredMessage(message) || isUsageLimitMessage(message))) {
|
|
44726
45275
|
const errorLines = Array.isArray(message.errors) ? uniqueNonEmptyLines(message.errors) : [];
|
|
44727
45276
|
const errors = errorLines.length > 0 ? errorLines.join("\n") : String(message.subtype ?? "Claude Code rate limit");
|
|
44728
|
-
const
|
|
45277
|
+
const extraUsage = isExtraUsageRequiredMessage(message);
|
|
45278
|
+
const openedExtraUsage = extraUsage && launchExtraUsageHelperIfAllowed(cwd, bridgeConfig, "result error");
|
|
44729
45279
|
ctx().handledTerminalError = true;
|
|
44730
45280
|
ctx().turnOutput.stopReason = "error";
|
|
44731
|
-
|
|
45281
|
+
const extraUsageHint = openedExtraUsage ? "\n\nOpened Claude Code /extra-usage helper. Complete billing/admin flow in the browser, then retry the prompt." : extraUsage ? "\n\nRun /claude-bridge:extra, or enable Allow extra usage helper in settings." : "";
|
|
45282
|
+
ctx().turnOutput.errorMessage = `${errors}${extraUsageHint}`;
|
|
44732
45283
|
ctx().currentPiStream?.push({ type: "error", reason: "error", error: ctx().turnOutput });
|
|
44733
45284
|
ctx().currentPiStream?.end();
|
|
44734
45285
|
ctx().currentPiStream = null;
|
|
@@ -44737,6 +45288,8 @@ async function consumeQuery(sdkQuery, customToolNameToPi, model, cwd, bridgeConf
|
|
|
44737
45288
|
case "system":
|
|
44738
45289
|
if (message.subtype === "init" && message.session_id) {
|
|
44739
45290
|
capturedSessionId = message.session_id;
|
|
45291
|
+
queryCtx.childSessionId = capturedSessionId;
|
|
45292
|
+
noteFastModeDisabledReason(message, bridgeConfig);
|
|
44740
45293
|
} else if (message.subtype === "model_refusal_fallback") {
|
|
44741
45294
|
const originalModel = message.original_model;
|
|
44742
45295
|
const fallbackModel = message.fallback_model;
|
|
@@ -44751,14 +45304,14 @@ async function consumeQuery(sdkQuery, customToolNameToPi, model, cwd, bridgeConf
|
|
|
44751
45304
|
}
|
|
44752
45305
|
break;
|
|
44753
45306
|
case "user":
|
|
45307
|
+
noteChildExecutedToolResults(message);
|
|
44754
45308
|
break;
|
|
44755
|
-
// SDK echo of user prompt — not needed
|
|
44756
45309
|
case "rate_limit_event": {
|
|
44757
45310
|
const info = message.rate_limit_info;
|
|
44758
45311
|
debug("consumeQuery: rate_limit_event", JSON.stringify(info).slice(0, 300));
|
|
44759
45312
|
if (info?.status === "rejected") {
|
|
44760
45313
|
const resetsAt = formatResetTimestamp(info.resetsAt);
|
|
44761
|
-
const resetAtMs =
|
|
45314
|
+
const resetAtMs = resetTimestampMs(info.resetsAt);
|
|
44762
45315
|
const reason = `${info.rateLimitType ?? "unknown"} rate limit`;
|
|
44763
45316
|
const launchedExtraUsage = isExtraUsageRequiredMessage(info) && launchExtraUsageHelperIfAllowed(cwd, bridgeConfig, reason);
|
|
44764
45317
|
emitRateLimitEvent({
|
|
@@ -44803,6 +45356,8 @@ function releaseProviderTokens(event) {
|
|
|
44803
45356
|
g[PRIMARY_INSTANCE_KEY] = void 0;
|
|
44804
45357
|
}
|
|
44805
45358
|
}
|
|
45359
|
+
var nativeProviderInstance;
|
|
45360
|
+
var notifiedNativeUnsupported = false;
|
|
44806
45361
|
function applyProviderRegistration(trigger) {
|
|
44807
45362
|
const pi = extensionApi;
|
|
44808
45363
|
if (!pi) {
|
|
@@ -44811,32 +45366,28 @@ function applyProviderRegistration(trigger) {
|
|
|
44811
45366
|
}
|
|
44812
45367
|
const g = globalThis;
|
|
44813
45368
|
const isPrimary = claimPrimaryInstance();
|
|
44814
|
-
|
|
44815
|
-
|
|
44816
|
-
|
|
44817
|
-
|
|
44818
|
-
if (
|
|
44819
|
-
|
|
44820
|
-
|
|
44821
|
-
|
|
44822
|
-
|
|
44823
|
-
apiKey: "not-used",
|
|
44824
|
-
api: "claude-bridge",
|
|
44825
|
-
models: MODELS,
|
|
44826
|
-
// Cast: pi-ai AssistantMessageEventStream diamond dep between pi-coding-agent and pi-agent-core
|
|
44827
|
-
streamSimple: streamClaudeAgentSdk
|
|
44828
|
-
});
|
|
44829
|
-
} catch (err) {
|
|
44830
|
-
if (g[ACTIVE_STREAM_SIMPLE_KEY] === streamClaudeAgentSdk) g[ACTIVE_STREAM_SIMPLE_KEY] = void 0;
|
|
44831
|
-
debug(`${trigger}: registerProvider threw; released stream guard for retry (kept primary):`, err);
|
|
44832
|
-
}
|
|
44833
|
-
} else if (decision === "unregister") {
|
|
44834
|
-
try {
|
|
44835
|
-
pi.unregisterProvider(PROVIDER_ID);
|
|
44836
|
-
} catch (err) {
|
|
44837
|
-
debug(`${trigger}: unregisterProvider threw (ignored):`, err);
|
|
45369
|
+
if (!isPrimary) {
|
|
45370
|
+
debug(`${trigger}: registration noop \u2014 non-primary instance (module=${moduleInstanceId})`);
|
|
45371
|
+
return;
|
|
45372
|
+
}
|
|
45373
|
+
if (!supportsNativeProvider(_piAi)) {
|
|
45374
|
+
debug(`${trigger}: host pi-ai lacks createProvider; refusing to register (module=${moduleInstanceId})`);
|
|
45375
|
+
if (!notifiedNativeUnsupported) {
|
|
45376
|
+
notifiedNativeUnsupported = true;
|
|
45377
|
+
safeNotify(NATIVE_PROVIDER_UNSUPPORTED_MESSAGE, "error");
|
|
44838
45378
|
}
|
|
45379
|
+
return;
|
|
45380
|
+
}
|
|
45381
|
+
const credentialed = hasClaudeCredentials();
|
|
45382
|
+
debug(`${trigger}: native registration upsert, credentialed=${credentialed} (module=${moduleInstanceId})`);
|
|
45383
|
+
if (credentialed && connectorsEnabledFor(loadConfig(process.cwd()))) primeConnectorServers();
|
|
45384
|
+
g[ACTIVE_STREAM_SIMPLE_KEY] = streamClaudeAgentSdk;
|
|
45385
|
+
try {
|
|
45386
|
+
nativeProviderInstance ??= buildNativeProvider(_piAi, MODELS, streamClaudeAgentSdk);
|
|
45387
|
+
pi.registerProvider(nativeProviderInstance);
|
|
45388
|
+
} catch (err) {
|
|
44839
45389
|
if (g[ACTIVE_STREAM_SIMPLE_KEY] === streamClaudeAgentSdk) g[ACTIVE_STREAM_SIMPLE_KEY] = void 0;
|
|
45390
|
+
debug(`${trigger}: registerProvider threw; released stream guard for retry (kept primary):`, err);
|
|
44840
45391
|
}
|
|
44841
45392
|
}
|
|
44842
45393
|
function streamClaudeAgentSdk(model, context, options) {
|
|
@@ -44974,6 +45525,7 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
44974
45525
|
const providerSettings = bridgeConfig.provider ?? {};
|
|
44975
45526
|
const enableCloudMcp = connectorsEnabledFor(bridgeConfig);
|
|
44976
45527
|
const connectorWriteMode = connectorWriteModeFor(bridgeConfig);
|
|
45528
|
+
const connectorServers = enableCloudMcp ? connectorServersSnapshot() : {};
|
|
44977
45529
|
const appendSystemPrompt = providerSettings.appendSystemPrompt !== false;
|
|
44978
45530
|
const agentsAppend = appendSystemPrompt ? extractAgentsAppend() : void 0;
|
|
44979
45531
|
const skillsAppend = appendSystemPrompt ? extractSkillsBlock(context.systemPrompt) : void 0;
|
|
@@ -44988,7 +45540,6 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
44988
45540
|
const requestedEffort = options?.reasoning ? model.thinkingLevelMap?.[options.reasoning] ?? REASONING_TO_EFFORT[options.reasoning] : void 0;
|
|
44989
45541
|
const effort = resolveConfiguredEffort(model.id, requestedEffort, providerSettings);
|
|
44990
45542
|
const extraArgs = {};
|
|
44991
|
-
if (strictMcpConfigEnabled) extraArgs["strict-mcp-config"] = null;
|
|
44992
45543
|
if (effort) extraArgs["thinking-display"] = "summarized";
|
|
44993
45544
|
const fallbackModel = fallbackModelForPrimaryModel(model.id);
|
|
44994
45545
|
const childEnv = { ...process.env, ENABLE_CLAUDEAI_MCP_SERVERS: enableCloudMcp ? "1" : "0", DISABLE_AUTO_COMPACT: "1" };
|
|
@@ -45007,9 +45558,10 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
45007
45558
|
append: systemPromptAppend ? systemPromptAppend : void 0
|
|
45008
45559
|
},
|
|
45009
45560
|
extraArgs,
|
|
45561
|
+
...strictMcpConfigEnabled ? { strictMcpConfig: true } : {},
|
|
45010
45562
|
...effort ? { effort } : {},
|
|
45011
45563
|
...settingSources ? { settingSources } : {},
|
|
45012
|
-
...mcpServers ? { mcpServers } : {},
|
|
45564
|
+
...mcpServers || Object.keys(connectorServers).length > 0 ? { mcpServers: { ...mcpServers ?? {}, ...connectorServers } } : {},
|
|
45013
45565
|
...resumeSessionId ? { resume: resumeSessionId } : {},
|
|
45014
45566
|
...claudeExecutable ? { pathToClaudeCodeExecutable: claudeExecutable } : {},
|
|
45015
45567
|
spawnClaudeCodeProcess: spawnClaudeCodeWithDiagnostics,
|
|
@@ -45100,7 +45652,7 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
45100
45652
|
else options.signal.addEventListener("abort", onAbort, { once: true });
|
|
45101
45653
|
}
|
|
45102
45654
|
consumeQuery(sdkQuery, customToolNameToPi, model, cwd, bridgeConfig, () => wasAborted).then(async ({ capturedSessionId }) => {
|
|
45103
|
-
debug(`provider: consumeQuery completed, stopReason=${
|
|
45655
|
+
debug(`provider: consumeQuery completed, stopReason=${abortCtx.turnOutput?.stopReason}, error=${abortCtx.turnOutput?.errorMessage}, aborted=${wasAborted}`);
|
|
45104
45656
|
if (streamIdleTimedOut) {
|
|
45105
45657
|
abortCtx.deferredUserMessages = [];
|
|
45106
45658
|
debug("provider: stream idle timeout already surfaced; skipping normal completion");
|
|
@@ -45108,29 +45660,29 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
45108
45660
|
}
|
|
45109
45661
|
if (wasAborted || options?.signal?.aborted) {
|
|
45110
45662
|
if (sharedSession) setSharedSession({ ...sharedSession, needsRebuild: true, forceRotate: true });
|
|
45111
|
-
|
|
45663
|
+
abortCtx.deferredUserMessages = [];
|
|
45112
45664
|
debug(`provider: abort detected, marked sharedSession needsRebuild + forceRotate`);
|
|
45113
|
-
if (
|
|
45114
|
-
|
|
45115
|
-
|
|
45665
|
+
if (abortCtx.turnOutput) {
|
|
45666
|
+
abortCtx.turnOutput.stopReason = "aborted";
|
|
45667
|
+
abortCtx.turnOutput.errorMessage = "Operation aborted";
|
|
45116
45668
|
}
|
|
45117
|
-
|
|
45118
|
-
|
|
45119
|
-
|
|
45669
|
+
abortCtx.currentPiStream?.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
|
|
45670
|
+
abortCtx.currentPiStream?.end();
|
|
45671
|
+
abortCtx.currentPiStream = null;
|
|
45120
45672
|
return;
|
|
45121
45673
|
}
|
|
45122
45674
|
const sessionId = capturedSessionId ?? sharedSession?.sessionId;
|
|
45123
45675
|
if (sessionId) {
|
|
45124
|
-
const cursor = Math.max(context.messages.length,
|
|
45676
|
+
const cursor = Math.max(context.messages.length, abortCtx.latestCursor, sharedSession?.cursor ?? 0);
|
|
45125
45677
|
debug(`provider: query done, session=${sessionId.slice(0, 8)}, cursor=${cursor}`);
|
|
45126
45678
|
setSharedSession({ sessionId, cursor, cwd });
|
|
45127
45679
|
}
|
|
45128
45680
|
try {
|
|
45129
|
-
while (
|
|
45130
|
-
const steerPrompt =
|
|
45681
|
+
while (abortCtx.deferredUserMessages.length > 0 && !isReentrant && !wasAborted) {
|
|
45682
|
+
const steerPrompt = abortCtx.deferredUserMessages.shift();
|
|
45131
45683
|
debug(`provider: replaying deferred user message: ${steerPrompt.slice(0, 60)}`);
|
|
45132
|
-
|
|
45133
|
-
|
|
45684
|
+
abortCtx.resetTurnState(model);
|
|
45685
|
+
abortCtx.resetToolTracking();
|
|
45134
45686
|
const resumeId = sharedSession?.sessionId;
|
|
45135
45687
|
if (!resumeId) {
|
|
45136
45688
|
debug(`WARNING: no session to resume for deferred message, dropping`);
|
|
@@ -45138,7 +45690,7 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
45138
45690
|
}
|
|
45139
45691
|
const contOptions = { ...queryOptions, resume: resumeId, ...makeCliDebugOptions("continuation") };
|
|
45140
45692
|
const contQuery = Okt({ prompt: steerPrompt, options: contOptions });
|
|
45141
|
-
|
|
45693
|
+
abortCtx.activeQuery = contQuery;
|
|
45142
45694
|
debug(`provider: continuation query, model=${model.id}, resume=${resumeId.slice(0, 8)}, prompt=${steerPrompt.slice(0, 60)}`);
|
|
45143
45695
|
try {
|
|
45144
45696
|
const { capturedSessionId: contSid } = await consumeQuery(contQuery, customToolNameToPi, model, cwd, bridgeConfig, () => wasAborted);
|
|
@@ -45154,46 +45706,36 @@ function streamClaudeAgentSdk(model, context, options) {
|
|
|
45154
45706
|
}
|
|
45155
45707
|
}
|
|
45156
45708
|
} finally {
|
|
45157
|
-
|
|
45709
|
+
abortCtx.activeQuery = sdkQuery;
|
|
45158
45710
|
}
|
|
45159
|
-
finalizeCurrentStream(
|
|
45711
|
+
finalizeCurrentStream(abortCtx.turnOutput?.stopReason, abortCtx);
|
|
45160
45712
|
}).catch((error51) => {
|
|
45161
45713
|
debug(`provider: query error, model=${model.id}, aborted=${Boolean(options?.signal?.aborted)}, error=`, error51);
|
|
45162
|
-
const suppressDuplicateError =
|
|
45714
|
+
const suppressDuplicateError = abortCtx.handledTerminalError || streamIdleTimedOut;
|
|
45163
45715
|
const openedExtraUsage = !suppressDuplicateError && isExtraUsageRequiredMessage(error51) && launchExtraUsageHelperIfAllowed(cwd, bridgeConfig, "query error");
|
|
45164
45716
|
if ((wasAborted || options?.signal?.aborted) && sharedSession) {
|
|
45165
45717
|
setSharedSession({ ...sharedSession, needsRebuild: true, forceRotate: true });
|
|
45166
45718
|
} else {
|
|
45167
45719
|
setSharedSession(null);
|
|
45168
45720
|
}
|
|
45169
|
-
|
|
45721
|
+
abortCtx.deferredUserMessages = [];
|
|
45170
45722
|
if (suppressDuplicateError) {
|
|
45171
45723
|
debug("provider: suppressing duplicate query error after terminal error was already emitted");
|
|
45172
45724
|
return;
|
|
45173
45725
|
}
|
|
45174
|
-
if (
|
|
45175
|
-
|
|
45176
|
-
|
|
45726
|
+
if (abortCtx.turnOutput) {
|
|
45727
|
+
abortCtx.turnOutput.stopReason = options?.signal?.aborted ? "aborted" : "error";
|
|
45728
|
+
abortCtx.turnOutput.errorMessage = `${error51 instanceof Error ? error51.message : String(error51)}${openedExtraUsage ? "\n\nOpened Claude Code /extra-usage helper. Complete billing/admin flow in the browser, then retry the prompt." : ""}`;
|
|
45177
45729
|
}
|
|
45178
|
-
|
|
45179
|
-
|
|
45180
|
-
|
|
45730
|
+
abortCtx.currentPiStream?.push({ type: "error", reason: abortCtx.turnOutput?.stopReason ?? "error", error: abortCtx.turnOutput });
|
|
45731
|
+
abortCtx.currentPiStream?.end();
|
|
45732
|
+
abortCtx.currentPiStream = null;
|
|
45181
45733
|
}).finally(() => {
|
|
45182
45734
|
streamIdleWatchdog?.dispose();
|
|
45183
45735
|
activeStreamIdleWatchdogs.delete(abortCtx);
|
|
45184
45736
|
if (options?.signal) options.signal.removeEventListener("abort", onAbort);
|
|
45185
|
-
|
|
45186
|
-
|
|
45187
|
-
reportToolResultMismatch(ctx(), "query teardown", cwd, { forceRotate: cause !== "query-end" });
|
|
45188
|
-
const drained = drainPendingToolCalls(ctx(), cause);
|
|
45189
|
-
if (drained > 0) debug(`provider: query teardown drained ${drained} waiting MCP handler(s) as errors (cause=${cause})`);
|
|
45190
|
-
ctx().pendingResults.clear();
|
|
45191
|
-
if (isReentrant) {
|
|
45192
|
-
popContext();
|
|
45193
|
-
} else {
|
|
45194
|
-
ctx().activeQuery = null;
|
|
45195
|
-
}
|
|
45196
|
-
}
|
|
45737
|
+
const cause = toolCallDrainCause({ wasAborted, signalAborted: options?.signal?.aborted, streamIdleTimedOut });
|
|
45738
|
+
teardownQuery(abortCtx, sdkQuery, cause, cwd, isReentrant);
|
|
45197
45739
|
sdkQuery.close();
|
|
45198
45740
|
});
|
|
45199
45741
|
return stream;
|
|
@@ -45228,6 +45770,58 @@ function readCredentialFile(path) {
|
|
|
45228
45770
|
return void 0;
|
|
45229
45771
|
}
|
|
45230
45772
|
}
|
|
45773
|
+
var connectorServerCache = /* @__PURE__ */ new Map();
|
|
45774
|
+
var connectorServerPending = /* @__PURE__ */ new Set();
|
|
45775
|
+
function connectorScopeKey() {
|
|
45776
|
+
return process.env.CLAUDE_CONFIG_DIR?.trim() || "<default>";
|
|
45777
|
+
}
|
|
45778
|
+
function primeConnectorServers() {
|
|
45779
|
+
const key = connectorScopeKey();
|
|
45780
|
+
if (connectorServerCache.has(key) || connectorServerPending.has(key)) return;
|
|
45781
|
+
connectorServerPending.add(key);
|
|
45782
|
+
void (async () => {
|
|
45783
|
+
try {
|
|
45784
|
+
const credentials = resolveClaudeOAuth(readCredentialFile);
|
|
45785
|
+
if (!credentials) {
|
|
45786
|
+
debug("connectors: no OAuth credentials; declaring none");
|
|
45787
|
+
connectorServerCache.set(key, {});
|
|
45788
|
+
return;
|
|
45789
|
+
}
|
|
45790
|
+
const inventory = await listAccountConnectors({ credentials });
|
|
45791
|
+
if (!inventory.ok) {
|
|
45792
|
+
debug(`connectors: inventory failed (${inventory.reason}); declaring none`);
|
|
45793
|
+
connectorServerCache.set(key, {});
|
|
45794
|
+
return;
|
|
45795
|
+
}
|
|
45796
|
+
const servers = connectorMcpServers(inventory);
|
|
45797
|
+
debug(
|
|
45798
|
+
`connectors: declaring ${Object.keys(servers).length} of ${inventory.connectors.length} installed`,
|
|
45799
|
+
Object.keys(servers).join(", ") || "none"
|
|
45800
|
+
);
|
|
45801
|
+
connectorServerCache.set(key, servers);
|
|
45802
|
+
if (writeCachedConnectors(inventory.connectors, key)) {
|
|
45803
|
+
debug(`connectors: cached ${inventory.connectors.length} entries`);
|
|
45804
|
+
}
|
|
45805
|
+
} catch (error51) {
|
|
45806
|
+
debug("connectors: declaration lookup threw; declaring none", error51);
|
|
45807
|
+
connectorServerCache.set(key, {});
|
|
45808
|
+
} finally {
|
|
45809
|
+
connectorServerPending.delete(key);
|
|
45810
|
+
}
|
|
45811
|
+
})();
|
|
45812
|
+
}
|
|
45813
|
+
function connectorServersSnapshot() {
|
|
45814
|
+
const key = connectorScopeKey();
|
|
45815
|
+
const ready = connectorServerCache.get(key);
|
|
45816
|
+
if (ready) return ready;
|
|
45817
|
+
primeConnectorServers();
|
|
45818
|
+
const cached2 = readCachedConnectors(key);
|
|
45819
|
+
if (!cached2) return {};
|
|
45820
|
+
const servers = connectorMcpServers({ ok: true, complete: true, connectors: cached2 });
|
|
45821
|
+
if (Object.keys(servers).length === 0) return {};
|
|
45822
|
+
debug(`connectors: turn-1 declarations from cache \u2014 ${Object.keys(servers).join(", ")}`);
|
|
45823
|
+
return servers;
|
|
45824
|
+
}
|
|
45231
45825
|
async function reportConnectorInventory(ctx2) {
|
|
45232
45826
|
const credentials = resolveClaudeOAuth(readCredentialFile);
|
|
45233
45827
|
if (!credentials) {
|
|
@@ -45334,17 +45928,31 @@ export {
|
|
|
45334
45928
|
ALLOWED_RATE_LIMIT_WARNING_UTILIZATION_THRESHOLD,
|
|
45335
45929
|
CLAUDE_AI_CONNECTOR_TOOL_PATTERNS,
|
|
45336
45930
|
CLAUDE_BRIDGE_TOOL_ISOLATION,
|
|
45931
|
+
CONNECTOR_CALL_CUSTOM_TYPE,
|
|
45337
45932
|
CONNECTOR_DISCOVERY_TOOLS,
|
|
45338
45933
|
CONNECTOR_WRITE_TOOLS,
|
|
45339
45934
|
DEFAULT_STREAM_IDLE_TIMEOUT_MS,
|
|
45340
45935
|
DISALLOWED_BUILTIN_TOOLS,
|
|
45936
|
+
INTEGRITY_CUSTOM_TYPE,
|
|
45937
|
+
NATIVE_PROVIDER_UNSUPPORTED_MESSAGE,
|
|
45341
45938
|
STREAM_IDLE_BACKOFF_HINT_MS,
|
|
45342
45939
|
STREAM_IDLE_TIMEOUT_ENV,
|
|
45343
45940
|
__testGetBridgeIntegrityState,
|
|
45344
45941
|
__testSetBridgeIntegrityState,
|
|
45942
|
+
appendIntegrityEntry,
|
|
45943
|
+
buildNativeProvider,
|
|
45345
45944
|
buildStreamIdleTimeoutErrorMessage,
|
|
45945
|
+
cancelScheduledToolUseEnd,
|
|
45346
45946
|
classifyClaudeExecutableBytes,
|
|
45947
|
+
claudeAuthSourceLabel,
|
|
45948
|
+
connectorCachePath,
|
|
45949
|
+
connectorCacheScopeKey,
|
|
45950
|
+
connectorDeclarationsDisabled,
|
|
45951
|
+
connectorMcpServers,
|
|
45952
|
+
connectorProxyUrl,
|
|
45347
45953
|
connectorQueryOptions,
|
|
45954
|
+
connectorResultByteSize,
|
|
45955
|
+
connectorServerName,
|
|
45348
45956
|
connectorServerNamespace,
|
|
45349
45957
|
connectorWriteDenyHook,
|
|
45350
45958
|
connectorWriteModeFor,
|
|
@@ -45355,27 +45963,43 @@ export {
|
|
|
45355
45963
|
createStreamIdleWatchdog,
|
|
45356
45964
|
credentialCandidatePaths,
|
|
45357
45965
|
index_default as default,
|
|
45966
|
+
endToolUseTurn,
|
|
45967
|
+
finalizeToolUseTurnFromMcpInvocation,
|
|
45968
|
+
flushConnectorCallAudit,
|
|
45358
45969
|
formatAllowedRateLimitWarning,
|
|
45359
45970
|
formatResetTimestamp,
|
|
45971
|
+
isChildExecutedTool,
|
|
45360
45972
|
isConnectorWriteTool,
|
|
45361
45973
|
isExtraUsageRequiredMessage,
|
|
45974
|
+
isUsageLimitMessage,
|
|
45362
45975
|
listAccountConnectors,
|
|
45363
45976
|
mapToolName,
|
|
45364
45977
|
normalizeRateLimitUtilization,
|
|
45978
|
+
noteChildExecutedToolResults,
|
|
45365
45979
|
preflightClaudeExecutable,
|
|
45980
|
+
primeConnectorServers,
|
|
45366
45981
|
processAssistantMessage,
|
|
45367
45982
|
processStreamEvent,
|
|
45983
|
+
readCachedConnectors,
|
|
45984
|
+
reapStaleQueuedResults,
|
|
45985
|
+
recordConnectorCallResult,
|
|
45368
45986
|
reportToolResultMismatch,
|
|
45987
|
+
resetTimestampMs,
|
|
45369
45988
|
resolveClaudeExecutable,
|
|
45370
45989
|
resolveClaudeOAuth,
|
|
45371
45990
|
resolveConfiguredEffort,
|
|
45991
|
+
resolveMcpTools,
|
|
45372
45992
|
restoreSharedSessionFromPi,
|
|
45993
|
+
scheduleToolUseTurnEnd,
|
|
45994
|
+
setConnectorCallAuditSink,
|
|
45373
45995
|
shouldRestorePersistedBridgeEntry,
|
|
45374
45996
|
spawnClaudeCodeWithDiagnostics,
|
|
45375
45997
|
streamIdleTimeoutMsFromEnv,
|
|
45998
|
+
supportsNativeProvider,
|
|
45376
45999
|
toolIsolationForQuery,
|
|
45377
46000
|
uniqueNonEmptyLines,
|
|
45378
|
-
wrapClaudeSpawnErrorForSdk
|
|
46001
|
+
wrapClaudeSpawnErrorForSdk,
|
|
46002
|
+
writeCachedConnectors
|
|
45379
46003
|
};
|
|
45380
46004
|
/*! Bundled license information:
|
|
45381
46005
|
|