pubblue 0.6.9 → 0.7.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.
@@ -56,8 +56,8 @@ var PubApiClient = class {
56
56
  getApiKey() {
57
57
  return this.apiKey;
58
58
  }
59
- async request(path4, options = {}) {
60
- const url = new URL(path4, this.baseUrl);
59
+ async request(path5, options = {}) {
60
+ const url = new URL(path5, this.baseUrl);
61
61
  const res = await fetch(url, {
62
62
  ...options,
63
63
  headers: {
@@ -169,8 +169,8 @@ var PubApiClient = class {
169
169
  params.set("daemonSessionId", daemonSessionId);
170
170
  }
171
171
  const query = params.toString();
172
- const path4 = query ? `/api/v1/agent/live?${query}` : "/api/v1/agent/live";
173
- const data = await this.request(path4);
172
+ const path5 = query ? `/api/v1/agent/live?${query}` : "/api/v1/agent/live";
173
+ const data = await this.request(path5);
174
174
  return data.live;
175
175
  }
176
176
  async signalAnswer(opts) {
@@ -185,8 +185,8 @@ var PubApiClient = class {
185
185
  params.set("daemonSessionId", daemonSessionId);
186
186
  }
187
187
  const query = params.toString();
188
- const path4 = query ? `/api/v1/agent/live?${query}` : "/api/v1/agent/live";
189
- await this.request(path4, { method: "DELETE" });
188
+ const path5 = query ? `/api/v1/agent/live?${query}` : "/api/v1/agent/live";
189
+ await this.request(path5, { method: "DELETE" });
190
190
  }
191
191
  // -- Telegram bot token ---------------------------------------------------
192
192
  async uploadBotToken(opts) {
@@ -809,25 +809,289 @@ async function createClaudeCodeBridgeRunner(config, abortSignal) {
809
809
  };
810
810
  }
811
811
 
812
+ // src/lib/live-bridge-claude-sdk.ts
813
+ import * as fs2 from "fs";
814
+ import * as os2 from "os";
815
+ import * as path2 from "path";
816
+ async function tryImportSdk() {
817
+ try {
818
+ return await import("./sdk-IV5ZYS3G.js");
819
+ } catch {
820
+ return null;
821
+ }
822
+ }
823
+ function isClaudeSdkAvailableInEnv(env) {
824
+ return isClaudeCodeAvailableInEnv(env);
825
+ }
826
+ async function isClaudeSdkImportable() {
827
+ return await tryImportSdk() !== null;
828
+ }
829
+ function buildSdkSessionOptions(env = process.env) {
830
+ const model = env.CLAUDE_CODE_MODEL?.trim() || "claude-sonnet-4-6";
831
+ const claudePath = resolveClaudeCodePath(env);
832
+ const allowedToolsRaw = env.CLAUDE_CODE_ALLOWED_TOOLS?.trim();
833
+ const allowedTools = allowedToolsRaw ? allowedToolsRaw.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
834
+ const sdkEnv = { ...env };
835
+ delete sdkEnv.CLAUDECODE;
836
+ return { model, claudePath, allowedTools, sdkEnv };
837
+ }
838
+ function buildAppendSystemPrompt(bridgeSystemPrompt, env = process.env) {
839
+ const userSystemPrompt = env.CLAUDE_CODE_APPEND_SYSTEM_PROMPT?.trim();
840
+ const effective = [bridgeSystemPrompt, userSystemPrompt].filter(Boolean).join("\n\n");
841
+ return effective.length > 0 ? effective : void 0;
842
+ }
843
+ async function runClaudeSdkBridgeStartupProbe(env = process.env) {
844
+ const { model, claudePath, allowedTools } = buildSdkSessionOptions(env);
845
+ const cwd = env.CLAUDE_CODE_CWD?.trim() || env.PUBBLUE_PROJECT_ROOT || void 0;
846
+ const sdk = await tryImportSdk();
847
+ if (!sdk) {
848
+ throw new Error(
849
+ "Claude Agent SDK (@anthropic-ai/claude-agent-sdk) is not importable. Install it and retry."
850
+ );
851
+ }
852
+ await runAgentWritePongProbe({
853
+ label: "Claude SDK",
854
+ baseEnv: env,
855
+ execute: async (probeEnv) => {
856
+ const probeEnvClean = { ...probeEnv };
857
+ delete probeEnvClean.CLAUDECODE;
858
+ const socketPath = probeEnv.PUBBLUE_AGENT_SOCKET ?? "";
859
+ const logPath = path2.join(os2.tmpdir(), "pubblue-sdk-probe.log");
860
+ const appendLog = (line) => {
861
+ try {
862
+ fs2.appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
863
+ `);
864
+ } catch {
865
+ }
866
+ };
867
+ appendLog(`probe start socket=${socketPath}`);
868
+ const prompt = [
869
+ "This is a startup connectivity probe.",
870
+ "Run this exact shell command now:",
871
+ `PUBBLUE_AGENT_SOCKET=${socketPath} pubblue write "pong"`,
872
+ "Do not explain. Just execute it."
873
+ ].join("\n");
874
+ const q = sdk.query({
875
+ prompt,
876
+ options: {
877
+ model,
878
+ pathToClaudeCodeExecutable: claudePath,
879
+ env: probeEnvClean,
880
+ allowedTools,
881
+ cwd: os2.tmpdir(),
882
+ maxTurns: 2,
883
+ persistSession: false,
884
+ canUseTool: async (toolName, input) => {
885
+ appendLog(`canUseTool: tool=${toolName}`);
886
+ return { behavior: "allow", updatedInput: input };
887
+ }
888
+ }
889
+ });
890
+ for await (const msg of q) {
891
+ appendLog(`msg: type=${msg.type} ${JSON.stringify(msg).slice(0, 300)}`);
892
+ }
893
+ appendLog("probe stream completed");
894
+ }
895
+ });
896
+ return { claudePath, cwd };
897
+ }
898
+ var MAX_SESSION_RECREATIONS = 2;
899
+ async function createClaudeSdkBridgeRunner(config, abortSignal) {
900
+ const { slug, sendMessage, debugLog, sessionBriefing } = config;
901
+ const env = process.env;
902
+ const sdk = await tryImportSdk();
903
+ if (!sdk) {
904
+ throw new Error("Claude Agent SDK is not importable.");
905
+ }
906
+ const { model, claudePath, allowedTools, sdkEnv } = buildSdkSessionOptions(env);
907
+ const appendSystemPrompt = buildAppendSystemPrompt(config.instructions.systemPrompt, env);
908
+ let sessionId;
909
+ let forwardedMessageCount = 0;
910
+ let lastError;
911
+ let stopped = abortSignal?.aborted ?? false;
912
+ let sessionRecreations = 0;
913
+ let activeSession = null;
914
+ if (abortSignal) {
915
+ abortSignal.addEventListener(
916
+ "abort",
917
+ () => {
918
+ stopped = true;
919
+ activeSession?.close();
920
+ },
921
+ { once: true }
922
+ );
923
+ }
924
+ const canvasReminderEvery = resolveCanvasReminderEvery();
925
+ function createSession() {
926
+ const session2 = sdk.unstable_v2_createSession({
927
+ model,
928
+ pathToClaudeCodeExecutable: claudePath,
929
+ env: {
930
+ ...sdkEnv,
931
+ ...appendSystemPrompt ? { CLAUDE_CODE_APPEND_SYSTEM_PROMPT: appendSystemPrompt } : {}
932
+ },
933
+ allowedTools,
934
+ canUseTool: async (_tool, input) => ({ behavior: "allow", updatedInput: input })
935
+ });
936
+ activeSession = session2;
937
+ return session2;
938
+ }
939
+ async function consumeStream(session2) {
940
+ for await (const msg of session2.stream()) {
941
+ if (stopped) break;
942
+ if (msg.type === "assistant") {
943
+ debugLog(`sdk assistant message received`);
944
+ } else if (msg.type === "result") {
945
+ if ("session_id" in msg && typeof msg.session_id === "string") {
946
+ sessionId = msg.session_id;
947
+ debugLog(`captured session_id: ${sessionId}`);
948
+ }
949
+ if (msg.subtype !== "success") {
950
+ throw new Error(`Claude SDK result error: ${msg.subtype}`);
951
+ }
952
+ }
953
+ }
954
+ }
955
+ async function sendAndStream(session2, prompt) {
956
+ await session2.send(prompt);
957
+ await consumeStream(session2);
958
+ }
959
+ async function deliverWithRecovery(prompt) {
960
+ if (stopped) return;
961
+ try {
962
+ if (!activeSession) throw new Error("session not initialized");
963
+ await sendAndStream(activeSession, prompt);
964
+ } catch (error) {
965
+ const msg = errorMessage(error);
966
+ debugLog(`session error: ${msg}`, error);
967
+ if (stopped || sessionRecreations >= MAX_SESSION_RECREATIONS) {
968
+ throw error;
969
+ }
970
+ debugLog(`recreating session (attempt ${sessionRecreations + 1}/${MAX_SESSION_RECREATIONS})`);
971
+ sessionRecreations += 1;
972
+ try {
973
+ activeSession?.close();
974
+ } catch {
975
+ }
976
+ const newSession = createSession();
977
+ await sendAndStream(newSession, sessionBriefing);
978
+ debugLog("session briefing re-delivered after recovery");
979
+ await sendAndStream(newSession, prompt);
980
+ }
981
+ }
982
+ const session = createSession();
983
+ await sendAndStream(session, sessionBriefing);
984
+ debugLog("session briefing delivered via SDK");
985
+ const queue = createBridgeEntryQueue({
986
+ onEntry: async (entry) => {
987
+ const chat = readTextChatMessage(entry);
988
+ if (chat) {
989
+ const includeCanvasReminder = shouldIncludeCanvasPolicyReminder(
990
+ forwardedMessageCount + 1,
991
+ canvasReminderEvery
992
+ );
993
+ const prompt = buildInboundPrompt(slug, chat, includeCanvasReminder, config.instructions);
994
+ await deliverWithRecovery(prompt);
995
+ forwardedMessageCount += 1;
996
+ config.onDeliveryUpdate?.({
997
+ channel: entry.channel,
998
+ messageId: entry.msg.id,
999
+ stage: "confirmed"
1000
+ });
1001
+ return;
1002
+ }
1003
+ const renderError = readRenderErrorMessage(entry);
1004
+ if (renderError) {
1005
+ const prompt = buildRenderErrorPrompt(slug, renderError, config.instructions);
1006
+ await deliverWithRecovery(prompt);
1007
+ forwardedMessageCount += 1;
1008
+ config.onDeliveryUpdate?.({
1009
+ channel: entry.channel,
1010
+ messageId: entry.msg.id,
1011
+ stage: "confirmed"
1012
+ });
1013
+ return;
1014
+ }
1015
+ if (entry.msg.type === "binary" || entry.msg.type === "stream-start" || entry.msg.type === "stream-end") {
1016
+ const streamId = typeof entry.msg.meta?.streamId === "string" ? entry.msg.meta.streamId : void 0;
1017
+ if (entry.msg.type === "binary" && streamId) return;
1018
+ const deliveryMessageId = entry.msg.type === "stream-end" && streamId ? streamId : entry.msg.id;
1019
+ config.onDeliveryUpdate?.({
1020
+ channel: entry.channel,
1021
+ messageId: deliveryMessageId,
1022
+ stage: "failed",
1023
+ error: "Attachments are not supported in Claude SDK bridge mode."
1024
+ });
1025
+ if (entry.msg.type !== "stream-end") {
1026
+ void sendMessage(CHANNELS.CHAT, {
1027
+ id: generateMessageId(),
1028
+ type: "text",
1029
+ data: "Attachments are not supported in Claude SDK bridge mode."
1030
+ });
1031
+ }
1032
+ }
1033
+ },
1034
+ onError: (error, entry) => {
1035
+ const message = errorMessage(error);
1036
+ lastError = message;
1037
+ debugLog(`bridge entry processing failed: ${message}`, error);
1038
+ const deliveryMessageId = entry.msg.type === "stream-end" && typeof entry.msg.meta?.streamId === "string" ? entry.msg.meta.streamId : entry.msg.id;
1039
+ config.onDeliveryUpdate?.({
1040
+ channel: entry.channel,
1041
+ messageId: deliveryMessageId,
1042
+ stage: "failed",
1043
+ error: message
1044
+ });
1045
+ void sendMessage(CHANNELS.CHAT, {
1046
+ id: generateMessageId(),
1047
+ type: "text",
1048
+ data: `Bridge error: ${message}`
1049
+ });
1050
+ }
1051
+ });
1052
+ debugLog(`claude-sdk bridge runner started (path=${claudePath})`);
1053
+ return {
1054
+ enqueue: (entries) => queue.enqueue(entries),
1055
+ async stop() {
1056
+ if (stopped) return;
1057
+ stopped = true;
1058
+ try {
1059
+ activeSession?.close();
1060
+ } catch {
1061
+ }
1062
+ activeSession = null;
1063
+ await queue.stop();
1064
+ },
1065
+ status() {
1066
+ return {
1067
+ running: !stopped,
1068
+ sessionId,
1069
+ lastError,
1070
+ forwardedMessages: forwardedMessageCount
1071
+ };
1072
+ }
1073
+ };
1074
+ }
1075
+
812
1076
  // src/lib/live-bridge-openclaw.ts
813
1077
  import { execFile } from "child_process";
814
1078
  import { existsSync as existsSync5 } from "fs";
815
- import { join as join5 } from "path";
1079
+ import { join as join6 } from "path";
816
1080
  import { promisify } from "util";
817
1081
 
818
1082
  // src/lib/live-bridge-openclaw-attachments.ts
819
1083
  import { createHash } from "crypto";
820
1084
  import { mkdirSync, renameSync, unlinkSync as unlinkSync2, writeFileSync } from "fs";
821
- import { basename, extname, join as join4 } from "path";
1085
+ import { basename, extname, join as join5 } from "path";
822
1086
 
823
1087
  // src/lib/live-bridge-openclaw-session.ts
824
1088
  import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
825
- import { join as join3 } from "path";
1089
+ import { join as join4 } from "path";
826
1090
 
827
1091
  // src/lib/openclaw-paths.ts
828
1092
  import { existsSync as existsSync3, readFileSync } from "fs";
829
1093
  import { homedir } from "os";
830
- import { dirname, isAbsolute, join as join2, resolve } from "path";
1094
+ import { dirname, isAbsolute, join as join3, resolve } from "path";
831
1095
  function trimToUndefined(value) {
832
1096
  const trimmed = value?.trim();
833
1097
  return trimmed ? trimmed : void 0;
@@ -846,7 +1110,7 @@ function resolveBaseHome(env) {
846
1110
  function expandHomePrefix(input, home) {
847
1111
  if (input === "~") return home;
848
1112
  if (input.startsWith("~/") || input.startsWith("~\\")) {
849
- return join2(home, input.slice(2));
1113
+ return join3(home, input.slice(2));
850
1114
  }
851
1115
  return input;
852
1116
  }
@@ -864,12 +1128,12 @@ function resolveOpenClawHome(env = process.env) {
864
1128
  function resolveOpenClawStateDir(env = process.env) {
865
1129
  const configured = trimToUndefined(env.OPENCLAW_STATE_DIR);
866
1130
  if (configured) return resolvePathFromInput(configured, env);
867
- return join2(resolveOpenClawHome(env), ".openclaw");
1131
+ return join3(resolveOpenClawHome(env), ".openclaw");
868
1132
  }
869
1133
  function resolveOpenClawConfigPath(env = process.env) {
870
1134
  const configured = trimToUndefined(env.OPENCLAW_CONFIG_PATH);
871
1135
  if (configured) return resolvePathFromInput(configured, env);
872
- return join2(resolveOpenClawStateDir(env), "openclaw.json");
1136
+ return join3(resolveOpenClawStateDir(env), "openclaw.json");
873
1137
  }
874
1138
  function readWorkspaceFromOpenClawConfig(configPath) {
875
1139
  if (!existsSync3(configPath)) return null;
@@ -899,13 +1163,13 @@ function resolveOpenClawWorkspaceDir(env = process.env) {
899
1163
  const configPath = resolveOpenClawConfigPath(env);
900
1164
  const fromConfig = readWorkspaceFromOpenClawConfig(configPath);
901
1165
  if (fromConfig) return resolveWorkspacePath(fromConfig, configPath, env);
902
- return join2(resolveOpenClawStateDir(env), "workspace");
1166
+ return join3(resolveOpenClawStateDir(env), "workspace");
903
1167
  }
904
1168
 
905
1169
  // src/lib/live-bridge-openclaw-session.ts
906
1170
  var OPENCLAW_MAIN_SESSION_KEY = "agent:main:main";
907
1171
  function resolveOpenClawSessionsPath(env = process.env) {
908
- return join3(resolveOpenClawStateDir(env), "agents", "main", "sessions", "sessions.json");
1172
+ return join4(resolveOpenClawStateDir(env), "agents", "main", "sessions", "sessions.json");
909
1173
  }
910
1174
  function buildThreadCandidateKeys(threadId) {
911
1175
  const trimmed = threadId?.trim();
@@ -981,7 +1245,7 @@ var DEFAULT_ATTACHMENT_MAX_BYTES = 5 * 1024 * 1024;
981
1245
  function resolveAttachmentRootDir() {
982
1246
  const configured = process.env.OPENCLAW_ATTACHMENT_DIR?.trim();
983
1247
  if (configured) return configured;
984
- return join4(resolveOpenClawStateDir(), "pubblue-inbox");
1248
+ return join5(resolveOpenClawStateDir(), "pubblue-inbox");
985
1249
  }
986
1250
  function resolveAttachmentMaxBytes() {
987
1251
  const raw = Number.parseInt(process.env.OPENCLAW_ATTACHMENT_MAX_BYTES ?? "", 10);
@@ -1022,12 +1286,12 @@ function resolveAttachmentFilename(params) {
1022
1286
  }
1023
1287
  function ensureDirectoryWritable(dirPath) {
1024
1288
  mkdirSync(dirPath, { recursive: true });
1025
- const probe = join4(dirPath, `.bridge-writecheck-${process.pid}-${Date.now()}`);
1289
+ const probe = join5(dirPath, `.bridge-writecheck-${process.pid}-${Date.now()}`);
1026
1290
  writeFileSync(probe, "ok\n", { mode: 384 });
1027
1291
  unlinkSync2(probe);
1028
1292
  }
1029
1293
  function stageAttachment(params) {
1030
- const slugDir = join4(params.attachmentRoot, sanitizeFilename(params.slug));
1294
+ const slugDir = join5(params.attachmentRoot, sanitizeFilename(params.slug));
1031
1295
  ensureDirectoryWritable(slugDir);
1032
1296
  const mime = (params.mime || "application/octet-stream").trim();
1033
1297
  const resolvedName = resolveAttachmentFilename({
@@ -1037,7 +1301,7 @@ function stageAttachment(params) {
1037
1301
  mime
1038
1302
  });
1039
1303
  const collisionSafeName = `${Date.now()}-${sanitizeFilename(params.messageId)}-${resolvedName}`;
1040
- const targetPath = join4(slugDir, collisionSafeName);
1304
+ const targetPath = join5(slugDir, collisionSafeName);
1041
1305
  const tempPath = `${targetPath}.tmp-${process.pid}`;
1042
1306
  writeFileSync(tempPath, params.bytes, { mode: 384 });
1043
1307
  renameSync(tempPath, targetPath);
@@ -1219,9 +1483,9 @@ function getOpenClawDiscoveryPaths(env = process.env) {
1219
1483
  return [
1220
1484
  .../* @__PURE__ */ new Set([
1221
1485
  "/app/dist/index.js",
1222
- join5(home, "openclaw", "dist", "index.js"),
1223
- join5(stateDir, "openclaw"),
1224
- join5(home, ".openclaw", "openclaw"),
1486
+ join6(home, "openclaw", "dist", "index.js"),
1487
+ join6(stateDir, "openclaw"),
1488
+ join6(home, ".openclaw", "openclaw"),
1225
1489
  "/usr/local/bin/openclaw",
1226
1490
  "/opt/homebrew/bin/openclaw"
1227
1491
  ])
@@ -1258,7 +1522,7 @@ function resolveOpenClawPath(env = process.env) {
1258
1522
  "OpenClaw executable was not found.",
1259
1523
  "Configure it with: pubblue configure --set openclaw.path=/absolute/path/to/openclaw",
1260
1524
  "Or set OPENCLAW_PATH in environment.",
1261
- "Checked: " + discoveryPaths.join(", ")
1525
+ `Checked: ${discoveryPaths.join(", ")}`
1262
1526
  ].join(" ")
1263
1527
  );
1264
1528
  }
@@ -1486,35 +1750,35 @@ async function createOpenClawBridgeRunner(config) {
1486
1750
  }
1487
1751
 
1488
1752
  // src/lib/live-runtime/daemon-files.ts
1489
- import * as fs3 from "fs";
1490
- import * as path3 from "path";
1753
+ import * as fs4 from "fs";
1754
+ import * as path4 from "path";
1491
1755
 
1492
1756
  // src/lib/config.ts
1493
- import * as fs2 from "fs";
1494
- import * as path2 from "path";
1757
+ import * as fs3 from "fs";
1758
+ import * as path3 from "path";
1495
1759
  var DEFAULT_BASE_URL = "https://silent-guanaco-514.convex.site";
1496
1760
  function getConfigDir(homeDir) {
1497
1761
  const explicit = process.env.PUBBLUE_CONFIG_DIR?.trim();
1498
1762
  if (explicit) return explicit;
1499
1763
  if (homeDir) {
1500
- return path2.join(path2.resolve(homeDir), ".openclaw", "pubblue");
1764
+ return path3.join(path3.resolve(homeDir), ".openclaw", "pubblue");
1501
1765
  }
1502
- return path2.join(resolveOpenClawStateDir(), "pubblue");
1766
+ return path3.join(resolveOpenClawStateDir(), "pubblue");
1503
1767
  }
1504
1768
  function getConfigPath(homeDir) {
1505
1769
  const dir = getConfigDir(homeDir);
1506
- fs2.mkdirSync(dir, { recursive: true, mode: 448 });
1507
- return path2.join(dir, "config.json");
1770
+ fs3.mkdirSync(dir, { recursive: true, mode: 448 });
1771
+ return path3.join(dir, "config.json");
1508
1772
  }
1509
1773
  function readConfig(homeDir) {
1510
1774
  const configPath = getConfigPath(homeDir);
1511
- if (!fs2.existsSync(configPath)) return null;
1512
- const raw = fs2.readFileSync(configPath, "utf-8");
1775
+ if (!fs3.existsSync(configPath)) return null;
1776
+ const raw = fs3.readFileSync(configPath, "utf-8");
1513
1777
  return JSON.parse(raw);
1514
1778
  }
1515
1779
  function saveConfig(config, homeDir) {
1516
1780
  const configPath = getConfigPath(homeDir);
1517
- fs2.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
1781
+ fs3.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
1518
1782
  `, {
1519
1783
  mode: 384
1520
1784
  });
@@ -1546,15 +1810,15 @@ function getTelegramMiniAppUrl(slug) {
1546
1810
 
1547
1811
  // src/lib/live-runtime/daemon-files.ts
1548
1812
  function liveInfoDir() {
1549
- const dir = path3.join(getConfigDir(), "lives");
1550
- fs3.mkdirSync(dir, { recursive: true });
1813
+ const dir = path4.join(getConfigDir(), "lives");
1814
+ fs4.mkdirSync(dir, { recursive: true });
1551
1815
  return dir;
1552
1816
  }
1553
1817
  function liveInfoPath(slug) {
1554
- return path3.join(liveInfoDir(), `${slug}.json`);
1818
+ return path4.join(liveInfoDir(), `${slug}.json`);
1555
1819
  }
1556
1820
  function liveLogPath(slug) {
1557
- return path3.join(liveInfoDir(), `${slug}.log`);
1821
+ return path4.join(liveInfoDir(), `${slug}.log`);
1558
1822
  }
1559
1823
  function sanitizeSlugForFilename(slug) {
1560
1824
  const sanitized = slug.trim().replace(/[^a-zA-Z0-9._-]/g, "-");
@@ -1569,16 +1833,16 @@ function resolveSessionContentExtension(contentType) {
1569
1833
  function liveSessionContentPath(slug, contentType, rootDir) {
1570
1834
  const safeSlug = sanitizeSlugForFilename(slug);
1571
1835
  const ext = resolveSessionContentExtension(contentType);
1572
- return path3.join(rootDir ?? liveInfoDir(), `${safeSlug}.session-content.${ext}`);
1836
+ return path4.join(rootDir ?? liveInfoDir(), `${safeSlug}.session-content.${ext}`);
1573
1837
  }
1574
1838
  function writeLiveSessionContentFile(params) {
1575
1839
  const filePath = liveSessionContentPath(params.slug, params.contentType, params.rootDir);
1576
- fs3.mkdirSync(path3.dirname(filePath), { recursive: true });
1577
- fs3.writeFileSync(filePath, params.content, "utf-8");
1840
+ fs4.mkdirSync(path4.dirname(filePath), { recursive: true });
1841
+ fs4.writeFileSync(filePath, params.content, "utf-8");
1578
1842
  return filePath;
1579
1843
  }
1580
1844
  function latestCliVersionPath() {
1581
- return path3.join(liveInfoDir(), "cli-version.txt");
1845
+ return path4.join(liveInfoDir(), "cli-version.txt");
1582
1846
  }
1583
1847
  function isMissingPathError(error) {
1584
1848
  if (typeof error !== "object" || error === null || !("code" in error)) return false;
@@ -1588,7 +1852,7 @@ function isMissingPathError(error) {
1588
1852
  function readLatestCliVersion(versionPath) {
1589
1853
  const resolved = versionPath || latestCliVersionPath();
1590
1854
  try {
1591
- const value = fs3.readFileSync(resolved, "utf-8").trim();
1855
+ const value = fs4.readFileSync(resolved, "utf-8").trim();
1592
1856
  return value.length === 0 ? null : value;
1593
1857
  } catch (error) {
1594
1858
  if (isMissingPathError(error)) return null;
@@ -1599,13 +1863,13 @@ function writeLatestCliVersion(version, versionPath) {
1599
1863
  const trimmed = version.trim();
1600
1864
  if (trimmed.length === 0) return;
1601
1865
  const resolved = versionPath || latestCliVersionPath();
1602
- const dir = path3.dirname(resolved);
1603
- fs3.mkdirSync(dir, { recursive: true });
1604
- fs3.writeFileSync(resolved, trimmed, "utf-8");
1866
+ const dir = path4.dirname(resolved);
1867
+ fs4.mkdirSync(dir, { recursive: true });
1868
+ fs4.writeFileSync(resolved, trimmed, "utf-8");
1605
1869
  }
1606
1870
  function readLogTail(logPath, maxChars = 4e3) {
1607
1871
  try {
1608
- const content = fs3.readFileSync(logPath, "utf-8");
1872
+ const content = fs4.readFileSync(logPath, "utf-8");
1609
1873
  if (content.length <= maxChars) return content;
1610
1874
  return content.slice(-maxChars);
1611
1875
  } catch (error) {
@@ -1644,6 +1908,10 @@ export {
1644
1908
  buildClaudeArgs,
1645
1909
  runClaudeCodeBridgeStartupProbe,
1646
1910
  createClaudeCodeBridgeRunner,
1911
+ isClaudeSdkAvailableInEnv,
1912
+ isClaudeSdkImportable,
1913
+ runClaudeSdkBridgeStartupProbe,
1914
+ createClaudeSdkBridgeRunner,
1647
1915
  isOpenClawAvailable,
1648
1916
  resolveOpenClawRuntime,
1649
1917
  runOpenClawBridgeStartupProbe,