@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.
- package/dist/cli.cjs +785 -484
- package/dist/index.js +653 -352
- 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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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:
|
|
4751
|
+
const { interval, path: path35, intervalBoundary } = this.options;
|
|
4752
4752
|
for (let index = 1; index < 1e3; ++index) {
|
|
4753
|
-
const filename =
|
|
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:
|
|
4783
|
+
const { compress, path: path35, rotate } = this.options;
|
|
4784
4784
|
let rotatedName = "";
|
|
4785
4785
|
for (let count = rotate; count > 0; --count) {
|
|
4786
|
-
const currName =
|
|
4787
|
-
const prevName = count === 1 ? this.filename :
|
|
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
|
|
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 || !
|
|
8348
|
+
if (!id || !path35 || !name || !displayName || !url2) return null;
|
|
8349
8349
|
return {
|
|
8350
8350
|
id,
|
|
8351
|
-
path:
|
|
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
|
|
8738
|
+
import fs7 from "fs/promises";
|
|
8739
8739
|
import os7 from "os";
|
|
8740
|
-
import
|
|
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,
|
|
10383
|
-
if (!
|
|
10384
|
+
function getElementAtPath(obj, path35) {
|
|
10385
|
+
if (!path35)
|
|
10384
10386
|
return obj;
|
|
10385
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 }, [...
|
|
10950
|
+
issue2.errors.map((issues) => processError({ issues }, [...path35, ...issue2.path]));
|
|
10949
10951
|
} else if (issue2.code === "invalid_key") {
|
|
10950
|
-
processError({ issues: issue2.issues }, [...
|
|
10952
|
+
processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
|
|
10951
10953
|
} else if (issue2.code === "invalid_element") {
|
|
10952
|
-
processError({ issues: issue2.issues }, [...
|
|
10954
|
+
processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
|
|
10953
10955
|
} else {
|
|
10954
|
-
const fullpath = [...
|
|
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,
|
|
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 }, [...
|
|
10987
|
+
issue2.errors.map((issues) => processError({ issues }, [...path35, ...issue2.path]));
|
|
10986
10988
|
} else if (issue2.code === "invalid_key") {
|
|
10987
|
-
processError({ issues: issue2.issues }, [...
|
|
10989
|
+
processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
|
|
10988
10990
|
} else if (issue2.code === "invalid_element") {
|
|
10989
|
-
processError({ issues: issue2.issues }, [...
|
|
10991
|
+
processError({ issues: issue2.issues }, [...path35, ...issue2.path]);
|
|
10990
10992
|
} else {
|
|
10991
|
-
const fullpath = [...
|
|
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
|
|
11024
|
-
for (const seg of
|
|
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
|
|
23717
|
-
if (
|
|
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 (
|
|
23722
|
-
const key =
|
|
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 = [
|
|
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
|
|
29718
|
-
import * as
|
|
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
|
|
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
|
|
29726
|
-
await
|
|
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
|
|
29988
|
+
const raw = await fs6.readFile(fp, "utf-8");
|
|
29733
29989
|
const meta3 = JSON.parse(raw);
|
|
29734
|
-
await
|
|
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
|
|
29762
|
-
var CLAUDE_PROJECTS_DIR =
|
|
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
|
|
30023
|
+
return path12.join(CLAUDE_PROJECTS_DIR, cwdToSlug(cwd));
|
|
29768
30024
|
}
|
|
29769
30025
|
function sessionFilePath(cwd, sessionId) {
|
|
29770
|
-
return
|
|
30026
|
+
return path12.join(sessionDirForCwd(cwd), `${sessionId}.jsonl`);
|
|
29771
30027
|
}
|
|
29772
30028
|
|
|
29773
30029
|
// src/workdirMapper.ts
|
|
29774
|
-
import
|
|
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
|
|
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 ?
|
|
30071
|
+
const remappedPath = parts.length > 0 ? path13.join(workspacesDir, ...parts) : workspacesDir;
|
|
29816
30072
|
return {
|
|
29817
30073
|
path: remappedPath,
|
|
29818
|
-
remapped:
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
30338
|
-
this.agentConfigDir =
|
|
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 =
|
|
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 ??
|
|
30361
|
-
this.agentConfigDir = options?.agentConfigDir ??
|
|
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 ??
|
|
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
|
|
30708
|
+
return path14.join(this.workspacesDir, ahchatSuffix);
|
|
30412
30709
|
}
|
|
30413
|
-
return
|
|
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
|
|
30721
|
+
return path14.join(this.workspacesDir, this.localScopeDirName(agentConfig, scope));
|
|
30425
30722
|
}
|
|
30426
|
-
const local =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
31027
|
+
return path14.join(effectiveConfigDir, "settings.json");
|
|
30731
31028
|
}
|
|
30732
31029
|
isSameRuntimeCwd(a, b) {
|
|
30733
|
-
const left =
|
|
30734
|
-
const right =
|
|
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
|
-
|
|
30740
|
-
|
|
30741
|
-
|
|
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) =>
|
|
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 =
|
|
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" ?
|
|
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" ?
|
|
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(
|
|
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
|
|
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 =
|
|
31473
|
+
effectiveConfigDir = path14.join(this.agentConfigDir, "api-key-agents", agentConfig.id);
|
|
31177
31474
|
let isNew = false;
|
|
31178
31475
|
try {
|
|
31179
|
-
await
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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 ?
|
|
31320
|
-
if (smithAgent && (Object.keys(resolvedExternalMcp.mcpServers).length
|
|
31321
|
-
logger14.info("Smith external MCP
|
|
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 =
|
|
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:
|
|
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
|
|
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 =
|
|
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
|
|
32736
|
-
filePath =
|
|
32737
|
-
await
|
|
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 =
|
|
33067
|
+
const candidate = path14.resolve(remapped.path);
|
|
32767
33068
|
if (!this.isPathInsideBase(candidate, runtime.cwd)) return null;
|
|
32768
33069
|
try {
|
|
32769
|
-
const stat3 = await
|
|
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 =
|
|
32785
|
-
const resolvedBase =
|
|
32786
|
-
const relative =
|
|
32787
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
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 =
|
|
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,
|
|
35168
|
-
return new URL(
|
|
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
|
|
35423
|
-
return `${base}${
|
|
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
|
|
35527
|
-
return `${base}${
|
|
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
|
|
35606
|
-
import
|
|
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
|
|
35629
|
-
return `${base}${
|
|
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 ??
|
|
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 ??
|
|
36125
|
+
const existsSync3 = options.existsSync ?? fs8.existsSync;
|
|
35825
36126
|
const distCliPath = firstExistingPath(
|
|
35826
36127
|
[
|
|
35827
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35850
|
-
|
|
35851
|
-
|
|
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
|
-
|
|
35865
|
-
|
|
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
|
|
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
|
|
35925
|
-
import
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
35952
|
-
return () =>
|
|
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
|
|
35961
|
-
import
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
36028
|
-
return () =>
|
|
36328
|
+
fs10.watchFile(this.filePath, { interval: 1e3 }, listener);
|
|
36329
|
+
return () => fs10.unwatchFile(this.filePath, listener);
|
|
36029
36330
|
}
|
|
36030
36331
|
write(skills) {
|
|
36031
|
-
|
|
36332
|
+
fs10.mkdirSync(this.dataDir, { recursive: true });
|
|
36032
36333
|
const payload = normalizeLocalSkillsFile({ version: 1, skills });
|
|
36033
36334
|
const tmpPath = `${this.filePath}.tmp`;
|
|
36034
|
-
|
|
36335
|
+
fs10.writeFileSync(tmpPath, `${JSON.stringify(payload, null, 2)}
|
|
36035
36336
|
`, { encoding: "utf8", mode: 384 });
|
|
36036
|
-
|
|
36337
|
+
fs10.renameSync(tmpPath, this.filePath);
|
|
36037
36338
|
try {
|
|
36038
|
-
|
|
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
|
|
37023
|
+
import fs11 from "fs/promises";
|
|
36723
37024
|
import os9 from "os";
|
|
36724
|
-
import
|
|
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
|
|
37055
|
+
return path18.join(projectsDir, slug, `${sessionId}.jsonl`);
|
|
36755
37056
|
}
|
|
36756
37057
|
function resolveProjectDirInProjectsDir(projectsDir, cwd) {
|
|
36757
37058
|
const slug = cwdToProjectSlug(cwd);
|
|
36758
|
-
return
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
36814
|
-
|
|
37114
|
+
path18.join(configDir, "api-key-agents", opts.agentId, "projects"),
|
|
37115
|
+
path18.join(configDir, "projects")
|
|
36815
37116
|
]),
|
|
36816
|
-
|
|
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
|
|
37122
|
+
if (suffix) return path18.join(workspacesDir, suffix);
|
|
36822
37123
|
const normalized = requestedCwd.trim();
|
|
36823
|
-
const basename = normalized ?
|
|
36824
|
-
const segment = basename && basename !== "." && basename !==
|
|
36825
|
-
return
|
|
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
|
|
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 (
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
37208
|
+
const jsonlPath = path18.join(projectDir, entry.name);
|
|
36908
37209
|
let stat3;
|
|
36909
37210
|
try {
|
|
36910
|
-
stat3 = await
|
|
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 =
|
|
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 =
|
|
36925
|
-
const marker =
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
37347
|
-
await
|
|
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 ?
|
|
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 =
|
|
37475
|
-
await
|
|
37775
|
+
const filePath = path18.join(dumpDir, filename);
|
|
37776
|
+
await fs11.writeFile(filePath, html, "utf-8");
|
|
37476
37777
|
dumpedFiles.push(filename);
|
|
37477
|
-
const stat3 = await
|
|
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
|
|
37818
|
+
import fs12 from "fs/promises";
|
|
37518
37819
|
import os10 from "os";
|
|
37519
|
-
import
|
|
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("~\\") ?
|
|
37531
|
-
return
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
37926
|
+
const buffer = await fs12.readFile(resolvedPath);
|
|
37626
37927
|
const mimeType = mimeTypeForFileName(resolvedPath);
|
|
37627
37928
|
return {
|
|
37628
|
-
fileName:
|
|
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
|
|
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
|
|
37702
|
-
import
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
37750
|
-
if (relative.startsWith("..") ||
|
|
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 (
|
|
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
|
-
|
|
37762
|
-
|
|
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 =
|
|
38071
|
+
const targetPath = path20.resolve(resolvedBaseDir, safeRelativePath);
|
|
37771
38072
|
ensureInsideBase(resolvedBaseDir, targetPath);
|
|
37772
38073
|
const buffer = Buffer.from(opts.contentBase64, "base64");
|
|
37773
|
-
await
|
|
37774
|
-
await
|
|
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
|
|
38087
|
+
const stat3 = await fs13.stat(safePath);
|
|
37787
38088
|
if (!stat3.isFile()) throw new Error("path is not a file");
|
|
37788
|
-
const buffer = await
|
|
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:
|
|
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 =
|
|
38102
|
+
const candidate = path20.join(trashDir, `${stamp}-${safeName}${suffix}`);
|
|
37802
38103
|
try {
|
|
37803
|
-
await
|
|
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
|
-
|
|
37820
|
-
|
|
38120
|
+
fs13.realpath(resolvedBaseDir),
|
|
38121
|
+
fs13.realpath(resolvedTargetPath)
|
|
37821
38122
|
]);
|
|
37822
38123
|
ensureInsideBase(realBase, realTarget);
|
|
37823
38124
|
ensureNotBaseDir(realBase, realTarget);
|
|
37824
|
-
const trashDir =
|
|
37825
|
-
await
|
|
37826
|
-
const trashedPath = await allocateTrashPath(trashDir,
|
|
37827
|
-
await
|
|
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
|
|
37839
|
-
import
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
37858
|
-
const stream =
|
|
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 =
|
|
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
|
|
38221
|
+
import fs15 from "fs";
|
|
37921
38222
|
import fsp from "fs/promises";
|
|
37922
|
-
import
|
|
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
|
|
38267
|
+
return path22.join(dataDir, "logs", "bridge.log");
|
|
37967
38268
|
}
|
|
37968
38269
|
function defaultCursorFile(dataDir) {
|
|
37969
|
-
return
|
|
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 ||
|
|
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 ??
|
|
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
|
|
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 =
|
|
37996
|
-
const baseName =
|
|
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:
|
|
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(
|
|
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 =
|
|
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
|
|
38360
|
-
import
|
|
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 =
|
|
38390
|
-
this.indexPath =
|
|
38391
|
-
|
|
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 =
|
|
38700
|
+
const filePath = path23.join(this.skillsDir, `${name}.md`);
|
|
38400
38701
|
try {
|
|
38401
|
-
const content =
|
|
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
|
|
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 =
|
|
38728
|
+
const filePath = path23.join(this.skillsDir, `${name}.md`);
|
|
38428
38729
|
const tmpPath = `${filePath}.tmp`;
|
|
38429
38730
|
let existing = "";
|
|
38430
38731
|
try {
|
|
38431
|
-
existing =
|
|
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
|
-
|
|
38440
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
38499
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
38580
|
-
import
|
|
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 (
|
|
38656
|
-
return
|
|
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 =
|
|
38983
|
+
const file2 = path24.join(dataDir, "bridge.lock");
|
|
38683
38984
|
lockPath = file2;
|
|
38684
|
-
if (
|
|
38685
|
-
const raw =
|
|
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
|
-
|
|
38695
|
-
|
|
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 &&
|
|
38705
|
-
const current =
|
|
39005
|
+
if (lockPath && fs17.existsSync(lockPath)) {
|
|
39006
|
+
const current = fs17.readFileSync(lockPath, "utf-8").trim();
|
|
38706
39007
|
if (current === String(process.pid)) {
|
|
38707
|
-
|
|
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
|
|
38720
|
-
import
|
|
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 =
|
|
39026
|
+
this.filePath = path25.join(dataDir, LOCAL_WORKDIR_OVERRIDES_FILENAME);
|
|
38726
39027
|
}
|
|
38727
39028
|
read() {
|
|
38728
39029
|
try {
|
|
38729
|
-
const raw =
|
|
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
|
-
|
|
38749
|
-
|
|
38750
|
-
|
|
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
|
|
39168
|
-
import
|
|
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 =
|
|
39177
|
-
this.fingerprintPath =
|
|
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 (!
|
|
39236
|
-
const raw =
|
|
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 (!
|
|
39261
|
-
const raw =
|
|
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 =
|
|
39277
|
-
|
|
39278
|
-
|
|
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 =
|
|
39286
|
-
|
|
39287
|
-
|
|
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
|
|
39303
|
-
import
|
|
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 (!
|
|
39316
|
-
|
|
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
|
|
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
|
|
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
|
|
39718
|
+
return path28.dirname(realpathSync(sdkEntry));
|
|
39418
39719
|
} catch {
|
|
39419
|
-
return
|
|
39720
|
+
return path28.dirname(sdkEntry);
|
|
39420
39721
|
}
|
|
39421
39722
|
}
|
|
39422
39723
|
function findPnpmStoreDir(fromDir) {
|
|
39423
39724
|
let current = fromDir;
|
|
39424
|
-
while (current !==
|
|
39425
|
-
if (
|
|
39426
|
-
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 =
|
|
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
|
-
|
|
39477
|
-
|
|
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
|
|
39610
|
-
import * as
|
|
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
|
|
39923
|
+
const stat3 = await fs21.stat(sourceWorkdir).catch(() => null);
|
|
39623
39924
|
if (stat3?.isDirectory()) {
|
|
39624
|
-
await
|
|
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
|
|
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 =
|
|
39640
|
-
const dstNotebookDir =
|
|
39641
|
-
const dstNotebook =
|
|
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
|
|
39944
|
+
const nbStat = await fs21.stat(srcNotebook).catch(() => null);
|
|
39644
39945
|
if (nbStat?.isFile()) {
|
|
39645
|
-
await
|
|
39646
|
-
await
|
|
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
|
|
39965
|
+
const srcStat = await fs21.stat(srcPath).catch(() => null);
|
|
39665
39966
|
if (srcStat?.isFile()) {
|
|
39666
39967
|
const dstDir = sessionDirForCwd(newWorkdir);
|
|
39667
|
-
await
|
|
39668
|
-
const dstPath =
|
|
39669
|
-
await
|
|
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
|
|
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:
|
|
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) ??
|
|
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${
|
|
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
|
|
40414
|
+
import fs22 from "fs/promises";
|
|
40114
40415
|
import os12 from "os";
|
|
40115
|
-
import
|
|
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 ??
|
|
40121
|
-
await
|
|
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
|
|
40487
|
+
import fs23 from "fs/promises";
|
|
40187
40488
|
import os13 from "os";
|
|
40188
|
-
import
|
|
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
|
|
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
|
|
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
|
|
40299
|
-
const tmpDir = await
|
|
40300
|
-
const tmpBinary =
|
|
40301
|
-
const tmpSums =
|
|
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
|
|
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 =
|
|
40324
|
-
await
|
|
40325
|
-
await
|
|
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
|
|
40328
|
-
await
|
|
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
|
|
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
|
|
40670
|
+
import fs24 from "fs/promises";
|
|
40370
40671
|
import os14 from "os";
|
|
40371
|
-
import
|
|
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 ??
|
|
40416
|
-
await
|
|
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 =
|
|
40679
|
-
const
|
|
40979
|
+
const rootClaudeDir = path34.join(process.env.HOME ?? "/root", ".claude");
|
|
40980
|
+
const fs25 = await import("fs/promises");
|
|
40680
40981
|
try {
|
|
40681
|
-
await
|
|
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 =
|
|
40690
|
-
const dest =
|
|
40990
|
+
const src = path34.join(rootClaudeDir, file2);
|
|
40991
|
+
const dest = path34.join(agentConfigDir, file2);
|
|
40691
40992
|
try {
|
|
40692
|
-
await
|
|
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
|
|
41002
|
+
const fs25 = await import("fs/promises");
|
|
40702
41003
|
try {
|
|
40703
|
-
await
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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);
|