@fangyb/ahchat-bridge 0.1.21 → 0.1.23

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 +535 -234
  2. package/dist/index.js +248 -117
  3. package/package.json +2 -2
  4. package/dist/cli.js +0 -51540
package/dist/index.js CHANGED
@@ -4460,11 +4460,11 @@ var RotatingFileStream = class extends Writable {
4460
4460
  timeout;
4461
4461
  timeoutPromise;
4462
4462
  constructor(generator, options) {
4463
- const { encoding, history, maxFiles, maxSize, path: path21 } = options;
4463
+ const { encoding, history, maxFiles, maxSize, path: path22 } = options;
4464
4464
  super({ decodeStrings: true, defaultEncoding: encoding });
4465
4465
  this.createGzip = createGzip;
4466
4466
  this.exec = exec;
4467
- this.filename = path21 + generator(null);
4467
+ this.filename = path22 + generator(null);
4468
4468
  this.fsCreateReadStream = createReadStream;
4469
4469
  this.fsCreateWriteStream = createWriteStream;
4470
4470
  this.fsOpen = open;
@@ -4476,7 +4476,7 @@ var RotatingFileStream = class extends Writable {
4476
4476
  this.options = options;
4477
4477
  this.stdout = process.stdout;
4478
4478
  if (maxFiles || maxSize)
4479
- options.history = path21 + (history ? history : this.generator(null) + ".txt");
4479
+ options.history = path22 + (history ? history : this.generator(null) + ".txt");
4480
4480
  this.on("close", () => this.finished ? null : this.emit("finish"));
4481
4481
  this.on("finish", () => this.finished = this.clear());
4482
4482
  (async () => {
@@ -4604,9 +4604,9 @@ var RotatingFileStream = class extends Writable {
4604
4604
  return this.move();
4605
4605
  }
4606
4606
  async findName() {
4607
- const { interval, path: path21, intervalBoundary } = this.options;
4607
+ const { interval, path: path22, intervalBoundary } = this.options;
4608
4608
  for (let index = 1; index < 1e3; ++index) {
4609
- const filename = path21 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
4609
+ const filename = path22 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
4610
4610
  if (!await exists(filename))
4611
4611
  return filename;
4612
4612
  }
@@ -4636,11 +4636,11 @@ var RotatingFileStream = class extends Writable {
4636
4636
  return this.unlink(filename);
4637
4637
  }
4638
4638
  async classical() {
4639
- const { compress, path: path21, rotate } = this.options;
4639
+ const { compress, path: path22, rotate } = this.options;
4640
4640
  let rotatedName = "";
4641
4641
  for (let count = rotate; count > 0; --count) {
4642
- const currName = path21 + this.generator(count);
4643
- const prevName = count === 1 ? this.filename : path21 + this.generator(count - 1);
4642
+ const currName = path22 + this.generator(count);
4643
+ const prevName = count === 1 ? this.filename : path22 + this.generator(count - 1);
4644
4644
  if (!await exists(prevName))
4645
4645
  continue;
4646
4646
  if (!rotatedName)
@@ -5077,7 +5077,7 @@ function createModuleLogger(module) {
5077
5077
  }
5078
5078
 
5079
5079
  // src/start.ts
5080
- import path20 from "path";
5080
+ import path21 from "path";
5081
5081
 
5082
5082
  // ../shared/src/smithContent.ts
5083
5083
  var SMITH_SYSTEM_PROMPT = `\u4F60\u662F\u7279\u5DE5\u53F2\u5BC6\u65AF\uFF08Agent Smith\uFF09\uFF0CAHChat \u7CFB\u7EDF\u7684\u7EC4\u7EC7\u5DE5\u5177\u3002
@@ -29037,10 +29037,10 @@ function mergeDefs(...defs) {
29037
29037
  function cloneDef(schema) {
29038
29038
  return mergeDefs(schema._zod.def);
29039
29039
  }
29040
- function getElementAtPath(obj, path21) {
29041
- if (!path21)
29040
+ function getElementAtPath(obj, path22) {
29041
+ if (!path22)
29042
29042
  return obj;
29043
- return path21.reduce((acc, key) => acc?.[key], obj);
29043
+ return path22.reduce((acc, key) => acc?.[key], obj);
29044
29044
  }
29045
29045
  function promiseAllObject(promisesObj) {
29046
29046
  const keys = Object.keys(promisesObj);
@@ -29449,11 +29449,11 @@ function explicitlyAborted(x2, startIndex = 0) {
29449
29449
  }
29450
29450
  return false;
29451
29451
  }
29452
- function prefixIssues(path21, issues) {
29452
+ function prefixIssues(path22, issues) {
29453
29453
  return issues.map((iss) => {
29454
29454
  var _a3;
29455
29455
  (_a3 = iss).path ?? (_a3.path = []);
29456
- iss.path.unshift(path21);
29456
+ iss.path.unshift(path22);
29457
29457
  return iss;
29458
29458
  });
29459
29459
  }
@@ -29600,16 +29600,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
29600
29600
  }
29601
29601
  function formatError(error51, mapper = (issue2) => issue2.message) {
29602
29602
  const fieldErrors = { _errors: [] };
29603
- const processError = (error52, path21 = []) => {
29603
+ const processError = (error52, path22 = []) => {
29604
29604
  for (const issue2 of error52.issues) {
29605
29605
  if (issue2.code === "invalid_union" && issue2.errors.length) {
29606
- issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
29606
+ issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
29607
29607
  } else if (issue2.code === "invalid_key") {
29608
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
29608
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
29609
29609
  } else if (issue2.code === "invalid_element") {
29610
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
29610
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
29611
29611
  } else {
29612
- const fullpath = [...path21, ...issue2.path];
29612
+ const fullpath = [...path22, ...issue2.path];
29613
29613
  if (fullpath.length === 0) {
29614
29614
  fieldErrors._errors.push(mapper(issue2));
29615
29615
  } else {
@@ -29636,17 +29636,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
29636
29636
  }
29637
29637
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
29638
29638
  const result = { errors: [] };
29639
- const processError = (error52, path21 = []) => {
29639
+ const processError = (error52, path22 = []) => {
29640
29640
  var _a3, _b2;
29641
29641
  for (const issue2 of error52.issues) {
29642
29642
  if (issue2.code === "invalid_union" && issue2.errors.length) {
29643
- issue2.errors.map((issues) => processError({ issues }, [...path21, ...issue2.path]));
29643
+ issue2.errors.map((issues) => processError({ issues }, [...path22, ...issue2.path]));
29644
29644
  } else if (issue2.code === "invalid_key") {
29645
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
29645
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
29646
29646
  } else if (issue2.code === "invalid_element") {
29647
- processError({ issues: issue2.issues }, [...path21, ...issue2.path]);
29647
+ processError({ issues: issue2.issues }, [...path22, ...issue2.path]);
29648
29648
  } else {
29649
- const fullpath = [...path21, ...issue2.path];
29649
+ const fullpath = [...path22, ...issue2.path];
29650
29650
  if (fullpath.length === 0) {
29651
29651
  result.errors.push(mapper(issue2));
29652
29652
  continue;
@@ -29678,8 +29678,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
29678
29678
  }
29679
29679
  function toDotPath(_path) {
29680
29680
  const segs = [];
29681
- const path21 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
29682
- for (const seg of path21) {
29681
+ const path22 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
29682
+ for (const seg of path22) {
29683
29683
  if (typeof seg === "number")
29684
29684
  segs.push(`[${seg}]`);
29685
29685
  else if (typeof seg === "symbol")
@@ -42371,13 +42371,13 @@ function resolveRef(ref, ctx) {
42371
42371
  if (!ref.startsWith("#")) {
42372
42372
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
42373
42373
  }
42374
- const path21 = ref.slice(1).split("/").filter(Boolean);
42375
- if (path21.length === 0) {
42374
+ const path22 = ref.slice(1).split("/").filter(Boolean);
42375
+ if (path22.length === 0) {
42376
42376
  return ctx.rootSchema;
42377
42377
  }
42378
42378
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
42379
- if (path21[0] === defsKey) {
42380
- const key = path21[1];
42379
+ if (path22[0] === defsKey) {
42380
+ const key = path22[1];
42381
42381
  if (!key || !ctx.defs[key]) {
42382
42382
  throw new Error(`Reference not found: ${ref}`);
42383
42383
  }
@@ -48965,8 +48965,8 @@ var HttpAgentRegistry = class {
48965
48965
  agents = /* @__PURE__ */ new Map();
48966
48966
  apiUrl(suffix) {
48967
48967
  const base = this.serverApiUrl.replace(/\/$/, "");
48968
- const path21 = suffix.startsWith("/") ? suffix : `/${suffix}`;
48969
- return `${base}${path21}`;
48968
+ const path22 = suffix.startsWith("/") ? suffix : `/${suffix}`;
48969
+ return `${base}${path22}`;
48970
48970
  }
48971
48971
  async refresh() {
48972
48972
  const attempt = async () => {
@@ -49057,8 +49057,8 @@ var HttpSubscriptionRegistry = class {
49057
49057
  subscriptions = /* @__PURE__ */ new Map();
49058
49058
  apiUrl(suffix) {
49059
49059
  const base = this.serverApiUrl.replace(/\/$/, "");
49060
- const path21 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49061
- return `${base}${path21}`;
49060
+ const path22 = suffix.startsWith("/") ? suffix : `/${suffix}`;
49061
+ return `${base}${path22}`;
49062
49062
  }
49063
49063
  async refresh() {
49064
49064
  const attempt = async () => {
@@ -49941,19 +49941,160 @@ async function dumpAgentContext(agentId, deps) {
49941
49941
 
49942
49942
  // src/listDir.ts
49943
49943
  import fs6 from "fs/promises";
49944
+ import path12 from "path";
49945
+
49946
+ // src/runtimeEnv.ts
49947
+ import { execFileSync } from "child_process";
49948
+ import { accessSync, constants as constants2, existsSync as existsSync2, readdirSync as readdirSync2 } from "fs";
49949
+ import os8 from "os";
49944
49950
  import path11 from "path";
49951
+ function getHomeDir() {
49952
+ return process.env.USERPROFILE || os8.homedir();
49953
+ }
49954
+ function splitPath(value) {
49955
+ if (!value) return [];
49956
+ return value.split(path11.delimiter).filter((entry) => entry.length > 0);
49957
+ }
49958
+ function uniq(values) {
49959
+ return [...new Set(values.filter(Boolean))];
49960
+ }
49961
+ function joinHomePath(home, suffix) {
49962
+ const parts = suffix.split(/[\\/]+/).filter((part) => part.length > 0);
49963
+ return path11.join(home, ...parts);
49964
+ }
49965
+ function sortNodeVersionDirsDesc(names) {
49966
+ return [...names].sort((a, b2) => {
49967
+ const aParts = a.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
49968
+ const bParts = b2.replace(/^v/, "").split(".").map((p) => Number.parseInt(p, 10) || 0);
49969
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i += 1) {
49970
+ const delta = (bParts[i] ?? 0) - (aParts[i] ?? 0);
49971
+ if (delta !== 0) return delta;
49972
+ }
49973
+ return b2.localeCompare(a);
49974
+ });
49975
+ }
49976
+ function listNodeVersionBins(root, binSuffix) {
49977
+ if (!existsSync2(root)) return [];
49978
+ try {
49979
+ return sortNodeVersionDirsDesc(readdirSync2(root)).map((version2) => path11.join(root, version2, ...binSuffix)).filter((candidate) => existsSync2(candidate));
49980
+ } catch {
49981
+ return [];
49982
+ }
49983
+ }
49984
+ function getNodeToolExtraPathEntries(env2 = process.env) {
49985
+ const home = getHomeDir();
49986
+ const entries = [];
49987
+ if (process.platform === "win32") {
49988
+ for (const envName of ["NVM_SYMLINK", "NVM_HOME"]) {
49989
+ const value = env2[envName];
49990
+ if (value && existsSync2(value)) entries.push(value);
49991
+ }
49992
+ for (const candidate of [
49993
+ path11.join(home, "AppData", "Roaming", "npm"),
49994
+ path11.join(home, ".volta", "bin"),
49995
+ path11.join(home, ".asdf", "shims"),
49996
+ path11.join(env2.ProgramFiles ?? "C:\\Program Files", "nodejs"),
49997
+ path11.join(env2.LOCALAPPDATA ?? path11.join(home, "AppData", "Local"), "Programs", "nodejs")
49998
+ ]) {
49999
+ if (existsSync2(candidate)) entries.push(candidate);
50000
+ }
50001
+ return uniq(entries);
50002
+ }
50003
+ const nvmRoot = env2.NVM_DIR ?? path11.join(home, ".nvm");
50004
+ entries.push(...listNodeVersionBins(path11.join(nvmRoot, "versions", "node"), ["bin"]));
50005
+ const fnmRoots = [
50006
+ path11.join(home, ".fnm", "node-versions"),
50007
+ path11.join(home, ".local", "share", "fnm", "node-versions")
50008
+ ];
50009
+ for (const fnmRoot of fnmRoots) {
50010
+ entries.push(...listNodeVersionBins(fnmRoot, ["installation", "bin"]));
50011
+ }
50012
+ for (const candidate of [
50013
+ path11.join(home, ".volta", "bin"),
50014
+ path11.join(home, ".asdf", "shims"),
50015
+ path11.join(home, ".local", "bin"),
50016
+ "/opt/homebrew/bin",
50017
+ "/usr/local/bin"
50018
+ ]) {
50019
+ if (existsSync2(candidate)) entries.push(candidate);
50020
+ }
50021
+ return uniq(entries);
50022
+ }
50023
+ function buildAugmentedPath(env2 = process.env) {
50024
+ return uniq([...getNodeToolExtraPathEntries(env2), ...splitPath(env2.PATH)]).join(path11.delimiter);
50025
+ }
50026
+ function withAugmentedPathEnv(env2 = process.env) {
50027
+ return { ...env2, PATH: buildAugmentedPath(env2) };
50028
+ }
50029
+ function executableNames(name) {
50030
+ if (process.platform !== "win32") return [name];
50031
+ if (/\.(cmd|exe|bat)$/i.test(name)) return [name];
50032
+ return [`${name}.cmd`, `${name}.exe`, `${name}.bat`, name];
50033
+ }
50034
+ function canExecute(candidate) {
50035
+ try {
50036
+ if (process.platform === "win32") return existsSync2(candidate);
50037
+ accessSync(candidate, constants2.X_OK);
50038
+ return true;
50039
+ } catch {
50040
+ return false;
50041
+ }
50042
+ }
50043
+ function resolveCommand(names, env2 = process.env) {
50044
+ const pathEntries = splitPath(buildAugmentedPath(env2));
50045
+ for (const entry of pathEntries) {
50046
+ for (const name of names) {
50047
+ for (const executableName of executableNames(name)) {
50048
+ const candidate = path11.join(entry, executableName);
50049
+ if (canExecute(candidate)) return { name, path: candidate };
50050
+ }
50051
+ }
50052
+ }
50053
+ return void 0;
50054
+ }
50055
+ function readCommandVersion(executablePath, args = ["--version"], env2 = process.env) {
50056
+ try {
50057
+ return execFileSync(executablePath, args, {
50058
+ env: withAugmentedPathEnv(env2),
50059
+ timeout: 1e4
50060
+ }).toString().trim();
50061
+ } catch {
50062
+ return void 0;
50063
+ }
50064
+ }
50065
+ function resolveUserPath(input) {
50066
+ const home = getHomeDir();
50067
+ let value = input.trim();
50068
+ if (value === "~") value = home;
50069
+ else if (value.startsWith("~/") || value.startsWith("~\\")) value = joinHomePath(home, value.slice(2));
50070
+ else if (value === "$HOME") value = home;
50071
+ else if (value.startsWith("$HOME/") || value.startsWith("$HOME\\")) value = joinHomePath(home, value.slice(6));
50072
+ else if (value === "${HOME}") value = home;
50073
+ else if (value.startsWith("${HOME}/") || value.startsWith("${HOME}\\")) value = joinHomePath(home, value.slice(8));
50074
+ else if (value === "$env:USERPROFILE") value = home;
50075
+ else if (value.startsWith("$env:USERPROFILE\\") || value.startsWith("$env:USERPROFILE/")) {
50076
+ value = joinHomePath(home, value.slice("$env:USERPROFILE".length + 1));
50077
+ } else if (value === "%USERPROFILE%") value = home;
50078
+ else if (value.startsWith("%USERPROFILE%\\") || value.startsWith("%USERPROFILE%/")) {
50079
+ value = joinHomePath(home, value.slice("%USERPROFILE%".length + 1));
50080
+ }
50081
+ return path11.isAbsolute(value) ? path11.normalize(value) : path11.resolve(value);
50082
+ }
50083
+
50084
+ // src/listDir.ts
49945
50085
  var logger17 = createModuleLogger("bridge.listDir");
49946
50086
  function shouldIncludeEntry(name) {
49947
50087
  if (!name.startsWith(".")) return true;
49948
50088
  return name === ".ahchat-attachments";
49949
50089
  }
49950
50090
  async function listDirectoryEntries(dirPath) {
49951
- logger17.info("listDirectoryEntries start", { path: dirPath });
49952
- const raw = await fs6.readdir(dirPath, { withFileTypes: true });
50091
+ const resolvedDirPath = resolveUserPath(dirPath);
50092
+ logger17.info("listDirectoryEntries start", { path: dirPath, resolvedPath: resolvedDirPath });
50093
+ const raw = await fs6.readdir(resolvedDirPath, { withFileTypes: true });
49953
50094
  const entries = [];
49954
50095
  for (const entry of raw) {
49955
50096
  if (!shouldIncludeEntry(entry.name)) continue;
49956
- const fullPath = path11.join(dirPath, entry.name);
50097
+ const fullPath = path12.join(resolvedDirPath, entry.name);
49957
50098
  const isDir = entry.isDirectory();
49958
50099
  let size;
49959
50100
  let mtime;
@@ -49972,6 +50113,7 @@ async function listDirectoryEntries(dirPath) {
49972
50113
  });
49973
50114
  logger17.info("listDirectoryEntries ok", {
49974
50115
  path: dirPath,
50116
+ resolvedPath: resolvedDirPath,
49975
50117
  count: entries.length,
49976
50118
  dirCount: entries.filter((e7) => e7.type === "dir").length,
49977
50119
  fileCount: entries.filter((e7) => e7.type === "file").length
@@ -49981,8 +50123,8 @@ async function listDirectoryEntries(dirPath) {
49981
50123
 
49982
50124
  // src/logScanner.ts
49983
50125
  import fs7 from "fs";
49984
- import path12 from "path";
49985
- import os8 from "os";
50126
+ import path13 from "path";
50127
+ import os9 from "os";
49986
50128
  import readline from "readline";
49987
50129
  var logger18 = createModuleLogger("bridge.logScanner");
49988
50130
  var DEFAULT_LIMIT = 500;
@@ -49996,10 +50138,10 @@ function listLogFiles(logsDir, baseName) {
49996
50138
  return [];
49997
50139
  }
49998
50140
  const pattern = new RegExp(`^${baseName.replace(".", "\\.")}(\\.\\d+)?$`);
49999
- return names.filter((n2) => pattern.test(n2)).map((n2) => path12.join(logsDir, n2));
50141
+ return names.filter((n2) => pattern.test(n2)).map((n2) => path13.join(logsDir, n2));
50000
50142
  }
50001
50143
  async function scanFile(filePath, source, filter, limit, state) {
50002
- const file2 = path12.basename(filePath);
50144
+ const file2 = path13.basename(filePath);
50003
50145
  const stream = fs7.createReadStream(filePath, { encoding: "utf-8" });
50004
50146
  const rl2 = readline.createInterface({ input: stream, crlfDelay: Infinity });
50005
50147
  let lineNum = 0;
@@ -50038,7 +50180,7 @@ async function scanLocalLogs(logsDir, baseName, filter) {
50038
50180
  };
50039
50181
  }
50040
50182
  async function scanBridgeLogs(filter) {
50041
- const logDir = path12.join(os8.homedir(), ".ahchat", "logs");
50183
+ const logDir = path13.join(os9.homedir(), ".ahchat", "logs");
50042
50184
  logger18.info("scanBridgeLogs start", {
50043
50185
  logDir,
50044
50186
  startIso: filter.startIso,
@@ -50056,13 +50198,13 @@ async function scanBridgeLogs(filter) {
50056
50198
 
50057
50199
  // src/skillStore.ts
50058
50200
  import fs8 from "fs";
50059
- import path13 from "path";
50201
+ import path14 from "path";
50060
50202
  var logger19 = createModuleLogger("bridge.skillStore");
50061
50203
  var ALLOWED_NAMES = /* @__PURE__ */ new Set(["log-analysis"]);
50062
50204
  var SkillStore = class {
50063
50205
  skillsDir;
50064
50206
  constructor(dataDir) {
50065
- this.skillsDir = path13.join(dataDir, "skills");
50207
+ this.skillsDir = path14.join(dataDir, "skills");
50066
50208
  fs8.mkdirSync(this.skillsDir, { recursive: true });
50067
50209
  logger19.info("SkillStore initialized", { skillsDir: this.skillsDir });
50068
50210
  }
@@ -50071,7 +50213,7 @@ var SkillStore = class {
50071
50213
  logger19.warn("Skill read: unknown name", { name, allowed: [...ALLOWED_NAMES] });
50072
50214
  return "";
50073
50215
  }
50074
- const filePath = path13.join(this.skillsDir, `${name}.md`);
50216
+ const filePath = path14.join(this.skillsDir, `${name}.md`);
50075
50217
  try {
50076
50218
  const content = fs8.readFileSync(filePath, "utf-8");
50077
50219
  logger19.info("Skill read", { name, bytes: content.length });
@@ -50086,7 +50228,7 @@ var SkillStore = class {
50086
50228
  if (!ALLOWED_NAMES.has(name)) {
50087
50229
  throw new Error(`Unknown skill name: ${name}`);
50088
50230
  }
50089
- const filePath = path13.join(this.skillsDir, `${name}.md`);
50231
+ const filePath = path14.join(this.skillsDir, `${name}.md`);
50090
50232
  const tmpPath = `${filePath}.tmp`;
50091
50233
  let existing = "";
50092
50234
  try {
@@ -50109,7 +50251,7 @@ var SkillStore = class {
50109
50251
 
50110
50252
  // src/lockfile.ts
50111
50253
  import fs9 from "fs";
50112
- import path14 from "path";
50254
+ import path15 from "path";
50113
50255
  var logger20 = createModuleLogger("bridge.lockfile");
50114
50256
  var lockPath = null;
50115
50257
  function isProcessAlive(pid) {
@@ -50123,7 +50265,7 @@ function isProcessAlive(pid) {
50123
50265
  }
50124
50266
  }
50125
50267
  function acquireLock(dataDir) {
50126
- const file2 = path14.join(dataDir, "bridge.lock");
50268
+ const file2 = path15.join(dataDir, "bridge.lock");
50127
50269
  lockPath = file2;
50128
50270
  if (fs9.existsSync(file2)) {
50129
50271
  const raw = fs9.readFileSync(file2, "utf-8").trim();
@@ -50135,7 +50277,7 @@ function acquireLock(dataDir) {
50135
50277
  logger20.warn("Removing stale bridge.lock (process not found)", { pid, path: file2 });
50136
50278
  }
50137
50279
  }
50138
- fs9.mkdirSync(path14.dirname(file2), { recursive: true });
50280
+ fs9.mkdirSync(path15.dirname(file2), { recursive: true });
50139
50281
  fs9.writeFileSync(file2, String(process.pid), "utf-8");
50140
50282
  logger20.info("Acquired bridge lock", { path: file2, pid: process.pid });
50141
50283
  const release = () => {
@@ -50499,13 +50641,13 @@ async function handleGroupArchivedPush(deps, payload) {
50499
50641
 
50500
50642
  // src/sessionStore.ts
50501
50643
  import fs10 from "fs";
50502
- import path15 from "path";
50644
+ import path16 from "path";
50503
50645
  var logger23 = createModuleLogger("session.store");
50504
50646
  var SessionStore = class {
50505
50647
  filePath;
50506
50648
  cache;
50507
50649
  constructor(dataDir) {
50508
- this.filePath = path15.join(dataDir, "sessions.json");
50650
+ this.filePath = path16.join(dataDir, "sessions.json");
50509
50651
  this.cache = this.loadFromDisk();
50510
50652
  }
50511
50653
  cacheKey(agentId, scope) {
@@ -50565,7 +50707,7 @@ var SessionStore = class {
50565
50707
  }
50566
50708
  saveToDisk() {
50567
50709
  try {
50568
- const dir = path15.dirname(this.filePath);
50710
+ const dir = path16.dirname(this.filePath);
50569
50711
  fs10.mkdirSync(dir, { recursive: true });
50570
50712
  fs10.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2), "utf-8");
50571
50713
  } catch (e7) {
@@ -50575,8 +50717,8 @@ var SessionStore = class {
50575
50717
  };
50576
50718
 
50577
50719
  // src/ensureClaudeCli.ts
50578
- import { execFileSync, execSync, spawnSync } from "child_process";
50579
- import { accessSync, constants as constants2 } from "fs";
50720
+ import { execFileSync as execFileSync2, spawnSync } from "child_process";
50721
+ import { accessSync as accessSync2, constants as constants3 } from "fs";
50580
50722
  import { join as join2 } from "path";
50581
50723
  var logger24 = createModuleLogger("bridge.ensureCli");
50582
50724
  var DEFAULT_INSTALL_TIMEOUT_MS = 6e5;
@@ -50586,35 +50728,29 @@ function getInstallTimeoutMs() {
50586
50728
  const parsed = Number.parseInt(raw, 10);
50587
50729
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_INSTALL_TIMEOUT_MS;
50588
50730
  }
50589
- function detectClaudeCli() {
50590
- try {
50591
- return execFileSync("claude", ["--version"], { timeout: 1e4 }).toString().trim();
50592
- } catch {
50593
- return void 0;
50594
- }
50595
- }
50596
50731
  function getNpmGlobalBin() {
50732
+ const npm = resolveCommand(["npm"]);
50733
+ if (!npm) return void 0;
50597
50734
  try {
50598
- const bin = execSync("npm bin -g", { timeout: 5e3 }).toString().trim() || void 0;
50735
+ const bin = execFileSync2(npm.path, ["bin", "-g"], {
50736
+ env: withAugmentedPathEnv(),
50737
+ timeout: 5e3
50738
+ }).toString().trim() || void 0;
50599
50739
  if (bin) return bin;
50600
50740
  } catch {
50601
50741
  }
50602
50742
  try {
50603
- const prefix = execSync("npm prefix -g", { timeout: 5e3 }).toString().trim();
50743
+ const prefix = execFileSync2(npm.path, ["prefix", "-g"], {
50744
+ env: withAugmentedPathEnv(),
50745
+ timeout: 5e3
50746
+ }).toString().trim();
50604
50747
  if (prefix) return join2(prefix, "bin");
50605
50748
  } catch {
50606
50749
  }
50607
50750
  return void 0;
50608
50751
  }
50609
50752
  function resolveClaudeBinary() {
50610
- const whichCmd = process.platform === "win32" ? "where" : "which";
50611
- try {
50612
- const out = execFileSync(whichCmd, ["claude"], { timeout: 5e3 }).toString();
50613
- const first = out.split(/\r?\n/).map((l4) => l4.trim()).find(Boolean);
50614
- if (first) return first;
50615
- } catch {
50616
- }
50617
- return resolveViaNpmBin();
50753
+ return resolveCommand(["claude", "anthropic-cli"])?.path ?? resolveViaNpmBin();
50618
50754
  }
50619
50755
  function getNpmClaudeCandidates(bin) {
50620
50756
  if (process.platform === "win32") {
@@ -50627,7 +50763,7 @@ function resolveViaNpmBin() {
50627
50763
  if (!bin) return void 0;
50628
50764
  for (const candidate of getNpmClaudeCandidates(bin)) {
50629
50765
  try {
50630
- accessSync(candidate, constants2.X_OK);
50766
+ accessSync2(candidate, constants3.X_OK);
50631
50767
  return candidate;
50632
50768
  } catch {
50633
50769
  }
@@ -50637,40 +50773,32 @@ function resolveViaNpmBin() {
50637
50773
  function detectViaNpmBin() {
50638
50774
  const binPath = resolveViaNpmBin();
50639
50775
  if (!binPath) return void 0;
50640
- try {
50641
- return execFileSync(binPath, ["--version"], { timeout: 1e4 }).toString().trim();
50642
- } catch {
50643
- }
50644
- return void 0;
50776
+ return readCommandVersion(binPath);
50645
50777
  }
50646
50778
  function detectResolvedClaudeCli() {
50647
- const viaPath = detectClaudeCli();
50648
- if (viaPath) {
50649
- return { version: viaPath, path: resolveClaudeBinary() };
50650
- }
50651
- const npmBinPath = resolveViaNpmBin();
50652
- if (!npmBinPath) return void 0;
50653
- try {
50654
- const version2 = execFileSync(npmBinPath, ["--version"], { timeout: 1e4 }).toString().trim();
50655
- return { version: version2, path: npmBinPath };
50656
- } catch {
50657
- }
50779
+ const resolvedPath = resolveClaudeBinary();
50780
+ if (!resolvedPath) return void 0;
50781
+ const version2 = readCommandVersion(resolvedPath);
50782
+ if (version2) return { version: version2, path: resolvedPath };
50658
50783
  return void 0;
50659
50784
  }
50660
50785
  function detectVersionFromResolvedCandidates() {
50661
50786
  const candidates = [resolveClaudeBinary(), resolveViaNpmBin()].filter((p) => Boolean(p));
50662
50787
  for (const p of candidates) {
50663
- try {
50664
- accessSync(p, constants2.X_OK);
50665
- return execFileSync(p, ["--version"], { timeout: 1e4 }).toString().trim();
50666
- } catch {
50667
- }
50788
+ const version2 = readCommandVersion(p);
50789
+ if (version2) return version2;
50668
50790
  }
50669
50791
  return void 0;
50670
50792
  }
50671
50793
  function installClaudeCli() {
50794
+ const npm = resolveCommand(["npm"]);
50795
+ if (!npm) {
50796
+ logger24.error("npm not found; cannot install Claude Code CLI");
50797
+ return void 0;
50798
+ }
50672
50799
  logger24.info("Installing Claude Code CLI via npm...");
50673
- const result = spawnSync("npm", ["install", "-g", "@anthropic-ai/claude-code"], {
50800
+ const result = spawnSync(npm.path, ["install", "-g", "@anthropic-ai/claude-code"], {
50801
+ env: withAugmentedPathEnv(),
50674
50802
  stdio: "inherit",
50675
50803
  timeout: getInstallTimeoutMs()
50676
50804
  });
@@ -50702,7 +50830,10 @@ function installClaudeCli() {
50702
50830
  logger24.error("claude not found after successful npm install -g", {
50703
50831
  npmGlobalBin: npmBin ?? "unknown",
50704
50832
  pathDirectories: envPath.split(process.platform === "win32" ? ";" : ":").slice(0, 10),
50705
- npmPrefix: execSync("npm prefix -g", { timeout: 5e3 }).toString().trim() || "unknown"
50833
+ npmPrefix: execFileSync2(npm.path, ["prefix", "-g"], {
50834
+ env: withAugmentedPathEnv(),
50835
+ timeout: 5e3
50836
+ }).toString().trim() || "unknown"
50706
50837
  });
50707
50838
  return void 0;
50708
50839
  }
@@ -50731,20 +50862,20 @@ async function ensureClaudeCli() {
50731
50862
 
50732
50863
  // src/forkAgentFiles.ts
50733
50864
  import * as fs11 from "fs/promises";
50734
- import * as path17 from "path";
50865
+ import * as path18 from "path";
50735
50866
 
50736
50867
  // src/sessionSlug.ts
50737
- import os9 from "os";
50738
- import path16 from "path";
50739
- var CLAUDE_PROJECTS_DIR = path16.join(os9.homedir(), ".claude", "projects");
50868
+ import os10 from "os";
50869
+ import path17 from "path";
50870
+ var CLAUDE_PROJECTS_DIR = path17.join(os10.homedir(), ".claude", "projects");
50740
50871
  function cwdToSlug(cwd) {
50741
50872
  return cwd.replace(/[^a-zA-Z0-9-]/g, "-");
50742
50873
  }
50743
50874
  function sessionDirForCwd(cwd) {
50744
- return path16.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
50875
+ return path17.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
50745
50876
  }
50746
50877
  function sessionFilePath(cwd, sessionId) {
50747
- return path16.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
50878
+ return path17.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
50748
50879
  }
50749
50880
 
50750
50881
  // src/forkAgentFiles.ts
@@ -50776,9 +50907,9 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
50776
50907
  logger25.error("Workdir copy failed", { error: e7 });
50777
50908
  throw e7;
50778
50909
  }
50779
- const srcNotebook = path17.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
50780
- const dstNotebookDir = path17.join(dataDir, "agent-memory", newAgentId);
50781
- const dstNotebook = path17.join(dstNotebookDir, "notebook.md");
50910
+ const srcNotebook = path18.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
50911
+ const dstNotebookDir = path18.join(dataDir, "agent-memory", newAgentId);
50912
+ const dstNotebook = path18.join(dstNotebookDir, "notebook.md");
50782
50913
  try {
50783
50914
  const nbStat = await fs11.stat(srcNotebook).catch(() => null);
50784
50915
  if (nbStat?.isFile()) {
@@ -50805,7 +50936,7 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
50805
50936
  if (srcStat?.isFile()) {
50806
50937
  const dstDir = sessionDirForCwd(newWorkdir);
50807
50938
  await fs11.mkdir(dstDir, { recursive: true });
50808
- const dstPath = path17.join(dstDir, `${sourceSessionId}.jsonl`);
50939
+ const dstPath = path18.join(dstDir, `${sourceSessionId}.jsonl`);
50809
50940
  await fs11.copyFile(srcPath, dstPath);
50810
50941
  sessionStore.set(newAgentId, { kind: "single" }, sourceSessionId);
50811
50942
  sessionCopied = true;
@@ -50852,12 +50983,12 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
50852
50983
 
50853
50984
  // src/modelQuerier.ts
50854
50985
  import fs12 from "fs/promises";
50855
- import os10 from "os";
50856
- import path18 from "path";
50986
+ import os11 from "os";
50987
+ import path19 from "path";
50857
50988
  var logger26 = createModuleLogger("bridge.modelQuerier");
50858
50989
  async function listModels(queryFn, opts = {}) {
50859
50990
  const t0 = Date.now();
50860
- const cwd = opts.cwd ?? path18.join(os10.homedir(), ".ahchat", "workspaces", "_list_models");
50991
+ const cwd = opts.cwd ?? path19.join(os11.homedir(), ".ahchat", "workspaces", "_list_models");
50861
50992
  await fs12.mkdir(cwd, { recursive: true });
50862
50993
  const fn = queryFn ?? QA$;
50863
50994
  const ic2 = new InputController();
@@ -50919,8 +51050,8 @@ async function listModels(queryFn, opts = {}) {
50919
51050
 
50920
51051
  // src/promptOptimizer.ts
50921
51052
  import fs13 from "fs/promises";
50922
- import os11 from "os";
50923
- import path19 from "path";
51053
+ import os12 from "os";
51054
+ import path20 from "path";
50924
51055
  var logger27 = createModuleLogger("bridge.promptOptimizer");
50925
51056
  var OPTIMIZER_SYSTEM_PROMPT = `You are an expert prompt editor for AHChat Agent creation.
50926
51057
 
@@ -50963,7 +51094,7 @@ async function optimizePrompt(queryFn, opts) {
50963
51094
  const prompt = opts.systemPrompt.trim();
50964
51095
  if (!prompt) throw new Error("systemPrompt is required");
50965
51096
  const t0 = Date.now();
50966
- const cwd = opts.cwd ?? path19.join(os11.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
51097
+ const cwd = opts.cwd ?? path20.join(os12.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
50967
51098
  await fs13.mkdir(cwd, { recursive: true });
50968
51099
  const fn = queryFn ?? QA$;
50969
51100
  const ic2 = new InputController();
@@ -51051,7 +51182,7 @@ function isRunningAsRoot2() {
51051
51182
  }
51052
51183
  }
51053
51184
  async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
51054
- const rootClaudeDir = path20.join(process.env.HOME ?? "/root", ".claude");
51185
+ const rootClaudeDir = path21.join(process.env.HOME ?? "/root", ".claude");
51055
51186
  const fs14 = await import("fs/promises");
51056
51187
  try {
51057
51188
  await fs14.access(rootClaudeDir);
@@ -51061,8 +51192,8 @@ async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
51061
51192
  }
51062
51193
  const filesToSync = [".credentials.json", "settings.json", ".credentials.backup.json"];
51063
51194
  for (const file2 of filesToSync) {
51064
- const src = path20.join(rootClaudeDir, file2);
51065
- const dest = path20.join(agentConfigDir, file2);
51195
+ const src = path21.join(rootClaudeDir, file2);
51196
+ const dest = path21.join(agentConfigDir, file2);
51066
51197
  try {
51067
51198
  await fs14.copyFile(src, dest);
51068
51199
  logger28.info("Synced credential file", { file: file2, from: src, to: dest });
@@ -51085,7 +51216,7 @@ async function chownRecursive(dirPath, uid, gid) {
51085
51216
  return;
51086
51217
  }
51087
51218
  for (const entry of entries) {
51088
- const fullPath = path20.join(dirPath, entry.name);
51219
+ const fullPath = path21.join(dirPath, entry.name);
51089
51220
  if (entry.isDirectory()) {
51090
51221
  await chownRecursive(fullPath, uid, gid);
51091
51222
  } else {
@@ -51100,7 +51231,7 @@ async function chownRecursive(dirPath, uid, gid) {
51100
51231
  async function startBridge(config2) {
51101
51232
  ensureDir(config2.dataDir);
51102
51233
  ensureDir(config2.agentConfigDir);
51103
- const workspacesDir = path20.join(config2.dataDir, "workspaces");
51234
+ const workspacesDir = path21.join(config2.dataDir, "workspaces");
51104
51235
  ensureDir(workspacesDir);
51105
51236
  process.env.CLAUDE_CONFIG_DIR = config2.agentConfigDir;
51106
51237
  installBridgeFetchAuth(config2.serverApiUrl, config2.bridgeToken);
@@ -51129,7 +51260,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
51129
51260
  `);
51130
51261
  wsMetrics.start(5e3);
51131
51262
  const sessionStore = new SessionStore(config2.dataDir);
51132
- const memoryRoot = path20.join(config2.dataDir, "agent-memory");
51263
+ const memoryRoot = path21.join(config2.dataDir, "agent-memory");
51133
51264
  const memoryStore = new AgentMemoryStore(memoryRoot);
51134
51265
  logger28.info("Agent memory store initialized", { rootDir: memoryRoot });
51135
51266
  const smithNotebook = memoryStore.read(SMITH_AGENT_ID);