@fangyb/ahchat-bridge 0.1.20 → 0.1.22

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.
Files changed (4) hide show
  1. package/dist/cli.cjs +616 -297
  2. package/dist/index.js +341 -181
  3. package/package.json +11 -11
  4. package/dist/cli.js +0 -51540
package/dist/cli.cjs CHANGED
@@ -3679,9 +3679,8 @@ var require_websocket_server = __commonJS({
3679
3679
 
3680
3680
  // src/cli.ts
3681
3681
  init_cjs_shims();
3682
- var import_node_os13 = __toESM(require("os"), 1);
3683
- var import_node_path21 = __toESM(require("path"), 1);
3684
- var import_node_fs10 = __toESM(require("fs"), 1);
3682
+ var import_node_path23 = __toESM(require("path"), 1);
3683
+ var import_node_fs11 = __toESM(require("fs"), 1);
3685
3684
 
3686
3685
  // ../../node_modules/.pnpm/cac@6.7.14/node_modules/cac/dist/index.mjs
3687
3686
  init_cjs_shims();
@@ -5097,11 +5096,11 @@ var RotatingFileStream = class extends import_stream.Writable {
5097
5096
  timeout;
5098
5097
  timeoutPromise;
5099
5098
  constructor(generator, options) {
5100
- const { encoding, history, maxFiles, maxSize, path: path22 } = options;
5099
+ const { encoding, history, maxFiles, maxSize, path: path24 } = options;
5101
5100
  super({ decodeStrings: true, defaultEncoding: encoding });
5102
5101
  this.createGzip = import_zlib.createGzip;
5103
5102
  this.exec = import_child_process.exec;
5104
- this.filename = path22 + generator(null);
5103
+ this.filename = path24 + generator(null);
5105
5104
  this.fsCreateReadStream = import_fs.createReadStream;
5106
5105
  this.fsCreateWriteStream = import_fs.createWriteStream;
5107
5106
  this.fsOpen = import_promises.open;
@@ -5113,7 +5112,7 @@ var RotatingFileStream = class extends import_stream.Writable {
5113
5112
  this.options = options;
5114
5113
  this.stdout = process.stdout;
5115
5114
  if (maxFiles || maxSize)
5116
- options.history = path22 + (history ? history : this.generator(null) + ".txt");
5115
+ options.history = path24 + (history ? history : this.generator(null) + ".txt");
5117
5116
  this.on("close", () => this.finished ? null : this.emit("finish"));
5118
5117
  this.on("finish", () => this.finished = this.clear());
5119
5118
  (async () => {
@@ -5241,9 +5240,9 @@ var RotatingFileStream = class extends import_stream.Writable {
5241
5240
  return this.move();
5242
5241
  }
5243
5242
  async findName() {
5244
- const { interval, path: path22, intervalBoundary } = this.options;
5243
+ const { interval, path: path24, intervalBoundary } = this.options;
5245
5244
  for (let index = 1; index < 1e3; ++index) {
5246
- const filename = path22 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
5245
+ const filename = path24 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
5247
5246
  if (!await exists(filename))
5248
5247
  return filename;
5249
5248
  }
@@ -5273,11 +5272,11 @@ var RotatingFileStream = class extends import_stream.Writable {
5273
5272
  return this.unlink(filename);
5274
5273
  }
5275
5274
  async classical() {
5276
- const { compress, path: path22, rotate } = this.options;
5275
+ const { compress, path: path24, rotate } = this.options;
5277
5276
  let rotatedName = "";
5278
5277
  for (let count = rotate; count > 0; --count) {
5279
- const currName = path22 + this.generator(count);
5280
- const prevName = count === 1 ? this.filename : path22 + this.generator(count - 1);
5278
+ const currName = path24 + this.generator(count);
5279
+ const prevName = count === 1 ? this.filename : path24 + this.generator(count - 1);
5281
5280
  if (!await exists(prevName))
5282
5281
  continue;
5283
5282
  if (!rotatedName)
@@ -5715,7 +5714,7 @@ function createModuleLogger(module2) {
5715
5714
 
5716
5715
  // src/start.ts
5717
5716
  init_cjs_shims();
5718
- var import_node_path19 = __toESM(require("path"), 1);
5717
+ var import_node_path21 = __toESM(require("path"), 1);
5719
5718
 
5720
5719
  // ../shared/src/index.ts
5721
5720
  init_cjs_shims();
@@ -6928,7 +6927,7 @@ var import_node_crypto3 = require("crypto");
6928
6927
  var import_node_fs3 = __toESM(require("fs"), 1);
6929
6928
  var import_promises8 = __toESM(require("fs/promises"), 1);
6930
6929
  var import_node_os5 = __toESM(require("os"), 1);
6931
- var import_node_path8 = __toESM(require("path"), 1);
6930
+ var import_node_path9 = __toESM(require("path"), 1);
6932
6931
 
6933
6932
  // ../../node_modules/.pnpm/@anthropic-ai+claude-agent-sdk@0.2.141_zod@4.4.3/node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
6934
6933
  init_cjs_shims();
@@ -29753,10 +29752,10 @@ function mergeDefs(...defs) {
29753
29752
  function cloneDef(schema) {
29754
29753
  return mergeDefs(schema._zod.def);
29755
29754
  }
29756
- function getElementAtPath(obj, path22) {
29757
- if (!path22)
29755
+ function getElementAtPath(obj, path24) {
29756
+ if (!path24)
29758
29757
  return obj;
29759
- return path22.reduce((acc, key) => acc?.[key], obj);
29758
+ return path24.reduce((acc, key) => acc?.[key], obj);
29760
29759
  }
29761
29760
  function promiseAllObject(promisesObj) {
29762
29761
  const keys = Object.keys(promisesObj);
@@ -30165,11 +30164,11 @@ function explicitlyAborted(x2, startIndex = 0) {
30165
30164
  }
30166
30165
  return false;
30167
30166
  }
30168
- function prefixIssues(path22, issues) {
30167
+ function prefixIssues(path24, issues) {
30169
30168
  return issues.map((iss) => {
30170
30169
  var _a3;
30171
30170
  (_a3 = iss).path ?? (_a3.path = []);
30172
- iss.path.unshift(path22);
30171
+ iss.path.unshift(path24);
30173
30172
  return iss;
30174
30173
  });
30175
30174
  }
@@ -30316,16 +30315,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
30316
30315
  }
30317
30316
  function formatError(error51, mapper = (issue2) => issue2.message) {
30318
30317
  const fieldErrors = { _errors: [] };
30319
- const processError = (error52, path22 = []) => {
30318
+ const processError = (error52, path24 = []) => {
30320
30319
  for (const issue2 of error52.issues) {
30321
30320
  if (issue2.code === "invalid_union" && issue2.errors.length) {
30322
- issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
30321
+ issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
30323
30322
  } else if (issue2.code === "invalid_key") {
30324
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
30323
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
30325
30324
  } else if (issue2.code === "invalid_element") {
30326
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
30325
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
30327
30326
  } else {
30328
- const fullpath = [...path22, ...issue2.path];
30327
+ const fullpath = [...path24, ...issue2.path];
30329
30328
  if (fullpath.length === 0) {
30330
30329
  fieldErrors._errors.push(mapper(issue2));
30331
30330
  } else {
@@ -30352,17 +30351,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
30352
30351
  }
30353
30352
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
30354
30353
  const result = { errors: [] };
30355
- const processError = (error52, path22 = []) => {
30354
+ const processError = (error52, path24 = []) => {
30356
30355
  var _a3, _b2;
30357
30356
  for (const issue2 of error52.issues) {
30358
30357
  if (issue2.code === "invalid_union" && issue2.errors.length) {
30359
- issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
30358
+ issue2.errors.map((issues) => processError({ issues }, [...path24, ...issue2.path]));
30360
30359
  } else if (issue2.code === "invalid_key") {
30361
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
30360
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
30362
30361
  } else if (issue2.code === "invalid_element") {
30363
- processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
30362
+ processError({ issues: issue2.issues }, [...path24, ...issue2.path]);
30364
30363
  } else {
30365
- const fullpath = [...path22, ...issue2.path];
30364
+ const fullpath = [...path24, ...issue2.path];
30366
30365
  if (fullpath.length === 0) {
30367
30366
  result.errors.push(mapper(issue2));
30368
30367
  continue;
@@ -30394,8 +30393,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
30394
30393
  }
30395
30394
  function toDotPath(_path) {
30396
30395
  const segs = [];
30397
- const path22 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
30398
- for (const seg of path22) {
30396
+ const path24 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
30397
+ for (const seg of path24) {
30399
30398
  if (typeof seg === "number")
30400
30399
  segs.push(`[${seg}]`);
30401
30400
  else if (typeof seg === "symbol")
@@ -43168,13 +43167,13 @@ function resolveRef(ref, ctx) {
43168
43167
  if (!ref.startsWith("#")) {
43169
43168
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
43170
43169
  }
43171
- const path22 = ref.slice(1).split("/").filter(Boolean);
43172
- if (path22.length === 0) {
43170
+ const path24 = ref.slice(1).split("/").filter(Boolean);
43171
+ if (path24.length === 0) {
43173
43172
  return ctx.rootSchema;
43174
43173
  }
43175
43174
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
43176
- if (path22[0] === defsKey) {
43177
- const key = path22[1];
43175
+ if (path24[0] === defsKey) {
43176
+ const key = path24[1];
43178
43177
  if (!key || !ctx.defs[key]) {
43179
43178
  throw new Error(`Reference not found: ${ref}`);
43180
43179
  }
@@ -46979,6 +46978,53 @@ function buildForkHistorySection(messages) {
46979
46978
  return lines.join("\n");
46980
46979
  }
46981
46980
 
46981
+ // src/workdirMapper.ts
46982
+ init_cjs_shims();
46983
+ var import_node_path8 = __toESM(require("path"), 1);
46984
+ function extractAhchatWorkspaceParts(requestedPath) {
46985
+ const normalized = requestedPath.trim().replace(/\\/g, "/");
46986
+ const marker = "/.ahchat/users/";
46987
+ const markerIndex = normalized.indexOf(marker);
46988
+ if (markerIndex >= 0) {
46989
+ const afterUsers = normalized.slice(markerIndex + marker.length);
46990
+ const workspaceMarker = "/workspaces/";
46991
+ const workspaceIndex = afterUsers.indexOf(workspaceMarker);
46992
+ if (workspaceIndex >= 0) {
46993
+ const suffix = afterUsers.slice(workspaceIndex + workspaceMarker.length);
46994
+ const parts = suffix.split("/").filter((part) => part && part !== "." && part !== "..");
46995
+ return parts;
46996
+ }
46997
+ const workspacesRootMarker = "/workspaces";
46998
+ const rootIndex = afterUsers.indexOf(workspacesRootMarker);
46999
+ if (rootIndex >= 0 && afterUsers.slice(rootIndex + workspacesRootMarker.length).length === 0) {
47000
+ return [];
47001
+ }
47002
+ }
47003
+ const legacyMarker = "/.ahchat/";
47004
+ const legacyIndex = normalized.indexOf(legacyMarker);
47005
+ if (legacyIndex >= 0) {
47006
+ const firstSegment = normalized.slice(legacyIndex + legacyMarker.length).split("/").find(Boolean);
47007
+ if (firstSegment && /^(Agent|Group)-/.test(firstSegment)) {
47008
+ return [firstSegment];
47009
+ }
47010
+ }
47011
+ return null;
47012
+ }
47013
+ function extractAhchatWorkspaceSuffix(requestedPath) {
47014
+ const parts = extractAhchatWorkspaceParts(requestedPath);
47015
+ if (!parts || parts.length === 0) return null;
47016
+ return import_node_path8.default.join(...parts);
47017
+ }
47018
+ function remapServerWorkspacePath(requestedPath, workspacesDir) {
47019
+ const parts = extractAhchatWorkspaceParts(requestedPath);
47020
+ if (!parts) return { path: requestedPath, remapped: false };
47021
+ const remappedPath = parts.length > 0 ? import_node_path8.default.join(workspacesDir, ...parts) : workspacesDir;
47022
+ return {
47023
+ path: remappedPath,
47024
+ remapped: import_node_path8.default.normalize(requestedPath) !== import_node_path8.default.normalize(remappedPath)
47025
+ };
47026
+ }
47027
+
46982
47028
  // src/wsMetrics.ts
46983
47029
  init_cjs_shims();
46984
47030
  var import_node_perf_hooks = require("perf_hooks");
@@ -47073,7 +47119,7 @@ async function chownForRootSpawn(targetPath, target) {
47073
47119
  }
47074
47120
  function readCronLockSnapshot() {
47075
47121
  try {
47076
- const lockPath2 = import_node_path8.default.join(import_node_os5.default.homedir(), ".claude", "scheduled_tasks.lock");
47122
+ const lockPath2 = import_node_path9.default.join(import_node_os5.default.homedir(), ".claude", "scheduled_tasks.lock");
47077
47123
  if (!import_node_fs3.default.existsSync(lockPath2)) {
47078
47124
  return { exists: false, sessionId: null, pid: null };
47079
47125
  }
@@ -47141,8 +47187,8 @@ var AgentManager = class {
47141
47187
  this.emit = emit;
47142
47188
  if (typeof options === "function") {
47143
47189
  this.queryFn = options;
47144
- this.workspacesDir = import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat", "workspaces");
47145
- this.agentConfigDir = import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat", "agent-config");
47190
+ this.workspacesDir = import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat", "workspaces");
47191
+ this.agentConfigDir = import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat", "agent-config");
47146
47192
  this.queryConfig = DEFAULT_QUERY_CONFIG;
47147
47193
  this.askQuestionRegistry = new AskQuestionRegistry();
47148
47194
  this.groupRegistry = null;
@@ -47153,11 +47199,11 @@ var AgentManager = class {
47153
47199
  this.serverApiUrl = null;
47154
47200
  this.bridgeToken = null;
47155
47201
  this.defaultModel = null;
47156
- this.dataDir = import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat");
47202
+ this.dataDir = import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat");
47157
47203
  } else {
47158
47204
  this.queryFn = options?.queryFn ?? null;
47159
- this.workspacesDir = options?.workspacesDir ?? import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat", "workspaces");
47160
- this.agentConfigDir = options?.agentConfigDir ?? import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat", "agent-config");
47205
+ this.workspacesDir = options?.workspacesDir ?? import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat", "workspaces");
47206
+ this.agentConfigDir = options?.agentConfigDir ?? import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat", "agent-config");
47161
47207
  this.queryConfig = options?.queryConfig ?? DEFAULT_QUERY_CONFIG;
47162
47208
  this.askQuestionRegistry = options?.askQuestionRegistry ?? new AskQuestionRegistry();
47163
47209
  this.groupRegistry = options?.groupRegistry ?? null;
@@ -47168,7 +47214,7 @@ var AgentManager = class {
47168
47214
  this.serverApiUrl = options?.serverApiUrl ?? null;
47169
47215
  this.bridgeToken = options?.bridgeToken ?? null;
47170
47216
  this.defaultModel = options?.defaultModel ?? null;
47171
- this.dataDir = options?.dataDir ?? import_node_path8.default.join(import_node_os5.default.homedir(), ".ahchat");
47217
+ this.dataDir = options?.dataDir ?? import_node_path9.default.join(import_node_os5.default.homedir(), ".ahchat");
47172
47218
  }
47173
47219
  this.evictionTimer = setInterval(() => {
47174
47220
  void this.evictIdle();
@@ -47179,52 +47225,26 @@ var AgentManager = class {
47179
47225
  this.queryFn = QA$;
47180
47226
  return this.queryFn;
47181
47227
  }
47182
- extractAhchatWorkspaceSuffix(requestedCwd) {
47183
- const normalized = requestedCwd.trim().replace(/\\/g, "/");
47184
- const marker = "/.ahchat/users/";
47185
- const markerIndex = normalized.indexOf(marker);
47186
- if (markerIndex >= 0) {
47187
- const afterUsers = normalized.slice(markerIndex + marker.length);
47188
- const workspaceMarker = "/workspaces/";
47189
- const workspaceIndex = afterUsers.indexOf(workspaceMarker);
47190
- if (workspaceIndex >= 0) {
47191
- const suffix = afterUsers.slice(workspaceIndex + workspaceMarker.length);
47192
- const parts = suffix.split("/").filter((part) => part && part !== "." && part !== "..");
47193
- return parts.length > 0 ? parts.join(import_node_path8.default.sep) : null;
47194
- }
47195
- }
47196
- const legacyMarker = "/.ahchat/";
47197
- const legacyIndex = normalized.indexOf(legacyMarker);
47198
- if (legacyIndex >= 0) {
47199
- const firstSegment = normalized.slice(legacyIndex + legacyMarker.length).split("/").find(Boolean);
47200
- if (firstSegment && /^(Agent|Group)-/.test(firstSegment)) {
47201
- return firstSegment;
47202
- }
47203
- }
47204
- return null;
47205
- }
47206
47228
  fallbackCwd(agentConfig, scope, requestedCwd) {
47207
47229
  const normalized = requestedCwd.trim();
47208
- const ahchatSuffix = this.extractAhchatWorkspaceSuffix(normalized);
47230
+ const ahchatSuffix = extractAhchatWorkspaceSuffix(normalized);
47209
47231
  if (ahchatSuffix) {
47210
- return import_node_path8.default.join(this.workspacesDir, ahchatSuffix);
47232
+ return import_node_path9.default.join(this.workspacesDir, ahchatSuffix);
47211
47233
  }
47212
- const basename = normalized ? import_node_path8.default.basename(import_node_path8.default.normalize(normalized)) : "";
47213
- const suffix = basename && basename !== "." && basename !== import_node_path8.default.sep ? basename : scope.kind === "group" ? `Group-${scope.groupId}` : agentConfig.id;
47214
- return import_node_path8.default.join(this.workspacesDir, suffix);
47234
+ const basename = normalized ? import_node_path9.default.basename(import_node_path9.default.normalize(normalized)) : "";
47235
+ const suffix = basename && basename !== "." && basename !== import_node_path9.default.sep ? basename : scope.kind === "group" ? `Group-${scope.groupId}` : agentConfig.id;
47236
+ return import_node_path9.default.join(this.workspacesDir, suffix);
47215
47237
  }
47216
47238
  remapServerWorkspaceCwd(agentConfig, scope, requestedCwd) {
47217
- const remapped = this.fallbackCwd(agentConfig, scope, requestedCwd);
47218
- const normalizedRequested = import_node_path8.default.normalize(requestedCwd);
47219
- const normalizedRemapped = import_node_path8.default.normalize(remapped);
47220
- if (this.extractAhchatWorkspaceSuffix(requestedCwd) && normalizedRequested !== normalizedRemapped) {
47239
+ const remapped = remapServerWorkspacePath(requestedCwd, this.workspacesDir);
47240
+ if (remapped.remapped) {
47221
47241
  logger10.info("Server working directory remapped to local Bridge workspace", {
47222
47242
  agentId: agentConfig.id,
47223
47243
  scope: scopeKey(scope),
47224
47244
  requested: requestedCwd,
47225
- remapped
47245
+ remapped: remapped.path
47226
47246
  });
47227
- return remapped;
47247
+ return remapped.path;
47228
47248
  }
47229
47249
  return requestedCwd;
47230
47250
  }
@@ -47465,12 +47485,12 @@ var AgentManager = class {
47465
47485
  const agentCwd = await this.resolveRuntimeCwd(agentConfig, scope, cwd);
47466
47486
  const cfg = await this.resolveAgentConfig(agentConfig);
47467
47487
  if (cfg.instructions?.trim()) {
47468
- await import_promises8.default.writeFile(import_node_path8.default.join(agentCwd, "CLAUDE.md"), cfg.instructions.trim(), "utf-8");
47488
+ await import_promises8.default.writeFile(import_node_path9.default.join(agentCwd, "CLAUDE.md"), cfg.instructions.trim(), "utf-8");
47469
47489
  logger10.info("CLAUDE.md written", { agentId: agentConfig.id, bytes: cfg.instructions.trim().length });
47470
47490
  }
47471
47491
  let effectiveConfigDir = this.agentConfigDir;
47472
47492
  if (cfg.subscriptionType !== "system" && cfg.apiKey) {
47473
- effectiveConfigDir = import_node_path8.default.join(this.agentConfigDir, "api-key-agents", agentConfig.id);
47493
+ effectiveConfigDir = import_node_path9.default.join(this.agentConfigDir, "api-key-agents", agentConfig.id);
47474
47494
  let isNew = false;
47475
47495
  try {
47476
47496
  await import_promises8.default.access(effectiveConfigDir);
@@ -47483,7 +47503,7 @@ var AgentManager = class {
47483
47503
  this.dispatchMemory.deleteScope(agentConfig.id, scope);
47484
47504
  logger10.info("New API-key agent config dir; cleared stale session", { agentId: agentConfig.id });
47485
47505
  }
47486
- const settingsPath = import_node_path8.default.join(effectiveConfigDir, "settings.json");
47506
+ const settingsPath = import_node_path9.default.join(effectiveConfigDir, "settings.json");
47487
47507
  const envEntries = {};
47488
47508
  if (cfg.apiKey) envEntries.ANTHROPIC_API_KEY = cfg.apiKey;
47489
47509
  if (cfg.apiBaseUrl) envEntries.ANTHROPIC_BASE_URL = cfg.apiBaseUrl;
@@ -47790,7 +47810,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
47790
47810
  settings: (() => {
47791
47811
  const isolated = cfg.subscriptionType === "project" && Boolean(cfg.apiKey ?? cfg.apiBaseUrl);
47792
47812
  if (!isolated) return void 0;
47793
- return import_node_path8.default.join(effectiveConfigDir, "settings.json");
47813
+ return import_node_path9.default.join(effectiveConfigDir, "settings.json");
47794
47814
  })(),
47795
47815
  canUseTool: async (toolName, input) => {
47796
47816
  if (toolName === "AskUserQuestion") {
@@ -47864,7 +47884,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
47864
47884
  if (isRunningAsRoot()) {
47865
47885
  await chownForRootSpawn(effectiveConfigDir, "configDir");
47866
47886
  await chownForRootSpawn(agentCwd, "agentCwd");
47867
- const settingsFilePath = import_node_path8.default.join(effectiveConfigDir, "settings.json");
47887
+ const settingsFilePath = import_node_path9.default.join(effectiveConfigDir, "settings.json");
47868
47888
  await chownForRootSpawn(settingsFilePath, "settingsFile");
47869
47889
  options.spawnClaudeCodeProcess = (spawnOptions) => {
47870
47890
  const env2 = { ...spawnOptions.env, HOME: "/home/node" };
@@ -48031,7 +48051,7 @@ ${trimmed}`;
48031
48051
  lines.push(` workdir: ${currentCwd}`);
48032
48052
  } else {
48033
48053
  const a = this.agentRegistry?.getById(agentId);
48034
- const singleCwd = a?.workingDirectory || import_node_path8.default.join(this.workspacesDir, agentId);
48054
+ const singleCwd = a?.workingDirectory || import_node_path9.default.join(this.workspacesDir, agentId);
48035
48055
  lines.push(` workdir: ${singleCwd}`);
48036
48056
  }
48037
48057
  let rosterCount = 0;
@@ -48043,7 +48063,7 @@ ${trimmed}`;
48043
48063
  if (key === curKey) {
48044
48064
  lines.push(` workdir: ${currentCwd}`);
48045
48065
  } else {
48046
- const groupCwd = g2.workingDirectory || import_node_path8.default.join(this.workspacesDir, g2.groupId);
48066
+ const groupCwd = g2.workingDirectory || import_node_path9.default.join(this.workspacesDir, g2.groupId);
48047
48067
  lines.push(` workdir: ${groupCwd}`);
48048
48068
  }
48049
48069
  const others = g2.members.filter((id) => id !== agentId).map((id) => {
@@ -48494,14 +48514,14 @@ ${lines.join("\n")}`;
48494
48514
  }
48495
48515
  async materializeAttachment(runtime, attachment, buffer) {
48496
48516
  const safeFileName = this.safeAttachmentFileName(attachment.fileName);
48497
- const dir = import_node_path8.default.join(runtime.cwd, ".ahchat-attachments", attachment.id);
48517
+ const dir = import_node_path9.default.join(runtime.cwd, ".ahchat-attachments", attachment.id);
48498
48518
  await import_promises8.default.mkdir(dir, { recursive: true });
48499
- const filePath = import_node_path8.default.join(dir, safeFileName);
48519
+ const filePath = import_node_path9.default.join(dir, safeFileName);
48500
48520
  await import_promises8.default.writeFile(filePath, buffer);
48501
48521
  return filePath;
48502
48522
  }
48503
48523
  safeAttachmentFileName(fileName) {
48504
- const baseName = import_node_path8.default.basename(fileName).replace(/[\0/:\\]/g, "_").trim();
48524
+ const baseName = import_node_path9.default.basename(fileName).replace(/[\0/:\\]/g, "_").trim();
48505
48525
  return baseName || "attachment";
48506
48526
  }
48507
48527
  /**
@@ -48516,7 +48536,7 @@ ${lines.join("\n")}`;
48516
48536
  async detectVisionSupport() {
48517
48537
  if (process.env.ANTHROPIC_BASE_URL) return false;
48518
48538
  try {
48519
- const settingsPath = import_node_path8.default.join(import_node_os5.default.homedir(), ".claude", "settings.json");
48539
+ const settingsPath = import_node_path9.default.join(import_node_os5.default.homedir(), ".claude", "settings.json");
48520
48540
  const raw = await import_promises8.default.readFile(settingsPath, "utf-8");
48521
48541
  const parsed = JSON.parse(raw);
48522
48542
  if (parsed.env?.ANTHROPIC_BASE_URL) return false;
@@ -48882,7 +48902,7 @@ ${lines.join("\n")}`;
48882
48902
  }
48883
48903
  cwd = payload.targetCwd;
48884
48904
  } else {
48885
- cwd = agentConfig.workingDirectory || import_node_path8.default.join(this.workspacesDir, agentConfig.id);
48905
+ cwd = agentConfig.workingDirectory || import_node_path9.default.join(this.workspacesDir, agentConfig.id);
48886
48906
  }
48887
48907
  void this.acquire(agentConfig, targetScope, cwd).then(() => {
48888
48908
  logger10.info("Neural send new runtime acquired", {
@@ -48988,7 +49008,7 @@ ${lines.join("\n")}`;
48988
49008
  conversationId,
48989
49009
  traceId
48990
49010
  });
48991
- const cwd = newAgent.workingDirectory || import_node_path8.default.join(this.workspacesDir, newAgent.id);
49011
+ const cwd = newAgent.workingDirectory || import_node_path9.default.join(this.workspacesDir, newAgent.id);
48992
49012
  const scope = { kind: "single" };
48993
49013
  try {
48994
49014
  await this.acquire(newAgent, scope, cwd);
@@ -49270,12 +49290,12 @@ ${lines.join("\n")}`;
49270
49290
  break;
49271
49291
  }
49272
49292
  try {
49273
- let cwd = agent.workingDirectory || import_node_path8.default.join(this.workspacesDir, agent.id);
49293
+ let cwd = agent.workingDirectory || import_node_path9.default.join(this.workspacesDir, agent.id);
49274
49294
  if (agent.workingDirectory) {
49275
49295
  try {
49276
49296
  await import_promises8.default.mkdir(cwd, { recursive: true });
49277
49297
  } catch {
49278
- cwd = import_node_path8.default.join(this.workspacesDir, agent.id);
49298
+ cwd = import_node_path9.default.join(this.workspacesDir, agent.id);
49279
49299
  logger10.warn("Stored workingDirectory inaccessible, falling back", {
49280
49300
  agentId: agent.id,
49281
49301
  stored: agent.workingDirectory,
@@ -49750,8 +49770,8 @@ var HttpAgentRegistry = class {
49750
49770
  agents = /* @__PURE__ */ new Map();
49751
49771
  apiUrl(suffix) {
49752
49772
  const base = this.serverApiUrl.replace(/\/$/, "");
49753
- const path22 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49754
- return `${base}${path22}`;
49773
+ const path24 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49774
+ return `${base}${path24}`;
49755
49775
  }
49756
49776
  async refresh() {
49757
49777
  const attempt = async () => {
@@ -49843,8 +49863,8 @@ var HttpSubscriptionRegistry = class {
49843
49863
  subscriptions = /* @__PURE__ */ new Map();
49844
49864
  apiUrl(suffix) {
49845
49865
  const base = this.serverApiUrl.replace(/\/$/, "");
49846
- const path22 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49847
- return `${base}${path22}`;
49866
+ const path24 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49867
+ return `${base}${path24}`;
49848
49868
  }
49849
49869
  async refresh() {
49850
49870
  const attempt = async () => {
@@ -50331,7 +50351,7 @@ var ServerConnector = class {
50331
50351
  init_cjs_shims();
50332
50352
  var import_promises9 = __toESM(require("fs/promises"), 1);
50333
50353
  var import_node_os7 = __toESM(require("os"), 1);
50334
- var import_node_path9 = __toESM(require("path"), 1);
50354
+ var import_node_path10 = __toESM(require("path"), 1);
50335
50355
  var logger16 = createModuleLogger("bridge.contextDumper");
50336
50356
  var TRUNCATE_THRESHOLD = 5e4;
50337
50357
  var TRUNCATE_HEAD = 8e3;
@@ -50360,7 +50380,7 @@ function cwdToProjectSlug(cwd) {
50360
50380
  }
50361
50381
  function resolveJsonlPath(sessionId, cwd) {
50362
50382
  const slug = cwdToProjectSlug(cwd);
50363
- return import_node_path9.default.join(import_node_os7.default.homedir(), ".claude", "projects", slug, `${sessionId}.jsonl`);
50383
+ return import_node_path10.default.join(import_node_os7.default.homedir(), ".claude", "projects", slug, `${sessionId}.jsonl`);
50364
50384
  }
50365
50385
  var RENDERABLE_TYPES = /* @__PURE__ */ new Set(["user", "assistant", "system", "attachment"]);
50366
50386
  async function readJsonlEntries(filePath) {
@@ -50620,7 +50640,7 @@ async function dumpAgentContext(agentId, deps) {
50620
50640
  if (!workdir) {
50621
50641
  return { ok: false, files: [], scopeErrors: [], error: "agent has no working directory" };
50622
50642
  }
50623
- const dumpDir = import_node_path9.default.join(workdir, "sessioninfo");
50643
+ const dumpDir = import_node_path10.default.join(workdir, "sessioninfo");
50624
50644
  await import_promises9.default.mkdir(dumpDir, { recursive: true });
50625
50645
  const prefix = `${agentId}::`;
50626
50646
  const scopeEntries = [];
@@ -50690,7 +50710,7 @@ async function dumpAgentContext(agentId, deps) {
50690
50710
  jsonlPath
50691
50711
  });
50692
50712
  const filename = scopeFilename(agent.name, scopeKey2, groupName);
50693
- const filePath = import_node_path9.default.join(dumpDir, filename);
50713
+ const filePath = import_node_path10.default.join(dumpDir, filename);
50694
50714
  await import_promises9.default.writeFile(filePath, html, "utf-8");
50695
50715
  dumpedFiles.push(filename);
50696
50716
  const stat3 = await import_promises9.default.stat(filePath);
@@ -50732,19 +50752,208 @@ async function dumpAgentContext(agentId, deps) {
50732
50752
  // src/listDir.ts
50733
50753
  init_cjs_shims();
50734
50754
  var import_promises10 = __toESM(require("fs/promises"), 1);
50735
- var import_node_path10 = __toESM(require("path"), 1);
50755
+ var import_node_path12 = __toESM(require("path"), 1);
50756
+
50757
+ // src/runtimeEnv.ts
50758
+ init_cjs_shims();
50759
+ var import_node_child_process2 = require("child_process");
50760
+ var import_node_fs4 = require("fs");
50761
+ var import_node_os8 = __toESM(require("os"), 1);
50762
+ var import_node_path11 = __toESM(require("path"), 1);
50763
+ var MIN_NODE_MAJOR = 20;
50764
+ function getHomeDir() {
50765
+ return process.env.USERPROFILE || import_node_os8.default.homedir();
50766
+ }
50767
+ function splitPath(value) {
50768
+ if (!value) return [];
50769
+ return value.split(import_node_path11.default.delimiter).filter((entry) => entry.length > 0);
50770
+ }
50771
+ function uniq(values) {
50772
+ return [...new Set(values.filter(Boolean))];
50773
+ }
50774
+ function parseNodeVersionMajor(version2) {
50775
+ const raw = version2.trim().replace(/^v/, "");
50776
+ const [majorRaw] = raw.split(".");
50777
+ if (!majorRaw) return null;
50778
+ const major = Number.parseInt(majorRaw, 10);
50779
+ return Number.isFinite(major) ? major : null;
50780
+ }
50781
+ function joinHomePath(home, suffix) {
50782
+ const parts = suffix.split(/[\\/]+/).filter((part) => part.length > 0);
50783
+ return import_node_path11.default.join(home, ...parts);
50784
+ }
50785
+ function sortNodeVersionDirsDesc(names) {
50786
+ return [...names].sort((a, b2) => {
50787
+ const aParts = a.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
50788
+ const bParts = b2.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
50789
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i += 1) {
50790
+ const delta = (bParts[i] ?? 0) - (aParts[i] ?? 0);
50791
+ if (delta !== 0) return delta;
50792
+ }
50793
+ return b2.localeCompare(a);
50794
+ });
50795
+ }
50796
+ function listNodeVersionBins(root, binSuffix) {
50797
+ if (!(0, import_node_fs4.existsSync)(root)) return [];
50798
+ try {
50799
+ return sortNodeVersionDirsDesc((0, import_node_fs4.readdirSync)(root)).map((version2) => import_node_path11.default.join(root, version2, ...binSuffix)).filter((candidate) => (0, import_node_fs4.existsSync)(candidate));
50800
+ } catch {
50801
+ return [];
50802
+ }
50803
+ }
50804
+ function getNodeRuntimeStatus(version2 = process.versions.node) {
50805
+ const major = parseNodeVersionMajor(version2);
50806
+ return {
50807
+ version: version2,
50808
+ major,
50809
+ supported: major !== null && major >= MIN_NODE_MAJOR
50810
+ };
50811
+ }
50812
+ function getNodeToolExtraPathEntries(env2 = process.env) {
50813
+ const home = getHomeDir();
50814
+ const entries = [];
50815
+ if (process.platform === "win32") {
50816
+ for (const envName of ["NVM_SYMLINK", "NVM_HOME"]) {
50817
+ const value = env2[envName];
50818
+ if (value && (0, import_node_fs4.existsSync)(value)) entries.push(value);
50819
+ }
50820
+ for (const candidate of [
50821
+ import_node_path11.default.join(home, "AppData", "Roaming", "npm"),
50822
+ import_node_path11.default.join(home, ".volta", "bin"),
50823
+ import_node_path11.default.join(home, ".asdf", "shims"),
50824
+ import_node_path11.default.join(env2.ProgramFiles ?? "C:\\Program Files", "nodejs"),
50825
+ import_node_path11.default.join(env2.LOCALAPPDATA ?? import_node_path11.default.join(home, "AppData", "Local"), "Programs", "nodejs")
50826
+ ]) {
50827
+ if ((0, import_node_fs4.existsSync)(candidate)) entries.push(candidate);
50828
+ }
50829
+ return uniq(entries);
50830
+ }
50831
+ const nvmRoot = env2.NVM_DIR ?? import_node_path11.default.join(home, ".nvm");
50832
+ entries.push(...listNodeVersionBins(import_node_path11.default.join(nvmRoot, "versions", "node"), ["bin"]));
50833
+ const fnmRoots = [
50834
+ import_node_path11.default.join(home, ".fnm", "node-versions"),
50835
+ import_node_path11.default.join(home, ".local", "share", "fnm", "node-versions")
50836
+ ];
50837
+ for (const fnmRoot of fnmRoots) {
50838
+ entries.push(...listNodeVersionBins(fnmRoot, ["installation", "bin"]));
50839
+ }
50840
+ for (const candidate of [
50841
+ import_node_path11.default.join(home, ".volta", "bin"),
50842
+ import_node_path11.default.join(home, ".asdf", "shims"),
50843
+ import_node_path11.default.join(home, ".local", "bin"),
50844
+ "/opt/homebrew/bin",
50845
+ "/usr/local/bin"
50846
+ ]) {
50847
+ if ((0, import_node_fs4.existsSync)(candidate)) entries.push(candidate);
50848
+ }
50849
+ return uniq(entries);
50850
+ }
50851
+ function buildAugmentedPath(env2 = process.env) {
50852
+ return uniq([...getNodeToolExtraPathEntries(env2), ...splitPath(env2.PATH)]).join(import_node_path11.default.delimiter);
50853
+ }
50854
+ function withAugmentedPathEnv(env2 = process.env) {
50855
+ return { ...env2, PATH: buildAugmentedPath(env2) };
50856
+ }
50857
+ function executableNames(name) {
50858
+ if (process.platform !== "win32") return [name];
50859
+ if (/\.(cmd|exe|bat)$/i.test(name)) return [name];
50860
+ return [`${name}.cmd`, `${name}.exe`, `${name}.bat`, name];
50861
+ }
50862
+ function canExecute(candidate) {
50863
+ try {
50864
+ if (process.platform === "win32") return (0, import_node_fs4.existsSync)(candidate);
50865
+ (0, import_node_fs4.accessSync)(candidate, import_node_fs4.constants.X_OK);
50866
+ return true;
50867
+ } catch {
50868
+ return false;
50869
+ }
50870
+ }
50871
+ function resolveCommand(names, env2 = process.env) {
50872
+ const pathEntries = splitPath(buildAugmentedPath(env2));
50873
+ for (const entry of pathEntries) {
50874
+ for (const name of names) {
50875
+ for (const executableName of executableNames(name)) {
50876
+ const candidate = import_node_path11.default.join(entry, executableName);
50877
+ if (canExecute(candidate)) return { name, path: candidate };
50878
+ }
50879
+ }
50880
+ }
50881
+ return void 0;
50882
+ }
50883
+ function readCommandVersion(executablePath, args = ["--version"], env2 = process.env) {
50884
+ try {
50885
+ return (0, import_node_child_process2.execFileSync)(executablePath, args, {
50886
+ env: withAugmentedPathEnv(env2),
50887
+ timeout: 1e4
50888
+ }).toString().trim();
50889
+ } catch {
50890
+ return void 0;
50891
+ }
50892
+ }
50893
+ function probeCommand(name, args = ["--version"], env2 = process.env) {
50894
+ const resolved = resolveCommand([name], env2);
50895
+ if (!resolved) {
50896
+ return {
50897
+ name,
50898
+ ok: false,
50899
+ message: `${name} was not found on PATH`
50900
+ };
50901
+ }
50902
+ const version2 = readCommandVersion(resolved.path, args, env2);
50903
+ return {
50904
+ name,
50905
+ path: resolved.path,
50906
+ version: version2,
50907
+ ok: Boolean(version2),
50908
+ message: version2 ? void 0 : `${name} was found but did not run successfully`
50909
+ };
50910
+ }
50911
+ function resolveUserPath(input) {
50912
+ const home = getHomeDir();
50913
+ let value = input.trim();
50914
+ if (value === "~") value = home;
50915
+ else if (value.startsWith("~/") || value.startsWith("~\\")) value = joinHomePath(home, value.slice(2));
50916
+ else if (value === "$HOME") value = home;
50917
+ else if (value.startsWith("$HOME/") || value.startsWith("$HOME\\")) value = joinHomePath(home, value.slice(6));
50918
+ else if (value === "${HOME}") value = home;
50919
+ else if (value.startsWith("${HOME}/") || value.startsWith("${HOME}\\")) value = joinHomePath(home, value.slice(8));
50920
+ else if (value === "$env:USERPROFILE") value = home;
50921
+ else if (value.startsWith("$env:USERPROFILE\\") || value.startsWith("$env:USERPROFILE/")) {
50922
+ value = joinHomePath(home, value.slice("$env:USERPROFILE".length + 1));
50923
+ } else if (value === "%USERPROFILE%") value = home;
50924
+ else if (value.startsWith("%USERPROFILE%\\") || value.startsWith("%USERPROFILE%/")) {
50925
+ value = joinHomePath(home, value.slice("%USERPROFILE%".length + 1));
50926
+ }
50927
+ return import_node_path11.default.isAbsolute(value) ? import_node_path11.default.normalize(value) : import_node_path11.default.resolve(value);
50928
+ }
50929
+ function normalizeBridgeServerUrls(rawUrl) {
50930
+ const url2 = new URL(rawUrl);
50931
+ if (url2.protocol === "http:" || url2.protocol === "https:") {
50932
+ url2.protocol = url2.protocol === "https:" ? "wss:" : "ws:";
50933
+ if (url2.pathname === "/" || url2.pathname === "") url2.pathname = "/ws/bridge";
50934
+ }
50935
+ if (url2.protocol !== "ws:" && url2.protocol !== "wss:") {
50936
+ throw new Error(`Unsupported bridge server URL protocol: ${url2.protocol}`);
50937
+ }
50938
+ const serverUrl = url2.toString();
50939
+ const serverApiUrl = `${url2.protocol === "wss:" ? "https" : "http"}://${url2.host}`;
50940
+ return { serverUrl, serverApiUrl };
50941
+ }
50942
+
50943
+ // src/listDir.ts
50736
50944
  var logger17 = createModuleLogger("bridge.listDir");
50737
50945
  function shouldIncludeEntry(name) {
50738
50946
  if (!name.startsWith(".")) return true;
50739
50947
  return name === ".ahchat-attachments";
50740
50948
  }
50741
50949
  async function listDirectoryEntries(dirPath) {
50742
- logger17.info("listDirectoryEntries start", { path: dirPath });
50743
- const raw = await import_promises10.default.readdir(dirPath, { withFileTypes: true });
50950
+ const resolvedDirPath = resolveUserPath(dirPath);
50951
+ logger17.info("listDirectoryEntries start", { path: dirPath, resolvedPath: resolvedDirPath });
50952
+ const raw = await import_promises10.default.readdir(resolvedDirPath, { withFileTypes: true });
50744
50953
  const entries = [];
50745
50954
  for (const entry of raw) {
50746
50955
  if (!shouldIncludeEntry(entry.name)) continue;
50747
- const fullPath = import_node_path10.default.join(dirPath, entry.name);
50956
+ const fullPath = import_node_path12.default.join(resolvedDirPath, entry.name);
50748
50957
  const isDir = entry.isDirectory();
50749
50958
  let size;
50750
50959
  let mtime;
@@ -50763,6 +50972,7 @@ async function listDirectoryEntries(dirPath) {
50763
50972
  });
50764
50973
  logger17.info("listDirectoryEntries ok", {
50765
50974
  path: dirPath,
50975
+ resolvedPath: resolvedDirPath,
50766
50976
  count: entries.length,
50767
50977
  dirCount: entries.filter((e7) => e7.type === "dir").length,
50768
50978
  fileCount: entries.filter((e7) => e7.type === "file").length
@@ -50772,9 +50982,9 @@ async function listDirectoryEntries(dirPath) {
50772
50982
 
50773
50983
  // src/logScanner.ts
50774
50984
  init_cjs_shims();
50775
- var import_node_fs4 = __toESM(require("fs"), 1);
50776
- var import_node_path11 = __toESM(require("path"), 1);
50777
- var import_node_os8 = __toESM(require("os"), 1);
50985
+ var import_node_fs5 = __toESM(require("fs"), 1);
50986
+ var import_node_path13 = __toESM(require("path"), 1);
50987
+ var import_node_os9 = __toESM(require("os"), 1);
50778
50988
  var import_node_readline = __toESM(require("readline"), 1);
50779
50989
  var logger18 = createModuleLogger("bridge.logScanner");
50780
50990
  var DEFAULT_LIMIT = 500;
@@ -50782,17 +50992,17 @@ var MAX_LIMIT = 2e3;
50782
50992
  function listLogFiles(logsDir, baseName) {
50783
50993
  let names;
50784
50994
  try {
50785
- names = import_node_fs4.default.readdirSync(logsDir);
50995
+ names = import_node_fs5.default.readdirSync(logsDir);
50786
50996
  } catch (e7) {
50787
50997
  logger18.warn("listLogFiles: readdir failed", { logsDir, error: e7 });
50788
50998
  return [];
50789
50999
  }
50790
51000
  const pattern = new RegExp(`^${baseName.replace(".", "\\.")}(\\.\\d+)?$`);
50791
- return names.filter((n2) => pattern.test(n2)).map((n2) => import_node_path11.default.join(logsDir, n2));
51001
+ return names.filter((n2) => pattern.test(n2)).map((n2) => import_node_path13.default.join(logsDir, n2));
50792
51002
  }
50793
51003
  async function scanFile(filePath, source, filter, limit, state) {
50794
- const file2 = import_node_path11.default.basename(filePath);
50795
- const stream = import_node_fs4.default.createReadStream(filePath, { encoding: "utf-8" });
51004
+ const file2 = import_node_path13.default.basename(filePath);
51005
+ const stream = import_node_fs5.default.createReadStream(filePath, { encoding: "utf-8" });
50796
51006
  const rl2 = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
50797
51007
  let lineNum = 0;
50798
51008
  for await (const line of rl2) {
@@ -50830,7 +51040,7 @@ async function scanLocalLogs(logsDir, baseName, filter) {
50830
51040
  };
50831
51041
  }
50832
51042
  async function scanBridgeLogs(filter) {
50833
- const logDir = import_node_path11.default.join(import_node_os8.default.homedir(), ".ahchat", "logs");
51043
+ const logDir = import_node_path13.default.join(import_node_os9.default.homedir(), ".ahchat", "logs");
50834
51044
  logger18.info("scanBridgeLogs start", {
50835
51045
  logDir,
50836
51046
  startIso: filter.startIso,
@@ -50848,15 +51058,15 @@ async function scanBridgeLogs(filter) {
50848
51058
 
50849
51059
  // src/skillStore.ts
50850
51060
  init_cjs_shims();
50851
- var import_node_fs5 = __toESM(require("fs"), 1);
50852
- var import_node_path12 = __toESM(require("path"), 1);
51061
+ var import_node_fs6 = __toESM(require("fs"), 1);
51062
+ var import_node_path14 = __toESM(require("path"), 1);
50853
51063
  var logger19 = createModuleLogger("bridge.skillStore");
50854
51064
  var ALLOWED_NAMES = /* @__PURE__ */ new Set(["log-analysis"]);
50855
51065
  var SkillStore = class {
50856
51066
  skillsDir;
50857
51067
  constructor(dataDir) {
50858
- this.skillsDir = import_node_path12.default.join(dataDir, "skills");
50859
- import_node_fs5.default.mkdirSync(this.skillsDir, { recursive: true });
51068
+ this.skillsDir = import_node_path14.default.join(dataDir, "skills");
51069
+ import_node_fs6.default.mkdirSync(this.skillsDir, { recursive: true });
50860
51070
  logger19.info("SkillStore initialized", { skillsDir: this.skillsDir });
50861
51071
  }
50862
51072
  read(name) {
@@ -50864,9 +51074,9 @@ var SkillStore = class {
50864
51074
  logger19.warn("Skill read: unknown name", { name, allowed: [...ALLOWED_NAMES] });
50865
51075
  return "";
50866
51076
  }
50867
- const filePath = import_node_path12.default.join(this.skillsDir, `${name}.md`);
51077
+ const filePath = import_node_path14.default.join(this.skillsDir, `${name}.md`);
50868
51078
  try {
50869
- const content = import_node_fs5.default.readFileSync(filePath, "utf-8");
51079
+ const content = import_node_fs6.default.readFileSync(filePath, "utf-8");
50870
51080
  logger19.info("Skill read", { name, bytes: content.length });
50871
51081
  return content;
50872
51082
  } catch (e7) {
@@ -50879,19 +51089,19 @@ var SkillStore = class {
50879
51089
  if (!ALLOWED_NAMES.has(name)) {
50880
51090
  throw new Error(`Unknown skill name: ${name}`);
50881
51091
  }
50882
- const filePath = import_node_path12.default.join(this.skillsDir, `${name}.md`);
51092
+ const filePath = import_node_path14.default.join(this.skillsDir, `${name}.md`);
50883
51093
  const tmpPath = `${filePath}.tmp`;
50884
51094
  let existing = "";
50885
51095
  try {
50886
- existing = import_node_fs5.default.readFileSync(filePath, "utf-8");
51096
+ existing = import_node_fs6.default.readFileSync(filePath, "utf-8");
50887
51097
  } catch {
50888
51098
  }
50889
51099
  if (existing === content) {
50890
51100
  logger19.info("Skill already in sync", { name, bytes: content.length });
50891
51101
  return;
50892
51102
  }
50893
- import_node_fs5.default.writeFileSync(tmpPath, content, "utf-8");
50894
- import_node_fs5.default.renameSync(tmpPath, filePath);
51103
+ import_node_fs6.default.writeFileSync(tmpPath, content, "utf-8");
51104
+ import_node_fs6.default.renameSync(tmpPath, filePath);
50895
51105
  logger19.info("Skill seeded/re-synced", {
50896
51106
  name,
50897
51107
  bytes: content.length,
@@ -50902,8 +51112,8 @@ var SkillStore = class {
50902
51112
 
50903
51113
  // src/lockfile.ts
50904
51114
  init_cjs_shims();
50905
- var import_node_fs6 = __toESM(require("fs"), 1);
50906
- var import_node_path13 = __toESM(require("path"), 1);
51115
+ var import_node_fs7 = __toESM(require("fs"), 1);
51116
+ var import_node_path15 = __toESM(require("path"), 1);
50907
51117
  var logger20 = createModuleLogger("bridge.lockfile");
50908
51118
  var lockPath = null;
50909
51119
  function isProcessAlive(pid) {
@@ -50917,10 +51127,10 @@ function isProcessAlive(pid) {
50917
51127
  }
50918
51128
  }
50919
51129
  function acquireLock(dataDir) {
50920
- const file2 = import_node_path13.default.join(dataDir, "bridge.lock");
51130
+ const file2 = import_node_path15.default.join(dataDir, "bridge.lock");
50921
51131
  lockPath = file2;
50922
- if (import_node_fs6.default.existsSync(file2)) {
50923
- const raw = import_node_fs6.default.readFileSync(file2, "utf-8").trim();
51132
+ if (import_node_fs7.default.existsSync(file2)) {
51133
+ const raw = import_node_fs7.default.readFileSync(file2, "utf-8").trim();
50924
51134
  const pid = Number.parseInt(raw, 10);
50925
51135
  if (Number.isFinite(pid) && pid > 0) {
50926
51136
  if (isProcessAlive(pid)) {
@@ -50929,15 +51139,15 @@ function acquireLock(dataDir) {
50929
51139
  logger20.warn("Removing stale bridge.lock (process not found)", { pid, path: file2 });
50930
51140
  }
50931
51141
  }
50932
- import_node_fs6.default.mkdirSync(import_node_path13.default.dirname(file2), { recursive: true });
50933
- import_node_fs6.default.writeFileSync(file2, String(process.pid), "utf-8");
51142
+ import_node_fs7.default.mkdirSync(import_node_path15.default.dirname(file2), { recursive: true });
51143
+ import_node_fs7.default.writeFileSync(file2, String(process.pid), "utf-8");
50934
51144
  logger20.info("Acquired bridge lock", { path: file2, pid: process.pid });
50935
51145
  const release = () => {
50936
51146
  try {
50937
- if (lockPath && import_node_fs6.default.existsSync(lockPath)) {
50938
- const current = import_node_fs6.default.readFileSync(lockPath, "utf-8").trim();
51147
+ if (lockPath && import_node_fs7.default.existsSync(lockPath)) {
51148
+ const current = import_node_fs7.default.readFileSync(lockPath, "utf-8").trim();
50939
51149
  if (current === String(process.pid)) {
50940
- import_node_fs6.default.unlinkSync(lockPath);
51150
+ import_node_fs7.default.unlinkSync(lockPath);
50941
51151
  logger20.info("Released bridge lock", { path: lockPath });
50942
51152
  }
50943
51153
  }
@@ -51298,14 +51508,14 @@ async function handleGroupArchivedPush(deps, payload) {
51298
51508
 
51299
51509
  // src/sessionStore.ts
51300
51510
  init_cjs_shims();
51301
- var import_node_fs7 = __toESM(require("fs"), 1);
51302
- var import_node_path14 = __toESM(require("path"), 1);
51511
+ var import_node_fs8 = __toESM(require("fs"), 1);
51512
+ var import_node_path16 = __toESM(require("path"), 1);
51303
51513
  var logger23 = createModuleLogger("session.store");
51304
51514
  var SessionStore = class {
51305
51515
  filePath;
51306
51516
  cache;
51307
51517
  constructor(dataDir) {
51308
- this.filePath = import_node_path14.default.join(dataDir, "sessions.json");
51518
+ this.filePath = import_node_path16.default.join(dataDir, "sessions.json");
51309
51519
  this.cache = this.loadFromDisk();
51310
51520
  }
51311
51521
  cacheKey(agentId, scope) {
@@ -51340,8 +51550,8 @@ var SessionStore = class {
51340
51550
  }
51341
51551
  loadFromDisk() {
51342
51552
  try {
51343
- if (!import_node_fs7.default.existsSync(this.filePath)) return {};
51344
- const raw = import_node_fs7.default.readFileSync(this.filePath, "utf-8");
51553
+ if (!import_node_fs8.default.existsSync(this.filePath)) return {};
51554
+ const raw = import_node_fs8.default.readFileSync(this.filePath, "utf-8");
51345
51555
  const parsed = JSON.parse(raw);
51346
51556
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
51347
51557
  const map2 = parsed;
@@ -51365,9 +51575,9 @@ var SessionStore = class {
51365
51575
  }
51366
51576
  saveToDisk() {
51367
51577
  try {
51368
- const dir = import_node_path14.default.dirname(this.filePath);
51369
- import_node_fs7.default.mkdirSync(dir, { recursive: true });
51370
- import_node_fs7.default.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2), "utf-8");
51578
+ const dir = import_node_path16.default.dirname(this.filePath);
51579
+ import_node_fs8.default.mkdirSync(dir, { recursive: true });
51580
+ import_node_fs8.default.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2), "utf-8");
51371
51581
  } catch (e7) {
51372
51582
  logger23.error("Failed to save sessions file", { error: e7, path: this.filePath });
51373
51583
  }
@@ -51376,9 +51586,9 @@ var SessionStore = class {
51376
51586
 
51377
51587
  // src/ensureClaudeCli.ts
51378
51588
  init_cjs_shims();
51379
- var import_node_child_process2 = require("child_process");
51380
- var import_node_fs8 = require("fs");
51381
- var import_node_path15 = require("path");
51589
+ var import_node_child_process3 = require("child_process");
51590
+ var import_node_fs9 = require("fs");
51591
+ var import_node_path17 = require("path");
51382
51592
  var logger24 = createModuleLogger("bridge.ensureCli");
51383
51593
  var DEFAULT_INSTALL_TIMEOUT_MS = 6e5;
51384
51594
  function getInstallTimeoutMs() {
@@ -51387,48 +51597,42 @@ function getInstallTimeoutMs() {
51387
51597
  const parsed = Number.parseInt(raw, 10);
51388
51598
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INSTALL_TIMEOUT_MS;
51389
51599
  }
51390
- function detectClaudeCli() {
51391
- try {
51392
- return (0, import_node_child_process2.execFileSync)("claude", ["--version"], { timeout: 1e4 }).toString().trim();
51393
- } catch {
51394
- return void 0;
51395
- }
51396
- }
51397
51600
  function getNpmGlobalBin() {
51601
+ const npm = resolveCommand(["npm"]);
51602
+ if (!npm) return void 0;
51398
51603
  try {
51399
- const bin = (0, import_node_child_process2.execSync)("npm bin -g", { timeout: 5e3 }).toString().trim() || void 0;
51604
+ const bin = (0, import_node_child_process3.execFileSync)(npm.path, ["bin", "-g"], {
51605
+ env: withAugmentedPathEnv(),
51606
+ timeout: 5e3
51607
+ }).toString().trim() || void 0;
51400
51608
  if (bin) return bin;
51401
51609
  } catch {
51402
51610
  }
51403
51611
  try {
51404
- const prefix = (0, import_node_child_process2.execSync)("npm prefix -g", { timeout: 5e3 }).toString().trim();
51405
- if (prefix) return (0, import_node_path15.join)(prefix, "bin");
51612
+ const prefix = (0, import_node_child_process3.execFileSync)(npm.path, ["prefix", "-g"], {
51613
+ env: withAugmentedPathEnv(),
51614
+ timeout: 5e3
51615
+ }).toString().trim();
51616
+ if (prefix) return (0, import_node_path17.join)(prefix, "bin");
51406
51617
  } catch {
51407
51618
  }
51408
51619
  return void 0;
51409
51620
  }
51410
51621
  function resolveClaudeBinary() {
51411
- const whichCmd = process.platform === "win32" ? "where" : "which";
51412
- try {
51413
- const out = (0, import_node_child_process2.execFileSync)(whichCmd, ["claude"], { timeout: 5e3 }).toString();
51414
- const first = out.split(/\r?\n/).map((l4) => l4.trim()).find(Boolean);
51415
- if (first) return first;
51416
- } catch {
51417
- }
51418
- return resolveViaNpmBin();
51622
+ return resolveCommand(["claude", "anthropic-cli"])?.path ?? resolveViaNpmBin();
51419
51623
  }
51420
51624
  function getNpmClaudeCandidates(bin) {
51421
51625
  if (process.platform === "win32") {
51422
- return ["claude.cmd", "claude.exe", "claude", "anthropic-cli.cmd", "anthropic-cli.exe", "anthropic-cli"].map((name) => (0, import_node_path15.join)(bin, name));
51626
+ return ["claude.cmd", "claude.exe", "claude", "anthropic-cli.cmd", "anthropic-cli.exe", "anthropic-cli"].map((name) => (0, import_node_path17.join)(bin, name));
51423
51627
  }
51424
- return [(0, import_node_path15.join)(bin, "claude"), (0, import_node_path15.join)(bin, "anthropic-cli")];
51628
+ return [(0, import_node_path17.join)(bin, "claude"), (0, import_node_path17.join)(bin, "anthropic-cli")];
51425
51629
  }
51426
51630
  function resolveViaNpmBin() {
51427
51631
  const bin = getNpmGlobalBin();
51428
51632
  if (!bin) return void 0;
51429
51633
  for (const candidate of getNpmClaudeCandidates(bin)) {
51430
51634
  try {
51431
- (0, import_node_fs8.accessSync)(candidate, import_node_fs8.constants.X_OK);
51635
+ (0, import_node_fs9.accessSync)(candidate, import_node_fs9.constants.X_OK);
51432
51636
  return candidate;
51433
51637
  } catch {
51434
51638
  }
@@ -51438,40 +51642,32 @@ function resolveViaNpmBin() {
51438
51642
  function detectViaNpmBin() {
51439
51643
  const binPath = resolveViaNpmBin();
51440
51644
  if (!binPath) return void 0;
51441
- try {
51442
- return (0, import_node_child_process2.execFileSync)(binPath, ["--version"], { timeout: 1e4 }).toString().trim();
51443
- } catch {
51444
- }
51445
- return void 0;
51645
+ return readCommandVersion(binPath);
51446
51646
  }
51447
51647
  function detectResolvedClaudeCli() {
51448
- const viaPath = detectClaudeCli();
51449
- if (viaPath) {
51450
- return { version: viaPath, path: resolveClaudeBinary() };
51451
- }
51452
- const npmBinPath = resolveViaNpmBin();
51453
- if (!npmBinPath) return void 0;
51454
- try {
51455
- const version2 = (0, import_node_child_process2.execFileSync)(npmBinPath, ["--version"], { timeout: 1e4 }).toString().trim();
51456
- return { version: version2, path: npmBinPath };
51457
- } catch {
51458
- }
51648
+ const resolvedPath = resolveClaudeBinary();
51649
+ if (!resolvedPath) return void 0;
51650
+ const version2 = readCommandVersion(resolvedPath);
51651
+ if (version2) return { version: version2, path: resolvedPath };
51459
51652
  return void 0;
51460
51653
  }
51461
51654
  function detectVersionFromResolvedCandidates() {
51462
51655
  const candidates = [resolveClaudeBinary(), resolveViaNpmBin()].filter((p) => Boolean(p));
51463
51656
  for (const p of candidates) {
51464
- try {
51465
- (0, import_node_fs8.accessSync)(p, import_node_fs8.constants.X_OK);
51466
- return (0, import_node_child_process2.execFileSync)(p, ["--version"], { timeout: 1e4 }).toString().trim();
51467
- } catch {
51468
- }
51657
+ const version2 = readCommandVersion(p);
51658
+ if (version2) return version2;
51469
51659
  }
51470
51660
  return void 0;
51471
51661
  }
51472
51662
  function installClaudeCli() {
51663
+ const npm = resolveCommand(["npm"]);
51664
+ if (!npm) {
51665
+ logger24.error("npm not found; cannot install Claude Code CLI");
51666
+ return void 0;
51667
+ }
51473
51668
  logger24.info("Installing Claude Code CLI via npm...");
51474
- const result = (0, import_node_child_process2.spawnSync)("npm", ["install", "-g", "@anthropic-ai/claude-code"], {
51669
+ const result = (0, import_node_child_process3.spawnSync)(npm.path, ["install", "-g", "@anthropic-ai/claude-code"], {
51670
+ env: withAugmentedPathEnv(),
51475
51671
  stdio: "inherit",
51476
51672
  timeout: getInstallTimeoutMs()
51477
51673
  });
@@ -51503,7 +51699,10 @@ function installClaudeCli() {
51503
51699
  logger24.error("claude not found after successful npm install -g", {
51504
51700
  npmGlobalBin: npmBin ?? "unknown",
51505
51701
  pathDirectories: envPath.split(process.platform === "win32" ? ";" : ":").slice(0, 10),
51506
- npmPrefix: (0, import_node_child_process2.execSync)("npm prefix -g", { timeout: 5e3 }).toString().trim() || "unknown"
51702
+ npmPrefix: (0, import_node_child_process3.execFileSync)(npm.path, ["prefix", "-g"], {
51703
+ env: withAugmentedPathEnv(),
51704
+ timeout: 5e3
51705
+ }).toString().trim() || "unknown"
51507
51706
  });
51508
51707
  return void 0;
51509
51708
  }
@@ -51533,21 +51732,21 @@ async function ensureClaudeCli() {
51533
51732
  // src/forkAgentFiles.ts
51534
51733
  init_cjs_shims();
51535
51734
  var fs11 = __toESM(require("fs/promises"), 1);
51536
- var path16 = __toESM(require("path"), 1);
51735
+ var path18 = __toESM(require("path"), 1);
51537
51736
 
51538
51737
  // src/sessionSlug.ts
51539
51738
  init_cjs_shims();
51540
- var import_node_os9 = __toESM(require("os"), 1);
51541
- var import_node_path16 = __toESM(require("path"), 1);
51542
- var CLAUDE_PROJECTS_DIR = import_node_path16.default.join(import_node_os9.default.homedir(), ".claude", "projects");
51739
+ var import_node_os10 = __toESM(require("os"), 1);
51740
+ var import_node_path18 = __toESM(require("path"), 1);
51741
+ var CLAUDE_PROJECTS_DIR = import_node_path18.default.join(import_node_os10.default.homedir(), ".claude", "projects");
51543
51742
  function cwdToSlug(cwd) {
51544
51743
  return cwd.replace(/[^a-zA-Z0-9-]/g, "-");
51545
51744
  }
51546
51745
  function sessionDirForCwd(cwd) {
51547
- return import_node_path16.default.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
51746
+ return import_node_path18.default.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
51548
51747
  }
51549
51748
  function sessionFilePath(cwd, sessionId) {
51550
- return import_node_path16.default.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
51749
+ return import_node_path18.default.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
51551
51750
  }
51552
51751
 
51553
51752
  // src/forkAgentFiles.ts
@@ -51579,9 +51778,9 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
51579
51778
  logger25.error("Workdir copy failed", { error: e7 });
51580
51779
  throw e7;
51581
51780
  }
51582
- const srcNotebook = path16.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
51583
- const dstNotebookDir = path16.join(dataDir, "agent-memory", newAgentId);
51584
- const dstNotebook = path16.join(dstNotebookDir, "notebook.md");
51781
+ const srcNotebook = path18.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
51782
+ const dstNotebookDir = path18.join(dataDir, "agent-memory", newAgentId);
51783
+ const dstNotebook = path18.join(dstNotebookDir, "notebook.md");
51585
51784
  try {
51586
51785
  const nbStat = await fs11.stat(srcNotebook).catch(() => null);
51587
51786
  if (nbStat?.isFile()) {
@@ -51608,7 +51807,7 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
51608
51807
  if (srcStat?.isFile()) {
51609
51808
  const dstDir = sessionDirForCwd(newWorkdir);
51610
51809
  await fs11.mkdir(dstDir, { recursive: true });
51611
- const dstPath = path16.join(dstDir, `${sourceSessionId}.jsonl`);
51810
+ const dstPath = path18.join(dstDir, `${sourceSessionId}.jsonl`);
51612
51811
  await fs11.copyFile(srcPath, dstPath);
51613
51812
  sessionStore.set(newAgentId, { kind: "single" }, sourceSessionId);
51614
51813
  sessionCopied = true;
@@ -51656,12 +51855,12 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
51656
51855
  // src/modelQuerier.ts
51657
51856
  init_cjs_shims();
51658
51857
  var import_promises11 = __toESM(require("fs/promises"), 1);
51659
- var import_node_os10 = __toESM(require("os"), 1);
51660
- var import_node_path17 = __toESM(require("path"), 1);
51858
+ var import_node_os11 = __toESM(require("os"), 1);
51859
+ var import_node_path19 = __toESM(require("path"), 1);
51661
51860
  var logger26 = createModuleLogger("bridge.modelQuerier");
51662
51861
  async function listModels(queryFn, opts = {}) {
51663
51862
  const t0 = Date.now();
51664
- const cwd = opts.cwd ?? import_node_path17.default.join(import_node_os10.default.homedir(), ".ahchat", "workspaces", "_list_models");
51863
+ const cwd = opts.cwd ?? import_node_path19.default.join(import_node_os11.default.homedir(), ".ahchat", "workspaces", "_list_models");
51665
51864
  await import_promises11.default.mkdir(cwd, { recursive: true });
51666
51865
  const fn = queryFn ?? QA$;
51667
51866
  const ic2 = new InputController();
@@ -51724,8 +51923,8 @@ async function listModels(queryFn, opts = {}) {
51724
51923
  // src/promptOptimizer.ts
51725
51924
  init_cjs_shims();
51726
51925
  var import_promises12 = __toESM(require("fs/promises"), 1);
51727
- var import_node_os11 = __toESM(require("os"), 1);
51728
- var import_node_path18 = __toESM(require("path"), 1);
51926
+ var import_node_os12 = __toESM(require("os"), 1);
51927
+ var import_node_path20 = __toESM(require("path"), 1);
51729
51928
  var logger27 = createModuleLogger("bridge.promptOptimizer");
51730
51929
  var OPTIMIZER_SYSTEM_PROMPT = `You are an expert prompt editor for AHChat Agent creation.
51731
51930
 
@@ -51768,7 +51967,7 @@ async function optimizePrompt(queryFn, opts) {
51768
51967
  const prompt = opts.systemPrompt.trim();
51769
51968
  if (!prompt) throw new Error("systemPrompt is required");
51770
51969
  const t0 = Date.now();
51771
- const cwd = opts.cwd ?? import_node_path18.default.join(import_node_os11.default.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
51970
+ const cwd = opts.cwd ?? import_node_path20.default.join(import_node_os12.default.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
51772
51971
  await import_promises12.default.mkdir(cwd, { recursive: true });
51773
51972
  const fn = queryFn ?? QA$;
51774
51973
  const ic2 = new InputController();
@@ -51856,7 +52055,7 @@ function isRunningAsRoot2() {
51856
52055
  }
51857
52056
  }
51858
52057
  async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
51859
- const rootClaudeDir = import_node_path19.default.join(process.env.HOME ?? "/root", ".claude");
52058
+ const rootClaudeDir = import_node_path21.default.join(process.env.HOME ?? "/root", ".claude");
51860
52059
  const fs16 = await import("fs/promises");
51861
52060
  try {
51862
52061
  await fs16.access(rootClaudeDir);
@@ -51866,8 +52065,8 @@ async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
51866
52065
  }
51867
52066
  const filesToSync = [".credentials.json", "settings.json", ".credentials.backup.json"];
51868
52067
  for (const file2 of filesToSync) {
51869
- const src = import_node_path19.default.join(rootClaudeDir, file2);
51870
- const dest = import_node_path19.default.join(agentConfigDir, file2);
52068
+ const src = import_node_path21.default.join(rootClaudeDir, file2);
52069
+ const dest = import_node_path21.default.join(agentConfigDir, file2);
51871
52070
  try {
51872
52071
  await fs16.copyFile(src, dest);
51873
52072
  logger28.info("Synced credential file", { file: file2, from: src, to: dest });
@@ -51890,7 +52089,7 @@ async function chownRecursive(dirPath, uid, gid) {
51890
52089
  return;
51891
52090
  }
51892
52091
  for (const entry of entries) {
51893
- const fullPath = import_node_path19.default.join(dirPath, entry.name);
52092
+ const fullPath = import_node_path21.default.join(dirPath, entry.name);
51894
52093
  if (entry.isDirectory()) {
51895
52094
  await chownRecursive(fullPath, uid, gid);
51896
52095
  } else {
@@ -51905,7 +52104,7 @@ async function chownRecursive(dirPath, uid, gid) {
51905
52104
  async function startBridge(config2) {
51906
52105
  ensureDir(config2.dataDir);
51907
52106
  ensureDir(config2.agentConfigDir);
51908
- const workspacesDir = import_node_path19.default.join(config2.dataDir, "workspaces");
52107
+ const workspacesDir = import_node_path21.default.join(config2.dataDir, "workspaces");
51909
52108
  ensureDir(workspacesDir);
51910
52109
  process.env.CLAUDE_CONFIG_DIR = config2.agentConfigDir;
51911
52110
  installBridgeFetchAuth(config2.serverApiUrl, config2.bridgeToken);
@@ -51934,7 +52133,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
51934
52133
  `);
51935
52134
  wsMetrics.start(5e3);
51936
52135
  const sessionStore = new SessionStore(config2.dataDir);
51937
- const memoryRoot = import_node_path19.default.join(config2.dataDir, "agent-memory");
52136
+ const memoryRoot = import_node_path21.default.join(config2.dataDir, "agent-memory");
51938
52137
  const memoryStore = new AgentMemoryStore(memoryRoot);
51939
52138
  logger28.info("Agent memory store initialized", { rootDir: memoryRoot });
51940
52139
  const smithNotebook = memoryStore.read(SMITH_AGENT_ID);
@@ -52111,7 +52310,16 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
52111
52310
  const { requestId, path: dirPath } = msg.payload;
52112
52311
  logger28.info("list_dir request received", { requestId, path: dirPath });
52113
52312
  try {
52114
- const entries = await listDirectoryEntries(dirPath);
52313
+ const resolved = remapServerWorkspacePath(dirPath, workspacesDir);
52314
+ if (resolved.remapped) {
52315
+ ensureDir(resolved.path);
52316
+ logger28.info("list_dir path remapped to local Bridge workspace", {
52317
+ requestId,
52318
+ requested: dirPath,
52319
+ remapped: resolved.path
52320
+ });
52321
+ }
52322
+ const entries = await listDirectoryEntries(resolved.path);
52115
52323
  connector?.send({
52116
52324
  type: "bridge:list_dir_response",
52117
52325
  payload: { requestId, entries }
@@ -52354,21 +52562,58 @@ function compactEnv(env2) {
52354
52562
 
52355
52563
  // src/protocol.ts
52356
52564
  init_cjs_shims();
52357
- var import_node_child_process3 = require("child_process");
52358
- var import_node_fs9 = __toESM(require("fs"), 1);
52359
- var import_node_os12 = __toESM(require("os"), 1);
52360
- var import_node_path20 = __toESM(require("path"), 1);
52565
+ var import_node_child_process4 = require("child_process");
52566
+ var import_node_fs10 = __toESM(require("fs"), 1);
52567
+ var import_node_os13 = __toESM(require("os"), 1);
52568
+ var import_node_path22 = __toESM(require("path"), 1);
52361
52569
  var logger29 = createModuleLogger("bridge.protocol");
52570
+ function shellSingleQuote(value) {
52571
+ return `'${value.replace(/'/g, `'\\''`)}'`;
52572
+ }
52573
+ function psSingleQuote(value) {
52574
+ return `'${value.replace(/'/g, "''")}'`;
52575
+ }
52576
+ function desktopExecQuote(value) {
52577
+ return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
52578
+ }
52579
+ function getStableCliPath() {
52580
+ return import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge", "cli.cjs");
52581
+ }
52362
52582
  function getStableExePath() {
52363
- const bridgeDir = import_node_path20.default.join(import_node_os12.default.homedir(), ".ahchat", "bridge");
52364
- import_node_fs9.default.mkdirSync(bridgeDir, { recursive: true });
52365
- const stablePath = import_node_path20.default.join(bridgeDir, "cli.cjs");
52366
- import_node_fs9.default.copyFileSync(__filename, stablePath);
52367
- if (process.platform !== "win32") import_node_fs9.default.chmodSync(stablePath, 493);
52583
+ const bridgeDir = import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge");
52584
+ import_node_fs10.default.mkdirSync(bridgeDir, { recursive: true });
52585
+ const stablePath = getStableCliPath();
52586
+ import_node_fs10.default.copyFileSync(__filename, stablePath);
52587
+ if (process.platform !== "win32") import_node_fs10.default.chmodSync(stablePath, 493);
52368
52588
  return stablePath;
52369
52589
  }
52590
+ function writePosixLauncher(bridgeDir, stableExePath) {
52591
+ const launchScriptPath = import_node_path22.default.join(bridgeDir, "launch-bridge.sh");
52592
+ const augmentedPath = buildAugmentedPath();
52593
+ import_node_fs10.default.writeFileSync(
52594
+ launchScriptPath,
52595
+ [
52596
+ "#!/bin/bash",
52597
+ "set -e",
52598
+ `export PATH=${shellSingleQuote(augmentedPath)}:"\${PATH:-}"`,
52599
+ `SAVED_NODE=${shellSingleQuote(process.execPath)}`,
52600
+ `BRIDGE_CLI=${shellSingleQuote(stableExePath)}`,
52601
+ 'NODE_BIN=""',
52602
+ 'if [ -x "$SAVED_NODE" ]; then NODE_BIN="$SAVED_NODE"; fi',
52603
+ 'if [ -z "$NODE_BIN" ]; then NODE_BIN="$(command -v node || true)"; fi',
52604
+ 'if [ -z "$NODE_BIN" ]; then',
52605
+ ` echo "Node.js ${MIN_NODE_MAJOR}+ is required to launch AHChat Bridge. Install Node, then rerun: npx -y @fangyb/ahchat-bridge install" >&2`,
52606
+ " exit 1",
52607
+ "fi",
52608
+ 'exec "$NODE_BIN" "$BRIDGE_CLI" launch --url "$1"',
52609
+ ""
52610
+ ].join("\n")
52611
+ );
52612
+ import_node_fs10.default.chmodSync(launchScriptPath, 493);
52613
+ return launchScriptPath;
52614
+ }
52370
52615
  function registerProtocolHandler() {
52371
- const platform = import_node_os12.default.platform();
52616
+ const platform = import_node_os13.default.platform();
52372
52617
  if (platform === "win32") {
52373
52618
  registerWindows();
52374
52619
  } else if (platform === "darwin") {
@@ -52381,22 +52626,42 @@ function registerProtocolHandler() {
52381
52626
  function registerWindows() {
52382
52627
  const nodeExe = process.execPath;
52383
52628
  const stableExePath = getStableExePath();
52384
- const bridgeDir = import_node_path20.default.join(import_node_os12.default.homedir(), ".ahchat", "bridge");
52385
- const psLauncherPath = import_node_path20.default.join(bridgeDir, "launch-bridge.ps1");
52386
- import_node_fs9.default.writeFileSync(
52629
+ const bridgeDir = import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge");
52630
+ const augmentedPath = buildAugmentedPath();
52631
+ const psLauncherPath = import_node_path22.default.join(bridgeDir, "launch-bridge.ps1");
52632
+ import_node_fs10.default.writeFileSync(
52387
52633
  psLauncherPath,
52388
52634
  [
52389
52635
  `param([string]$url)`,
52390
- `& '${nodeExe.replace(/'/g, "''")}' '${stableExePath.replace(/'/g, "''")}' launch --url $url`
52636
+ `$env:PATH = ${psSingleQuote(augmentedPath)} + [System.IO.Path]::PathSeparator + $env:PATH`,
52637
+ `$candidates = @(`,
52638
+ ` ${psSingleQuote(nodeExe)},`,
52639
+ ` "$env:NVM_SYMLINK\\node.exe",`,
52640
+ ` "$env:ProgramFiles\\nodejs\\node.exe",`,
52641
+ ` "$env:LOCALAPPDATA\\Programs\\nodejs\\node.exe"`,
52642
+ `)`,
52643
+ `$node = $null`,
52644
+ `foreach ($candidate in $candidates) {`,
52645
+ ` if ($candidate -and (Test-Path $candidate)) { $node = $candidate; break }`,
52646
+ `}`,
52647
+ `if (-not $node) {`,
52648
+ ` $cmd = Get-Command node -ErrorAction SilentlyContinue`,
52649
+ ` if ($cmd) { $node = $cmd.Source }`,
52650
+ `}`,
52651
+ `if (-not $node) {`,
52652
+ ` Write-Error 'Node.js ${MIN_NODE_MAJOR}+ is required to launch AHChat Bridge. Install Node, then rerun: npx -y @fangyb/ahchat-bridge install'`,
52653
+ ` exit 1`,
52654
+ `}`,
52655
+ `& $node ${psSingleQuote(stableExePath)} launch --url $url`
52391
52656
  ].join("\r\n")
52392
52657
  );
52393
52658
  const handlerValue = `powershell -ExecutionPolicy Bypass -File "${psLauncherPath}" -url "%1"`;
52394
- const psRegisterPath = import_node_path20.default.join(bridgeDir, "register-protocol.ps1");
52395
- import_node_fs9.default.writeFileSync(
52659
+ const psRegisterPath = import_node_path22.default.join(bridgeDir, "register-protocol.ps1");
52660
+ import_node_fs10.default.writeFileSync(
52396
52661
  psRegisterPath,
52397
52662
  [
52398
- `$handler = '${handlerValue.replace(/'/g, "''")}'`,
52399
- `$icon = '${nodeExe.replace(/'/g, "''")}'`,
52663
+ `$handler = ${psSingleQuote(handlerValue)}`,
52664
+ `$icon = ${psSingleQuote(nodeExe)}`,
52400
52665
  `New-Item -Path 'HKCU:\\Software\\Classes\\ahchat' -Force | Out-Null`,
52401
52666
  `Set-ItemProperty -Path 'HKCU:\\Software\\Classes\\ahchat' -Name '(Default)' -Value 'URL:ahchat' -Force`,
52402
52667
  `New-ItemProperty -Path 'HKCU:\\Software\\Classes\\ahchat' -Name 'URL Protocol' -Value '' -PropertyType String -Force | Out-Null`,
@@ -52407,7 +52672,7 @@ function registerWindows() {
52407
52672
  ].join("\r\n")
52408
52673
  );
52409
52674
  try {
52410
- (0, import_node_child_process3.execSync)(`powershell -ExecutionPolicy Bypass -File "${psRegisterPath}"`, { stdio: "pipe" });
52675
+ (0, import_node_child_process4.execSync)(`powershell -ExecutionPolicy Bypass -File "${psRegisterPath}"`, { stdio: "pipe" });
52411
52676
  } catch (e7) {
52412
52677
  logger29.error("Failed to register Windows protocol handler", { error: e7 });
52413
52678
  throw new Error("Failed to register Windows protocol handler");
@@ -52415,18 +52680,10 @@ function registerWindows() {
52415
52680
  logger29.info("Windows protocol handler registered", { psLauncherPath });
52416
52681
  }
52417
52682
  function registerMacOS() {
52418
- const appDir = import_node_path20.default.join(import_node_os12.default.homedir(), "Applications", "AHChatBridge.app");
52419
- const nodeExe = process.execPath;
52683
+ const appDir = import_node_path22.default.join(import_node_os13.default.homedir(), "Applications", "AHChatBridge.app");
52420
52684
  const stableExePath = getStableExePath();
52421
- const bridgeDir = import_node_path20.default.join(import_node_os12.default.homedir(), ".ahchat", "bridge");
52422
- const launchScriptPath = import_node_path20.default.join(bridgeDir, "launch-bridge.sh");
52423
- import_node_fs9.default.writeFileSync(
52424
- launchScriptPath,
52425
- `#!/bin/bash
52426
- exec ${JSON.stringify(nodeExe)} ${JSON.stringify(stableExePath)} launch --url "$1"
52427
- `
52428
- );
52429
- import_node_fs9.default.chmodSync(launchScriptPath, 493);
52685
+ const bridgeDir = import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge");
52686
+ const launchScriptPath = writePosixLauncher(bridgeDir, stableExePath);
52430
52687
  const escapedScriptPath = launchScriptPath.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
52431
52688
  const appleScript = [
52432
52689
  `on open location thisURL`,
@@ -52434,29 +52691,29 @@ exec ${JSON.stringify(nodeExe)} ${JSON.stringify(stableExePath)} launch --url "$
52434
52691
  ` do shell script "/bin/bash " & (quoted form of launchScript) & " " & (quoted form of thisURL) & " >/tmp/ahchat-bridge.log 2>&1 &"`,
52435
52692
  `end open location`
52436
52693
  ].join("\n");
52437
- const tmpScript = import_node_path20.default.join(import_node_os12.default.tmpdir(), "AHChatBridge.applescript");
52438
- import_node_fs9.default.writeFileSync(tmpScript, appleScript);
52694
+ const tmpScript = import_node_path22.default.join(import_node_os13.default.tmpdir(), "AHChatBridge.applescript");
52695
+ import_node_fs10.default.writeFileSync(tmpScript, appleScript);
52439
52696
  try {
52440
- import_node_fs9.default.rmSync(appDir, { recursive: true, force: true });
52697
+ import_node_fs10.default.rmSync(appDir, { recursive: true, force: true });
52441
52698
  } catch {
52442
52699
  }
52443
52700
  try {
52444
- (0, import_node_child_process3.execSync)(`osacompile -o ${JSON.stringify(appDir)} ${JSON.stringify(tmpScript)}`, { stdio: "pipe" });
52701
+ (0, import_node_child_process4.execSync)(`osacompile -o ${JSON.stringify(appDir)} ${JSON.stringify(tmpScript)}`, { stdio: "pipe" });
52445
52702
  } finally {
52446
52703
  try {
52447
- import_node_fs9.default.unlinkSync(tmpScript);
52704
+ import_node_fs10.default.unlinkSync(tmpScript);
52448
52705
  } catch {
52449
52706
  }
52450
52707
  }
52451
- const plistPath = import_node_path20.default.join(appDir, "Contents", "Info.plist");
52708
+ const plistPath = import_node_path22.default.join(appDir, "Contents", "Info.plist");
52452
52709
  const urlTypes = JSON.stringify([{ CFBundleURLName: "AHChat Bridge", CFBundleURLSchemes: ["ahchat"] }]);
52453
- (0, import_node_child_process3.execSync)(
52710
+ (0, import_node_child_process4.execSync)(
52454
52711
  `/usr/bin/plutil -insert CFBundleURLTypes -json ${JSON.stringify(urlTypes)} ${JSON.stringify(plistPath)}`,
52455
52712
  { stdio: "pipe" }
52456
52713
  );
52457
52714
  const lsregister = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister";
52458
52715
  try {
52459
- (0, import_node_child_process3.execSync)(`${lsregister} -f ${JSON.stringify(appDir)}`, { stdio: "pipe" });
52716
+ (0, import_node_child_process4.execSync)(`${lsregister} -f ${JSON.stringify(appDir)}`, { stdio: "pipe" });
52460
52717
  } catch (e7) {
52461
52718
  logger29.warn("lsregister failed; URL scheme registration may be delayed", { error: e7 });
52462
52719
  }
@@ -52464,36 +52721,38 @@ exec ${JSON.stringify(nodeExe)} ${JSON.stringify(stableExePath)} launch --url "$
52464
52721
  }
52465
52722
  function registerLinux() {
52466
52723
  const stableExePath = getStableExePath();
52724
+ const bridgeDir = import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge");
52725
+ const launchScriptPath = writePosixLauncher(bridgeDir, stableExePath);
52467
52726
  const desktopFile = [
52468
52727
  `[Desktop Entry]`,
52469
52728
  `Name=AHChat Bridge`,
52470
- `Exec=${process.execPath} ${stableExePath} launch --url %u`,
52729
+ `Exec=${desktopExecQuote(launchScriptPath)} %u`,
52471
52730
  `Type=Application`,
52472
52731
  `NoDisplay=true`,
52473
52732
  `MimeType=x-scheme-handler/ahchat;`
52474
52733
  ].join("\n");
52475
- const desktopPath = import_node_path20.default.join(import_node_os12.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52476
- import_node_fs9.default.mkdirSync(import_node_path20.default.dirname(desktopPath), { recursive: true });
52477
- import_node_fs9.default.writeFileSync(desktopPath, desktopFile);
52734
+ const desktopPath = import_node_path22.default.join(import_node_os13.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52735
+ import_node_fs10.default.mkdirSync(import_node_path22.default.dirname(desktopPath), { recursive: true });
52736
+ import_node_fs10.default.writeFileSync(desktopPath, desktopFile);
52478
52737
  try {
52479
- (0, import_node_child_process3.execSync)("update-desktop-database ~/.local/share/applications/", { stdio: "pipe" });
52738
+ (0, import_node_child_process4.execSync)("update-desktop-database ~/.local/share/applications/", { stdio: "pipe" });
52480
52739
  } catch (e7) {
52481
52740
  logger29.warn("update-desktop-database not available; run it manually if needed", { error: e7 });
52482
52741
  }
52483
52742
  logger29.info("Linux protocol handler registered", { desktopPath });
52484
52743
  }
52485
52744
  function unregisterProtocolHandler() {
52486
- const platform = import_node_os12.default.platform();
52745
+ const platform = import_node_os13.default.platform();
52487
52746
  if (platform === "win32") {
52488
52747
  try {
52489
- (0, import_node_child_process3.execSync)(
52748
+ (0, import_node_child_process4.execSync)(
52490
52749
  `powershell -ExecutionPolicy Bypass -Command "Remove-Item -Path 'HKCU:\\Software\\Classes\\ahchat' -Recurse -Force -ErrorAction SilentlyContinue"`,
52491
52750
  { stdio: "pipe" }
52492
52751
  );
52493
- const bridgeDir = import_node_path20.default.join(import_node_os12.default.homedir(), ".ahchat", "bridge");
52752
+ const bridgeDir = import_node_path22.default.join(import_node_os13.default.homedir(), ".ahchat", "bridge");
52494
52753
  for (const f7 of ["launch-bridge.ps1", "register-protocol.ps1"]) {
52495
52754
  try {
52496
- import_node_fs9.default.unlinkSync(import_node_path20.default.join(bridgeDir, f7));
52755
+ import_node_fs10.default.unlinkSync(import_node_path22.default.join(bridgeDir, f7));
52497
52756
  } catch {
52498
52757
  }
52499
52758
  }
@@ -52502,17 +52761,17 @@ function unregisterProtocolHandler() {
52502
52761
  logger29.warn("Failed to unregister Windows protocol handler", { error: e7 });
52503
52762
  }
52504
52763
  } else if (platform === "darwin") {
52505
- const appDir = import_node_path20.default.join(import_node_os12.default.homedir(), "Applications", "AHChatBridge.app");
52764
+ const appDir = import_node_path22.default.join(import_node_os13.default.homedir(), "Applications", "AHChatBridge.app");
52506
52765
  try {
52507
- import_node_fs9.default.rmSync(appDir, { recursive: true, force: true });
52766
+ import_node_fs10.default.rmSync(appDir, { recursive: true, force: true });
52508
52767
  logger29.info("macOS protocol handler unregistered");
52509
52768
  } catch (e7) {
52510
52769
  logger29.warn("Failed to unregister macOS protocol handler", { error: e7 });
52511
52770
  }
52512
52771
  } else {
52513
- const desktopPath = import_node_path20.default.join(import_node_os12.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52772
+ const desktopPath = import_node_path22.default.join(import_node_os13.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52514
52773
  try {
52515
- import_node_fs9.default.unlinkSync(desktopPath);
52774
+ import_node_fs10.default.unlinkSync(desktopPath);
52516
52775
  logger29.info("Linux protocol handler unregistered");
52517
52776
  } catch (e7) {
52518
52777
  logger29.warn("Failed to unregister Linux protocol handler", { error: e7 });
@@ -52520,20 +52779,21 @@ function unregisterProtocolHandler() {
52520
52779
  }
52521
52780
  }
52522
52781
  function isProtocolRegistered() {
52523
- const platform = import_node_os12.default.platform();
52782
+ const platform = import_node_os13.default.platform();
52783
+ const stableCliExists = import_node_fs10.default.existsSync(getStableCliPath());
52524
52784
  if (platform === "win32") {
52525
52785
  try {
52526
- (0, import_node_child_process3.execSync)('REG QUERY "HKCU\\Software\\Classes\\ahchat" /ve', { stdio: "pipe" });
52527
- return true;
52786
+ (0, import_node_child_process4.execSync)('REG QUERY "HKCU\\Software\\Classes\\ahchat" /ve', { stdio: "pipe" });
52787
+ return stableCliExists;
52528
52788
  } catch {
52529
52789
  return false;
52530
52790
  }
52531
52791
  } else if (platform === "darwin") {
52532
- const appDir = import_node_path20.default.join(import_node_os12.default.homedir(), "Applications", "AHChatBridge.app");
52533
- return import_node_fs9.default.existsSync(import_node_path20.default.join(appDir, "Contents", "Info.plist"));
52792
+ const appDir = import_node_path22.default.join(import_node_os13.default.homedir(), "Applications", "AHChatBridge.app");
52793
+ return stableCliExists && import_node_fs10.default.existsSync(import_node_path22.default.join(appDir, "Contents", "Info.plist"));
52534
52794
  } else {
52535
- const desktopPath = import_node_path20.default.join(import_node_os12.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52536
- return import_node_fs9.default.existsSync(desktopPath);
52795
+ const desktopPath = import_node_path22.default.join(import_node_os13.default.homedir(), ".local", "share", "applications", "ahchat-bridge.desktop");
52796
+ return stableCliExists && import_node_fs10.default.existsSync(desktopPath);
52537
52797
  }
52538
52798
  }
52539
52799
 
@@ -52541,14 +52801,14 @@ function isProtocolRegistered() {
52541
52801
  var logger30 = createModuleLogger("bridge");
52542
52802
  function readCliVersion() {
52543
52803
  const candidates = [
52544
- import_node_path21.default.resolve(__dirname, "../package.json"),
52545
- import_node_path21.default.resolve(__dirname, "../../package.json"),
52546
- import_node_path21.default.resolve(process.cwd(), "packages/bridge/package.json")
52804
+ import_node_path23.default.resolve(__dirname, "../package.json"),
52805
+ import_node_path23.default.resolve(__dirname, "../../package.json"),
52806
+ import_node_path23.default.resolve(process.cwd(), "packages/bridge/package.json")
52547
52807
  ];
52548
52808
  for (const candidate of candidates) {
52549
- if (!import_node_fs10.default.existsSync(candidate)) continue;
52809
+ if (!import_node_fs11.default.existsSync(candidate)) continue;
52550
52810
  try {
52551
- const parsed = JSON.parse(import_node_fs10.default.readFileSync(candidate, "utf8"));
52811
+ const parsed = JSON.parse(import_node_fs11.default.readFileSync(candidate, "utf8"));
52552
52812
  if (parsed && typeof parsed === "object" && "version" in parsed && typeof parsed.version === "string" && parsed.version.length > 0) {
52553
52813
  return parsed.version;
52554
52814
  }
@@ -52556,26 +52816,7 @@ function readCliVersion() {
52556
52816
  logger30.warn("Unable to read CLI package version candidate", { error: e7, candidate });
52557
52817
  }
52558
52818
  }
52559
- return "0.1.20";
52560
- }
52561
- function resolveDataDir(dataDir) {
52562
- const userHome = process.env.USERPROFILE || import_node_os13.default.homedir();
52563
- if (/^~[/\\]/.test(dataDir)) {
52564
- return import_node_path21.default.join(import_node_os13.default.homedir(), dataDir.slice(2));
52565
- }
52566
- if (dataDir === "$env:USERPROFILE") {
52567
- return userHome;
52568
- }
52569
- if (dataDir.startsWith("$env:USERPROFILE\\") || dataDir.startsWith("$env:USERPROFILE/")) {
52570
- return import_node_path21.default.join(userHome, dataDir.slice("$env:USERPROFILE".length + 1));
52571
- }
52572
- if (dataDir === "%USERPROFILE%") {
52573
- return userHome;
52574
- }
52575
- if (dataDir.startsWith("%USERPROFILE%\\") || dataDir.startsWith("%USERPROFILE%/")) {
52576
- return import_node_path21.default.join(userHome, dataDir.slice("%USERPROFILE%".length + 1));
52577
- }
52578
- return dataDir;
52819
+ return "0.1.21";
52579
52820
  }
52580
52821
  function parseAhchatUrl(url2) {
52581
52822
  try {
@@ -52590,22 +52831,97 @@ function parseAhchatUrl(url2) {
52590
52831
  const token = decodeURIComponent(rest.slice(lastTilde + 1));
52591
52832
  if (!serverUrl || !token) return null;
52592
52833
  return { serverUrl, token };
52593
- } catch {
52834
+ } catch (e7) {
52835
+ logger30.warn("Unable to parse ahchat launch URL", { error: e7 });
52594
52836
  return null;
52595
52837
  }
52596
52838
  }
52839
+ function assertSupportedNode() {
52840
+ const status = getNodeRuntimeStatus();
52841
+ if (status.supported) return;
52842
+ throw new Error(
52843
+ `Node.js ${MIN_NODE_MAJOR}+ is required to run AHChat Bridge. Current version: ${status.version}`
52844
+ );
52845
+ }
52597
52846
  async function run(args) {
52598
- const dataDir = args.dataDir ? resolveDataDir(args.dataDir) : void 0;
52847
+ assertSupportedNode();
52848
+ process.env.PATH = buildAugmentedPath();
52849
+ const dataDir = args.dataDir ? resolveUserPath(args.dataDir) : void 0;
52599
52850
  let config2 = loadBridgeConfig(dataDir ? { dataDir } : void 0);
52600
52851
  if (args.serverUrl) {
52601
- const wsUrl = new URL(args.serverUrl);
52602
- const httpBase = `${wsUrl.protocol === "wss:" ? "https" : "http"}://${wsUrl.host}`;
52603
- config2 = { ...config2, serverUrl: args.serverUrl, serverApiUrl: httpBase };
52852
+ const urls = normalizeBridgeServerUrls(args.serverUrl);
52853
+ config2 = { ...config2, serverUrl: urls.serverUrl, serverApiUrl: urls.serverApiUrl };
52604
52854
  }
52605
52855
  if (args.token) config2 = { ...config2, bridgeToken: args.token };
52606
52856
  if (args.logLevel) config2 = { ...config2, logLevel: args.logLevel };
52607
52857
  await startBridge(config2);
52608
52858
  }
52859
+ function buildDoctorReport(args) {
52860
+ process.env.PATH = buildAugmentedPath();
52861
+ const node = getNodeRuntimeStatus();
52862
+ let server = null;
52863
+ if (args.serverUrl) {
52864
+ try {
52865
+ server = { ok: true, ...normalizeBridgeServerUrls(args.serverUrl) };
52866
+ } catch (e7) {
52867
+ server = {
52868
+ ok: false,
52869
+ error: e7 instanceof Error ? e7.message : String(e7)
52870
+ };
52871
+ }
52872
+ }
52873
+ const claude = resolveCommand(["claude", "anthropic-cli"]);
52874
+ return {
52875
+ node,
52876
+ npm: probeCommand("npm"),
52877
+ npx: probeCommand("npx"),
52878
+ claude: claude ? { ok: true, name: claude.name, path: claude.path } : { ok: false, name: "claude", message: "claude was not found on PATH" },
52879
+ dataDir: args.dataDir ? resolveUserPath(args.dataDir) : resolveUserPath("~/.ahchat"),
52880
+ server,
52881
+ tokenProvided: Boolean(args.token),
52882
+ pathPreview: (process.env.PATH ?? "").split(import_node_path23.default.delimiter).slice(0, 12)
52883
+ };
52884
+ }
52885
+ function writeDoctorText(report) {
52886
+ const node = report.node;
52887
+ const npm = report.npm;
52888
+ const npx = report.npx;
52889
+ const claude = report.claude;
52890
+ const server = report.server;
52891
+ const lines = [
52892
+ "AHChat Bridge doctor",
52893
+ `- Node: ${node.supported ? "ok" : "error"} (${node.version}, requires >=${MIN_NODE_MAJOR})`,
52894
+ `- npm: ${npm.ok ? `ok (${npm.version ?? npm.path})` : `missing (${npm.message ?? "not found"})`}`,
52895
+ `- npx: ${npx.ok ? `ok (${npx.version ?? npx.path})` : `missing (${npx.message ?? "not found"})`}`,
52896
+ `- Claude CLI: ${claude.ok ? `ok (${claude.path})` : `missing (${claude.message ?? "not found"})`}`,
52897
+ `- Data dir: ${String(report.dataDir)}`,
52898
+ `- Token: ${report.tokenProvided ? "provided" : "not provided"}`
52899
+ ];
52900
+ if (server) {
52901
+ lines.push(
52902
+ server.ok ? `- Server: ok (${server.serverUrl}, api ${server.serverApiUrl})` : `- Server: error (${server.error ?? "invalid URL"})`
52903
+ );
52904
+ }
52905
+ if (!node.supported) {
52906
+ lines.push(`
52907
+ Install Node.js ${MIN_NODE_MAJOR}+ first, then rerun the bridge command.`);
52908
+ } else if (!npm.ok || !npx.ok) {
52909
+ lines.push("\nNode is installed, but npm/npx is not available on PATH. Reinstall Node.js or fix PATH.");
52910
+ } else if (!claude.ok) {
52911
+ lines.push("\nClaude Code CLI is missing. The bridge can try to install it on first run with npm.");
52912
+ }
52913
+ process.stdout.write(`${lines.join("\n")}
52914
+ `);
52915
+ }
52916
+ function doctor(args) {
52917
+ const report = buildDoctorReport(args);
52918
+ if (args.json) {
52919
+ process.stdout.write(`${JSON.stringify(report, null, 2)}
52920
+ `);
52921
+ return;
52922
+ }
52923
+ writeDoctorText(report);
52924
+ }
52609
52925
  var cli = dist_default("ahchat-bridge");
52610
52926
  cli.command("run", "Start the bridge and connect to server").option("--server-url <url>", "WebSocket URL of the AHChat server").option("--token <token>", "Auth token for server registration").option("--data-dir <dir>", "Data directory (default: ~/.ahchat)").option("--log-level <level>", "Log level (default: INFO)").action((args) => {
52611
52927
  void run(args).catch((e7) => {
@@ -52613,6 +52929,9 @@ cli.command("run", "Start the bridge and connect to server").option("--server-ur
52613
52929
  process.exit(1);
52614
52930
  });
52615
52931
  });
52932
+ cli.command("doctor", "Check Node, npm, Claude CLI, PATH, and bridge launch options").option("--server-url <url>", "WebSocket URL of the AHChat server").option("--token <token>", "Auth token for server registration").option("--data-dir <dir>", "Data directory (default: ~/.ahchat)").option("--json", "Print machine-readable JSON").action((args) => {
52933
+ doctor(args);
52934
+ });
52616
52935
  cli.command("launch", "Launch bridge from ahchat:// URL (called by OS)").option("--url <url>", "ahchat:// URL with server and token params").action((args) => {
52617
52936
  const parsed = parseAhchatUrl(args.url);
52618
52937
  if (!parsed) {