@fangyb/ahchat-bridge 0.1.41 → 0.1.42

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 (3) hide show
  1. package/dist/cli.cjs +785 -484
  2. package/dist/index.js +653 -352
  3. package/package.json +12 -12
package/dist/index.js CHANGED
@@ -3801,7 +3801,7 @@ function ensureDir(dirPath) {
3801
3801
 
3802
3802
  // src/start.ts
3803
3803
  import os15 from "os";
3804
- import path33 from "path";
3804
+ import path34 from "path";
3805
3805
  import crypto5 from "crypto";
3806
3806
 
3807
3807
  // ../logger/src/types.ts
@@ -4604,11 +4604,11 @@ var RotatingFileStream = class extends Writable {
4604
4604
  timeout;
4605
4605
  timeoutPromise;
4606
4606
  constructor(generator, options) {
4607
- const { encoding, history, maxFiles, maxSize, path: path34 } = options;
4607
+ const { encoding, history, maxFiles, maxSize, path: path35 } = options;
4608
4608
  super({ decodeStrings: true, defaultEncoding: encoding });
4609
4609
  this.createGzip = createGzip;
4610
4610
  this.exec = exec;
4611
- this.filename = path34 + generator(null);
4611
+ this.filename = path35 + generator(null);
4612
4612
  this.fsCreateReadStream = createReadStream;
4613
4613
  this.fsCreateWriteStream = createWriteStream;
4614
4614
  this.fsOpen = open;
@@ -4620,7 +4620,7 @@ var RotatingFileStream = class extends Writable {
4620
4620
  this.options = options;
4621
4621
  this.stdout = process.stdout;
4622
4622
  if (maxFiles || maxSize)
4623
- options.history = path34 + (history ? history : this.generator(null) + ".txt");
4623
+ options.history = path35 + (history ? history : this.generator(null) + ".txt");
4624
4624
  this.on("close", () => this.finished ? null : this.emit("finish"));
4625
4625
  this.on("finish", () => this.finished = this.clear());
4626
4626
  (async () => {
@@ -4748,9 +4748,9 @@ var RotatingFileStream = class extends Writable {
4748
4748
  return this.move();
4749
4749
  }
4750
4750
  async findName() {
4751
- const { interval, path: path34, intervalBoundary } = this.options;
4751
+ const { interval, path: path35, intervalBoundary } = this.options;
4752
4752
  for (let index = 1; index < 1e3; ++index) {
4753
- const filename = path34 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
4753
+ const filename = path35 + this.generator(interval && intervalBoundary ? new Date(this.prev) : this.rotation, index);
4754
4754
  if (!await exists(filename))
4755
4755
  return filename;
4756
4756
  }
@@ -4780,11 +4780,11 @@ var RotatingFileStream = class extends Writable {
4780
4780
  return this.unlink(filename);
4781
4781
  }
4782
4782
  async classical() {
4783
- const { compress, path: path34, rotate } = this.options;
4783
+ const { compress, path: path35, rotate } = this.options;
4784
4784
  let rotatedName = "";
4785
4785
  for (let count = rotate; count > 0; --count) {
4786
- const currName = path34 + this.generator(count);
4787
- const prevName = count === 1 ? this.filename : path34 + this.generator(count - 1);
4786
+ const currName = path35 + this.generator(count);
4787
+ const prevName = count === 1 ? this.filename : path35 + this.generator(count - 1);
4788
4788
  if (!await exists(prevName))
4789
4789
  continue;
4790
4790
  if (!rotatedName)
@@ -8341,14 +8341,14 @@ function agentIdArray(value) {
8341
8341
  function normalizeModelScopeSkill(value) {
8342
8342
  if (!isRecord2(value)) return null;
8343
8343
  const id = stringValue(value.id);
8344
- const path34 = stringValue(value.path);
8344
+ const path35 = stringValue(value.path);
8345
8345
  const name = stringValue(value.name);
8346
8346
  const displayName = stringValue(value.displayName, name);
8347
8347
  const url2 = stringValue(value.url);
8348
- if (!id || !path34 || !name || !displayName || !url2) return null;
8348
+ if (!id || !path35 || !name || !displayName || !url2) return null;
8349
8349
  return {
8350
8350
  id,
8351
- path: path34,
8351
+ path: path35,
8352
8352
  name,
8353
8353
  displayName,
8354
8354
  description: stringValue(value.description),
@@ -8735,9 +8735,9 @@ var AgentMemoryStore = class {
8735
8735
  import { spawn as nodeSpawn } from "child_process";
8736
8736
  import { createHash } from "crypto";
8737
8737
  import fsSync from "fs";
8738
- import fs6 from "fs/promises";
8738
+ import fs7 from "fs/promises";
8739
8739
  import os7 from "os";
8740
- import path13 from "path";
8740
+ import path14 from "path";
8741
8741
  import * as sdk2 from "@anthropic-ai/claude-agent-sdk";
8742
8742
 
8743
8743
  // src/attachmentText.ts
@@ -9611,6 +9611,8 @@ var HttpMcpAuditClient = class {
9611
9611
  };
9612
9612
 
9613
9613
  // src/neuralMcpServer.ts
9614
+ import fs5 from "fs/promises";
9615
+ import path10 from "path";
9614
9616
  import * as sdk from "@anthropic-ai/claude-agent-sdk";
9615
9617
 
9616
9618
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -10379,10 +10381,10 @@ function mergeDefs(...defs) {
10379
10381
  function cloneDef(schema) {
10380
10382
  return mergeDefs(schema._zod.def);
10381
10383
  }
10382
- function getElementAtPath(obj, path34) {
10383
- if (!path34)
10384
+ function getElementAtPath(obj, path35) {
10385
+ if (!path35)
10384
10386
  return obj;
10385
- return path34.reduce((acc, key) => acc?.[key], obj);
10387
+ return path35.reduce((acc, key) => acc?.[key], obj);
10386
10388
  }
10387
10389
  function promiseAllObject(promisesObj) {
10388
10390
  const keys = Object.keys(promisesObj);
@@ -10791,11 +10793,11 @@ function explicitlyAborted(x, startIndex = 0) {
10791
10793
  }
10792
10794
  return false;
10793
10795
  }
10794
- function prefixIssues(path34, issues) {
10796
+ function prefixIssues(path35, issues) {
10795
10797
  return issues.map((iss) => {
10796
10798
  var _a3;
10797
10799
  (_a3 = iss).path ?? (_a3.path = []);
10798
- iss.path.unshift(path34);
10800
+ iss.path.unshift(path35);
10799
10801
  return iss;
10800
10802
  });
10801
10803
  }
@@ -10942,16 +10944,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
10942
10944
  }
10943
10945
  function formatError(error51, mapper = (issue2) => issue2.message) {
10944
10946
  const fieldErrors = { _errors: [] };
10945
- const processError = (error52, path34 = []) => {
10947
+ const processError = (error52, path35 = []) => {
10946
10948
  for (const issue2 of error52.issues) {
10947
10949
  if (issue2.code === "invalid_union" && issue2.errors.length) {
10948
- issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
10950
+ issue2.errors.map((issues) => processError({ issues }, [...path35, ...issue2.path]));
10949
10951
  } else if (issue2.code === "invalid_key") {
10950
- processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
10952
+ processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
10951
10953
  } else if (issue2.code === "invalid_element") {
10952
- processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
10954
+ processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
10953
10955
  } else {
10954
- const fullpath = [...path34, ...issue2.path];
10956
+ const fullpath = [...path35, ...issue2.path];
10955
10957
  if (fullpath.length === 0) {
10956
10958
  fieldErrors._errors.push(mapper(issue2));
10957
10959
  } else {
@@ -10978,17 +10980,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
10978
10980
  }
10979
10981
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
10980
10982
  const result = { errors: [] };
10981
- const processError = (error52, path34 = []) => {
10983
+ const processError = (error52, path35 = []) => {
10982
10984
  var _a3, _b;
10983
10985
  for (const issue2 of error52.issues) {
10984
10986
  if (issue2.code === "invalid_union" && issue2.errors.length) {
10985
- issue2.errors.map((issues) => processError({ issues }, [...path34, ...issue2.path]));
10987
+ issue2.errors.map((issues) => processError({ issues }, [...path35, ...issue2.path]));
10986
10988
  } else if (issue2.code === "invalid_key") {
10987
- processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
10989
+ processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
10988
10990
  } else if (issue2.code === "invalid_element") {
10989
- processError({ issues: issue2.issues }, [...path34, ...issue2.path]);
10991
+ processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
10990
10992
  } else {
10991
- const fullpath = [...path34, ...issue2.path];
10993
+ const fullpath = [...path35, ...issue2.path];
10992
10994
  if (fullpath.length === 0) {
10993
10995
  result.errors.push(mapper(issue2));
10994
10996
  continue;
@@ -11020,8 +11022,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
11020
11022
  }
11021
11023
  function toDotPath(_path) {
11022
11024
  const segs = [];
11023
- const path34 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11024
- for (const seg of path34) {
11025
+ const path35 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
11026
+ for (const seg of path35) {
11025
11027
  if (typeof seg === "number")
11026
11028
  segs.push(`[${seg}]`);
11027
11029
  else if (typeof seg === "symbol")
@@ -23713,13 +23715,13 @@ function resolveRef(ref, ctx) {
23713
23715
  if (!ref.startsWith("#")) {
23714
23716
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
23715
23717
  }
23716
- const path34 = ref.slice(1).split("/").filter(Boolean);
23717
- if (path34.length === 0) {
23718
+ const path35 = ref.slice(1).split("/").filter(Boolean);
23719
+ if (path35.length === 0) {
23718
23720
  return ctx.rootSchema;
23719
23721
  }
23720
23722
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
23721
- if (path34[0] === defsKey) {
23722
- const key = path34[1];
23723
+ if (path35[0] === defsKey) {
23724
+ const key = path35[1];
23723
23725
  if (!key || !ctx.defs[key]) {
23724
23726
  throw new Error(`Reference not found: ${ref}`);
23725
23727
  }
@@ -24649,6 +24651,138 @@ function normalizeDocumentText(value) {
24649
24651
  var logger9 = createModuleLogger("neural.mcpServer");
24650
24652
  var VIDEO_GENERATION_SKILL_ID = OFFICIAL_MEDIA_SKILL_IDS[0];
24651
24653
  var AUTO_LOCAL_ENHANCER_LIMIT = 2;
24654
+ var WORKDIR_ATTACHMENT_MARKER_KIND = "ahchat_workdir_attachment";
24655
+ var WORKDIR_FIND_DEFAULT_MAX_RESULTS = 20;
24656
+ var WORKDIR_FIND_MAX_RESULTS = 50;
24657
+ var WORKDIR_FIND_MAX_SCANNED_FILES = 5e3;
24658
+ var WORKDIR_FIND_MAX_DEPTH = 8;
24659
+ var WORKDIR_FIND_SKIP_DIRS = /* @__PURE__ */ new Set([
24660
+ ".ahchat-attachments",
24661
+ ".git",
24662
+ ".next",
24663
+ ".turbo",
24664
+ "build",
24665
+ "coverage",
24666
+ "dist",
24667
+ "node_modules"
24668
+ ]);
24669
+ var WORKDIR_FILE_MIME_BY_EXT = {
24670
+ ".csv": "text/csv",
24671
+ ".doc": "application/msword",
24672
+ ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
24673
+ ".gif": "image/gif",
24674
+ ".htm": "text/html",
24675
+ ".html": "text/html",
24676
+ ".jpeg": "image/jpeg",
24677
+ ".jpg": "image/jpeg",
24678
+ ".json": "application/json",
24679
+ ".m4a": "audio/mp4",
24680
+ ".md": "text/markdown",
24681
+ ".mp3": "audio/mpeg",
24682
+ ".mp4": "video/mp4",
24683
+ ".pdf": "application/pdf",
24684
+ ".png": "image/png",
24685
+ ".ppt": "application/vnd.ms-powerpoint",
24686
+ ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
24687
+ ".svg": "image/svg+xml",
24688
+ ".txt": "text/plain",
24689
+ ".wav": "audio/wav",
24690
+ ".webm": "video/webm",
24691
+ ".webp": "image/webp",
24692
+ ".xls": "application/vnd.ms-excel",
24693
+ ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
24694
+ };
24695
+ function normalizeWorkdirRelativePath(value) {
24696
+ return value.split(path10.sep).join("/");
24697
+ }
24698
+ function inferWorkdirFileMimeType(filePath) {
24699
+ return WORKDIR_FILE_MIME_BY_EXT[path10.extname(filePath).toLowerCase()] ?? "application/octet-stream";
24700
+ }
24701
+ function boundedWorkdirResultLimit(value) {
24702
+ if (!Number.isFinite(value)) return WORKDIR_FIND_DEFAULT_MAX_RESULTS;
24703
+ return Math.min(WORKDIR_FIND_MAX_RESULTS, Math.max(1, Math.floor(value)));
24704
+ }
24705
+ async function resolveWorkdirRoot(cwd) {
24706
+ const rawCwd = (cwd ?? process.cwd()).trim();
24707
+ if (!rawCwd) throw new Error("\u5F53\u524D scope \u6CA1\u6709\u53EF\u7528\u5DE5\u4F5C\u76EE\u5F55\u3002");
24708
+ const resolvedCwd = path10.resolve(rawCwd);
24709
+ const stat3 = await fs5.stat(resolvedCwd).catch(() => null);
24710
+ if (!stat3?.isDirectory()) throw new Error(`\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u53EF\u7528\uFF1A${resolvedCwd}`);
24711
+ return { cwd: resolvedCwd, realCwd: await fs5.realpath(resolvedCwd) };
24712
+ }
24713
+ async function resolveWorkdirFilePath(requestedPath, cwd) {
24714
+ const trimmed = requestedPath.trim();
24715
+ if (!trimmed) throw new Error("path \u4E0D\u80FD\u4E3A\u7A7A\u3002");
24716
+ const root = await resolveWorkdirRoot(cwd);
24717
+ const candidate = path10.resolve(root.cwd, trimmed);
24718
+ let realTarget;
24719
+ try {
24720
+ realTarget = await fs5.realpath(candidate);
24721
+ } catch {
24722
+ throw new Error(`\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${trimmed}`);
24723
+ }
24724
+ if (!isPathInside(root.realCwd, realTarget)) {
24725
+ throw new Error("\u53EA\u80FD\u8BBF\u95EE\u5F53\u524D scope \u5DE5\u4F5C\u76EE\u5F55\u5185\u7684\u6587\u4EF6\u3002");
24726
+ }
24727
+ const stat3 = await fs5.stat(realTarget);
24728
+ if (!stat3.isFile()) throw new Error(`\u4E0D\u662F\u53EF\u53D1\u9001\u6587\u4EF6\uFF1A${trimmed}`);
24729
+ const relativePath = normalizeWorkdirRelativePath(path10.relative(root.realCwd, realTarget));
24730
+ return {
24731
+ absolutePath: realTarget,
24732
+ fileName: path10.basename(realTarget),
24733
+ relativePath,
24734
+ size: stat3.size,
24735
+ mtimeMs: stat3.mtimeMs
24736
+ };
24737
+ }
24738
+ function formatWorkdirFileSize(bytes) {
24739
+ if (bytes < 1024) return `${bytes} B`;
24740
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
24741
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
24742
+ }
24743
+ async function findWorkdirFiles(args) {
24744
+ const root = await resolveWorkdirRoot(args.cwd);
24745
+ const needle = args.query?.trim().toLowerCase() ?? "";
24746
+ const limit = boundedWorkdirResultLimit(args.maxResults);
24747
+ const results = [];
24748
+ let scanned = 0;
24749
+ async function walk(dir, depth) {
24750
+ if (results.length >= limit || scanned >= WORKDIR_FIND_MAX_SCANNED_FILES || depth > WORKDIR_FIND_MAX_DEPTH) return;
24751
+ let entries;
24752
+ try {
24753
+ entries = await fs5.readdir(dir, { withFileTypes: true });
24754
+ } catch {
24755
+ return;
24756
+ }
24757
+ entries.sort((a, b) => a.name.localeCompare(b.name));
24758
+ for (const entry of entries) {
24759
+ if (results.length >= limit || scanned >= WORKDIR_FIND_MAX_SCANNED_FILES) break;
24760
+ if (entry.isDirectory()) {
24761
+ if (!WORKDIR_FIND_SKIP_DIRS.has(entry.name)) {
24762
+ await walk(path10.join(dir, entry.name), depth + 1);
24763
+ }
24764
+ continue;
24765
+ }
24766
+ if (!entry.isFile()) continue;
24767
+ scanned++;
24768
+ const absolutePath = path10.join(dir, entry.name);
24769
+ const relativePath = normalizeWorkdirRelativePath(path10.relative(root.realCwd, absolutePath));
24770
+ if (needle && !relativePath.toLowerCase().includes(needle) && !entry.name.toLowerCase().includes(needle)) {
24771
+ continue;
24772
+ }
24773
+ const stat3 = await fs5.stat(absolutePath).catch(() => null);
24774
+ if (!stat3?.isFile()) continue;
24775
+ results.push({
24776
+ relativePath,
24777
+ fileName: entry.name,
24778
+ size: stat3.size,
24779
+ mtimeMs: stat3.mtimeMs
24780
+ });
24781
+ }
24782
+ }
24783
+ await walk(root.realCwd, 0);
24784
+ return results.sort((a, b) => b.mtimeMs - a.mtimeMs).slice(0, limit);
24785
+ }
24652
24786
  function formatSkillEntry(entry, index) {
24653
24787
  return [
24654
24788
  `${index + 1}. ${entry.displayName} (${entry.name})`,
@@ -25603,6 +25737,122 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
25603
25737
  },
25604
25738
  {}
25605
25739
  );
25740
+ const findWorkdirFilesTool = sdk.tool(
25741
+ "find_workdir_files",
25742
+ `Find files inside the current scope working directory only.
25743
+ Use this when the user asks you to locate a generated/output file before sending it as an attachment. It returns relative paths that can be passed to send_workdir_file.`,
25744
+ {
25745
+ query: external_exports.string().optional().describe("Optional case-insensitive substring to match against file names or relative paths."),
25746
+ max_results: external_exports.number().int().min(1).max(WORKDIR_FIND_MAX_RESULTS).optional().describe(
25747
+ `Maximum files to return. Defaults to ${WORKDIR_FIND_DEFAULT_MAX_RESULTS}, hard max ${WORKDIR_FIND_MAX_RESULTS}.`
25748
+ )
25749
+ },
25750
+ async (args) => {
25751
+ const query4 = args.query?.trim();
25752
+ const maxResults = boundedWorkdirResultLimit(args.max_results);
25753
+ logger9.info("find_workdir_files tool called", {
25754
+ agentId: deps.agentId,
25755
+ scope: currentScopeKey,
25756
+ query: query4 ?? null,
25757
+ maxResults
25758
+ });
25759
+ try {
25760
+ const files = await findWorkdirFiles({
25761
+ cwd: deps.cwd,
25762
+ query: query4,
25763
+ maxResults
25764
+ });
25765
+ if (files.length === 0) {
25766
+ return {
25767
+ content: [{
25768
+ type: "text",
25769
+ text: `[find_workdir_files] \u672A\u627E\u5230\u5339\u914D\u6587\u4EF6\u3002scope=${currentScopeKey}`
25770
+ }]
25771
+ };
25772
+ }
25773
+ const lines = files.map((file2, index) => {
25774
+ const modified = new Date(file2.mtimeMs).toISOString();
25775
+ return `${index + 1}. ${file2.relativePath} (${formatWorkdirFileSize(file2.size)}, modified ${modified})`;
25776
+ });
25777
+ return {
25778
+ content: [{
25779
+ type: "text",
25780
+ text: [
25781
+ `[find_workdir_files] \u627E\u5230 ${files.length} \u4E2A\u6587\u4EF6\uFF08\u53EA\u80FD\u53D1\u9001\u5F53\u524D scope \u5DE5\u4F5C\u76EE\u5F55\u5185\u6587\u4EF6\uFF09\uFF1A`,
25782
+ ...lines,
25783
+ "",
25784
+ '\u8981\u53D1\u7ED9\u7528\u6237\u65F6\uFF0C\u8C03\u7528 send_workdir_file(path="<\u4E0A\u9762\u7684\u76F8\u5BF9\u8DEF\u5F84>")\u3002'
25785
+ ].join("\n")
25786
+ }]
25787
+ };
25788
+ } catch (e) {
25789
+ const message = e instanceof Error ? e.message : String(e);
25790
+ logger9.error("find_workdir_files failed", {
25791
+ agentId: deps.agentId,
25792
+ scope: currentScopeKey,
25793
+ query: query4 ?? null,
25794
+ error: e
25795
+ });
25796
+ return {
25797
+ content: [{ type: "text", text: `[find_workdir_files] failed: ${message}` }],
25798
+ isError: true
25799
+ };
25800
+ }
25801
+ },
25802
+ {}
25803
+ );
25804
+ const sendWorkdirFileTool = sdk.tool(
25805
+ "send_workdir_file",
25806
+ `Send a real file from the current scope working directory as a clickable AHChat attachment on this visible reply.
25807
+ Only files inside the current scope cwd are allowed. Directories, missing files, and paths outside cwd are rejected. Pass a relative path from find_workdir_files when possible.`,
25808
+ {
25809
+ path: external_exports.string().min(1).describe("File path to send. Prefer a relative path returned by find_workdir_files; absolute paths are accepted only when they are inside the current scope cwd.")
25810
+ },
25811
+ async (args) => {
25812
+ const requestedPath = args.path.trim();
25813
+ logger9.info("send_workdir_file tool called", {
25814
+ agentId: deps.agentId,
25815
+ scope: currentScopeKey,
25816
+ path: requestedPath
25817
+ });
25818
+ try {
25819
+ const file2 = await resolveWorkdirFilePath(requestedPath, deps.cwd);
25820
+ const marker = {
25821
+ ok: true,
25822
+ kind: WORKDIR_ATTACHMENT_MARKER_KIND,
25823
+ path: file2.absolutePath,
25824
+ relative_path: file2.relativePath,
25825
+ file_name: file2.fileName,
25826
+ mime_type: inferWorkdirFileMimeType(file2.absolutePath),
25827
+ size: file2.size,
25828
+ attachment_source: "agent_explicit_send"
25829
+ };
25830
+ return {
25831
+ content: [{
25832
+ type: "text",
25833
+ text: [
25834
+ JSON.stringify(marker),
25835
+ "",
25836
+ `[send_workdir_file] \u5DF2\u51C6\u5907\u53D1\u9001\u9644\u4EF6\uFF1A${file2.relativePath} (${formatWorkdirFileSize(file2.size)})\u3002\u8BF7\u5728\u672C\u8F6E\u53EF\u89C1\u56DE\u590D\u91CC\u7B80\u77ED\u8BF4\u660E\u9644\u4EF6\u5DF2\u9644\u4E0A\uFF0C\u4E0D\u8981\u91CD\u590D\u8F93\u51FA\u6587\u4EF6\u5168\u6587\u3002`
25837
+ ].join("\n")
25838
+ }]
25839
+ };
25840
+ } catch (e) {
25841
+ const message = e instanceof Error ? e.message : String(e);
25842
+ logger9.error("send_workdir_file failed", {
25843
+ agentId: deps.agentId,
25844
+ scope: currentScopeKey,
25845
+ path: requestedPath,
25846
+ error: e
25847
+ });
25848
+ return {
25849
+ content: [{ type: "text", text: `[send_workdir_file] failed: ${message}` }],
25850
+ isError: true
25851
+ };
25852
+ }
25853
+ },
25854
+ {}
25855
+ );
25606
25856
  const createGroupIssueTool = deps.serverApiUrl ? sdk.tool(
25607
25857
  "create_group_issue",
25608
25858
  `\u628A\u5F53\u524D\u7FA4\u91CC\u7684\u771F\u5B9E\u95EE\u9898\u5199\u5165\u95EE\u9898\u9762\u677F\u3002
@@ -27934,7 +28184,13 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
27934
28184
  },
27935
28185
  {}
27936
28186
  ) : null;
27937
- const tools = [neuralSend, neuralListScopes, readDocumentTool];
28187
+ const tools = [
28188
+ neuralSend,
28189
+ neuralListScopes,
28190
+ readDocumentTool,
28191
+ findWorkdirFilesTool,
28192
+ sendWorkdirFileTool
28193
+ ];
27938
28194
  if (readChatHistory) tools.push(readChatHistory);
27939
28195
  if (selfNote) tools.push(selfNote);
27940
28196
  if (listContacts) tools.push(listContacts);
@@ -27966,7 +28222,7 @@ nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=
27966
28222
  version: "2.3.0",
27967
28223
  tools
27968
28224
  });
27969
- const toolNames = ["neural_send", "neural_list_scopes", "read_document"];
28225
+ const toolNames = ["neural_send", "neural_list_scopes", "read_document", "find_workdir_files", "send_workdir_file"];
27970
28226
  if (readChatHistory) toolNames.push("read_chat_history");
27971
28227
  if (selfNote) toolNames.push("self_note");
27972
28228
  if (listContacts) toolNames.push("list_contacts");
@@ -29714,24 +29970,24 @@ function resetAccumulators(proc) {
29714
29970
  }
29715
29971
 
29716
29972
  // src/forkHistoryReplay.ts
29717
- import * as fs5 from "fs/promises";
29718
- import * as path10 from "path";
29973
+ import * as fs6 from "fs/promises";
29974
+ import * as path11 from "path";
29719
29975
  var logger12 = createModuleLogger("bridge.forkHistoryReplay");
29720
29976
  function metaPath(dataDir, agentId) {
29721
- return path10.join(dataDir, "fork-meta", `${agentId}.json`);
29977
+ return path11.join(dataDir, "fork-meta", `${agentId}.json`);
29722
29978
  }
29723
29979
  async function writeForkMeta(dataDir, agentId, meta3) {
29724
29980
  const fp = metaPath(dataDir, agentId);
29725
- await fs5.mkdir(path10.dirname(fp), { recursive: true });
29726
- await fs5.writeFile(fp, JSON.stringify(meta3), "utf-8");
29981
+ await fs6.mkdir(path11.dirname(fp), { recursive: true });
29982
+ await fs6.writeFile(fp, JSON.stringify(meta3), "utf-8");
29727
29983
  logger12.info("Fork meta written", { agentId, fp, sourceConversationId: meta3.sourceConversationId });
29728
29984
  }
29729
29985
  async function consumeForkMeta(dataDir, agentId) {
29730
29986
  const fp = metaPath(dataDir, agentId);
29731
29987
  try {
29732
- const raw = await fs5.readFile(fp, "utf-8");
29988
+ const raw = await fs6.readFile(fp, "utf-8");
29733
29989
  const meta3 = JSON.parse(raw);
29734
- await fs5.unlink(fp);
29990
+ await fs6.unlink(fp);
29735
29991
  logger12.info("Fork meta consumed (one-shot)", { agentId, sourceConversationId: meta3.sourceConversationId });
29736
29992
  return meta3;
29737
29993
  } catch {
@@ -29758,20 +30014,20 @@ function buildForkHistorySection(messages) {
29758
30014
 
29759
30015
  // src/sessionSlug.ts
29760
30016
  import os6 from "os";
29761
- import path11 from "path";
29762
- var CLAUDE_PROJECTS_DIR = path11.join(os6.homedir(), ".claude", "projects");
30017
+ import path12 from "path";
30018
+ var CLAUDE_PROJECTS_DIR = path12.join(os6.homedir(), ".claude", "projects");
29763
30019
  function cwdToSlug(cwd) {
29764
30020
  return cwd.replace(/[^a-zA-Z0-9-]/g, "-");
29765
30021
  }
29766
30022
  function sessionDirForCwd(cwd) {
29767
- return path11.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
30023
+ return path12.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
29768
30024
  }
29769
30025
  function sessionFilePath(cwd, sessionId) {
29770
- return path11.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
30026
+ return path12.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
29771
30027
  }
29772
30028
 
29773
30029
  // src/workdirMapper.ts
29774
- import path12 from "path";
30030
+ import path13 from "path";
29775
30031
  function extractAhchatWorkspaceParts(requestedPath) {
29776
30032
  const normalized = requestedPath.trim().replace(/\\/g, "/");
29777
30033
  const marker = "/.ahchat/users/";
@@ -29807,15 +30063,15 @@ function extractAhchatWorkspaceParts(requestedPath) {
29807
30063
  function extractAhchatWorkspaceSuffix(requestedPath) {
29808
30064
  const parts = extractAhchatWorkspaceParts(requestedPath);
29809
30065
  if (!parts || parts.length === 0) return null;
29810
- return path12.join(...parts);
30066
+ return path13.join(...parts);
29811
30067
  }
29812
30068
  function remapServerWorkspacePath(requestedPath, workspacesDir) {
29813
30069
  const parts = extractAhchatWorkspaceParts(requestedPath);
29814
30070
  if (!parts) return { path: requestedPath, remapped: false };
29815
- const remappedPath = parts.length > 0 ? path12.join(workspacesDir, ...parts) : workspacesDir;
30071
+ const remappedPath = parts.length > 0 ? path13.join(workspacesDir, ...parts) : workspacesDir;
29816
30072
  return {
29817
30073
  path: remappedPath,
29818
- remapped: path12.normalize(requestedPath) !== path12.normalize(remappedPath)
30074
+ remapped: path13.normalize(requestedPath) !== path13.normalize(remappedPath)
29819
30075
  };
29820
30076
  }
29821
30077
 
@@ -29935,10 +30191,51 @@ var SMITH_ALLOWED_TOOLS = [
29935
30191
  // neural bridge — cross-scope coordination when Smith is pulled into a group
29936
30192
  "mcp__neural__neural_send",
29937
30193
  "mcp__neural__neural_list_scopes",
30194
+ // bounded current-scope workdir attachments
30195
+ "mcp__neural__find_workdir_files",
30196
+ "mcp__neural__send_workdir_file",
29938
30197
  // interaction / planning
29939
30198
  "AskUserQuestion",
29940
30199
  "Write"
29941
30200
  ];
30201
+ function isVisionMcpServerName(serverName) {
30202
+ return serverName === "vision";
30203
+ }
30204
+ function selectSmithVisionMcp(resolved) {
30205
+ const resolvedMcpServers = resolved.mcpServers ?? {};
30206
+ const resolvedAllowedTools = resolved.allowedTools ?? [];
30207
+ const resolvedToolAbi = resolved.toolAbi ?? [];
30208
+ const visionServerNames = /* @__PURE__ */ new Set();
30209
+ for (const server of resolvedToolAbi) {
30210
+ if (server.providerId === "volcengine_vision" || isVisionMcpServerName(server.serverName)) {
30211
+ visionServerNames.add(server.serverName);
30212
+ }
30213
+ }
30214
+ for (const toolName of resolvedAllowedTools) {
30215
+ const parsed = parseMcpRuntimeToolName(toolName);
30216
+ if (parsed && isVisionMcpServerName(parsed.serverName)) {
30217
+ visionServerNames.add(parsed.serverName);
30218
+ }
30219
+ }
30220
+ for (const serverName of Object.keys(resolvedMcpServers)) {
30221
+ if (isVisionMcpServerName(serverName)) {
30222
+ visionServerNames.add(serverName);
30223
+ }
30224
+ }
30225
+ if (visionServerNames.size === 0) {
30226
+ return { mcpServers: {}, allowedTools: [], toolAbi: [] };
30227
+ }
30228
+ return {
30229
+ mcpServers: Object.fromEntries(
30230
+ Object.entries(resolvedMcpServers).filter(([serverName]) => visionServerNames.has(serverName))
30231
+ ),
30232
+ allowedTools: resolvedAllowedTools.filter((toolName) => {
30233
+ const parsed = parseMcpRuntimeToolName(toolName);
30234
+ return Boolean(parsed && visionServerNames.has(parsed.serverName));
30235
+ }),
30236
+ toolAbi: resolvedToolAbi.filter((server) => visionServerNames.has(server.serverName))
30237
+ };
30238
+ }
29942
30239
  function resolveVisionMcpToolHints(externalMcp) {
29943
30240
  let describe3 = null;
29944
30241
  let ocr = null;
@@ -30006,7 +30303,7 @@ function uniqueNormalizedPaths(paths) {
30006
30303
  for (const item of paths) {
30007
30304
  const trimmed = item.trim();
30008
30305
  if (!trimmed) continue;
30009
- const normalized = path13.normalize(trimmed);
30306
+ const normalized = path14.normalize(trimmed);
30010
30307
  const key = process.platform === "win32" ? normalized.toLowerCase() : normalized;
30011
30308
  if (seen.has(key)) continue;
30012
30309
  seen.add(key);
@@ -30036,7 +30333,7 @@ function resolveReadToolImagePath(input, cwd) {
30036
30333
  if (typeof raw !== "string" || raw.trim().length === 0) return null;
30037
30334
  const trimmed = raw.trim();
30038
30335
  if (!IMAGE_READ_EXT_RE.test(trimmed)) return null;
30039
- const abs = path13.isAbsolute(trimmed) ? path13.normalize(trimmed) : path13.resolve(cwd, trimmed);
30336
+ const abs = path14.isAbsolute(trimmed) ? path14.normalize(trimmed) : path14.resolve(cwd, trimmed);
30040
30337
  return { raw: trimmed, abs };
30041
30338
  }
30042
30339
  function usesIsolatedProjectBackend(cfg) {
@@ -30055,14 +30352,14 @@ function buildModelGatewayBaseUrl(serverApiUrl, subscriptionId) {
30055
30352
  }
30056
30353
  async function chownForRootSpawn(targetPath, target) {
30057
30354
  try {
30058
- await fs6.chown(targetPath, NODE_USER_UID, NODE_USER_UID);
30355
+ await fs7.chown(targetPath, NODE_USER_UID, NODE_USER_UID);
30059
30356
  } catch (error51) {
30060
30357
  logger14.error("Best-effort root chown failed", { error: error51, target, path: targetPath });
30061
30358
  }
30062
30359
  }
30063
30360
  function readCronLockSnapshot() {
30064
30361
  try {
30065
- const lockPath2 = path13.join(os7.homedir(), ".claude", "scheduled_tasks.lock");
30362
+ const lockPath2 = path14.join(os7.homedir(), ".claude", "scheduled_tasks.lock");
30066
30363
  if (!fsSync.existsSync(lockPath2)) {
30067
30364
  return { exists: false, sessionId: null, pid: null };
30068
30365
  }
@@ -30334,8 +30631,8 @@ var AgentManager = class {
30334
30631
  this.emit = emit;
30335
30632
  if (typeof options === "function") {
30336
30633
  this.queryFn = options;
30337
- this.workspacesDir = path13.join(os7.homedir(), ".ahchat", "workspaces");
30338
- this.agentConfigDir = path13.join(os7.homedir(), ".ahchat", "agent-config");
30634
+ this.workspacesDir = path14.join(os7.homedir(), ".ahchat", "workspaces");
30635
+ this.agentConfigDir = path14.join(os7.homedir(), ".ahchat", "agent-config");
30339
30636
  this.queryConfig = DEFAULT_QUERY_CONFIG;
30340
30637
  this.askQuestionRegistry = new AskQuestionRegistry();
30341
30638
  this.groupRegistry = null;
@@ -30352,13 +30649,13 @@ var AgentManager = class {
30352
30649
  this.bridgeToken = null;
30353
30650
  this.currentBridgeKey = null;
30354
30651
  this.defaultModel = null;
30355
- this.dataDir = path13.join(os7.homedir(), ".ahchat");
30652
+ this.dataDir = path14.join(os7.homedir(), ".ahchat");
30356
30653
  this.workdirOverrideStore = null;
30357
30654
  this.officeCliRuntime = null;
30358
30655
  } else {
30359
30656
  this.queryFn = options?.queryFn ?? null;
30360
- this.workspacesDir = options?.workspacesDir ?? path13.join(os7.homedir(), ".ahchat", "workspaces");
30361
- this.agentConfigDir = options?.agentConfigDir ?? path13.join(os7.homedir(), ".ahchat", "agent-config");
30657
+ this.workspacesDir = options?.workspacesDir ?? path14.join(os7.homedir(), ".ahchat", "workspaces");
30658
+ this.agentConfigDir = options?.agentConfigDir ?? path14.join(os7.homedir(), ".ahchat", "agent-config");
30362
30659
  this.queryConfig = options?.queryConfig ?? DEFAULT_QUERY_CONFIG;
30363
30660
  this.askQuestionRegistry = options?.askQuestionRegistry ?? new AskQuestionRegistry();
30364
30661
  this.groupRegistry = options?.groupRegistry ?? null;
@@ -30375,7 +30672,7 @@ var AgentManager = class {
30375
30672
  this.mcpAuditRecorder = options?.mcpAuditRecorder ?? new HttpMcpAuditClient(this.serverApiUrl, this.bridgeToken);
30376
30673
  this.mcpBillingPreflightChecker = options?.mcpBillingPreflightChecker ?? new HttpMcpBillingClient(this.serverApiUrl, this.bridgeToken);
30377
30674
  this.defaultModel = options?.defaultModel ?? null;
30378
- this.dataDir = options?.dataDir ?? path13.join(os7.homedir(), ".ahchat");
30675
+ this.dataDir = options?.dataDir ?? path14.join(os7.homedir(), ".ahchat");
30379
30676
  this.workdirOverrideStore = options?.workdirOverrideStore ?? null;
30380
30677
  this.officeCliRuntime = options?.officeCliRuntime ?? null;
30381
30678
  }
@@ -30408,9 +30705,9 @@ var AgentManager = class {
30408
30705
  const normalized = requestedCwd.trim();
30409
30706
  const ahchatSuffix = extractAhchatWorkspaceSuffix(normalized);
30410
30707
  if (ahchatSuffix) {
30411
- return path13.join(this.workspacesDir, ahchatSuffix);
30708
+ return path14.join(this.workspacesDir, ahchatSuffix);
30412
30709
  }
30413
- return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30710
+ return path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30414
30711
  }
30415
30712
  localScopeDirName(agentConfig, scope) {
30416
30713
  if (scope.kind === "group") return `Group-${scope.groupId}`;
@@ -30421,9 +30718,9 @@ var AgentManager = class {
30421
30718
  if (scope.kind === "group") {
30422
30719
  const groupCwd = this.groupRegistry?.getById(scope.groupId)?.workingDirectory?.trim();
30423
30720
  if (groupCwd) return groupCwd;
30424
- return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30721
+ return path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30425
30722
  }
30426
- const local = path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30723
+ const local = path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30427
30724
  return agentConfig.workingDirectory?.trim() || local;
30428
30725
  }
30429
30726
  runtimeCwdInput(agentConfig, scope, cwd) {
@@ -30435,7 +30732,7 @@ var AgentManager = class {
30435
30732
  if (requested && (!agentCwd || !this.isSameRuntimeCwd(requested, agentCwd))) {
30436
30733
  return requested;
30437
30734
  }
30438
- return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30735
+ return path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30439
30736
  }
30440
30737
  return agentConfig.workingDirectory?.trim() || requested || this.scopeCwdInput(agentConfig, scope);
30441
30738
  }
@@ -30470,7 +30767,7 @@ var AgentManager = class {
30470
30767
  let cwd = this.remapServerWorkspaceCwd(agentConfig, scope, requestedCwd);
30471
30768
  let fallbackForensicsId;
30472
30769
  if (!isFullyQualifiedAbsolutePath(cwd)) {
30473
- const fallback = path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30770
+ const fallback = path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
30474
30771
  logger14.error(
30475
30772
  "Working directory is not usable on this machine; using local sandbox fallback",
30476
30773
  {
@@ -30506,7 +30803,7 @@ var AgentManager = class {
30506
30803
  cwd = this.fallbackCwd(agentConfig, scope, cwd);
30507
30804
  }
30508
30805
  try {
30509
- await fs6.mkdir(cwd, { recursive: true });
30806
+ await fs7.mkdir(cwd, { recursive: true });
30510
30807
  return cwd;
30511
30808
  } catch (e) {
30512
30809
  const fallback = this.fallbackCwd(agentConfig, scope, cwd);
@@ -30533,7 +30830,7 @@ var AgentManager = class {
30533
30830
  },
30534
30831
  outcome: { result: "second_layer_fallback" }
30535
30832
  });
30536
- await fs6.mkdir(fallback, { recursive: true });
30833
+ await fs7.mkdir(fallback, { recursive: true });
30537
30834
  return fallback;
30538
30835
  }
30539
30836
  }
@@ -30727,25 +31024,25 @@ var AgentManager = class {
30727
31024
  }
30728
31025
  settingsPathForConfig(cfg, effectiveConfigDir) {
30729
31026
  if (!usesIsolatedProjectBackend(cfg)) return void 0;
30730
- return path13.join(effectiveConfigDir, "settings.json");
31027
+ return path14.join(effectiveConfigDir, "settings.json");
30731
31028
  }
30732
31029
  isSameRuntimeCwd(a, b) {
30733
- const left = path13.normalize(a);
30734
- const right = path13.normalize(b);
31030
+ const left = path14.normalize(a);
31031
+ const right = path14.normalize(b);
30735
31032
  return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
30736
31033
  }
30737
31034
  sessionProjectDirs(agentConfig, effectiveConfigDir) {
30738
31035
  return uniqueNormalizedPaths([
30739
- path13.join(effectiveConfigDir, "api-key-agents", agentConfig.id, "projects"),
30740
- path13.join(effectiveConfigDir, "projects"),
30741
- path13.join(os7.homedir(), ".claude", "projects")
31036
+ path14.join(effectiveConfigDir, "api-key-agents", agentConfig.id, "projects"),
31037
+ path14.join(effectiveConfigDir, "projects"),
31038
+ path14.join(os7.homedir(), ".claude", "projects")
30742
31039
  ]);
30743
31040
  }
30744
31041
  sessionPathsForCwd(projectsDirs, cwd, sessionId) {
30745
31042
  return uniqueNormalizedPaths(
30746
31043
  projectsDirs.flatMap(
30747
31044
  (projectsDir) => claudeProjectSlugCandidates(cwd).map(
30748
- (slug) => path13.join(projectsDir, slug, `${sessionId}.jsonl`)
31045
+ (slug) => path14.join(projectsDir, slug, `${sessionId}.jsonl`)
30749
31046
  )
30750
31047
  )
30751
31048
  );
@@ -30766,7 +31063,7 @@ var AgentManager = class {
30766
31063
  }
30767
31064
  for (const entry of entries) {
30768
31065
  if (!entry.isDirectory()) continue;
30769
- const candidate = path13.join(projectsDir, entry.name, `${sessionId}.jsonl`);
31066
+ const candidate = path14.join(projectsDir, entry.name, `${sessionId}.jsonl`);
30770
31067
  if (fsSync.existsSync(candidate)) found.push(candidate);
30771
31068
  }
30772
31069
  }
@@ -30781,12 +31078,12 @@ var AgentManager = class {
30781
31078
  }
30782
31079
  const currentPathSet = new Set(
30783
31080
  currentCwdPaths.map(
30784
- (candidate) => process.platform === "win32" ? path13.normalize(candidate).toLowerCase() : path13.normalize(candidate)
31081
+ (candidate) => process.platform === "win32" ? path14.normalize(candidate).toLowerCase() : path14.normalize(candidate)
30785
31082
  )
30786
31083
  );
30787
31084
  const foundElsewhere = this.findSessionJsonlFiles(projectsDirs, sessionId).filter(
30788
31085
  (candidate) => {
30789
- const normalized = process.platform === "win32" ? path13.normalize(candidate).toLowerCase() : path13.normalize(candidate);
31086
+ const normalized = process.platform === "win32" ? path14.normalize(candidate).toLowerCase() : path14.normalize(candidate);
30790
31087
  return !currentPathSet.has(normalized);
30791
31088
  }
30792
31089
  );
@@ -30807,7 +31104,7 @@ var AgentManager = class {
30807
31104
  return null;
30808
31105
  }
30809
31106
  scopePromptFingerprint(agentConfig, scope, agentCwd, scopesSection, externalMcpFingerprint, runtimeToolPolicyFingerprint = "") {
30810
- const hash2 = createHash("sha256").update(SCOPE_PROMPT_FINGERPRINT_REVISION).update("\0").update(agentConfig.id).update("\0").update(agentConfig.name).update("\0").update(scopeKey(scope)).update("\0").update(path13.normalize(agentCwd)).update("\0").update(scopesSection).update("\0").update(externalMcpFingerprint);
31107
+ const hash2 = createHash("sha256").update(SCOPE_PROMPT_FINGERPRINT_REVISION).update("\0").update(agentConfig.id).update("\0").update(agentConfig.name).update("\0").update(scopeKey(scope)).update("\0").update(path14.normalize(agentCwd)).update("\0").update(scopesSection).update("\0").update(externalMcpFingerprint);
30811
31108
  if (runtimeToolPolicyFingerprint) {
30812
31109
  hash2.update("\0runtimeToolPolicy\0").update(runtimeToolPolicyFingerprint);
30813
31110
  }
@@ -31164,7 +31461,7 @@ var AgentManager = class {
31164
31461
  const scopedInstructions = cfg.instructions?.trim() && scope.kind === "group" ? `# Agent project instructions
31165
31462
  ${cfg.instructions.trim()}` : "";
31166
31463
  if (cfg.instructions?.trim() && scope.kind === "single") {
31167
- await fs6.writeFile(path13.join(agentCwd, "CLAUDE.md"), cfg.instructions.trim(), "utf-8");
31464
+ await fs7.writeFile(path14.join(agentCwd, "CLAUDE.md"), cfg.instructions.trim(), "utf-8");
31168
31465
  logger14.info("CLAUDE.md written", {
31169
31466
  agentId: agentConfig.id,
31170
31467
  scope: scopeKey(scope),
@@ -31173,10 +31470,10 @@ ${cfg.instructions.trim()}` : "";
31173
31470
  }
31174
31471
  let effectiveConfigDir = this.agentConfigDir;
31175
31472
  if (cfg.subscriptionType !== "system" && cfg.apiKey) {
31176
- effectiveConfigDir = path13.join(this.agentConfigDir, "api-key-agents", agentConfig.id);
31473
+ effectiveConfigDir = path14.join(this.agentConfigDir, "api-key-agents", agentConfig.id);
31177
31474
  let isNew = false;
31178
31475
  try {
31179
- await fs6.access(effectiveConfigDir);
31476
+ await fs7.access(effectiveConfigDir);
31180
31477
  } catch (e) {
31181
31478
  logger14.debug("Agent API key config dir missing; creating isolated dir", {
31182
31479
  error: e,
@@ -31184,7 +31481,7 @@ ${cfg.instructions.trim()}` : "";
31184
31481
  });
31185
31482
  isNew = true;
31186
31483
  }
31187
- await fs6.mkdir(effectiveConfigDir, { recursive: true });
31484
+ await fs7.mkdir(effectiveConfigDir, { recursive: true });
31188
31485
  if (isNew) {
31189
31486
  this.sessionStore.delete(agentConfig.id, scope);
31190
31487
  this.dispatchMemory.deleteScope(agentConfig.id, scope);
@@ -31192,13 +31489,13 @@ ${cfg.instructions.trim()}` : "";
31192
31489
  agentId: agentConfig.id
31193
31490
  });
31194
31491
  }
31195
- const settingsPath = path13.join(effectiveConfigDir, "settings.json");
31492
+ const settingsPath = path14.join(effectiveConfigDir, "settings.json");
31196
31493
  const envEntries = buildAnthropicCredentialEnv(cfg);
31197
31494
  if (cfg.apiBaseUrl) envEntries.ANTHROPIC_BASE_URL = cfg.apiBaseUrl;
31198
31495
  let existingSettings = {};
31199
31496
  if (fsSync.existsSync(settingsPath)) {
31200
31497
  try {
31201
- const raw = await fs6.readFile(settingsPath, "utf-8");
31498
+ const raw = await fs7.readFile(settingsPath, "utf-8");
31202
31499
  existingSettings = JSON.parse(raw);
31203
31500
  } catch (error51) {
31204
31501
  logger14.error("Failed to read existing API-key agent settings; starting fresh", {
@@ -31213,7 +31510,7 @@ ${cfg.instructions.trim()}` : "";
31213
31510
  if (envEntries.ANTHROPIC_AUTH_TOKEN) delete mergedEnv.ANTHROPIC_API_KEY;
31214
31511
  if (envEntries.ANTHROPIC_API_KEY) delete mergedEnv.ANTHROPIC_AUTH_TOKEN;
31215
31512
  const mergedSettings = { ...existingSettings, env: mergedEnv };
31216
- await fs6.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
31513
+ await fs7.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2), "utf-8");
31217
31514
  logger14.info("API-key agent using isolated config dir", {
31218
31515
  agentId: agentConfig.id,
31219
31516
  configDirKind: "api-key-agent",
@@ -31316,13 +31613,15 @@ ${cfg.instructions.trim()}` : "";
31316
31613
  isSmith: smithAgent,
31317
31614
  cwd: agentCwd
31318
31615
  }) ?? { mcpServers: {}, allowedTools: [], toolAbi: [] };
31319
- const externalMcp = smithAgent ? { mcpServers: {}, allowedTools: [], toolAbi: [] } : resolvedExternalMcp;
31320
- if (smithAgent && (Object.keys(resolvedExternalMcp.mcpServers).length > 0 || resolvedExternalMcp.allowedTools.length > 0 || (resolvedExternalMcp.toolAbi?.length ?? 0) > 0)) {
31321
- logger14.info("Smith external MCP ignored by fixed tool whitelist", {
31616
+ const externalMcp = smithAgent ? selectSmithVisionMcp(resolvedExternalMcp) : resolvedExternalMcp;
31617
+ if (smithAgent && (Object.keys(resolvedExternalMcp.mcpServers).length !== Object.keys(externalMcp.mcpServers).length || resolvedExternalMcp.allowedTools.length !== externalMcp.allowedTools.length || (resolvedExternalMcp.toolAbi?.length ?? 0) !== (externalMcp.toolAbi?.length ?? 0))) {
31618
+ logger14.info("Smith external MCP filtered by fixed tool whitelist", {
31322
31619
  agentId: agentConfig.id,
31323
31620
  scope: scopeKey(scope),
31324
31621
  serverNames: Object.keys(resolvedExternalMcp.mcpServers),
31325
- allowedToolCount: resolvedExternalMcp.allowedTools.length
31622
+ allowedToolCount: resolvedExternalMcp.allowedTools.length,
31623
+ retainedServerNames: Object.keys(externalMcp.mcpServers),
31624
+ retainedAllowedToolCount: externalMcp.allowedTools.length
31326
31625
  });
31327
31626
  }
31328
31627
  const visionMcpTools = resolveVisionMcpToolHints(externalMcp);
@@ -31446,6 +31745,8 @@ ${cfg.instructions.trim()}` : "";
31446
31745
  "AskUserQuestion",
31447
31746
  "mcp__neural__neural_send",
31448
31747
  "mcp__neural__neural_list_scopes",
31748
+ "mcp__neural__find_workdir_files",
31749
+ "mcp__neural__send_workdir_file",
31449
31750
  "mcp__neural__self_note",
31450
31751
  "mcp__neural__list_contacts",
31451
31752
  "mcp__neural__create_group",
@@ -31766,7 +32067,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
31766
32067
  if (isRunningAsRoot()) {
31767
32068
  await chownForRootSpawn(effectiveConfigDir, "configDir");
31768
32069
  await chownForRootSpawn(agentCwd, "agentCwd");
31769
- const settingsFilePath = path13.join(effectiveConfigDir, "settings.json");
32070
+ const settingsFilePath = path14.join(effectiveConfigDir, "settings.json");
31770
32071
  await chownForRootSpawn(settingsFilePath, "settingsFile");
31771
32072
  options.spawnClaudeCodeProcess = (spawnOptions) => {
31772
32073
  const env2 = { ...spawnOptions.env, HOME: "/home/node" };
@@ -31836,7 +32137,7 @@ Do NOT use "..." as content \u2014 write specific, project-relevant content.`;
31836
32137
  mergedTasks: [],
31837
32138
  planModeBuffer: [],
31838
32139
  createdAt: Date.now(),
31839
- supportsVision: modelInputMode === "vision",
32140
+ supportsVision: cfg.supportsVision === true,
31840
32141
  modelInputMode,
31841
32142
  visionMcpTools,
31842
32143
  quietFlushTimer: null,
@@ -32024,7 +32325,7 @@ ${trimmed}`;
32024
32325
  promptWorkdir(agentConfig, scope, requestedCwd) {
32025
32326
  const remapped = this.remapServerWorkspaceCwd(agentConfig, scope, requestedCwd);
32026
32327
  if (!isFullyQualifiedAbsolutePath(remapped)) {
32027
- return path13.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
32328
+ return path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
32028
32329
  }
32029
32330
  return remapped;
32030
32331
  }
@@ -32729,12 +33030,12 @@ ${lines.join("\n")}`;
32729
33030
  }
32730
33031
  async materializeAttachment(runtime, attachment, buffer) {
32731
33032
  const safeFileName = this.safeAttachmentFileName(attachment.fileName);
32732
- const attachmentDir = path13.join(runtime.cwd, ".ahchat-attachments", attachment.id);
33033
+ const attachmentDir = path14.join(runtime.cwd, ".ahchat-attachments", attachment.id);
32733
33034
  let filePath = await this.resolveExistingWorkspaceAttachmentPath(runtime, attachment);
32734
33035
  if (!filePath) {
32735
- await fs6.mkdir(attachmentDir, { recursive: true });
32736
- filePath = path13.join(attachmentDir, safeFileName);
32737
- await fs6.writeFile(filePath, buffer);
33036
+ await fs7.mkdir(attachmentDir, { recursive: true });
33037
+ filePath = path14.join(attachmentDir, safeFileName);
33038
+ await fs7.writeFile(filePath, buffer);
32738
33039
  }
32739
33040
  const materialized = { filePath };
32740
33041
  if (isReadableDocumentPath(filePath)) {
@@ -32763,10 +33064,10 @@ ${lines.join("\n")}`;
32763
33064
  const rawPath = typeof localWorkspacePath === "string" && localWorkspacePath.trim() ? localWorkspacePath : workspacePath;
32764
33065
  if (typeof rawPath !== "string" || !rawPath.trim()) return null;
32765
33066
  const remapped = remapServerWorkspacePath(rawPath, this.workspacesDir);
32766
- const candidate = path13.resolve(remapped.path);
33067
+ const candidate = path14.resolve(remapped.path);
32767
33068
  if (!this.isPathInsideBase(candidate, runtime.cwd)) return null;
32768
33069
  try {
32769
- const stat3 = await fs6.stat(candidate);
33070
+ const stat3 = await fs7.stat(candidate);
32770
33071
  return stat3.isFile() ? candidate : null;
32771
33072
  } catch (e) {
32772
33073
  logger14.warn("Workspace attachment path unavailable", {
@@ -32781,13 +33082,13 @@ ${lines.join("\n")}`;
32781
33082
  }
32782
33083
  }
32783
33084
  isPathInsideBase(filePath, basePath) {
32784
- const resolvedFile = path13.resolve(filePath);
32785
- const resolvedBase = path13.resolve(basePath);
32786
- const relative = path13.relative(resolvedBase, resolvedFile);
32787
- return relative === "" || !relative.startsWith("..") && !path13.isAbsolute(relative);
33085
+ const resolvedFile = path14.resolve(filePath);
33086
+ const resolvedBase = path14.resolve(basePath);
33087
+ const relative = path14.relative(resolvedBase, resolvedFile);
33088
+ return relative === "" || !relative.startsWith("..") && !path14.isAbsolute(relative);
32788
33089
  }
32789
33090
  safeAttachmentFileName(fileName) {
32790
- const baseName = path13.basename(fileName).replace(/[\0/:\\]/g, "_").trim();
33091
+ const baseName = path14.basename(fileName).replace(/[\0/:\\]/g, "_").trim();
32791
33092
  return baseName || "attachment";
32792
33093
  }
32793
33094
  emitTaskPushError(runtime, task, error51) {
@@ -35164,8 +35465,8 @@ async function readJson(res) {
35164
35465
  return null;
35165
35466
  }
35166
35467
  }
35167
- function apiUrl(baseUrl, path34) {
35168
- return new URL(path34, baseUrl).toString();
35468
+ function apiUrl(baseUrl, path35) {
35469
+ return new URL(path35, baseUrl).toString();
35169
35470
  }
35170
35471
  async function fetchServerSkillSet(options) {
35171
35472
  try {
@@ -35419,8 +35720,8 @@ var HttpAgentRegistry = class {
35419
35720
  lastRefreshCount = null;
35420
35721
  apiUrl(suffix) {
35421
35722
  const base = this.serverApiUrl.replace(/\/$/, "");
35422
- const path34 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35423
- return `${base}${path34}`;
35723
+ const path35 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35724
+ return `${base}${path35}`;
35424
35725
  }
35425
35726
  async refresh() {
35426
35727
  const attempt = async () => {
@@ -35523,8 +35824,8 @@ var HttpSubscriptionRegistry = class {
35523
35824
  lastRefreshCount = null;
35524
35825
  apiUrl(suffix) {
35525
35826
  const base = this.serverApiUrl.replace(/\/$/, "");
35526
- const path34 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35527
- return `${base}${path34}`;
35827
+ const path35 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35828
+ return `${base}${path35}`;
35528
35829
  }
35529
35830
  rebuildPrimaryAlias() {
35530
35831
  this.subscriptions.delete(PRIMARY_COMPANY_SUBSCRIPTION_ID);
@@ -35602,8 +35903,8 @@ var HttpSubscriptionRegistry = class {
35602
35903
  };
35603
35904
 
35604
35905
  // src/mcpRegistry.ts
35605
- import fs7 from "fs";
35606
- import path14 from "path";
35906
+ import fs8 from "fs";
35907
+ import path15 from "path";
35607
35908
  import { fileURLToPath } from "url";
35608
35909
  var logger19 = createModuleLogger("mcp.registry");
35609
35910
  var AHCHAT_BUILTIN_MCP_COMMAND = "ahchat-builtin";
@@ -35625,8 +35926,8 @@ var HttpMcpRegistry = class {
35625
35926
  lastRefreshCount = null;
35626
35927
  apiUrl(suffix) {
35627
35928
  const base = this.serverApiUrl.replace(/\/$/, "");
35628
- const path34 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35629
- return `${base}${path34}`;
35929
+ const path35 = suffix.startsWith("/") ? suffix : `/${suffix}`;
35930
+ return `${base}${path35}`;
35630
35931
  }
35631
35932
  async refresh() {
35632
35933
  this.refreshLocal();
@@ -35818,13 +36119,13 @@ function resolveVisionMcpExecutable(extraArgs, options = {}) {
35818
36119
  return resolveBundledMcpExecutable("visionMcpCli", extraArgs, options);
35819
36120
  }
35820
36121
  function resolveBundledMcpExecutable(cliBaseName, extraArgs, options = {}) {
35821
- const currentDir = options.currentDir ?? path14.dirname(fileURLToPath(import.meta.url));
36122
+ const currentDir = options.currentDir ?? path15.dirname(fileURLToPath(import.meta.url));
35822
36123
  const cwd = options.cwd ?? process.cwd();
35823
36124
  const execPath = options.execPath ?? process.execPath;
35824
- const existsSync3 = options.existsSync ?? fs7.existsSync;
36125
+ const existsSync3 = options.existsSync ?? fs8.existsSync;
35825
36126
  const distCliPath = firstExistingPath(
35826
36127
  [
35827
- path14.join(currentDir, `${cliBaseName}.cjs`)
36128
+ path15.join(currentDir, `${cliBaseName}.cjs`)
35828
36129
  ],
35829
36130
  existsSync3
35830
36131
  );
@@ -35837,7 +36138,7 @@ function resolveBundledMcpExecutable(cliBaseName, extraArgs, options = {}) {
35837
36138
  }
35838
36139
  const sourceCliPath = firstExistingPath(
35839
36140
  [
35840
- path14.join(currentDir, `${cliBaseName}.ts`)
36141
+ path15.join(currentDir, `${cliBaseName}.ts`)
35841
36142
  ],
35842
36143
  existsSync3
35843
36144
  );
@@ -35846,9 +36147,9 @@ function resolveBundledMcpExecutable(cliBaseName, extraArgs, options = {}) {
35846
36147
  }
35847
36148
  const workspaceDistCliPath = firstExistingPath(
35848
36149
  [
35849
- path14.resolve(currentDir, `../../bridge/dist/${cliBaseName}.cjs`),
35850
- path14.resolve(cwd, `packages/desktop/dist/${cliBaseName}.cjs`),
35851
- path14.resolve(cwd, `packages/bridge/dist/${cliBaseName}.cjs`)
36150
+ path15.resolve(currentDir, `../../bridge/dist/${cliBaseName}.cjs`),
36151
+ path15.resolve(cwd, `packages/desktop/dist/${cliBaseName}.cjs`),
36152
+ path15.resolve(cwd, `packages/bridge/dist/${cliBaseName}.cjs`)
35852
36153
  ],
35853
36154
  existsSync3
35854
36155
  );
@@ -35861,8 +36162,8 @@ function resolveBundledMcpExecutable(cliBaseName, extraArgs, options = {}) {
35861
36162
  }
35862
36163
  const workspaceSourceCliPath = firstExistingPath(
35863
36164
  [
35864
- path14.resolve(currentDir, `../../bridge/src/${cliBaseName}.ts`),
35865
- path14.resolve(cwd, `packages/bridge/src/${cliBaseName}.ts`)
36165
+ path15.resolve(currentDir, `../../bridge/src/${cliBaseName}.ts`),
36166
+ path15.resolve(cwd, `packages/bridge/src/${cliBaseName}.ts`)
35866
36167
  ],
35867
36168
  existsSync3
35868
36169
  );
@@ -35883,7 +36184,7 @@ function firstExistingPath(paths, existsSync3) {
35883
36184
  function shouldRunExecPathAsNode(execPath, options) {
35884
36185
  if (typeof options.isElectron === "boolean") return options.isElectron;
35885
36186
  if (process.versions.electron) return true;
35886
- return path14.basename(execPath).toLowerCase().includes("electron");
36187
+ return path15.basename(execPath).toLowerCase().includes("electron");
35887
36188
  }
35888
36189
  function uniqueServerName(serverName, usedNames) {
35889
36190
  if (!usedNames.has(serverName)) return serverName;
@@ -35921,19 +36222,19 @@ function toolPolicies(connection) {
35921
36222
  }
35922
36223
 
35923
36224
  // src/localMcpStore.ts
35924
- import fs8 from "fs";
35925
- import path15 from "path";
36225
+ import fs9 from "fs";
36226
+ import path16 from "path";
35926
36227
  var logger20 = createModuleLogger("bridge.localMcpStore");
35927
36228
  var LocalMcpStore = class {
35928
36229
  constructor(dataDir) {
35929
36230
  this.dataDir = dataDir;
35930
- this.filePath = path15.join(dataDir, LOCAL_MCP_CONNECTIONS_FILENAME);
36231
+ this.filePath = path16.join(dataDir, LOCAL_MCP_CONNECTIONS_FILENAME);
35931
36232
  }
35932
36233
  dataDir;
35933
36234
  filePath;
35934
36235
  list() {
35935
36236
  try {
35936
- const raw = fs8.readFileSync(this.filePath, "utf8");
36237
+ const raw = fs9.readFileSync(this.filePath, "utf8");
35937
36238
  return normalizeLocalMcpConnectionsFile(JSON.parse(raw)).connections;
35938
36239
  } catch (error51) {
35939
36240
  if (isNodeErrorCode(error51, "ENOENT")) return [];
@@ -35942,14 +36243,14 @@ var LocalMcpStore = class {
35942
36243
  }
35943
36244
  }
35944
36245
  watch(onChange) {
35945
- fs8.mkdirSync(this.dataDir, { recursive: true });
36246
+ fs9.mkdirSync(this.dataDir, { recursive: true });
35946
36247
  const listener = () => {
35947
36248
  void Promise.resolve(onChange()).catch((error51) => {
35948
36249
  logger20.error("Local MCP change handler failed", { filePath: this.filePath, error: error51 });
35949
36250
  });
35950
36251
  };
35951
- fs8.watchFile(this.filePath, { interval: 1e3 }, listener);
35952
- return () => fs8.unwatchFile(this.filePath, listener);
36252
+ fs9.watchFile(this.filePath, { interval: 1e3 }, listener);
36253
+ return () => fs9.unwatchFile(this.filePath, listener);
35953
36254
  }
35954
36255
  };
35955
36256
  function isNodeErrorCode(error51, code) {
@@ -35957,13 +36258,13 @@ function isNodeErrorCode(error51, code) {
35957
36258
  }
35958
36259
 
35959
36260
  // src/localSkillStore.ts
35960
- import fs9 from "fs";
35961
- import path16 from "path";
36261
+ import fs10 from "fs";
36262
+ import path17 from "path";
35962
36263
  var logger21 = createModuleLogger("bridge.localSkillStore");
35963
36264
  var LocalSkillStore = class {
35964
36265
  constructor(dataDir, runtimeScope = {}) {
35965
36266
  this.dataDir = dataDir;
35966
- this.filePath = path16.join(dataDir, LOCAL_SKILLS_FILENAME);
36267
+ this.filePath = path17.join(dataDir, LOCAL_SKILLS_FILENAME);
35967
36268
  this.runtimeScope = runtimeScope;
35968
36269
  }
35969
36270
  dataDir;
@@ -35974,7 +36275,7 @@ var LocalSkillStore = class {
35974
36275
  }
35975
36276
  readAll() {
35976
36277
  try {
35977
- const raw = fs9.readFileSync(this.filePath, "utf8");
36278
+ const raw = fs10.readFileSync(this.filePath, "utf8");
35978
36279
  return normalizeLocalSkillsFile(JSON.parse(raw)).skills;
35979
36280
  } catch (error51) {
35980
36281
  if (isNodeErrorCode2(error51, "ENOENT")) return [];
@@ -36018,24 +36319,24 @@ var LocalSkillStore = class {
36018
36319
  return nextEntry;
36019
36320
  }
36020
36321
  watch(onChange) {
36021
- fs9.mkdirSync(this.dataDir, { recursive: true });
36322
+ fs10.mkdirSync(this.dataDir, { recursive: true });
36022
36323
  const listener = () => {
36023
36324
  void Promise.resolve(onChange()).catch((error51) => {
36024
36325
  logger21.error("Local skill change handler failed", { filePath: this.filePath, error: error51 });
36025
36326
  });
36026
36327
  };
36027
- fs9.watchFile(this.filePath, { interval: 1e3 }, listener);
36028
- return () => fs9.unwatchFile(this.filePath, listener);
36328
+ fs10.watchFile(this.filePath, { interval: 1e3 }, listener);
36329
+ return () => fs10.unwatchFile(this.filePath, listener);
36029
36330
  }
36030
36331
  write(skills) {
36031
- fs9.mkdirSync(this.dataDir, { recursive: true });
36332
+ fs10.mkdirSync(this.dataDir, { recursive: true });
36032
36333
  const payload = normalizeLocalSkillsFile({ version: 1, skills });
36033
36334
  const tmpPath = `${this.filePath}.tmp`;
36034
- fs9.writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}
36335
+ fs10.writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}
36035
36336
  `, { encoding: "utf8", mode: 384 });
36036
- fs9.renameSync(tmpPath, this.filePath);
36337
+ fs10.renameSync(tmpPath, this.filePath);
36037
36338
  try {
36038
- fs9.chmodSync(this.filePath, 384);
36339
+ fs10.chmodSync(this.filePath, 384);
36039
36340
  } catch (error51) {
36040
36341
  logger21.warn("Failed to harden local skill file permissions", { filePath: this.filePath, error: error51 });
36041
36342
  }
@@ -36719,9 +37020,9 @@ var ServerConnector = class {
36719
37020
  };
36720
37021
 
36721
37022
  // src/contextDumper.ts
36722
- import fs10 from "fs/promises";
37023
+ import fs11 from "fs/promises";
36723
37024
  import os9 from "os";
36724
- import path17 from "path";
37025
+ import path18 from "path";
36725
37026
  import * as sdk3 from "@anthropic-ai/claude-agent-sdk";
36726
37027
  var logger24 = createModuleLogger("bridge.contextDumper");
36727
37028
  var TRUNCATE_THRESHOLD = 5e4;
@@ -36751,11 +37052,11 @@ function cwdToProjectSlug(cwd) {
36751
37052
  }
36752
37053
  function resolveJsonlPathInProjectsDir(projectsDir, sessionId, cwd) {
36753
37054
  const slug = cwdToProjectSlug(cwd);
36754
- return path17.join(projectsDir, slug, `${sessionId}.jsonl`);
37055
+ return path18.join(projectsDir, slug, `${sessionId}.jsonl`);
36755
37056
  }
36756
37057
  function resolveProjectDirInProjectsDir(projectsDir, cwd) {
36757
37058
  const slug = cwdToProjectSlug(cwd);
36758
- return path17.join(projectsDir, slug);
37059
+ return path18.join(projectsDir, slug);
36759
37060
  }
36760
37061
  function errorCode(e) {
36761
37062
  if (e instanceof Error && "code" in e) {
@@ -36766,7 +37067,7 @@ function errorCode(e) {
36766
37067
  }
36767
37068
  async function isReadableFile(filePath) {
36768
37069
  try {
36769
- const stat3 = await fs10.stat(filePath);
37070
+ const stat3 = await fs11.stat(filePath);
36770
37071
  return stat3.isFile();
36771
37072
  } catch (e) {
36772
37073
  const code = errorCode(e);
@@ -36781,7 +37082,7 @@ function uniquePaths(paths) {
36781
37082
  for (const p of paths) {
36782
37083
  const trimmed = p.trim();
36783
37084
  if (!trimmed) continue;
36784
- const key = path17.normalize(trimmed);
37085
+ const key = path18.normalize(trimmed);
36785
37086
  if (seen.has(key)) continue;
36786
37087
  seen.add(key);
36787
37088
  out.push(trimmed);
@@ -36797,7 +37098,7 @@ function inferAhchatUserAgentConfigDir(workdir) {
36797
37098
  const userSlug = afterMarker.split("/").find(Boolean);
36798
37099
  if (!userSlug) return null;
36799
37100
  const userDataDir2 = normalized.slice(0, markerIndex + marker.length + userSlug.length);
36800
- return path17.join(path17.normalize(userDataDir2), "agent-config");
37101
+ return path18.join(path18.normalize(userDataDir2), "agent-config");
36801
37102
  }
36802
37103
  function inferredAgentConfigDirsFromWorkdirs(workdirs) {
36803
37104
  return uniquePaths(workdirs.map((workdir) => inferAhchatUserAgentConfigDir(workdir) ?? ""));
@@ -36810,19 +37111,19 @@ function claudeProjectsDirs(opts) {
36810
37111
  ]);
36811
37112
  return uniquePaths([
36812
37113
  ...configDirs.flatMap((configDir) => [
36813
- path17.join(configDir, "api-key-agents", opts.agentId, "projects"),
36814
- path17.join(configDir, "projects")
37114
+ path18.join(configDir, "api-key-agents", opts.agentId, "projects"),
37115
+ path18.join(configDir, "projects")
36815
37116
  ]),
36816
- path17.join(os9.homedir(), ".claude", "projects")
37117
+ path18.join(os9.homedir(), ".claude", "projects")
36817
37118
  ]);
36818
37119
  }
36819
37120
  function fallbackBridgeWorkspacePath(requestedCwd, workspacesDir, fallbackSegment) {
36820
37121
  const suffix = extractAhchatWorkspaceSuffix(requestedCwd);
36821
- if (suffix) return path17.join(workspacesDir, suffix);
37122
+ if (suffix) return path18.join(workspacesDir, suffix);
36822
37123
  const normalized = requestedCwd.trim();
36823
- const basename = normalized ? path17.basename(path17.normalize(normalized)) : "";
36824
- const segment = basename && basename !== "." && basename !== path17.sep ? basename : fallbackSegment;
36825
- return path17.join(workspacesDir, segment);
37124
+ const basename = normalized ? path18.basename(path18.normalize(normalized)) : "";
37125
+ const segment = basename && basename !== "." && basename !== path18.sep ? basename : fallbackSegment;
37126
+ return path18.join(workspacesDir, segment);
36826
37127
  }
36827
37128
  function cwdCandidatesForBridge(requestedCwd, opts) {
36828
37129
  const candidates = [requestedCwd];
@@ -36858,11 +37159,11 @@ async function resolveDumpWorkdir(requestedCwd, opts) {
36858
37159
  return remapped.path;
36859
37160
  }
36860
37161
  try {
36861
- await fs10.mkdir(requestedCwd, { recursive: true });
37162
+ await fs11.mkdir(requestedCwd, { recursive: true });
36862
37163
  return requestedCwd;
36863
37164
  } catch (e) {
36864
37165
  const fallback = fallbackBridgeWorkspacePath(requestedCwd, opts.workspacesDir, opts.fallbackSegment);
36865
- if (path17.normalize(fallback) === path17.normalize(requestedCwd)) throw e;
37166
+ if (path18.normalize(fallback) === path18.normalize(requestedCwd)) throw e;
36866
37167
  logger24.warn("Dump workdir inaccessible; using local Bridge workspace fallback", {
36867
37168
  agentId: opts.agentId,
36868
37169
  requested: requestedCwd,
@@ -36876,7 +37177,7 @@ async function findJsonlInClaudeProjects(sessionId, projectsDirs) {
36876
37177
  for (const projectsDir of projectsDirs) {
36877
37178
  let dirs;
36878
37179
  try {
36879
- dirs = await fs10.readdir(projectsDir, { withFileTypes: true });
37180
+ dirs = await fs11.readdir(projectsDir, { withFileTypes: true });
36880
37181
  } catch (e) {
36881
37182
  const code = errorCode(e);
36882
37183
  if (code === "ENOENT" || code === "ENOTDIR") continue;
@@ -36885,7 +37186,7 @@ async function findJsonlInClaudeProjects(sessionId, projectsDirs) {
36885
37186
  }
36886
37187
  for (const dir of dirs) {
36887
37188
  if (!dir.isDirectory()) continue;
36888
- const candidate = path17.join(projectsDir, dir.name, `${sessionId}.jsonl`);
37189
+ const candidate = path18.join(projectsDir, dir.name, `${sessionId}.jsonl`);
36889
37190
  if (await isReadableFile(candidate)) return candidate;
36890
37191
  }
36891
37192
  }
@@ -36894,7 +37195,7 @@ async function findJsonlInClaudeProjects(sessionId, projectsDirs) {
36894
37195
  async function latestJsonlInProjectDir(projectDir) {
36895
37196
  let entries;
36896
37197
  try {
36897
- entries = await fs10.readdir(projectDir, { withFileTypes: true });
37198
+ entries = await fs11.readdir(projectDir, { withFileTypes: true });
36898
37199
  } catch (e) {
36899
37200
  const code = errorCode(e);
36900
37201
  if (code === "ENOENT" || code === "ENOTDIR") return null;
@@ -36904,15 +37205,15 @@ async function latestJsonlInProjectDir(projectDir) {
36904
37205
  let latest = null;
36905
37206
  for (const entry of entries) {
36906
37207
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
36907
- const jsonlPath = path17.join(projectDir, entry.name);
37208
+ const jsonlPath = path18.join(projectDir, entry.name);
36908
37209
  let stat3;
36909
37210
  try {
36910
- stat3 = await fs10.stat(jsonlPath);
37211
+ stat3 = await fs11.stat(jsonlPath);
36911
37212
  } catch (e) {
36912
37213
  logger24.warn("Discovered JSONL stat failed", { jsonlPath, error: e });
36913
37214
  continue;
36914
37215
  }
36915
- const sessionId = path17.basename(entry.name, ".jsonl");
37216
+ const sessionId = path18.basename(entry.name, ".jsonl");
36916
37217
  const discovered = { sessionId, jsonlPath, lastModified: stat3.mtimeMs };
36917
37218
  if (!latest || discovered.lastModified > latest.lastModified) {
36918
37219
  latest = discovered;
@@ -36921,8 +37222,8 @@ async function latestJsonlInProjectDir(projectDir) {
36921
37222
  return latest;
36922
37223
  }
36923
37224
  function isAgentIsolatedProjectsDir(projectsDir, agentId) {
36924
- const normalized = path17.normalize(projectsDir).toLowerCase();
36925
- const marker = path17.normalize(path17.join("api-key-agents", agentId, "projects")).toLowerCase();
37225
+ const normalized = path18.normalize(projectsDir).toLowerCase();
37226
+ const marker = path18.normalize(path18.join("api-key-agents", agentId, "projects")).toLowerCase();
36926
37227
  return normalized.endsWith(marker);
36927
37228
  }
36928
37229
  async function discoverLatestJsonlForScope(opts) {
@@ -36941,7 +37242,7 @@ async function discoverLatestJsonlForScope(opts) {
36941
37242
  if (!isAgentIsolatedProjectsDir(projectsDir, opts.agentId)) continue;
36942
37243
  let dirs;
36943
37244
  try {
36944
- dirs = await fs10.readdir(projectsDir, { withFileTypes: true });
37245
+ dirs = await fs11.readdir(projectsDir, { withFileTypes: true });
36945
37246
  } catch (e) {
36946
37247
  const code = errorCode(e);
36947
37248
  if (code === "ENOENT" || code === "ENOTDIR") continue;
@@ -36950,7 +37251,7 @@ async function discoverLatestJsonlForScope(opts) {
36950
37251
  }
36951
37252
  for (const dir of dirs) {
36952
37253
  if (!dir.isDirectory()) continue;
36953
- const latest = await latestJsonlInProjectDir(path17.join(projectsDir, dir.name));
37254
+ const latest = await latestJsonlInProjectDir(path18.join(projectsDir, dir.name));
36954
37255
  if (latest) discovered.push(latest);
36955
37256
  }
36956
37257
  }
@@ -36987,7 +37288,7 @@ function friendlyScopeError(e) {
36987
37288
  }
36988
37289
  var RENDERABLE_TYPES = /* @__PURE__ */ new Set(["user", "assistant", "system", "attachment"]);
36989
37290
  async function readJsonlEntries(filePath) {
36990
- const raw = await fs10.readFile(filePath, "utf-8");
37291
+ const raw = await fs11.readFile(filePath, "utf-8");
36991
37292
  const entries = [];
36992
37293
  for (const line of raw.split("\n")) {
36993
37294
  const trimmed = line.trim();
@@ -37343,8 +37644,8 @@ async function dumpAgentContext(agentId, deps) {
37343
37644
  agentId,
37344
37645
  workdirOverrideStore: deps.workdirOverrideStore
37345
37646
  });
37346
- const dumpDir = path17.join(localWorkdir, "sessioninfo");
37347
- await fs10.mkdir(dumpDir, { recursive: true });
37647
+ const dumpDir = path18.join(localWorkdir, "sessioninfo");
37648
+ await fs11.mkdir(dumpDir, { recursive: true });
37348
37649
  const groupWorkdirs = deps.groupRegistry?.getMyGroups(agentId).map((group) => group.workingDirectory) ?? [];
37349
37650
  const inferredAgentConfigDirs = inferredAgentConfigDirsFromWorkdirs([
37350
37651
  workdir,
@@ -37422,7 +37723,7 @@ async function dumpAgentContext(agentId, deps) {
37422
37723
  projectsDirs,
37423
37724
  sessionStore: deps.sessionStore
37424
37725
  });
37425
- resolvedSessionId = recovered ? path17.basename(jsonlPath, ".jsonl") : resolvedSessionId;
37726
+ resolvedSessionId = recovered ? path18.basename(jsonlPath, ".jsonl") : resolvedSessionId;
37426
37727
  if (recovered) {
37427
37728
  try {
37428
37729
  const info = await sdk3.getSessionInfo(resolvedSessionId);
@@ -37471,10 +37772,10 @@ async function dumpAgentContext(agentId, deps) {
37471
37772
  jsonlPath
37472
37773
  });
37473
37774
  const filename = scopeFilename(agent.name, scopeKey2, groupName);
37474
- const filePath = path17.join(dumpDir, filename);
37475
- await fs10.writeFile(filePath, html, "utf-8");
37775
+ const filePath = path18.join(dumpDir, filename);
37776
+ await fs11.writeFile(filePath, html, "utf-8");
37476
37777
  dumpedFiles.push(filename);
37477
- const stat3 = await fs10.stat(filePath);
37778
+ const stat3 = await fs11.stat(filePath);
37478
37779
  logger24.info("Scope context dumped", {
37479
37780
  agentId,
37480
37781
  scopeKey: scopeKey2,
@@ -37514,9 +37815,9 @@ async function dumpAgentContext(agentId, deps) {
37514
37815
  // src/clipboardFiles.ts
37515
37816
  import { execFile as execFile2 } from "child_process";
37516
37817
  import crypto3 from "crypto";
37517
- import fs11 from "fs/promises";
37818
+ import fs12 from "fs/promises";
37518
37819
  import os10 from "os";
37519
- import path18 from "path";
37820
+ import path19 from "path";
37520
37821
  import { promisify as promisify2 } from "util";
37521
37822
  var logger25 = createModuleLogger("bridge.clipboardFiles");
37522
37823
  var execFileAsync2 = promisify2(execFile2);
@@ -37527,28 +37828,28 @@ function isRecord5(value) {
37527
37828
  }
37528
37829
  function normalizeLocalPath(targetPath) {
37529
37830
  const trimmed = targetPath.trim();
37530
- const expanded = trimmed === "~" || trimmed.startsWith("~/") || trimmed.startsWith("~\\") ? path18.join(os10.homedir(), trimmed.slice(2)) : trimmed;
37531
- return path18.normalize(path18.resolve(expanded));
37831
+ const expanded = trimmed === "~" || trimmed.startsWith("~/") || trimmed.startsWith("~\\") ? path19.join(os10.homedir(), trimmed.slice(2)) : trimmed;
37832
+ return path19.normalize(path19.resolve(expanded));
37532
37833
  }
37533
37834
  function normalizeClipboardIdentityKey(value) {
37534
37835
  return process.platform === "win32" ? value.toLowerCase() : value;
37535
37836
  }
37536
37837
  async function resolveClipboardPathKey(resolvedPath) {
37537
37838
  try {
37538
- return normalizeClipboardIdentityKey(await fs11.realpath(resolvedPath));
37839
+ return normalizeClipboardIdentityKey(await fs12.realpath(resolvedPath));
37539
37840
  } catch (e) {
37540
37841
  logger25.debug("Clipboard realpath read skipped", { error: e, path: resolvedPath });
37541
37842
  return normalizeClipboardIdentityKey(resolvedPath);
37542
37843
  }
37543
37844
  }
37544
37845
  function looksLikeWindowsShortFileName(fileName) {
37545
- return /~\d/i.test(path18.basename(fileName));
37846
+ return /~\d/i.test(path19.basename(fileName));
37546
37847
  }
37547
37848
  function fileContentHash(buffer) {
37548
37849
  return crypto3.createHash("sha256").update(buffer).digest("hex");
37549
37850
  }
37550
37851
  function mimeTypeForFileName(fileName) {
37551
- const ext = path18.extname(fileName).toLowerCase();
37852
+ const ext = path19.extname(fileName).toLowerCase();
37552
37853
  if (ext === ".jpg" || ext === ".jpeg") return "image/jpeg";
37553
37854
  if (ext === ".png") return "image/png";
37554
37855
  if (ext === ".webp") return "image/webp";
@@ -37613,7 +37914,7 @@ async function readWindowsClipboardPathCandidates() {
37613
37914
  }
37614
37915
  }
37615
37916
  async function filePayloadFromPath(resolvedPath) {
37616
- const stat3 = await fs11.stat(resolvedPath);
37917
+ const stat3 = await fs12.stat(resolvedPath);
37617
37918
  if (!stat3.isFile()) return null;
37618
37919
  if (stat3.size > MAX_CLIPBOARD_FILE_SIZE) {
37619
37920
  logger25.warn("Clipboard file skipped because it is too large", {
@@ -37622,10 +37923,10 @@ async function filePayloadFromPath(resolvedPath) {
37622
37923
  });
37623
37924
  return null;
37624
37925
  }
37625
- const buffer = await fs11.readFile(resolvedPath);
37926
+ const buffer = await fs12.readFile(resolvedPath);
37626
37927
  const mimeType = mimeTypeForFileName(resolvedPath);
37627
37928
  return {
37628
- fileName: path18.basename(resolvedPath),
37929
+ fileName: path19.basename(resolvedPath),
37629
37930
  mimeType,
37630
37931
  contentBase64: buffer.toString("base64"),
37631
37932
  size: buffer.length,
@@ -37649,7 +37950,7 @@ async function readClipboardFiles() {
37649
37950
  const contentIndexes = /* @__PURE__ */ new Map();
37650
37951
  for (const resolvedPath of pathCandidates) {
37651
37952
  try {
37652
- const stat3 = await fs11.stat(resolvedPath);
37953
+ const stat3 = await fs12.stat(resolvedPath);
37653
37954
  if (stat3.isDirectory()) {
37654
37955
  skippedDirectoryCount += 1;
37655
37956
  continue;
@@ -37698,8 +37999,8 @@ async function readClipboardFiles() {
37698
37999
  }
37699
38000
 
37700
38001
  // src/listDir.ts
37701
- import fs12 from "fs/promises";
37702
- import path19 from "path";
38002
+ import fs13 from "fs/promises";
38003
+ import path20 from "path";
37703
38004
  var logger26 = createModuleLogger("bridge.listDir");
37704
38005
  function shouldIncludeEntry(name) {
37705
38006
  if (!name.startsWith(".")) return true;
@@ -37708,16 +38009,16 @@ function shouldIncludeEntry(name) {
37708
38009
  async function listDirectoryEntries(dirPath) {
37709
38010
  const resolvedDirPath = resolveUserPath(dirPath);
37710
38011
  logger26.info("listDirectoryEntries start", { path: dirPath, resolvedPath: resolvedDirPath });
37711
- const raw = await fs12.readdir(resolvedDirPath, { withFileTypes: true });
38012
+ const raw = await fs13.readdir(resolvedDirPath, { withFileTypes: true });
37712
38013
  const entries = [];
37713
38014
  for (const entry of raw) {
37714
38015
  if (!shouldIncludeEntry(entry.name)) continue;
37715
- const fullPath = path19.join(resolvedDirPath, entry.name);
38016
+ const fullPath = path20.join(resolvedDirPath, entry.name);
37716
38017
  const isDir = entry.isDirectory();
37717
38018
  let size;
37718
38019
  let mtime;
37719
38020
  try {
37720
- const stat3 = await fs12.stat(fullPath);
38021
+ const stat3 = await fs13.stat(fullPath);
37721
38022
  mtime = stat3.mtime.toISOString();
37722
38023
  if (!isDir) size = stat3.size;
37723
38024
  } catch (statErr) {
@@ -37746,20 +38047,20 @@ function normalizeRelativePath(relativePath) {
37746
38047
  return normalized;
37747
38048
  }
37748
38049
  function ensureInsideBase(baseDir, targetPath) {
37749
- const relative = path19.relative(baseDir, targetPath);
37750
- if (relative.startsWith("..") || path19.isAbsolute(relative)) {
38050
+ const relative = path20.relative(baseDir, targetPath);
38051
+ if (relative.startsWith("..") || path20.isAbsolute(relative)) {
37751
38052
  throw new Error("path is outside working directory");
37752
38053
  }
37753
38054
  }
37754
38055
  function ensureNotBaseDir(baseDir, targetPath) {
37755
- if (path19.relative(baseDir, targetPath) === "") {
38056
+ if (path20.relative(baseDir, targetPath) === "") {
37756
38057
  throw new Error("refusing to delete working directory root");
37757
38058
  }
37758
38059
  }
37759
38060
  async function ensureRealPathInsideBase(baseDir, targetPath) {
37760
38061
  const [realBase, realTarget] = await Promise.all([
37761
- fs12.realpath(baseDir),
37762
- fs12.realpath(targetPath)
38062
+ fs13.realpath(baseDir),
38063
+ fs13.realpath(targetPath)
37763
38064
  ]);
37764
38065
  ensureInsideBase(realBase, realTarget);
37765
38066
  return realTarget;
@@ -37767,11 +38068,11 @@ async function ensureRealPathInsideBase(baseDir, targetPath) {
37767
38068
  async function writeWorkdirFile(opts) {
37768
38069
  const resolvedBaseDir = resolveUserPath(opts.baseDir);
37769
38070
  const safeRelativePath = normalizeRelativePath(opts.relativePath);
37770
- const targetPath = path19.resolve(resolvedBaseDir, safeRelativePath);
38071
+ const targetPath = path20.resolve(resolvedBaseDir, safeRelativePath);
37771
38072
  ensureInsideBase(resolvedBaseDir, targetPath);
37772
38073
  const buffer = Buffer.from(opts.contentBase64, "base64");
37773
- await fs12.mkdir(path19.dirname(targetPath), { recursive: true });
37774
- await fs12.writeFile(targetPath, buffer, { flag: opts.overwrite ? "w" : "wx" });
38074
+ await fs13.mkdir(path20.dirname(targetPath), { recursive: true });
38075
+ await fs13.writeFile(targetPath, buffer, { flag: opts.overwrite ? "w" : "wx" });
37775
38076
  logger26.info("writeWorkdirFile ok", {
37776
38077
  baseDir: opts.baseDir,
37777
38078
  path: targetPath,
@@ -37783,12 +38084,12 @@ async function writeWorkdirFile(opts) {
37783
38084
  async function readWorkdirFile(filePath, baseDir) {
37784
38085
  const resolvedPath = resolveUserPath(filePath);
37785
38086
  const safePath = baseDir ? await ensureRealPathInsideBase(resolveUserPath(baseDir), resolvedPath) : resolvedPath;
37786
- const stat3 = await fs12.stat(safePath);
38087
+ const stat3 = await fs13.stat(safePath);
37787
38088
  if (!stat3.isFile()) throw new Error("path is not a file");
37788
- const buffer = await fs12.readFile(safePath);
38089
+ const buffer = await fs13.readFile(safePath);
37789
38090
  logger26.info("readWorkdirFile ok", { path: filePath, baseDir, resolvedPath: safePath, size: buffer.length });
37790
38091
  return {
37791
- fileName: path19.basename(safePath),
38092
+ fileName: path20.basename(safePath),
37792
38093
  contentBase64: buffer.toString("base64"),
37793
38094
  size: buffer.length
37794
38095
  };
@@ -37798,9 +38099,9 @@ async function allocateTrashPath(trashDir, name) {
37798
38099
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
37799
38100
  for (let index = 0; index < 1e3; index += 1) {
37800
38101
  const suffix = index === 0 ? "" : `-${index}`;
37801
- const candidate = path19.join(trashDir, `${stamp}-${safeName}${suffix}`);
38102
+ const candidate = path20.join(trashDir, `${stamp}-${safeName}${suffix}`);
37802
38103
  try {
37803
- await fs12.lstat(candidate);
38104
+ await fs13.lstat(candidate);
37804
38105
  } catch (e) {
37805
38106
  if (e instanceof Error && "code" in e && e.code === "ENOENT") return candidate;
37806
38107
  throw e;
@@ -37816,15 +38117,15 @@ async function trashWorkdirPath(opts) {
37816
38117
  const resolvedBaseDir = resolveUserPath(opts.baseDir);
37817
38118
  const resolvedTargetPath = resolveUserPath(opts.targetPath);
37818
38119
  const [realBase, realTarget] = await Promise.all([
37819
- fs12.realpath(resolvedBaseDir),
37820
- fs12.realpath(resolvedTargetPath)
38120
+ fs13.realpath(resolvedBaseDir),
38121
+ fs13.realpath(resolvedTargetPath)
37821
38122
  ]);
37822
38123
  ensureInsideBase(realBase, realTarget);
37823
38124
  ensureNotBaseDir(realBase, realTarget);
37824
- const trashDir = path19.join(resolvedBaseDir, ".ahchat-trash");
37825
- await fs12.mkdir(trashDir, { recursive: true });
37826
- const trashedPath = await allocateTrashPath(trashDir, path19.basename(resolvedTargetPath));
37827
- await fs12.rename(resolvedTargetPath, trashedPath);
38125
+ const trashDir = path20.join(resolvedBaseDir, ".ahchat-trash");
38126
+ await fs13.mkdir(trashDir, { recursive: true });
38127
+ const trashedPath = await allocateTrashPath(trashDir, path20.basename(resolvedTargetPath));
38128
+ await fs13.rename(resolvedTargetPath, trashedPath);
37828
38129
  logger26.info("trashWorkdirPath ok", {
37829
38130
  path: opts.targetPath,
37830
38131
  baseDir: opts.baseDir,
@@ -37835,8 +38136,8 @@ async function trashWorkdirPath(opts) {
37835
38136
  }
37836
38137
 
37837
38138
  // src/logScanner.ts
37838
- import fs13 from "fs";
37839
- import path20 from "path";
38139
+ import fs14 from "fs";
38140
+ import path21 from "path";
37840
38141
  import os11 from "os";
37841
38142
  import readline from "readline";
37842
38143
  var logger27 = createModuleLogger("bridge.logScanner");
@@ -37844,18 +38145,18 @@ var MAX_LIMIT = 2e3;
37844
38145
  function listLogFiles(logsDir, baseName) {
37845
38146
  let names;
37846
38147
  try {
37847
- names = fs13.readdirSync(logsDir);
38148
+ names = fs14.readdirSync(logsDir);
37848
38149
  } catch (e) {
37849
38150
  logger27.warn("listLogFiles: readdir failed", { logsDir, error: e });
37850
38151
  return [];
37851
38152
  }
37852
38153
  const escapedBaseName = baseName.replace(".", "\\.");
37853
38154
  const pattern = new RegExp(`^${escapedBaseName}(?:[.-].+)?$`);
37854
- return names.filter((n) => pattern.test(n)).map((n) => path20.join(logsDir, n));
38155
+ return names.filter((n) => pattern.test(n)).map((n) => path21.join(logsDir, n));
37855
38156
  }
37856
38157
  async function scanFile(filePath, source, filter, state) {
37857
- const file2 = path20.basename(filePath);
37858
- const stream = fs13.createReadStream(filePath, { encoding: "utf-8" });
38158
+ const file2 = path21.basename(filePath);
38159
+ const stream = fs14.createReadStream(filePath, { encoding: "utf-8" });
37859
38160
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
37860
38161
  let lineNum = 0;
37861
38162
  for await (const line of rl) {
@@ -37898,7 +38199,7 @@ async function scanLocalLogs(logsDir, baseName, filter) {
37898
38199
  };
37899
38200
  }
37900
38201
  async function scanBridgeLogs(filter) {
37901
- const logDir = path20.join(loadBridgeConfig().dataDir || path20.join(os11.homedir(), ".ahchat"), "logs");
38202
+ const logDir = path21.join(loadBridgeConfig().dataDir || path21.join(os11.homedir(), ".ahchat"), "logs");
37902
38203
  logger27.info("scanBridgeLogs start", {
37903
38204
  logDir,
37904
38205
  startIso: filter.startIso,
@@ -37917,9 +38218,9 @@ async function scanBridgeLogs(filter) {
37917
38218
  }
37918
38219
 
37919
38220
  // src/logUploader.ts
37920
- import fs14 from "fs";
38221
+ import fs15 from "fs";
37921
38222
  import fsp from "fs/promises";
37922
- import path21 from "path";
38223
+ import path22 from "path";
37923
38224
  var logger28 = createModuleLogger("bridge.logUploader");
37924
38225
  var STALE_RATE_LIMIT_SKIP_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
37925
38226
  var DEFAULT_LOG_UPLOAD_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -37963,27 +38264,27 @@ function parseUploadErrorBody(bodyText) {
37963
38264
  }
37964
38265
  }
37965
38266
  function defaultLogFile(dataDir) {
37966
- return path21.join(dataDir, "logs", "bridge.log");
38267
+ return path22.join(dataDir, "logs", "bridge.log");
37967
38268
  }
37968
38269
  function defaultCursorFile(dataDir) {
37969
- return path21.join(dataDir, "log-upload-cursor.json");
38270
+ return path22.join(dataDir, "log-upload-cursor.json");
37970
38271
  }
37971
38272
  function uploadedFileName(logFile, explicit) {
37972
38273
  const trimmed = explicit?.trim();
37973
- return trimmed || path21.basename(logFile);
38274
+ return trimmed || path22.basename(logFile);
37974
38275
  }
37975
38276
  function normalizeTarget(file2, dataDir) {
37976
38277
  const fileName = uploadedFileName(file2.logFile, file2.uploadedFileName);
37977
38278
  const safeName = fileName.replace(/[^a-zA-Z0-9._-]/g, "_");
37978
38279
  return {
37979
38280
  logFile: file2.logFile,
37980
- cursorFile: file2.cursorFile ?? path21.join(dataDir, `log-upload-cursor-${safeName}.json`),
38281
+ cursorFile: file2.cursorFile ?? path22.join(dataDir, `log-upload-cursor-${safeName}.json`),
37981
38282
  uploadedFileName: fileName
37982
38283
  };
37983
38284
  }
37984
38285
  function cursorFileForLog(dataDir, fileName) {
37985
38286
  const safeName = fileName.replace(/[^a-zA-Z0-9._-]/g, "_");
37986
- return path21.join(dataDir, `log-upload-cursor-${safeName}.json`);
38287
+ return path22.join(dataDir, `log-upload-cursor-${safeName}.json`);
37987
38288
  }
37988
38289
  function logFileFingerprint(stat3) {
37989
38290
  if (typeof stat3.dev === "number" && typeof stat3.ino === "number" && stat3.ino > 0) {
@@ -37992,8 +38293,8 @@ function logFileFingerprint(stat3) {
37992
38293
  return void 0;
37993
38294
  }
37994
38295
  async function listRotatedBridgeTargets(primary, dataDir) {
37995
- const logDir = path21.dirname(primary.logFile);
37996
- const baseName = path21.basename(primary.logFile);
38296
+ const logDir = path22.dirname(primary.logFile);
38297
+ const baseName = path22.basename(primary.logFile);
37997
38298
  let names;
37998
38299
  try {
37999
38300
  names = await fsp.readdir(logDir);
@@ -38006,7 +38307,7 @@ async function listRotatedBridgeTargets(primary, dataDir) {
38006
38307
  return names.filter((name) => pattern.test(name)).sort().map((name) => {
38007
38308
  if (name === baseName) return primary;
38008
38309
  return {
38009
- logFile: path21.join(logDir, name),
38310
+ logFile: path22.join(logDir, name),
38010
38311
  cursorFile: cursorFileForLog(dataDir, name),
38011
38312
  uploadedFileName: name
38012
38313
  };
@@ -38034,11 +38335,11 @@ async function readCursor(filePath) {
38034
38335
  }
38035
38336
  }
38036
38337
  async function writeCursor(filePath, cursor) {
38037
- await fsp.mkdir(path21.dirname(filePath), { recursive: true });
38338
+ await fsp.mkdir(path22.dirname(filePath), { recursive: true });
38038
38339
  await fsp.writeFile(filePath, JSON.stringify(cursor), "utf8");
38039
38340
  }
38040
38341
  async function readStreamText(filePath, start) {
38041
- const stream = fs14.createReadStream(filePath, { start, encoding: "utf8" });
38342
+ const stream = fs15.createReadStream(filePath, { start, encoding: "utf8" });
38042
38343
  let raw = "";
38043
38344
  for await (const chunk of stream) {
38044
38345
  raw += chunk;
@@ -38356,8 +38657,8 @@ var BridgeLogUploader = class {
38356
38657
  };
38357
38658
 
38358
38659
  // src/skillStore.ts
38359
- import fs15 from "fs";
38360
- import path22 from "path";
38660
+ import fs16 from "fs";
38661
+ import path23 from "path";
38361
38662
  var logger29 = createModuleLogger("bridge.skillStore");
38362
38663
  var MANAGED_CACHE_MARKER = "<!-- ahchat-skill-cache";
38363
38664
  var SAFE_SKILL_NAME_RE = /^[a-zA-Z0-9_-]+$/;
@@ -38386,9 +38687,9 @@ var SkillStore = class {
38386
38687
  skillsDir;
38387
38688
  indexPath;
38388
38689
  constructor(dataDir) {
38389
- this.skillsDir = path22.join(dataDir, "skills");
38390
- this.indexPath = path22.join(this.skillsDir, INDEX_FILE_NAME);
38391
- fs15.mkdirSync(this.skillsDir, { recursive: true });
38690
+ this.skillsDir = path23.join(dataDir, "skills");
38691
+ this.indexPath = path23.join(this.skillsDir, INDEX_FILE_NAME);
38692
+ fs16.mkdirSync(this.skillsDir, { recursive: true });
38392
38693
  logger29.info("SkillStore initialized", { skillsDir: this.skillsDir });
38393
38694
  }
38394
38695
  read(name) {
@@ -38396,9 +38697,9 @@ var SkillStore = class {
38396
38697
  logger29.warn("Skill read: unsafe name", { name });
38397
38698
  return "";
38398
38699
  }
38399
- const filePath = path22.join(this.skillsDir, `${name}.md`);
38700
+ const filePath = path23.join(this.skillsDir, `${name}.md`);
38400
38701
  try {
38401
- const content = fs15.readFileSync(filePath, "utf-8");
38702
+ const content = fs16.readFileSync(filePath, "utf-8");
38402
38703
  logger29.info("Skill read", { name, bytes: content.length });
38403
38704
  return content;
38404
38705
  } catch (e) {
@@ -38409,7 +38710,7 @@ var SkillStore = class {
38409
38710
  allowedNames() {
38410
38711
  const names = /* @__PURE__ */ new Set();
38411
38712
  try {
38412
- for (const entry of fs15.readdirSync(this.skillsDir, { withFileTypes: true })) {
38713
+ for (const entry of fs16.readdirSync(this.skillsDir, { withFileTypes: true })) {
38413
38714
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
38414
38715
  const name = entry.name.slice(0, -3);
38415
38716
  if (isSafeSkillName(name)) names.add(name);
@@ -38424,11 +38725,11 @@ var SkillStore = class {
38424
38725
  if (!isSafeSkillName(name)) {
38425
38726
  throw new Error(`Unsafe skill name: ${name}`);
38426
38727
  }
38427
- const filePath = path22.join(this.skillsDir, `${name}.md`);
38728
+ const filePath = path23.join(this.skillsDir, `${name}.md`);
38428
38729
  const tmpPath = `${filePath}.tmp`;
38429
38730
  let existing = "";
38430
38731
  try {
38431
- existing = fs15.readFileSync(filePath, "utf-8");
38732
+ existing = fs16.readFileSync(filePath, "utf-8");
38432
38733
  } catch (e) {
38433
38734
  if (!isNotFoundError(e)) logger29.warn("Skill seed existing read failed", { name, filePath, error: e });
38434
38735
  }
@@ -38436,8 +38737,8 @@ var SkillStore = class {
38436
38737
  logger29.debug("Skill already in sync", { name, bytes: content.length });
38437
38738
  return;
38438
38739
  }
38439
- fs15.writeFileSync(tmpPath, content, "utf-8");
38440
- fs15.renameSync(tmpPath, filePath);
38740
+ fs16.writeFileSync(tmpPath, content, "utf-8");
38741
+ fs16.renameSync(tmpPath, filePath);
38441
38742
  logger29.info("Skill seeded/re-synced", {
38442
38743
  name,
38443
38744
  bytes: content.length,
@@ -38469,7 +38770,7 @@ var SkillStore = class {
38469
38770
  const content = this.readExisting(name);
38470
38771
  if (!isPrunableManagedSkillCache(content)) continue;
38471
38772
  try {
38472
- fs15.unlinkSync(path22.join(this.skillsDir, `${name}.md`));
38773
+ fs16.unlinkSync(path23.join(this.skillsDir, `${name}.md`));
38473
38774
  pruned += 1;
38474
38775
  logger29.info("Managed skill cache pruned", { name });
38475
38776
  } catch (e) {
@@ -38487,7 +38788,7 @@ var SkillStore = class {
38487
38788
  const tmpPath = `${this.indexPath}.tmp`;
38488
38789
  let existing = "";
38489
38790
  try {
38490
- existing = fs15.readFileSync(this.indexPath, "utf-8");
38791
+ existing = fs16.readFileSync(this.indexPath, "utf-8");
38491
38792
  } catch (e) {
38492
38793
  if (!isNotFoundError(e)) logger29.warn("Runtime skill index existing read failed", { error: e });
38493
38794
  }
@@ -38495,8 +38796,8 @@ var SkillStore = class {
38495
38796
  logger29.info("Runtime skill index already in sync", { count: safeEntries.length });
38496
38797
  return;
38497
38798
  }
38498
- fs15.writeFileSync(tmpPath, content, "utf-8");
38499
- fs15.renameSync(tmpPath, this.indexPath);
38799
+ fs16.writeFileSync(tmpPath, content, "utf-8");
38800
+ fs16.renameSync(tmpPath, this.indexPath);
38500
38801
  logger29.info("Runtime skill index synced", { count: safeEntries.length });
38501
38802
  }
38502
38803
  pruneManagedSkillsBySource(source, desiredNames) {
@@ -38506,7 +38807,7 @@ var SkillStore = class {
38506
38807
  const content = this.readExisting(name);
38507
38808
  if (managedSkillCacheSource(content) !== source) continue;
38508
38809
  try {
38509
- fs15.unlinkSync(path22.join(this.skillsDir, `${name}.md`));
38810
+ fs16.unlinkSync(path23.join(this.skillsDir, `${name}.md`));
38510
38811
  pruned += 1;
38511
38812
  logger29.info("Managed skill cache pruned by source", { name, source });
38512
38813
  } catch (e) {
@@ -38517,7 +38818,7 @@ var SkillStore = class {
38517
38818
  }
38518
38819
  listIndexEntries() {
38519
38820
  try {
38520
- const parsed = JSON.parse(fs15.readFileSync(this.indexPath, "utf-8"));
38821
+ const parsed = JSON.parse(fs16.readFileSync(this.indexPath, "utf-8"));
38521
38822
  if (!Array.isArray(parsed)) return [];
38522
38823
  return parsed.map(normalizeSkillIndexEntry).filter((entry) => entry !== null);
38523
38824
  } catch (e) {
@@ -38530,7 +38831,7 @@ var SkillStore = class {
38530
38831
  }
38531
38832
  readExisting(name) {
38532
38833
  try {
38533
- return fs15.readFileSync(path22.join(this.skillsDir, `${name}.md`), "utf-8");
38834
+ return fs16.readFileSync(path23.join(this.skillsDir, `${name}.md`), "utf-8");
38534
38835
  } catch (e) {
38535
38836
  if (!isNotFoundError(e)) logger29.warn("Managed skill cache read failed", { name, error: e });
38536
38837
  return "";
@@ -38576,8 +38877,8 @@ function normalizeSkillIndexEntry(value) {
38576
38877
 
38577
38878
  // src/lockfile.ts
38578
38879
  import * as childProcess from "child_process";
38579
- import fs16 from "fs";
38580
- import path23 from "path";
38880
+ import fs17 from "fs";
38881
+ import path24 from "path";
38581
38882
  var logger30 = createModuleLogger("bridge.lockfile");
38582
38883
  var lockPath = null;
38583
38884
  var releaseRegistered = false;
@@ -38652,8 +38953,8 @@ function readProcessCommand(pid) {
38652
38953
  return readWindowsProcessCommand(pid);
38653
38954
  }
38654
38955
  const procCmdline = `/proc/${pid}/cmdline`;
38655
- if (fs16.existsSync(procCmdline)) {
38656
- return fs16.readFileSync(procCmdline, "utf-8").replace(/\0/g, " ");
38956
+ if (fs17.existsSync(procCmdline)) {
38957
+ return fs17.readFileSync(procCmdline, "utf-8").replace(/\0/g, " ");
38657
38958
  }
38658
38959
  return childProcess.execFileSync("ps", ["-p", String(pid), "-o", "comm=", "-o", "args="], {
38659
38960
  encoding: "utf-8",
@@ -38679,10 +38980,10 @@ function isLiveBridgeLockOwner(pid) {
38679
38980
  return false;
38680
38981
  }
38681
38982
  function acquireLock(dataDir) {
38682
- const file2 = path23.join(dataDir, "bridge.lock");
38983
+ const file2 = path24.join(dataDir, "bridge.lock");
38683
38984
  lockPath = file2;
38684
- if (fs16.existsSync(file2)) {
38685
- const raw = fs16.readFileSync(file2, "utf-8").trim();
38985
+ if (fs17.existsSync(file2)) {
38986
+ const raw = fs17.readFileSync(file2, "utf-8").trim();
38686
38987
  const pid = Number.parseInt(raw, 10);
38687
38988
  if (Number.isFinite(pid) && pid > 0) {
38688
38989
  if (isLiveBridgeLockOwner(pid)) {
@@ -38691,8 +38992,8 @@ function acquireLock(dataDir) {
38691
38992
  logger30.info("Removing stale bridge.lock", { pid, path: file2 });
38692
38993
  }
38693
38994
  }
38694
- fs16.mkdirSync(path23.dirname(file2), { recursive: true });
38695
- fs16.writeFileSync(file2, String(process.pid), "utf-8");
38995
+ fs17.mkdirSync(path24.dirname(file2), { recursive: true });
38996
+ fs17.writeFileSync(file2, String(process.pid), "utf-8");
38696
38997
  logger30.info("Acquired bridge lock", { path: file2, pid: process.pid });
38697
38998
  if (!releaseRegistered) {
38698
38999
  releaseRegistered = true;
@@ -38701,10 +39002,10 @@ function acquireLock(dataDir) {
38701
39002
  }
38702
39003
  function releaseLock() {
38703
39004
  try {
38704
- if (lockPath && fs16.existsSync(lockPath)) {
38705
- const current = fs16.readFileSync(lockPath, "utf-8").trim();
39005
+ if (lockPath && fs17.existsSync(lockPath)) {
39006
+ const current = fs17.readFileSync(lockPath, "utf-8").trim();
38706
39007
  if (current === String(process.pid)) {
38707
- fs16.unlinkSync(lockPath);
39008
+ fs17.unlinkSync(lockPath);
38708
39009
  logger30.info("Released bridge lock", { path: lockPath });
38709
39010
  }
38710
39011
  }
@@ -38716,17 +39017,17 @@ function releaseLock() {
38716
39017
  }
38717
39018
 
38718
39019
  // src/localWorkdirOverrideStore.ts
38719
- import fs17 from "fs";
38720
- import path24 from "path";
39020
+ import fs18 from "fs";
39021
+ import path25 from "path";
38721
39022
  var logger31 = createModuleLogger("bridge.localWorkdirOverride");
38722
39023
  var LocalWorkdirOverrideStore = class {
38723
39024
  filePath;
38724
39025
  constructor(dataDir) {
38725
- this.filePath = path24.join(dataDir, LOCAL_WORKDIR_OVERRIDES_FILENAME);
39026
+ this.filePath = path25.join(dataDir, LOCAL_WORKDIR_OVERRIDES_FILENAME);
38726
39027
  }
38727
39028
  read() {
38728
39029
  try {
38729
- const raw = fs17.readFileSync(this.filePath, "utf8");
39030
+ const raw = fs18.readFileSync(this.filePath, "utf8");
38730
39031
  return normalizeLocalWorkdirOverridesFile(JSON.parse(raw)).overrides;
38731
39032
  } catch (error51) {
38732
39033
  if (error51 instanceof Error && "code" in error51 && error51.code === "ENOENT") return [];
@@ -38745,9 +39046,9 @@ var LocalWorkdirOverrideStore = class {
38745
39046
  if (!args.localWorkdir.trim()) throw new Error("local workdir is required");
38746
39047
  const current = { version: 1, overrides: this.read() };
38747
39048
  const next = upsertLocalWorkdirOverride(current, args);
38748
- fs17.mkdirSync(args.localWorkdir, { recursive: true });
38749
- fs17.mkdirSync(path24.dirname(this.filePath), { recursive: true });
38750
- fs17.writeFileSync(this.filePath, `${JSON.stringify(next, null, 2)}
39049
+ fs18.mkdirSync(args.localWorkdir, { recursive: true });
39050
+ fs18.mkdirSync(path25.dirname(this.filePath), { recursive: true });
39051
+ fs18.writeFileSync(this.filePath, `${JSON.stringify(next, null, 2)}
38751
39052
  `, "utf8");
38752
39053
  const saved = next.overrides.find(
38753
39054
  (item) => item.targetKind === args.targetKind && item.targetId === args.targetId
@@ -39164,8 +39465,8 @@ async function handleGroupArchivedPush(deps, payload) {
39164
39465
  }
39165
39466
 
39166
39467
  // src/sessionStore.ts
39167
- import fs18 from "fs";
39168
- import path25 from "path";
39468
+ import fs19 from "fs";
39469
+ import path26 from "path";
39169
39470
  var logger34 = createModuleLogger("session.store");
39170
39471
  var SessionStore = class {
39171
39472
  filePath;
@@ -39173,8 +39474,8 @@ var SessionStore = class {
39173
39474
  cache;
39174
39475
  fingerprints;
39175
39476
  constructor(dataDir) {
39176
- this.filePath = path25.join(dataDir, "sessions.json");
39177
- this.fingerprintPath = path25.join(dataDir, "session-fingerprints.json");
39477
+ this.filePath = path26.join(dataDir, "sessions.json");
39478
+ this.fingerprintPath = path26.join(dataDir, "session-fingerprints.json");
39178
39479
  this.cache = this.loadFromDisk();
39179
39480
  this.fingerprints = this.loadMapFromDisk(this.fingerprintPath, "session fingerprints");
39180
39481
  }
@@ -39232,8 +39533,8 @@ var SessionStore = class {
39232
39533
  }
39233
39534
  loadFromDisk() {
39234
39535
  try {
39235
- if (!fs18.existsSync(this.filePath)) return {};
39236
- const raw = fs18.readFileSync(this.filePath, "utf-8");
39536
+ if (!fs19.existsSync(this.filePath)) return {};
39537
+ const raw = fs19.readFileSync(this.filePath, "utf-8");
39237
39538
  const parsed = JSON.parse(raw);
39238
39539
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
39239
39540
  const map2 = parsed;
@@ -39257,8 +39558,8 @@ var SessionStore = class {
39257
39558
  }
39258
39559
  loadMapFromDisk(filePath, label) {
39259
39560
  try {
39260
- if (!fs18.existsSync(filePath)) return {};
39261
- const raw = fs18.readFileSync(filePath, "utf-8");
39561
+ if (!fs19.existsSync(filePath)) return {};
39562
+ const raw = fs19.readFileSync(filePath, "utf-8");
39262
39563
  const parsed = JSON.parse(raw);
39263
39564
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return {};
39264
39565
  const out = {};
@@ -39273,18 +39574,18 @@ var SessionStore = class {
39273
39574
  }
39274
39575
  saveToDisk() {
39275
39576
  try {
39276
- const dir = path25.dirname(this.filePath);
39277
- fs18.mkdirSync(dir, { recursive: true });
39278
- fs18.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2), "utf-8");
39577
+ const dir = path26.dirname(this.filePath);
39578
+ fs19.mkdirSync(dir, { recursive: true });
39579
+ fs19.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2), "utf-8");
39279
39580
  } catch (e) {
39280
39581
  logger34.error("Failed to save sessions file", { error: e, path: this.filePath });
39281
39582
  }
39282
39583
  }
39283
39584
  saveFingerprintsToDisk() {
39284
39585
  try {
39285
- const dir = path25.dirname(this.fingerprintPath);
39286
- fs18.mkdirSync(dir, { recursive: true });
39287
- fs18.writeFileSync(
39586
+ const dir = path26.dirname(this.fingerprintPath);
39587
+ fs19.mkdirSync(dir, { recursive: true });
39588
+ fs19.writeFileSync(
39288
39589
  this.fingerprintPath,
39289
39590
  JSON.stringify(this.fingerprints, null, 2),
39290
39591
  "utf-8"
@@ -39299,8 +39600,8 @@ var SessionStore = class {
39299
39600
  };
39300
39601
 
39301
39602
  // src/workdirEnsure.ts
39302
- import fs19 from "fs";
39303
- import path26 from "path";
39603
+ import fs20 from "fs";
39604
+ import path27 from "path";
39304
39605
  function resolveBridgeWorkdirPath(requestedPath, workspacesDir, workdirOverrideStore, target) {
39305
39606
  const overridden = target ? workdirOverrideStore?.resolvePath(requestedPath, target) : workdirOverrideStore?.resolvePath(requestedPath);
39306
39607
  if (overridden?.overridden) {
@@ -39312,15 +39613,15 @@ function ensureBridgeWorkdirExists(requestedPath, workspacesDir, workdirOverride
39312
39613
  const trimmed = requestedPath.trim();
39313
39614
  if (!trimmed) return null;
39314
39615
  const resolved = resolveBridgeWorkdirPath(trimmed, workspacesDir, workdirOverrideStore, target);
39315
- if (!path26.isAbsolute(resolved.path)) return { ...resolved, ensured: false };
39316
- fs19.mkdirSync(resolved.path, { recursive: true });
39616
+ if (!path27.isAbsolute(resolved.path)) return { ...resolved, ensured: false };
39617
+ fs20.mkdirSync(resolved.path, { recursive: true });
39317
39618
  return { ...resolved, ensured: true };
39318
39619
  }
39319
39620
 
39320
39621
  // src/claudeRuntime.ts
39321
39622
  import { accessSync as accessSync2, constants as constants3, existsSync as existsSync2, readdirSync as readdirSync2, realpathSync } from "fs";
39322
39623
  import { createRequire } from "module";
39323
- import path27 from "path";
39624
+ import path28 from "path";
39324
39625
  var logger35 = createModuleLogger("bridge.claudeRuntime");
39325
39626
  var require2 = createRequire(import.meta.url);
39326
39627
  var CLAUDE_RUNTIME_VERSION_TIMEOUT_MS = 3e4;
@@ -39330,7 +39631,7 @@ function normalizePath(value) {
39330
39631
  const trimmed = value?.trim();
39331
39632
  if (!trimmed) return void 0;
39332
39633
  const expanded = resolveUserPath(trimmed);
39333
- return path27.isAbsolute(expanded) ? expanded : path27.resolve(expanded);
39634
+ return path28.isAbsolute(expanded) ? expanded : path28.resolve(expanded);
39334
39635
  }
39335
39636
  function canExecute2(candidate) {
39336
39637
  try {
@@ -39414,16 +39715,16 @@ function resolveClaudeAgentSdkDir() {
39414
39715
  const sdkEntry = safeResolve("@anthropic-ai/claude-agent-sdk");
39415
39716
  if (!sdkEntry) return void 0;
39416
39717
  try {
39417
- return path27.dirname(realpathSync(sdkEntry));
39718
+ return path28.dirname(realpathSync(sdkEntry));
39418
39719
  } catch {
39419
- return path27.dirname(sdkEntry);
39720
+ return path28.dirname(sdkEntry);
39420
39721
  }
39421
39722
  }
39422
39723
  function findPnpmStoreDir(fromDir) {
39423
39724
  let current = fromDir;
39424
- while (current !== path27.dirname(current)) {
39425
- if (path27.basename(current) === ".pnpm") return current;
39426
- current = path27.dirname(current);
39725
+ while (current !== path28.dirname(current)) {
39726
+ if (path28.basename(current) === ".pnpm") return current;
39727
+ current = path28.dirname(current);
39427
39728
  }
39428
39729
  return void 0;
39429
39730
  }
@@ -39441,7 +39742,7 @@ function resolvePnpmRuntimeBinary(sdkDir, target) {
39441
39742
  for (const entry of entries) {
39442
39743
  if (!entry.startsWith(`${encodedName}@`)) continue;
39443
39744
  const version2 = entry.slice(encodedName.length + 1);
39444
- const candidate = path27.join(
39745
+ const candidate = path28.join(
39445
39746
  pnpmStoreDir,
39446
39747
  entry,
39447
39748
  "node_modules",
@@ -39473,8 +39774,8 @@ function resolveSdkRuntimeBinary(target) {
39473
39774
  const scopedPackageName = target.packageName.split("/")[1] ?? target.packageName;
39474
39775
  const candidates = [
39475
39776
  safeResolve(`${target.packageName}/${target.binaryName}`, [sdkDir]),
39476
- path27.join(sdkDir, "..", scopedPackageName, target.binaryName),
39477
- path27.join(sdkDir, "node_modules", ...target.packageName.split("/"), target.binaryName),
39777
+ path28.join(sdkDir, "..", scopedPackageName, target.binaryName),
39778
+ path28.join(sdkDir, "node_modules", ...target.packageName.split("/"), target.binaryName),
39478
39779
  resolvePnpmRuntimeBinary(sdkDir, target)
39479
39780
  ].filter((candidate) => Boolean(candidate));
39480
39781
  return candidates.find((candidate) => existsSync2(candidate));
@@ -39606,8 +39907,8 @@ function logClaudeRuntimeResolution(resolution) {
39606
39907
  }
39607
39908
 
39608
39909
  // src/forkAgentFiles.ts
39609
- import * as fs20 from "fs/promises";
39610
- import * as path28 from "path";
39910
+ import * as fs21 from "fs/promises";
39911
+ import * as path29 from "path";
39611
39912
  var logger36 = createModuleLogger("bridge.forkAgentFiles");
39612
39913
  async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkdir, dataDir, sessionStore, sourceConversationId) {
39613
39914
  logger36.info("Fork file copy starting", {
@@ -39619,15 +39920,15 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
39619
39920
  sourceConversationId
39620
39921
  });
39621
39922
  try {
39622
- const stat3 = await fs20.stat(sourceWorkdir).catch(() => null);
39923
+ const stat3 = await fs21.stat(sourceWorkdir).catch(() => null);
39623
39924
  if (stat3?.isDirectory()) {
39624
- await fs20.cp(sourceWorkdir, newWorkdir, { recursive: true });
39925
+ await fs21.cp(sourceWorkdir, newWorkdir, { recursive: true });
39625
39926
  logger36.info("Workdir copied", {
39626
39927
  from: sourceWorkdir,
39627
39928
  to: newWorkdir
39628
39929
  });
39629
39930
  } else {
39630
- await fs20.mkdir(newWorkdir, { recursive: true });
39931
+ await fs21.mkdir(newWorkdir, { recursive: true });
39631
39932
  logger36.info("Workdir created (source did not exist)", {
39632
39933
  newWorkdir
39633
39934
  });
@@ -39636,14 +39937,14 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
39636
39937
  logger36.error("Workdir copy failed", { error: e });
39637
39938
  throw e;
39638
39939
  }
39639
- const srcNotebook = path28.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
39640
- const dstNotebookDir = path28.join(dataDir, "agent-memory", newAgentId);
39641
- const dstNotebook = path28.join(dstNotebookDir, "notebook.md");
39940
+ const srcNotebook = path29.join(dataDir, "agent-memory", sourceAgentId, "notebook.md");
39941
+ const dstNotebookDir = path29.join(dataDir, "agent-memory", newAgentId);
39942
+ const dstNotebook = path29.join(dstNotebookDir, "notebook.md");
39642
39943
  try {
39643
- const nbStat = await fs20.stat(srcNotebook).catch(() => null);
39944
+ const nbStat = await fs21.stat(srcNotebook).catch(() => null);
39644
39945
  if (nbStat?.isFile()) {
39645
- await fs20.mkdir(dstNotebookDir, { recursive: true });
39646
- await fs20.copyFile(srcNotebook, dstNotebook);
39946
+ await fs21.mkdir(dstNotebookDir, { recursive: true });
39947
+ await fs21.copyFile(srcNotebook, dstNotebook);
39647
39948
  logger36.info("Notebook copied", {
39648
39949
  from: srcNotebook,
39649
39950
  to: dstNotebook
@@ -39661,12 +39962,12 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
39661
39962
  if (sourceSessionId) {
39662
39963
  try {
39663
39964
  const srcPath = sessionFilePath(sourceWorkdir, sourceSessionId);
39664
- const srcStat = await fs20.stat(srcPath).catch(() => null);
39965
+ const srcStat = await fs21.stat(srcPath).catch(() => null);
39665
39966
  if (srcStat?.isFile()) {
39666
39967
  const dstDir = sessionDirForCwd(newWorkdir);
39667
- await fs20.mkdir(dstDir, { recursive: true });
39668
- const dstPath = path28.join(dstDir, `${sourceSessionId}.jsonl`);
39669
- await fs20.copyFile(srcPath, dstPath);
39968
+ await fs21.mkdir(dstDir, { recursive: true });
39969
+ const dstPath = path29.join(dstDir, `${sourceSessionId}.jsonl`);
39970
+ await fs21.copyFile(srcPath, dstPath);
39670
39971
  sessionStore.set(newAgentId, { kind: "single" }, sourceSessionId);
39671
39972
  sessionCopied = true;
39672
39973
  logger36.info("Session JSONL copied and registered", {
@@ -39712,7 +40013,7 @@ async function forkAgentFiles(sourceAgentId, newAgentId, sourceWorkdir, newWorkd
39712
40013
 
39713
40014
  // src/feedbackCodexAnalyzer.ts
39714
40015
  import { spawn, spawnSync } from "child_process";
39715
- import path29 from "path";
40016
+ import path30 from "path";
39716
40017
  var logger37 = createModuleLogger("feedbackCodexAnalyzer");
39717
40018
  var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
39718
40019
  var MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
@@ -39737,12 +40038,12 @@ function resolveFeedbackCodexOptions(defaultWorkdir, env2 = process.env) {
39737
40038
  const logDataDir = readOptionalEnv("AHCHAT_FEEDBACK_LOG_DATA_DIR", env2) ?? DEFAULT_LOG_DATA_DIR;
39738
40039
  return {
39739
40040
  executable: readOptionalEnv("AHCHAT_FEEDBACK_CODEX_EXECUTABLE", env2) ?? readOptionalEnv("CODEX_EXECUTABLE", env2) ?? "codex",
39740
- workdir: path29.resolve(readOptionalEnv("AHCHAT_FEEDBACK_CODEX_WORKDIR", env2) ?? defaultWorkdir),
40041
+ workdir: path30.resolve(readOptionalEnv("AHCHAT_FEEDBACK_CODEX_WORKDIR", env2) ?? defaultWorkdir),
39741
40042
  model: readOptionalEnv("AHCHAT_FEEDBACK_CODEX_MODEL", env2),
39742
40043
  timeoutMs: readPositiveIntEnv("AHCHAT_FEEDBACK_CODEX_TIMEOUT_MS", DEFAULT_TIMEOUT_MS2, env2),
39743
40044
  logSshTarget: readOptionalEnv("AHCHAT_FEEDBACK_LOG_SSH_TARGET", env2) ?? DEFAULT_LOG_SSH_TARGET,
39744
40045
  logDataDir,
39745
- logServerLogDir: readOptionalEnv("AHCHAT_FEEDBACK_LOG_SERVER_LOG_DIR", env2) ?? path29.posix.join(logDataDir, "logs"),
40046
+ logServerLogDir: readOptionalEnv("AHCHAT_FEEDBACK_LOG_SERVER_LOG_DIR", env2) ?? path30.posix.join(logDataDir, "logs"),
39746
40047
  logUploadTable: readOptionalEnv("AHCHAT_FEEDBACK_LOG_UPLOAD_TABLE", env2) ?? DEFAULT_LOG_UPLOAD_TABLE
39747
40048
  };
39748
40049
  }
@@ -39935,7 +40236,7 @@ function buildFeedbackAnalysisPrompt(payload, options, attachments) {
39935
40236
  - \u751F\u4EA7\u65E5\u5FD7\u76EE\u6807\uFF1A${options.logSshTarget}
39936
40237
  - AHChat \u6570\u636E\u76EE\u5F55\uFF1A${options.logDataDir}
39937
40238
  - \u670D\u52A1\u7AEF\u65E5\u5FD7\u76EE\u5F55\uFF1A${options.logServerLogDir}
39938
- - Bridge \u4E0A\u4F20\u65E5\u5FD7\u6570\u636E\u5E93\uFF1A${path29.posix.join(options.logDataDir, "data.db")}
40239
+ - Bridge \u4E0A\u4F20\u65E5\u5FD7\u6570\u636E\u5E93\uFF1A${path30.posix.join(options.logDataDir, "data.db")}
39939
40240
  - \u4E0A\u4F20\u65E5\u5FD7\u8868\uFF1A${options.logUploadTable}
39940
40241
  - \u5982\u679C\u76EE\u6807\u673A\u5668\u4E0A\u7684\u5B9A\u65F6\u4EFB\u52A1\u6216\u670D\u52A1\u914D\u7F6E\u663E\u793A\u65E5\u5FD7\u76EE\u5F55\u4E0D\u540C\uFF0C\u4EE5\u5B9E\u9645\u914D\u7F6E\u4E3A\u51C6\u3002
39941
40242
  - \u53EA\u505A\u53EA\u8BFB\u67E5\u8BE2\uFF1B\u4E0D\u8981\u590D\u5236\u6570\u636E\u5E93\uFF1B\u53EF\u7528 ssh \u5230\u76EE\u6807\u673A\u5668\u540E\u901A\u8FC7 python3/sqlite3 \u67E5\u8BE2\u3002
@@ -40110,15 +40411,15 @@ async function analyzeFeedbackWithLocalCodex(payload, options, attachments = [])
40110
40411
  }
40111
40412
 
40112
40413
  // src/modelQuerier.ts
40113
- import fs21 from "fs/promises";
40414
+ import fs22 from "fs/promises";
40114
40415
  import os12 from "os";
40115
- import path30 from "path";
40416
+ import path31 from "path";
40116
40417
  import * as sdk4 from "@anthropic-ai/claude-agent-sdk";
40117
40418
  var logger38 = createModuleLogger("bridge.modelQuerier");
40118
40419
  async function listModels(queryFn, opts = {}) {
40119
40420
  const t0 = Date.now();
40120
- const cwd = opts.cwd ?? path30.join(os12.homedir(), ".ahchat", "workspaces", "_list_models");
40121
- await fs21.mkdir(cwd, { recursive: true });
40421
+ const cwd = opts.cwd ?? path31.join(os12.homedir(), ".ahchat", "workspaces", "_list_models");
40422
+ await fs22.mkdir(cwd, { recursive: true });
40122
40423
  const fn = queryFn ?? sdk4.query;
40123
40424
  const ic = new InputController();
40124
40425
  ic.push("Reply with exactly: PING", "");
@@ -40183,9 +40484,9 @@ async function listModels(queryFn, opts = {}) {
40183
40484
  import { execFile as execFile3 } from "child_process";
40184
40485
  import crypto4 from "crypto";
40185
40486
  import fsSync2 from "fs";
40186
- import fs22 from "fs/promises";
40487
+ import fs23 from "fs/promises";
40187
40488
  import os13 from "os";
40188
- import path31 from "path";
40489
+ import path32 from "path";
40189
40490
  import { promisify as promisify3 } from "util";
40190
40491
  var execFileAsync3 = promisify3(execFile3);
40191
40492
  var logger39 = createModuleLogger("bridge.officeRuntimeSetup");
@@ -40245,7 +40546,7 @@ async function fetchUrl(url2, outputPath, timeoutMs) {
40245
40546
  const res = await fetch(url2, { signal: controller.signal });
40246
40547
  if (!res.ok) return false;
40247
40548
  const bytes = Buffer.from(await res.arrayBuffer());
40248
- await fs22.writeFile(outputPath, bytes);
40549
+ await fs23.writeFile(outputPath, bytes);
40249
40550
  return true;
40250
40551
  } catch (error51) {
40251
40552
  logger39.error("OfficeCLI runtime download failed", { error: error51, url: url2 });
@@ -40267,7 +40568,7 @@ function parseChecksumManifest(raw, asset) {
40267
40568
  return null;
40268
40569
  }
40269
40570
  async function sha256(filePath) {
40270
- return crypto4.createHash("sha256").update(await fs22.readFile(filePath)).digest("hex");
40571
+ return crypto4.createHash("sha256").update(await fs23.readFile(filePath)).digest("hex");
40271
40572
  }
40272
40573
  async function runBestEffort(command, args) {
40273
40574
  try {
@@ -40295,10 +40596,10 @@ async function installManagedOfficeCliRuntime(env2) {
40295
40596
  const githubBase = `https://github.com/${REPO}/releases/download/${version2}`;
40296
40597
  const mirrorAssetBase = `${mirrorBase(env2)}/releases/download/${version2}`;
40297
40598
  const timeoutMs = readTimeoutMs(env2);
40298
- await fs22.mkdir(binDir, { recursive: true });
40299
- const tmpDir = await fs22.mkdtemp(path31.join(os13.tmpdir(), "ahchat-officecli-"));
40300
- const tmpBinary = path31.join(tmpDir, asset);
40301
- const tmpSums = path31.join(tmpDir, "SHA256SUMS");
40599
+ await fs23.mkdir(binDir, { recursive: true });
40600
+ const tmpDir = await fs23.mkdtemp(path32.join(os13.tmpdir(), "ahchat-officecli-"));
40601
+ const tmpBinary = path32.join(tmpDir, asset);
40602
+ const tmpSums = path32.join(tmpDir, "SHA256SUMS");
40302
40603
  try {
40303
40604
  const binarySource = await fetchWithFallback(
40304
40605
  `${mirrorAssetBase}/${asset}`,
@@ -40314,21 +40615,21 @@ async function installManagedOfficeCliRuntime(env2) {
40314
40615
  timeoutMs
40315
40616
  );
40316
40617
  if (!checksumSource) throw new Error(`Could not download SHA256SUMS for OfficeCLI ${version2}`);
40317
- const expected = parseChecksumManifest(await fs22.readFile(tmpSums, "utf-8"), asset);
40618
+ const expected = parseChecksumManifest(await fs23.readFile(tmpSums, "utf-8"), asset);
40318
40619
  if (!expected) throw new Error(`SHA256SUMS does not contain ${asset}`);
40319
40620
  const actual = await sha256(tmpBinary);
40320
40621
  if (expected !== actual) {
40321
40622
  throw new Error(`Checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
40322
40623
  }
40323
- const staged = path31.join(binDir, `${path31.basename(target)}.new`);
40324
- await fs22.copyFile(tmpBinary, staged);
40325
- await fs22.chmod(staged, 493);
40624
+ const staged = path32.join(binDir, `${path32.basename(target)}.new`);
40625
+ await fs23.copyFile(tmpBinary, staged);
40626
+ await fs23.chmod(staged, 493);
40326
40627
  await codesignIfNeeded(staged);
40327
- await fs22.rm(target, { force: true });
40328
- await fs22.rename(staged, target);
40628
+ await fs23.rm(target, { force: true });
40629
+ await fs23.rename(staged, target);
40329
40630
  return { path: target, asset, binarySource, checksumSource };
40330
40631
  } finally {
40331
- await fs22.rm(tmpDir, { recursive: true, force: true });
40632
+ await fs23.rm(tmpDir, { recursive: true, force: true });
40332
40633
  }
40333
40634
  }
40334
40635
  async function ensureOfficeCliRuntime(env2 = process.env) {
@@ -40366,9 +40667,9 @@ async function ensureOfficeCliRuntime(env2 = process.env) {
40366
40667
  }
40367
40668
 
40368
40669
  // src/promptOptimizer.ts
40369
- import fs23 from "fs/promises";
40670
+ import fs24 from "fs/promises";
40370
40671
  import os14 from "os";
40371
- import path32 from "path";
40672
+ import path33 from "path";
40372
40673
  import * as sdk5 from "@anthropic-ai/claude-agent-sdk";
40373
40674
  var logger40 = createModuleLogger("bridge.promptOptimizer");
40374
40675
  var OPTIMIZER_SYSTEM_PROMPT = `You are an expert prompt editor for ALL-CAN Agent creation.
@@ -40412,8 +40713,8 @@ async function optimizePrompt(queryFn, opts) {
40412
40713
  const prompt = opts.systemPrompt.trim();
40413
40714
  if (!prompt) throw new Error("systemPrompt is required");
40414
40715
  const t0 = Date.now();
40415
- const cwd = opts.cwd ?? path32.join(os14.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
40416
- await fs23.mkdir(cwd, { recursive: true });
40716
+ const cwd = opts.cwd ?? path33.join(os14.homedir(), ".ahchat", "workspaces", "_prompt_optimizer");
40717
+ await fs24.mkdir(cwd, { recursive: true });
40417
40718
  const fn = queryFn ?? sdk5.query;
40418
40719
  const ic = new InputController();
40419
40720
  ic.push(buildUserPrompt(opts), "");
@@ -40675,10 +40976,10 @@ function agentRuntimeConfigSnapshot(rawConfig) {
40675
40976
  };
40676
40977
  }
40677
40978
  async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
40678
- const rootClaudeDir = path33.join(process.env.HOME ?? "/root", ".claude");
40679
- const fs24 = await import("fs/promises");
40979
+ const rootClaudeDir = path34.join(process.env.HOME ?? "/root", ".claude");
40980
+ const fs25 = await import("fs/promises");
40680
40981
  try {
40681
- await fs24.access(rootClaudeDir);
40982
+ await fs25.access(rootClaudeDir);
40682
40983
  } catch (e) {
40683
40984
  logger42.info("No /root/.claude to sync", { rootClaudeDir });
40684
40985
  logger42.debug("Root Claude dir access failed", { error: e });
@@ -40686,10 +40987,10 @@ async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
40686
40987
  }
40687
40988
  const filesToSync = [".credentials.json", "settings.json", ".credentials.backup.json"];
40688
40989
  for (const file2 of filesToSync) {
40689
- const src = path33.join(rootClaudeDir, file2);
40690
- const dest = path33.join(agentConfigDir, file2);
40990
+ const src = path34.join(rootClaudeDir, file2);
40991
+ const dest = path34.join(agentConfigDir, file2);
40691
40992
  try {
40692
- await fs24.copyFile(src, dest);
40993
+ await fs25.copyFile(src, dest);
40693
40994
  logger42.info("Synced credential file", { file: file2, from: src, to: dest });
40694
40995
  } catch (e) {
40695
40996
  logger42.debug("Credential file not present, skipping", { file: file2, src });
@@ -40698,26 +40999,26 @@ async function syncClaudeCredentialsToNodeAccessibleDir(agentConfigDir) {
40698
40999
  }
40699
41000
  }
40700
41001
  async function chownRecursive(dirPath, uid, gid) {
40701
- const fs24 = await import("fs/promises");
41002
+ const fs25 = await import("fs/promises");
40702
41003
  try {
40703
- await fs24.chown(dirPath, uid, gid);
41004
+ await fs25.chown(dirPath, uid, gid);
40704
41005
  } catch (e) {
40705
41006
  logger42.debug("chown skipped", { error: e, uid, gid });
40706
41007
  }
40707
41008
  let entries;
40708
41009
  try {
40709
- entries = await fs24.readdir(dirPath, { withFileTypes: true });
41010
+ entries = await fs25.readdir(dirPath, { withFileTypes: true });
40710
41011
  } catch (e) {
40711
41012
  logger42.debug("chown directory read skipped", { error: e });
40712
41013
  return;
40713
41014
  }
40714
41015
  for (const entry of entries) {
40715
- const fullPath = path33.join(dirPath, entry.name);
41016
+ const fullPath = path34.join(dirPath, entry.name);
40716
41017
  if (entry.isDirectory()) {
40717
41018
  await chownRecursive(fullPath, uid, gid);
40718
41019
  } else {
40719
41020
  try {
40720
- await fs24.chown(fullPath, uid, gid);
41021
+ await fs25.chown(fullPath, uid, gid);
40721
41022
  } catch (e) {
40722
41023
  logger42.debug("chown skipped", { error: e, uid, gid });
40723
41024
  }
@@ -40729,7 +41030,7 @@ async function startBridge(config2) {
40729
41030
  configureBridgeLogger(config2);
40730
41031
  ensureDir(config2.dataDir);
40731
41032
  ensureDir(config2.agentConfigDir);
40732
- const workspacesDir = path33.join(config2.dataDir, "workspaces");
41033
+ const workspacesDir = path34.join(config2.dataDir, "workspaces");
40733
41034
  ensureDir(workspacesDir);
40734
41035
  process.env.CLAUDE_CONFIG_DIR = config2.agentConfigDir;
40735
41036
  installBridgeFetchAuth(config2.serverApiUrl, config2.bridgeToken);
@@ -40824,7 +41125,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
40824
41125
  wsMetrics.start(5e3);
40825
41126
  const sessionStore = new SessionStore(config2.dataDir);
40826
41127
  const workdirOverrideStore = new LocalWorkdirOverrideStore(config2.dataDir);
40827
- const memoryRoot = path33.join(config2.dataDir, "agent-memory");
41128
+ const memoryRoot = path34.join(config2.dataDir, "agent-memory");
40828
41129
  const memoryStore = new AgentMemoryStore(memoryRoot, config2.serverApiUrl, config2.bridgeToken);
40829
41130
  logger42.info("Agent memory store initialized", { rootDir: memoryRoot });
40830
41131
  const smithNotebook = memoryStore.read(SMITH_AGENT_ID);