@fangyb/ahchat-bridge 0.1.24 → 0.1.26
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 +382 -60
- package/dist/index.js +376 -52
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -27107,8 +27107,8 @@ function getReadableStream(readStream) {
|
|
|
27107
27107
|
if (typeof Readable2.toWeb === "function") {
|
|
27108
27108
|
return Readable2.toWeb(readStream);
|
|
27109
27109
|
}
|
|
27110
|
-
const
|
|
27111
|
-
const polyfill =
|
|
27110
|
+
const require3 = process.getBuiltinModule("module").createRequire(importMetaUrl);
|
|
27111
|
+
const polyfill = require3("node-readable-to-web-readable-stream");
|
|
27112
27112
|
return polyfill.makeDefaultReadableStreamFromNodeReadable(readStream);
|
|
27113
27113
|
}
|
|
27114
27114
|
function getNetworkStream(url2) {
|
|
@@ -35773,8 +35773,8 @@ var init_pdf = __esm({
|
|
|
35773
35773
|
};
|
|
35774
35774
|
NodeCanvasFactory = class extends BaseCanvasFactory {
|
|
35775
35775
|
_createCanvas(width, height) {
|
|
35776
|
-
const
|
|
35777
|
-
const canvas =
|
|
35776
|
+
const require3 = process.getBuiltinModule("module").createRequire(importMetaUrl);
|
|
35777
|
+
const canvas = require3("@napi-rs/canvas");
|
|
35778
35778
|
return canvas.createCanvas(width, height);
|
|
35779
35779
|
}
|
|
35780
35780
|
};
|
|
@@ -60030,6 +60030,7 @@ function ensureDir(dirPath) {
|
|
|
60030
60030
|
// src/claudeRuntime.ts
|
|
60031
60031
|
init_cjs_shims();
|
|
60032
60032
|
var import_node_fs3 = require("fs");
|
|
60033
|
+
var import_node_module = require("module");
|
|
60033
60034
|
var import_node_path5 = __toESM(require("path"), 1);
|
|
60034
60035
|
|
|
60035
60036
|
// src/logger.ts
|
|
@@ -61536,6 +61537,7 @@ function normalizeBridgeServerUrls(rawUrl) {
|
|
|
61536
61537
|
|
|
61537
61538
|
// src/claudeRuntime.ts
|
|
61538
61539
|
var logger = createModuleLogger("bridge.claudeRuntime");
|
|
61540
|
+
var require2 = (0, import_node_module.createRequire)(importMetaUrl);
|
|
61539
61541
|
var EXPLICIT_CLAUDE_EXECUTABLE_ENV = "AHCHAT_CLAUDE_EXECUTABLE";
|
|
61540
61542
|
var BUNDLED_CLAUDE_PATH_ENV = "AHCHAT_BUNDLED_CLAUDE_PATH";
|
|
61541
61543
|
function normalizePath(value) {
|
|
@@ -61585,6 +61587,118 @@ function validateCandidate(source, candidatePath) {
|
|
|
61585
61587
|
version: version3
|
|
61586
61588
|
};
|
|
61587
61589
|
}
|
|
61590
|
+
function getSdkRuntimeTargets() {
|
|
61591
|
+
const binaryName = process.platform === "win32" ? "claude.exe" : "claude";
|
|
61592
|
+
const targetPrefix = "@anthropic-ai/claude-agent-sdk";
|
|
61593
|
+
if (process.platform === "darwin") {
|
|
61594
|
+
if (process.arch === "arm64" || process.arch === "x64") {
|
|
61595
|
+
return [{ packageName: `${targetPrefix}-darwin-${process.arch}`, binaryName }];
|
|
61596
|
+
}
|
|
61597
|
+
return [];
|
|
61598
|
+
}
|
|
61599
|
+
if (process.platform === "win32") {
|
|
61600
|
+
if (process.arch === "arm64" || process.arch === "x64") {
|
|
61601
|
+
return [{ packageName: `${targetPrefix}-win32-${process.arch}`, binaryName }];
|
|
61602
|
+
}
|
|
61603
|
+
return [];
|
|
61604
|
+
}
|
|
61605
|
+
if (process.platform === "linux") {
|
|
61606
|
+
if (process.arch === "arm64" || process.arch === "x64") {
|
|
61607
|
+
return [
|
|
61608
|
+
{ packageName: `${targetPrefix}-linux-${process.arch}`, binaryName },
|
|
61609
|
+
{ packageName: `${targetPrefix}-linux-${process.arch}-musl`, binaryName }
|
|
61610
|
+
];
|
|
61611
|
+
}
|
|
61612
|
+
}
|
|
61613
|
+
return [];
|
|
61614
|
+
}
|
|
61615
|
+
function safeResolve(specifier, paths) {
|
|
61616
|
+
try {
|
|
61617
|
+
return require2.resolve(specifier, paths ? { paths } : void 0);
|
|
61618
|
+
} catch {
|
|
61619
|
+
return void 0;
|
|
61620
|
+
}
|
|
61621
|
+
}
|
|
61622
|
+
function resolveClaudeAgentSdkDir() {
|
|
61623
|
+
const sdkEntry = safeResolve("@anthropic-ai/claude-agent-sdk");
|
|
61624
|
+
if (!sdkEntry) return void 0;
|
|
61625
|
+
try {
|
|
61626
|
+
return import_node_path5.default.dirname((0, import_node_fs3.realpathSync)(sdkEntry));
|
|
61627
|
+
} catch {
|
|
61628
|
+
return import_node_path5.default.dirname(sdkEntry);
|
|
61629
|
+
}
|
|
61630
|
+
}
|
|
61631
|
+
function findPnpmStoreDir(fromDir) {
|
|
61632
|
+
let current = fromDir;
|
|
61633
|
+
while (current !== import_node_path5.default.dirname(current)) {
|
|
61634
|
+
if (import_node_path5.default.basename(current) === ".pnpm") return current;
|
|
61635
|
+
current = import_node_path5.default.dirname(current);
|
|
61636
|
+
}
|
|
61637
|
+
return void 0;
|
|
61638
|
+
}
|
|
61639
|
+
function resolvePnpmRuntimeBinary(sdkDir, target) {
|
|
61640
|
+
const pnpmStoreDir = findPnpmStoreDir(sdkDir);
|
|
61641
|
+
if (!pnpmStoreDir) return void 0;
|
|
61642
|
+
const encodedName = target.packageName.replace("/", "+");
|
|
61643
|
+
let entries;
|
|
61644
|
+
try {
|
|
61645
|
+
entries = (0, import_node_fs3.readdirSync)(pnpmStoreDir);
|
|
61646
|
+
} catch {
|
|
61647
|
+
return void 0;
|
|
61648
|
+
}
|
|
61649
|
+
for (const entry of entries) {
|
|
61650
|
+
if (!entry.startsWith(`${encodedName}@`)) continue;
|
|
61651
|
+
const candidate = import_node_path5.default.join(
|
|
61652
|
+
pnpmStoreDir,
|
|
61653
|
+
entry,
|
|
61654
|
+
"node_modules",
|
|
61655
|
+
...target.packageName.split("/"),
|
|
61656
|
+
target.binaryName
|
|
61657
|
+
);
|
|
61658
|
+
if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
|
|
61659
|
+
}
|
|
61660
|
+
return void 0;
|
|
61661
|
+
}
|
|
61662
|
+
function resolveSdkRuntimeBinary(target) {
|
|
61663
|
+
const directPath = safeResolve(`${target.packageName}/${target.binaryName}`);
|
|
61664
|
+
if (directPath && (0, import_node_fs3.existsSync)(directPath)) return directPath;
|
|
61665
|
+
const sdkDir = resolveClaudeAgentSdkDir();
|
|
61666
|
+
if (!sdkDir) return void 0;
|
|
61667
|
+
const scopedPackageName = target.packageName.split("/")[1] ?? target.packageName;
|
|
61668
|
+
const candidates = [
|
|
61669
|
+
safeResolve(`${target.packageName}/${target.binaryName}`, [sdkDir]),
|
|
61670
|
+
import_node_path5.default.join(sdkDir, "..", scopedPackageName, target.binaryName),
|
|
61671
|
+
import_node_path5.default.join(sdkDir, "node_modules", ...target.packageName.split("/"), target.binaryName),
|
|
61672
|
+
resolvePnpmRuntimeBinary(sdkDir, target)
|
|
61673
|
+
].filter((candidate) => Boolean(candidate));
|
|
61674
|
+
return candidates.find((candidate) => (0, import_node_fs3.existsSync)(candidate));
|
|
61675
|
+
}
|
|
61676
|
+
function resolveSdkBundledAttempts() {
|
|
61677
|
+
const targets = getSdkRuntimeTargets();
|
|
61678
|
+
if (targets.length === 0) {
|
|
61679
|
+
return [{
|
|
61680
|
+
source: "sdk-bundled",
|
|
61681
|
+
ok: false,
|
|
61682
|
+
error: `unsupported platform for Claude Agent SDK runtime: ${process.platform}-${process.arch}`
|
|
61683
|
+
}];
|
|
61684
|
+
}
|
|
61685
|
+
const attempts = [];
|
|
61686
|
+
for (const target of targets) {
|
|
61687
|
+
const binaryPath = resolveSdkRuntimeBinary(target);
|
|
61688
|
+
if (!binaryPath) {
|
|
61689
|
+
attempts.push({
|
|
61690
|
+
source: "sdk-bundled",
|
|
61691
|
+
ok: false,
|
|
61692
|
+
error: `optional runtime package ${target.packageName} is not installed`
|
|
61693
|
+
});
|
|
61694
|
+
continue;
|
|
61695
|
+
}
|
|
61696
|
+
const attempt = validateCandidate("sdk-bundled", binaryPath);
|
|
61697
|
+
attempts.push(attempt);
|
|
61698
|
+
if (attempt.ok) break;
|
|
61699
|
+
}
|
|
61700
|
+
return attempts;
|
|
61701
|
+
}
|
|
61588
61702
|
function resolvePathCandidate() {
|
|
61589
61703
|
const resolved = resolveCommand(["claude", "anthropic-cli"]);
|
|
61590
61704
|
if (!resolved) return void 0;
|
|
@@ -61592,12 +61706,13 @@ function resolvePathCandidate() {
|
|
|
61592
61706
|
}
|
|
61593
61707
|
function buildMissingError(attempts) {
|
|
61594
61708
|
if (attempts.length === 0) {
|
|
61595
|
-
return "Claude runtime not found.
|
|
61709
|
+
return "Claude runtime not found. Reinstall @fangyb/ahchat-bridge with npm optional dependencies, install Claude Code manually, or use the bundled desktop runtime.";
|
|
61596
61710
|
}
|
|
61597
|
-
|
|
61711
|
+
const attemptDetails = attempts.map((attempt) => {
|
|
61598
61712
|
const pathSuffix = attempt.path ? ` at ${attempt.path}` : "";
|
|
61599
61713
|
return `${attempt.source}${pathSuffix}: ${attempt.error ?? "unavailable"}`;
|
|
61600
61714
|
}).join("; ");
|
|
61715
|
+
return `Claude runtime not found. ${attemptDetails}. Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUDE_EXECUTABLE, install Claude Code manually, or use the bundled desktop runtime.`;
|
|
61601
61716
|
}
|
|
61602
61717
|
function resolveClaudeRuntime(env2 = process.env) {
|
|
61603
61718
|
const attempts = [];
|
|
@@ -61635,6 +61750,19 @@ function resolveClaudeRuntime(env2 = process.env) {
|
|
|
61635
61750
|
};
|
|
61636
61751
|
}
|
|
61637
61752
|
}
|
|
61753
|
+
const sdkAttempts = resolveSdkBundledAttempts();
|
|
61754
|
+
for (const attempt of sdkAttempts) {
|
|
61755
|
+
attempts.push(attempt);
|
|
61756
|
+
if (attempt.ok) {
|
|
61757
|
+
return {
|
|
61758
|
+
ok: true,
|
|
61759
|
+
source: "sdk-bundled",
|
|
61760
|
+
path: attempt.path,
|
|
61761
|
+
version: attempt.version,
|
|
61762
|
+
attempts
|
|
61763
|
+
};
|
|
61764
|
+
}
|
|
61765
|
+
}
|
|
61638
61766
|
const pathAttempt = resolvePathCandidate();
|
|
61639
61767
|
if (pathAttempt) {
|
|
61640
61768
|
attempts.push(pathAttempt);
|
|
@@ -62099,6 +62227,14 @@ runtime\u3002\u5B83\u4EEC\u4E0D\u662F"\u4E0D\u540C\u7684\u4EBA"\u2014\u2014\u516
|
|
|
62099
62227
|
\`# \u3010\u6807\u9898\u3011\` (a single \`#\` followed by Chinese bracket-enclosed title).
|
|
62100
62228
|
For single-topic or short conversational replies, omit headings entirely.
|
|
62101
62229
|
|
|
62230
|
+
# AskUserQuestion tool
|
|
62231
|
+
- When you need the user to choose from options or answer a clarification question, call the real
|
|
62232
|
+
\`AskUserQuestion\` tool with a \`questions\` array.
|
|
62233
|
+
- Never output \`<AskUserQuestion>\`, \`</AskUserQuestion>\`, or raw JSON question payloads as chat text.
|
|
62234
|
+
Text like that is not an interactive panel and the user cannot answer it through the tool flow.
|
|
62235
|
+
- If you are not able to call \`AskUserQuestion\`, ask the question as plain natural language instead of
|
|
62236
|
+
emitting tool-shaped XML or JSON.
|
|
62237
|
+
|
|
62102
62238
|
# Runtime payload \u2014 how to read unread messages
|
|
62103
62239
|
|
|
62104
62240
|
\u6BCF\u4E2A turn \u91CC runtime \u4F1A\u7ED9\u4F60\u300C\u672A\u8BFB\u7FA4\u6D88\u606F\uFF08N \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09\u300D\u6BB5\u3002\u8BFB\u6CD5\uFF1A
|
|
@@ -62547,6 +62683,11 @@ function parseWSMessage(raw) {
|
|
|
62547
62683
|
}
|
|
62548
62684
|
return parsed;
|
|
62549
62685
|
}
|
|
62686
|
+
function isAskUserQuestionToolName(toolName) {
|
|
62687
|
+
if (!toolName) return false;
|
|
62688
|
+
const normalized = toolName.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
|
|
62689
|
+
return normalized === "askuserquestion" || normalized.endsWith("askuserquestion");
|
|
62690
|
+
}
|
|
62550
62691
|
|
|
62551
62692
|
// ../shared/src/utils/workdir.ts
|
|
62552
62693
|
init_cjs_shims();
|
|
@@ -62559,9 +62700,13 @@ init_cjs_shims();
|
|
|
62559
62700
|
|
|
62560
62701
|
// ../shared/src/utils/subscription.ts
|
|
62561
62702
|
init_cjs_shims();
|
|
62703
|
+
var PRIMARY_COMPANY_SUBSCRIPTION_ID = "sub_company_primary";
|
|
62562
62704
|
function isSubscriptionType(v) {
|
|
62563
62705
|
return v === "system" || v === "project";
|
|
62564
62706
|
}
|
|
62707
|
+
function isPrimaryCompanySubscriptionId(v) {
|
|
62708
|
+
return v === PRIMARY_COMPANY_SUBSCRIPTION_ID;
|
|
62709
|
+
}
|
|
62565
62710
|
|
|
62566
62711
|
// ../shared/src/utils/agentConfig.ts
|
|
62567
62712
|
function parseAgentConfig(raw) {
|
|
@@ -78157,6 +78302,14 @@ function normalizeDocumentText(value) {
|
|
|
78157
78302
|
return value.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
78158
78303
|
}
|
|
78159
78304
|
|
|
78305
|
+
// src/bridgeHttp.ts
|
|
78306
|
+
init_cjs_shims();
|
|
78307
|
+
var BRIDGE_TOKEN_HEADER = "X-AHChat-Bridge-Token";
|
|
78308
|
+
function bridgeAuthHeaders(bridgeToken) {
|
|
78309
|
+
const token = bridgeToken?.trim();
|
|
78310
|
+
return token ? { [BRIDGE_TOKEN_HEADER]: token } : {};
|
|
78311
|
+
}
|
|
78312
|
+
|
|
78160
78313
|
// src/neuralMcpServer.ts
|
|
78161
78314
|
var logger7 = createModuleLogger("neural.mcpServer");
|
|
78162
78315
|
function formatScopeLabel(key, groupName) {
|
|
@@ -78175,6 +78328,26 @@ function filterContactsByOwner(all, ownerId) {
|
|
|
78175
78328
|
(a) => a.kind === "system" || a.ownerId === ownerId || a.ownerId == null || a.kind === "human" && a.id === ownerId
|
|
78176
78329
|
);
|
|
78177
78330
|
}
|
|
78331
|
+
async function resolveTierSubscriptionPreference(preferredSubscriptionId, deps) {
|
|
78332
|
+
if (!preferredSubscriptionId || !isPrimaryCompanySubscriptionId(preferredSubscriptionId)) {
|
|
78333
|
+
return preferredSubscriptionId;
|
|
78334
|
+
}
|
|
78335
|
+
if (!deps.serverApiUrl) return preferredSubscriptionId;
|
|
78336
|
+
try {
|
|
78337
|
+
const base = deps.serverApiUrl.replace(/\/$/, "");
|
|
78338
|
+
const res = await fetch(`${base}/api/subscriptions`, {
|
|
78339
|
+
headers: bridgeAuthHeaders(deps.bridgeToken ?? null)
|
|
78340
|
+
});
|
|
78341
|
+
if (!res.ok) return preferredSubscriptionId;
|
|
78342
|
+
const subscriptions = await res.json();
|
|
78343
|
+
return subscriptions.find(
|
|
78344
|
+
(subscription) => subscription.billingMode === "company_billable" && subscription.isPrimaryCompany === true
|
|
78345
|
+
)?.id ?? preferredSubscriptionId;
|
|
78346
|
+
} catch (e) {
|
|
78347
|
+
logger7.warn("Primary company tier preference resolution failed", { error: e });
|
|
78348
|
+
return preferredSubscriptionId;
|
|
78349
|
+
}
|
|
78350
|
+
}
|
|
78178
78351
|
function resolveMyHuman(registry2, agentId) {
|
|
78179
78352
|
const all = registry2.getAll();
|
|
78180
78353
|
const myOwnerId = contactOwnerId(registry2, agentId);
|
|
@@ -79330,8 +79503,8 @@ ${result.warnings.map((warning) => `- ${warning}`).join("\n")}
|
|
|
79330
79503
|
"fetch_logs",
|
|
79331
79504
|
`\u62C9\u53D6\u7CFB\u7EDF\u65E5\u5FD7\uFF08\u6309\u65F6\u95F4\u7A97 + \u53EF\u9009 traceId / module / level \u8FC7\u6EE4\uFF09\u3002
|
|
79332
79505
|
\u8BFB SKILL "log-analysis" \u540E\u624D\u7528\u8FD9\u4E2A\u5DE5\u5177\u3002\u4E00\u6B21\u8C03\u7528\u53EA\u80FD\u62C9\u4E00\u4E2A source\uFF08server \u6216 bridge\uFF09\uFF0C\u5168\u666F\u9700\u8981\u4E24\u6B21\u3002
|
|
79333
|
-
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\
|
|
79334
|
-
\u6CE8\u610F\uFF1A\u5982\u679C\
|
|
79506
|
+
limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\uFF1B\u652F\u6301 offset \u5206\u9875\u3002\u8FD4\u56DE\u7ED3\u679C\u9876\u90E8\u5E26\u5206\u7EA7\u7EDF\u8BA1\uFF08ERROR/WARN/INFO \u5404\u591A\u5C11\u6761\uFF09\uFF0C\u6309\u65F6\u95F4\u5012\u5E8F\u6392\u5217\uFF0C\u6700\u65B0\u65E5\u5FD7\u5728\u524D\u3002\u6BCF\u884C\u5E26 file / lineNum\uFF0C\u5F15\u7528\u65E5\u5FD7\u65F6\u5FC5\u987B\u7CBE\u786E\u5199 [<file>:L<lineNum>]\u3002
|
|
79507
|
+
\u6CE8\u610F\uFF1A\u5982\u679C\u8FD8\u6709\u66F4\u591A\u7ED3\u679C\uFF0Cheader \u4F1A\u6807\u6CE8 nextOffset\uFF1B\u7EE7\u7EED\u67E5\u8BE2\u65F6\u5E26\u4E0A offset=nextOffset\u3002`,
|
|
79335
79508
|
{
|
|
79336
79509
|
source: external_exports.enum(["server", "bridge"]).describe('\u65E5\u5FD7\u6765\u6E90\uFF0C\u5FC5\u987B\u662F "server" \u6216 "bridge" \u4E4B\u4E00\u3002'),
|
|
79337
79510
|
start_iso: external_exports.string().describe('\u8D77\u59CB\u65F6\u95F4\uFF0CISO 8601 \u6216\u76F8\u5BF9\u683C\u5F0F\uFF1A"now-5m" / "now-1h" / "now-24h"\u3002'),
|
|
@@ -79340,7 +79513,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79340
79513
|
trace_id: external_exports.string().optional().describe("\u8FC7\u6EE4\u7279\u5B9A traceId\uFF08\u7CBE\u786E\u5339\u914D\uFF09\u3002"),
|
|
79341
79514
|
module: external_exports.string().optional().describe('\u8FC7\u6EE4 module \u524D\u7F00\uFF08\u5982 "ws.handler" / "agent.manager"\uFF09\u3002'),
|
|
79342
79515
|
msg_contains: external_exports.string().optional().describe("msg \u5B50\u4E32\u8FC7\u6EE4\uFF08\u533A\u5206\u5927\u5C0F\u5199\uFF09\u3002"),
|
|
79343
|
-
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002")
|
|
79516
|
+
limit: external_exports.number().int().min(1).max(2e3).optional().describe("\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 500\uFF0C\u6700\u5927 2000\u3002"),
|
|
79517
|
+
offset: external_exports.number().int().min(0).optional().describe("\u5206\u9875\u504F\u79FB\u91CF\uFF1B\u9996\u6B21\u67E5\u8BE2\u4E0D\u4F20\uFF0C\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20\u4E0A\u6B21\u8FD4\u56DE\u7684 nextOffset\u3002")
|
|
79344
79518
|
},
|
|
79345
79519
|
async (args) => {
|
|
79346
79520
|
if (!deps.isSmith) {
|
|
@@ -79365,9 +79539,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79365
79539
|
traceId: args.trace_id,
|
|
79366
79540
|
module: args.module,
|
|
79367
79541
|
levelMin: args.level_min,
|
|
79368
|
-
limit: args.limit
|
|
79542
|
+
limit: args.limit,
|
|
79543
|
+
offset: args.offset
|
|
79369
79544
|
});
|
|
79370
79545
|
const parsedLimit = typeof args.limit === "number" && Number.isFinite(args.limit) ? args.limit : 500;
|
|
79546
|
+
const parsedOffset = typeof args.offset === "number" && Number.isFinite(args.offset) ? args.offset : 0;
|
|
79371
79547
|
try {
|
|
79372
79548
|
const url2 = `${deps.serverApiUrl.replace(/\/$/, "")}/api/admin/logs`;
|
|
79373
79549
|
const body = {
|
|
@@ -79378,7 +79554,8 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79378
79554
|
traceId: args.trace_id,
|
|
79379
79555
|
module: args.module,
|
|
79380
79556
|
msgContains: args.msg_contains,
|
|
79381
|
-
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500
|
|
79557
|
+
limit: Number.isFinite(parsedLimit) ? parsedLimit : 500,
|
|
79558
|
+
offset: Number.isFinite(parsedOffset) ? parsedOffset : 0
|
|
79382
79559
|
};
|
|
79383
79560
|
const res = await fetch(url2, {
|
|
79384
79561
|
method: "POST",
|
|
@@ -79401,7 +79578,9 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79401
79578
|
source,
|
|
79402
79579
|
count: json2.entries.length,
|
|
79403
79580
|
truncated: json2.truncated,
|
|
79404
|
-
totalScanned: json2.totalScanned
|
|
79581
|
+
totalScanned: json2.totalScanned,
|
|
79582
|
+
totalMatched: json2.totalMatched,
|
|
79583
|
+
nextOffset: json2.nextOffset
|
|
79405
79584
|
});
|
|
79406
79585
|
const lines = json2.entries.map((e) => {
|
|
79407
79586
|
const dataStr = e.data ? ` data=${JSON.stringify(e.data).slice(0, 200)}` : "";
|
|
@@ -79414,9 +79593,10 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79414
79593
|
const infoCount = json2.entries.filter((e) => e.level === "INFO").length;
|
|
79415
79594
|
const traceCount = json2.entries.filter((e) => e.level === "TRACE" || e.level === "DEBUG").length;
|
|
79416
79595
|
const header = [
|
|
79417
|
-
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u547D\u4E2D ${json2.entries.length} \u6761`,
|
|
79596
|
+
`[${source}] \u5171\u626B ${json2.totalScanned} \u884C\uFF0C\u5DF2\u8FD4\u56DE ${json2.entries.length} \u6761\uFF0C\u547D\u4E2D ${json2.totalMatched ?? json2.entries.length} \u6761`,
|
|
79418
79597
|
` ERROR/FATAL: ${errorCount} | WARN: ${warnCount} | INFO: ${infoCount} | TRACE/DEBUG: ${traceCount}`
|
|
79419
|
-
].join("\n") + (json2.
|
|
79598
|
+
].join("\n") + (json2.nextOffset != null ? `
|
|
79599
|
+
nextOffset=${json2.nextOffset}\uFF08\u7EE7\u7EED\u67E5\u8BE2\u65F6\u4F20 offset=${json2.nextOffset}\uFF09` : "");
|
|
79420
79600
|
const text = [header, "", ...lines].join("\n");
|
|
79421
79601
|
return { content: [{ type: "text", text }] };
|
|
79422
79602
|
} catch (e) {
|
|
@@ -79503,7 +79683,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79503
79683
|
const tiers = await tierRes.json();
|
|
79504
79684
|
const self = deps.agentRegistry?.getById(deps.agentId);
|
|
79505
79685
|
const preferredSubscriptionId = parseAgentConfig(self?.config).subscriptionId;
|
|
79506
|
-
const
|
|
79686
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
79687
|
+
preferredSubscriptionId,
|
|
79688
|
+
deps
|
|
79689
|
+
);
|
|
79690
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
79507
79691
|
if (tierConfig) {
|
|
79508
79692
|
agentConfig = JSON.stringify({
|
|
79509
79693
|
capabilityTier: tier,
|
|
@@ -79658,7 +79842,11 @@ limit \u9ED8\u8BA4 500\uFF0C\u786C\u4E0A\u9650 2000\u3002\u8FD4\u56DE\u7ED3\u679
|
|
|
79658
79842
|
if (tierRes.ok) {
|
|
79659
79843
|
const tiers = await tierRes.json();
|
|
79660
79844
|
const preferredSubscriptionId = parseAgentConfig(existing.config).subscriptionId;
|
|
79661
|
-
const
|
|
79845
|
+
const resolvedPreferredSubscriptionId = await resolveTierSubscriptionPreference(
|
|
79846
|
+
preferredSubscriptionId,
|
|
79847
|
+
deps
|
|
79848
|
+
);
|
|
79849
|
+
const tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === resolvedPreferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
|
|
79662
79850
|
if (tierConfig) {
|
|
79663
79851
|
agentConfig = JSON.stringify({
|
|
79664
79852
|
capabilityTier: tier,
|
|
@@ -80291,6 +80479,8 @@ var GroupDispatchMemoryStore = class {
|
|
|
80291
80479
|
|
|
80292
80480
|
// src/groupInboxPromptBuilder.ts
|
|
80293
80481
|
init_cjs_shims();
|
|
80482
|
+
var MAX_SYSTEM_NOTE_COUNT = 8;
|
|
80483
|
+
var MAX_SYSTEM_NOTE_LEN = 1e3;
|
|
80294
80484
|
function formatHHMM(epochMs) {
|
|
80295
80485
|
const d = new Date(epochMs);
|
|
80296
80486
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -80301,6 +80491,37 @@ function truncate(text, maxLen) {
|
|
|
80301
80491
|
if (text.length <= maxLen) return text;
|
|
80302
80492
|
return `${text.slice(0, maxLen)}\u2026`;
|
|
80303
80493
|
}
|
|
80494
|
+
function formatIsoHHMM(iso) {
|
|
80495
|
+
const epochMs = Date.parse(iso);
|
|
80496
|
+
if (!Number.isFinite(epochMs)) return "";
|
|
80497
|
+
return formatHHMM(epochMs);
|
|
80498
|
+
}
|
|
80499
|
+
function collectSystemNotes(entries) {
|
|
80500
|
+
const byId = /* @__PURE__ */ new Map();
|
|
80501
|
+
for (const entry of entries) {
|
|
80502
|
+
for (const msg of entry.context) {
|
|
80503
|
+
if (msg.role !== "system") continue;
|
|
80504
|
+
byId.set(msg.id, {
|
|
80505
|
+
id: msg.id,
|
|
80506
|
+
time: formatIsoHHMM(msg.createdAt),
|
|
80507
|
+
content: truncate(msg.content, MAX_SYSTEM_NOTE_LEN)
|
|
80508
|
+
});
|
|
80509
|
+
}
|
|
80510
|
+
}
|
|
80511
|
+
return [...byId.values()].slice(-MAX_SYSTEM_NOTE_COUNT);
|
|
80512
|
+
}
|
|
80513
|
+
function appendSystemNotes(lines, entries) {
|
|
80514
|
+
const notes = collectSystemNotes(entries);
|
|
80515
|
+
if (notes.length === 0) return;
|
|
80516
|
+
lines.push(`--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55\uFF08${notes.length} \u6761\uFF0C\u4F9B\u4E0A\u4E0B\u6587\uFF1B\u975E\u666E\u901A\u804A\u5929\u5386\u53F2\uFF09---`);
|
|
80517
|
+
lines.push("\u8FD9\u4E9B\u8BB0\u5F55\u53EA\u7528\u4E8E\u7406\u89E3\u7528\u6237\u5DF2\u4F5C\u51FA\u7684 AskUserQuestion/\u7CFB\u7EDF\u51B3\u7B56\uFF1B\u4E0D\u8981\u76F4\u63A5\u56DE\u590D\u7CFB\u7EDF\u8BB0\u5F55\u672C\u8EAB\u3002");
|
|
80518
|
+
for (const note of notes) {
|
|
80519
|
+
const prefix = note.time ? `[${note.time}] system:` : "system:";
|
|
80520
|
+
lines.push(`${prefix} ${note.content}`);
|
|
80521
|
+
}
|
|
80522
|
+
lines.push("--- \u7FA4\u5185\u7CFB\u7EDF\u8BB0\u5F55 end ---");
|
|
80523
|
+
lines.push("");
|
|
80524
|
+
}
|
|
80304
80525
|
function appendBoardContext(lines, latest) {
|
|
80305
80526
|
if (latest.boardMeta?.vision) {
|
|
80306
80527
|
lines.push("--- project vision ---");
|
|
@@ -80369,6 +80590,7 @@ function buildGroupInboxPrompt(entries, opts = {}) {
|
|
|
80369
80590
|
);
|
|
80370
80591
|
}
|
|
80371
80592
|
lines.push("");
|
|
80593
|
+
appendSystemNotes(lines, entries);
|
|
80372
80594
|
lines.push(`--- \u672A\u8BFB\u7FA4\u6D88\u606F\uFF08${entries.length} \u6761\uFF0C\u6309\u65F6\u95F4\u987A\u5E8F\uFF09---`);
|
|
80373
80595
|
for (const e of entries) {
|
|
80374
80596
|
const ts = formatHHMM(e.arrivedAt);
|
|
@@ -80713,6 +80935,31 @@ function extractUsage(message) {
|
|
|
80713
80935
|
}
|
|
80714
80936
|
return result;
|
|
80715
80937
|
}
|
|
80938
|
+
function hasUsageValue(usage) {
|
|
80939
|
+
return typeof usage.tokenCount === "number" || typeof usage.inputTokens === "number" || typeof usage.cacheReadTokens === "number" || typeof usage.cacheCreationTokens === "number" || typeof usage.costUsd === "number";
|
|
80940
|
+
}
|
|
80941
|
+
function emitUsageReported(proc, emit, base, usage, messageId) {
|
|
80942
|
+
if (!hasUsageValue(usage)) return;
|
|
80943
|
+
const groupId = proc.currentTask?.groupId;
|
|
80944
|
+
const scopeKeyValue = proc.scope.kind === "group" ? `group:${proc.scope.groupId}` : "single";
|
|
80945
|
+
emit({
|
|
80946
|
+
type: "agent:usage_reported",
|
|
80947
|
+
payload: {
|
|
80948
|
+
...wireBase(base),
|
|
80949
|
+
...messageId ? { messageId } : {},
|
|
80950
|
+
...groupId ? { groupId } : {},
|
|
80951
|
+
scopeKey: scopeKeyValue,
|
|
80952
|
+
model: usage.model,
|
|
80953
|
+
usage: {
|
|
80954
|
+
inputTokens: usage.inputTokens,
|
|
80955
|
+
outputTokens: usage.tokenCount,
|
|
80956
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
80957
|
+
cacheCreationTokens: usage.cacheCreationTokens
|
|
80958
|
+
},
|
|
80959
|
+
providerCostUsd: usage.costUsd
|
|
80960
|
+
}
|
|
80961
|
+
});
|
|
80962
|
+
}
|
|
80716
80963
|
function isGroupTask(proc) {
|
|
80717
80964
|
return proc.currentTask?.groupId != null;
|
|
80718
80965
|
}
|
|
@@ -80974,7 +81221,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
80974
81221
|
proc.currentToolName = block.name ?? "unknown";
|
|
80975
81222
|
proc.accumulatedToolInput = "";
|
|
80976
81223
|
const toolName = block.name ?? "unknown";
|
|
80977
|
-
if (toolName !== "ExitPlanMode" && toolName
|
|
81224
|
+
if (toolName !== "ExitPlanMode" && !isAskUserQuestionToolName(toolName)) {
|
|
80978
81225
|
emit({
|
|
80979
81226
|
type: "agent:tool_use",
|
|
80980
81227
|
payload: {
|
|
@@ -81138,9 +81385,9 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81138
81385
|
});
|
|
81139
81386
|
}
|
|
81140
81387
|
}
|
|
81141
|
-
if (proc.currentToolName
|
|
81388
|
+
if (isAskUserQuestionToolName(proc.currentToolName)) {
|
|
81142
81389
|
const last = proc.contentBlocks[proc.contentBlocks.length - 1];
|
|
81143
|
-
if (last?.type === "tool_use" && last.toolName
|
|
81390
|
+
if (last?.type === "tool_use" && isAskUserQuestionToolName(last.toolName)) {
|
|
81144
81391
|
proc.contentBlocks.pop();
|
|
81145
81392
|
}
|
|
81146
81393
|
}
|
|
@@ -81192,7 +81439,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81192
81439
|
const toolName = proc.currentToolName ?? "unknown";
|
|
81193
81440
|
const isError = toolName === "ExitPlanMode" ? false : !!b.is_error;
|
|
81194
81441
|
const output = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
|
|
81195
|
-
if (toolName
|
|
81442
|
+
if (isAskUserQuestionToolName(toolName)) {
|
|
81196
81443
|
proc.currentToolName = null;
|
|
81197
81444
|
continue;
|
|
81198
81445
|
}
|
|
@@ -81276,6 +81523,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81276
81523
|
const watermarkUsage = proc.peakContextUsage ?? usage;
|
|
81277
81524
|
if (trimmed === NO_REPLY_TOKEN) {
|
|
81278
81525
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81526
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81279
81527
|
if (groupMode && proc.contentBlocks.length > 0) {
|
|
81280
81528
|
emitGroupSegment(
|
|
81281
81529
|
proc,
|
|
@@ -81315,6 +81563,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81315
81563
|
}
|
|
81316
81564
|
if (groupMode) {
|
|
81317
81565
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81566
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81318
81567
|
if (proc.contentBlocks.length > 0) {
|
|
81319
81568
|
logger9.info("Group turn trailing audit segment", {
|
|
81320
81569
|
agentId: proc.agentId,
|
|
@@ -81349,6 +81598,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81349
81598
|
}
|
|
81350
81599
|
if (proc.accumulatedText.length === 0 && proc.contentBlocks.length === 0) {
|
|
81351
81600
|
cleanupPlanMode(proc, emit, base, "error");
|
|
81601
|
+
emitUsageReported(proc, emit, base, usage);
|
|
81352
81602
|
logger9.warn("SDK success produced empty assistant output; emitting agent:error", {
|
|
81353
81603
|
agentId: proc.agentId,
|
|
81354
81604
|
ackId: base.replyMessageId,
|
|
@@ -81376,6 +81626,7 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81376
81626
|
checkInputTokenWatermark(proc, watermarkUsage, base.traceId);
|
|
81377
81627
|
cleanupPlanMode(proc, emit, base, "success");
|
|
81378
81628
|
carrierMessageId = createMessageId();
|
|
81629
|
+
emitUsageReported(proc, emit, base, usage, carrierMessageId);
|
|
81379
81630
|
logger9.info("Agent task done, emitting agent:done", {
|
|
81380
81631
|
agentId: proc.agentId,
|
|
81381
81632
|
ackId: base.replyMessageId,
|
|
@@ -81396,6 +81647,11 @@ function mapSDKMessage(proc, message, rawEmit, sessionStore, onCompleted) {
|
|
|
81396
81647
|
thinkingDuration: Date.now() - proc.currentTaskStartedAt,
|
|
81397
81648
|
toolCallCount: proc.contentBlocks.filter((b) => b.type === "tool_use").length,
|
|
81398
81649
|
tokenCount: usage.tokenCount,
|
|
81650
|
+
outputTokens: usage.tokenCount,
|
|
81651
|
+
inputTokens: usage.inputTokens,
|
|
81652
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
81653
|
+
cacheCreationTokens: usage.cacheCreationTokens,
|
|
81654
|
+
costUsd: usage.costUsd,
|
|
81399
81655
|
model: usage.model
|
|
81400
81656
|
}
|
|
81401
81657
|
}
|
|
@@ -81724,6 +81980,12 @@ var wsMetrics = new WsMetrics();
|
|
|
81724
81980
|
|
|
81725
81981
|
// src/agentManager.ts
|
|
81726
81982
|
var logger12 = createModuleLogger("agent.manager");
|
|
81983
|
+
function missingSubscriptionMessage(subscriptionId) {
|
|
81984
|
+
if (isPrimaryCompanySubscriptionId(subscriptionId)) {
|
|
81985
|
+
return "AHChat \u9ED8\u8BA4\u6A21\u578B\u6682\u65F6\u4E0D\u53EF\u7528\uFF1A\u8FD9\u53F0\u673A\u5668\u8FD8\u6CA1\u6709\u540C\u6B65\u5230\u7BA1\u7406\u5458\u542F\u7528\u7684\u9ED8\u8BA4\u6A21\u578B\uFF0C\u8BF7\u66F4\u65B0\u5E76\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002";
|
|
81986
|
+
}
|
|
81987
|
+
return `\u8BA2\u9605\u6E90\u4E0D\u53EF\u7528\uFF1A${subscriptionId}\u3002\u8BF7\u91CD\u65B0\u9009\u62E9\u6A21\u578B\u6765\u6E90\uFF0C\u6216\u91CD\u542F Bridge \u540E\u91CD\u8BD5\u3002`;
|
|
81988
|
+
}
|
|
81727
81989
|
var NODE_USER_UID = 1e3;
|
|
81728
81990
|
var POST_MERGE_CONTINUATION_ROUTE_MS = 15e3;
|
|
81729
81991
|
var DOCUMENT_READING_RULES = `DOCUMENT READING:
|
|
@@ -81788,6 +82050,27 @@ var BridgeBusyError = class extends Error {
|
|
|
81788
82050
|
this.name = "BridgeBusyError";
|
|
81789
82051
|
}
|
|
81790
82052
|
};
|
|
82053
|
+
function senderLabelForQuote(message) {
|
|
82054
|
+
if (message.senderAgentName) return message.senderAgentName;
|
|
82055
|
+
if (message.role === "user") return "user";
|
|
82056
|
+
if (message.role === "agent") return `agent:${message.senderAgentId ?? "unknown"}`;
|
|
82057
|
+
return "system";
|
|
82058
|
+
}
|
|
82059
|
+
function buildSingleReplyPrompt(task) {
|
|
82060
|
+
if (!task.replyToMessage) return task.content;
|
|
82061
|
+
const quoted = task.replyToMessage;
|
|
82062
|
+
const label = senderLabelForQuote(quoted);
|
|
82063
|
+
return [
|
|
82064
|
+
"--- reply-to message ---",
|
|
82065
|
+
`You are replying to this earlier message from [${label}]:`,
|
|
82066
|
+
quoted.content || (quoted.attachments?.length ? "[attachment]" : ""),
|
|
82067
|
+
"--- end reply-to message ---",
|
|
82068
|
+
"",
|
|
82069
|
+
"--- user message ---",
|
|
82070
|
+
task.content,
|
|
82071
|
+
"--- end user message ---"
|
|
82072
|
+
].join("\n");
|
|
82073
|
+
}
|
|
81791
82074
|
var AgentManager = class {
|
|
81792
82075
|
agents = /* @__PURE__ */ new Map();
|
|
81793
82076
|
lastUsedAt = /* @__PURE__ */ new Map();
|
|
@@ -81923,16 +82206,16 @@ var AgentManager = class {
|
|
|
81923
82206
|
agentId: agent.id,
|
|
81924
82207
|
subscriptionId: cfg.subscriptionId
|
|
81925
82208
|
});
|
|
81926
|
-
|
|
82209
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
81927
82210
|
}
|
|
81928
82211
|
let sub = this.subscriptionRegistry.getById(cfg.subscriptionId);
|
|
81929
82212
|
if (!sub) sub = await this.subscriptionRegistry.fetchById(cfg.subscriptionId);
|
|
81930
82213
|
if (!sub) {
|
|
81931
|
-
logger12.warn("Subscription not found;
|
|
82214
|
+
logger12.warn("Subscription not found; refusing native OAuth fallback", {
|
|
81932
82215
|
agentId: agent.id,
|
|
81933
82216
|
subscriptionId: cfg.subscriptionId
|
|
81934
82217
|
});
|
|
81935
|
-
|
|
82218
|
+
throw new Error(missingSubscriptionMessage(cfg.subscriptionId));
|
|
81936
82219
|
}
|
|
81937
82220
|
const isPinnedModel = cfg.model && cfg.model !== "default";
|
|
81938
82221
|
const resolvedModel = isPinnedModel ? cfg.model : sub.defaultModel;
|
|
@@ -83131,8 +83414,9 @@ ${lines.join("\n")}`;
|
|
|
83131
83414
|
});
|
|
83132
83415
|
}
|
|
83133
83416
|
async pushTaskContent(runtime, task, onYielded) {
|
|
83417
|
+
const textContent = buildSingleReplyPrompt(task);
|
|
83134
83418
|
if (!task.attachments || task.attachments.length === 0) {
|
|
83135
|
-
runtime.inputController.push(
|
|
83419
|
+
runtime.inputController.push(textContent, runtime.ccSessionId ?? "", onYielded);
|
|
83136
83420
|
return;
|
|
83137
83421
|
}
|
|
83138
83422
|
const supportsVision = await this.detectVisionSupport();
|
|
@@ -83144,7 +83428,7 @@ ${lines.join("\n")}`;
|
|
|
83144
83428
|
supportsVision
|
|
83145
83429
|
}
|
|
83146
83430
|
);
|
|
83147
|
-
const text =
|
|
83431
|
+
const text = textContent.trim() || "\u8BF7\u67E5\u770B\u6211\u53D1\u9001\u7684\u9644\u4EF6\u3002";
|
|
83148
83432
|
const contentParts = [
|
|
83149
83433
|
{ type: "text", text },
|
|
83150
83434
|
...attachmentBlocks
|
|
@@ -83182,9 +83466,12 @@ ${lines.join("\n")}`;
|
|
|
83182
83466
|
return materialized;
|
|
83183
83467
|
}
|
|
83184
83468
|
async resolveExistingWorkspaceAttachmentPath(runtime, attachment) {
|
|
83469
|
+
const localWorkspacePath = attachment.metadata?.localWorkspacePath;
|
|
83185
83470
|
const workspacePath = attachment.metadata?.workspacePath;
|
|
83186
|
-
|
|
83187
|
-
|
|
83471
|
+
const rawPath = typeof localWorkspacePath === "string" && localWorkspacePath.trim() ? localWorkspacePath : workspacePath;
|
|
83472
|
+
if (typeof rawPath !== "string" || !rawPath.trim()) return null;
|
|
83473
|
+
const remapped = remapServerWorkspacePath(rawPath, this.workspacesDir);
|
|
83474
|
+
const candidate = import_node_path11.default.resolve(remapped.path);
|
|
83188
83475
|
if (!this.isPathInsideBase(candidate, runtime.cwd)) return null;
|
|
83189
83476
|
try {
|
|
83190
83477
|
const stat3 = await import_promises3.default.stat(candidate);
|
|
@@ -83194,6 +83481,8 @@ ${lines.join("\n")}`;
|
|
|
83194
83481
|
agentId: runtime.agentId,
|
|
83195
83482
|
attachmentId: attachment.id,
|
|
83196
83483
|
workspacePath,
|
|
83484
|
+
localWorkspacePath,
|
|
83485
|
+
resolvedPath: candidate,
|
|
83197
83486
|
error: e
|
|
83198
83487
|
});
|
|
83199
83488
|
return null;
|
|
@@ -84393,7 +84682,7 @@ function computeBoardSignature(entry) {
|
|
|
84393
84682
|
// src/bridgeFetchAuth.ts
|
|
84394
84683
|
init_cjs_shims();
|
|
84395
84684
|
var logger13 = createModuleLogger("bridge.fetchAuth");
|
|
84396
|
-
var
|
|
84685
|
+
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
84397
84686
|
function installBridgeFetchAuth(serverApiUrl, token) {
|
|
84398
84687
|
if (typeof globalThis.fetch !== "function") {
|
|
84399
84688
|
logger13.warn("globalThis.fetch not available, cannot install bridge fetch auth");
|
|
@@ -84421,8 +84710,8 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
84421
84710
|
else url2 = input.url;
|
|
84422
84711
|
if (!shouldInject(url2)) return original(input, init);
|
|
84423
84712
|
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
84424
|
-
if (!headers.has(
|
|
84425
|
-
headers.set(
|
|
84713
|
+
if (!headers.has(BRIDGE_TOKEN_HEADER2)) {
|
|
84714
|
+
headers.set(BRIDGE_TOKEN_HEADER2, token);
|
|
84426
84715
|
}
|
|
84427
84716
|
return original(input, { ...init, headers });
|
|
84428
84717
|
});
|
|
@@ -84434,16 +84723,6 @@ function installBridgeFetchAuth(serverApiUrl, token) {
|
|
|
84434
84723
|
|
|
84435
84724
|
// src/agentRegistry.ts
|
|
84436
84725
|
init_cjs_shims();
|
|
84437
|
-
|
|
84438
|
-
// src/bridgeHttp.ts
|
|
84439
|
-
init_cjs_shims();
|
|
84440
|
-
var BRIDGE_TOKEN_HEADER2 = "X-AHChat-Bridge-Token";
|
|
84441
|
-
function bridgeAuthHeaders(bridgeToken) {
|
|
84442
|
-
const token = bridgeToken?.trim();
|
|
84443
|
-
return token ? { [BRIDGE_TOKEN_HEADER2]: token } : {};
|
|
84444
|
-
}
|
|
84445
|
-
|
|
84446
|
-
// src/agentRegistry.ts
|
|
84447
84726
|
var logger14 = createModuleLogger("agent.registry");
|
|
84448
84727
|
var HttpAgentRegistry = class {
|
|
84449
84728
|
constructor(serverApiUrl, bridgeToken = null) {
|
|
@@ -84557,6 +84836,23 @@ var HttpSubscriptionRegistry = class {
|
|
|
84557
84836
|
const path26 = suffix.startsWith("/") ? suffix : `/${suffix}`;
|
|
84558
84837
|
return `${base}${path26}`;
|
|
84559
84838
|
}
|
|
84839
|
+
primaryAliasFrom(sub) {
|
|
84840
|
+
return {
|
|
84841
|
+
...sub,
|
|
84842
|
+
id: PRIMARY_COMPANY_SUBSCRIPTION_ID,
|
|
84843
|
+
name: "\u516C\u53F8\u4E3B\u8BA2\u9605",
|
|
84844
|
+
resolvedSubscriptionId: sub.id,
|
|
84845
|
+
isVirtual: true
|
|
84846
|
+
};
|
|
84847
|
+
}
|
|
84848
|
+
rebuildPrimaryAlias() {
|
|
84849
|
+
this.subscriptions.delete(PRIMARY_COMPANY_SUBSCRIPTION_ID);
|
|
84850
|
+
const primary = Array.from(this.subscriptions.values()).find(
|
|
84851
|
+
(sub) => sub.billingMode === "company_billable" && sub.isPrimaryCompany === true
|
|
84852
|
+
);
|
|
84853
|
+
if (!primary) return;
|
|
84854
|
+
this.subscriptions.set(PRIMARY_COMPANY_SUBSCRIPTION_ID, this.primaryAliasFrom(primary));
|
|
84855
|
+
}
|
|
84560
84856
|
async refresh() {
|
|
84561
84857
|
const attempt = async () => {
|
|
84562
84858
|
try {
|
|
@@ -84584,6 +84880,7 @@ var HttpSubscriptionRegistry = class {
|
|
|
84584
84880
|
const s = item;
|
|
84585
84881
|
if (s && typeof s.id === "string") this.subscriptions.set(s.id, s);
|
|
84586
84882
|
}
|
|
84883
|
+
this.rebuildPrimaryAlias();
|
|
84587
84884
|
logger15.info("Subscription registry refreshed", { count: this.subscriptions.size });
|
|
84588
84885
|
} catch (e) {
|
|
84589
84886
|
logger15.warn("Subscription registry parse failed", { error: e });
|
|
@@ -84593,6 +84890,10 @@ var HttpSubscriptionRegistry = class {
|
|
|
84593
84890
|
return this.subscriptions.get(id) ?? null;
|
|
84594
84891
|
}
|
|
84595
84892
|
async fetchById(id) {
|
|
84893
|
+
if (isPrimaryCompanySubscriptionId(id)) {
|
|
84894
|
+
await this.refresh();
|
|
84895
|
+
return this.getById(id);
|
|
84896
|
+
}
|
|
84596
84897
|
try {
|
|
84597
84898
|
const res = await fetch(this.apiUrl(`/api/subscriptions/${encodeURIComponent(id)}`), {
|
|
84598
84899
|
headers: bridgeAuthHeaders(this.bridgeToken)
|
|
@@ -84608,9 +84909,11 @@ var HttpSubscriptionRegistry = class {
|
|
|
84608
84909
|
}
|
|
84609
84910
|
upsert(sub) {
|
|
84610
84911
|
this.subscriptions.set(sub.id, sub);
|
|
84912
|
+
this.rebuildPrimaryAlias();
|
|
84611
84913
|
}
|
|
84612
84914
|
remove(id) {
|
|
84613
84915
|
this.subscriptions.delete(id);
|
|
84916
|
+
this.rebuildPrimaryAlias();
|
|
84614
84917
|
}
|
|
84615
84918
|
};
|
|
84616
84919
|
|
|
@@ -85555,7 +85858,6 @@ var import_node_path14 = __toESM(require("path"), 1);
|
|
|
85555
85858
|
var import_node_os8 = __toESM(require("os"), 1);
|
|
85556
85859
|
var import_node_readline = __toESM(require("readline"), 1);
|
|
85557
85860
|
var logger20 = createModuleLogger("bridge.logScanner");
|
|
85558
|
-
var DEFAULT_LIMIT = 500;
|
|
85559
85861
|
var MAX_LIMIT = 2e3;
|
|
85560
85862
|
function listLogFiles(logsDir, baseName) {
|
|
85561
85863
|
let names;
|
|
@@ -85568,7 +85870,7 @@ function listLogFiles(logsDir, baseName) {
|
|
|
85568
85870
|
const pattern = new RegExp(`^${baseName.replace(".", "\\.")}(\\.\\d+)?$`);
|
|
85569
85871
|
return names.filter((n) => pattern.test(n)).map((n) => import_node_path14.default.join(logsDir, n));
|
|
85570
85872
|
}
|
|
85571
|
-
async function scanFile(filePath, source, filter,
|
|
85873
|
+
async function scanFile(filePath, source, filter, state) {
|
|
85572
85874
|
const file2 = import_node_path14.default.basename(filePath);
|
|
85573
85875
|
const stream = import_node_fs6.default.createReadStream(filePath, { encoding: "utf-8" });
|
|
85574
85876
|
const rl = import_node_readline.default.createInterface({ input: stream, crlfDelay: Infinity });
|
|
@@ -85580,31 +85882,36 @@ async function scanFile(filePath, source, filter, limit, state) {
|
|
|
85580
85882
|
if (!parsed) continue;
|
|
85581
85883
|
if (parsed.source !== source) continue;
|
|
85582
85884
|
if (!matchesFilter(parsed, filter)) continue;
|
|
85583
|
-
state.hits.push({ ...parsed, file: file2, lineNum });
|
|
85584
|
-
if (state.hits.length > limit) {
|
|
85585
|
-
state.truncated = true;
|
|
85586
|
-
state.hits.length = limit;
|
|
85587
|
-
}
|
|
85885
|
+
state.hits.push({ ...parsed, raw: line, file: file2, lineNum });
|
|
85588
85886
|
}
|
|
85589
85887
|
}
|
|
85590
85888
|
async function scanLocalLogs(logsDir, baseName, filter) {
|
|
85591
85889
|
const source = filter.source;
|
|
85592
|
-
const limit = Math.min(Math.max(filter.limit
|
|
85890
|
+
const limit = filter.limit == null ? null : Math.min(Math.max(filter.limit, 1), MAX_LIMIT);
|
|
85891
|
+
const offset = Math.max(filter.offset ?? 0, 0);
|
|
85593
85892
|
const files = listLogFiles(logsDir, baseName);
|
|
85594
85893
|
const state = { hits: [], totalScanned: 0, truncated: false };
|
|
85595
85894
|
for (const filePath of files) {
|
|
85596
|
-
if (state.truncated) break;
|
|
85597
85895
|
try {
|
|
85598
|
-
await scanFile(filePath, source, filter,
|
|
85896
|
+
await scanFile(filePath, source, filter, state);
|
|
85599
85897
|
} catch (e) {
|
|
85600
85898
|
logger20.warn("scanLocalLogs: file read failed", { filePath, error: e });
|
|
85601
85899
|
}
|
|
85602
85900
|
}
|
|
85603
|
-
state.hits.sort((a, b) =>
|
|
85901
|
+
state.hits.sort((a, b) => b.ts.localeCompare(a.ts));
|
|
85902
|
+
const totalMatched = state.hits.length;
|
|
85903
|
+
const endOffset = limit === null ? totalMatched : offset + limit;
|
|
85904
|
+
const entries = state.hits.slice(offset, endOffset);
|
|
85905
|
+
const nextOffset = endOffset < totalMatched ? endOffset : void 0;
|
|
85906
|
+
if (nextOffset !== void 0) {
|
|
85907
|
+
state.truncated = true;
|
|
85908
|
+
}
|
|
85604
85909
|
return {
|
|
85605
|
-
entries
|
|
85910
|
+
entries,
|
|
85606
85911
|
truncated: state.truncated,
|
|
85607
|
-
totalScanned: state.totalScanned
|
|
85912
|
+
totalScanned: state.totalScanned,
|
|
85913
|
+
totalMatched,
|
|
85914
|
+
nextOffset
|
|
85608
85915
|
};
|
|
85609
85916
|
}
|
|
85610
85917
|
async function scanBridgeLogs(filter) {
|
|
@@ -85618,6 +85925,8 @@ async function scanBridgeLogs(filter) {
|
|
|
85618
85925
|
const result = await scanLocalLogs(logDir, "bridge.log", { ...filter, source: "bridge" });
|
|
85619
85926
|
logger20.info("scanBridgeLogs complete", {
|
|
85620
85927
|
hitCount: result.entries.length,
|
|
85928
|
+
totalMatched: result.totalMatched,
|
|
85929
|
+
nextOffset: result.nextOffset,
|
|
85621
85930
|
totalScanned: result.totalScanned,
|
|
85622
85931
|
truncated: result.truncated
|
|
85623
85932
|
});
|
|
@@ -85692,6 +86001,10 @@ function isProcessAlive(pid) {
|
|
|
85692
86001
|
} catch (e) {
|
|
85693
86002
|
const err = e;
|
|
85694
86003
|
if (err.code === "ESRCH") return false;
|
|
86004
|
+
if (err.code === "EPERM") {
|
|
86005
|
+
logger22.warn("Treating inaccessible lock PID as stale", { pid, error: e });
|
|
86006
|
+
return false;
|
|
86007
|
+
}
|
|
85695
86008
|
throw e;
|
|
85696
86009
|
}
|
|
85697
86010
|
}
|
|
@@ -85821,6 +86134,7 @@ function createTaskDispatchHandler(agentManager, agentRegistry, emit) {
|
|
|
85821
86134
|
conversationId: payload.conversationId,
|
|
85822
86135
|
content: payload.content,
|
|
85823
86136
|
attachments: payload.attachments ?? void 0,
|
|
86137
|
+
replyToMessage: payload.replyToMessage ?? void 0,
|
|
85824
86138
|
replyMessageId: payload.ackId,
|
|
85825
86139
|
traceId: payload.traceId,
|
|
85826
86140
|
planMode: payload.planMode ?? void 0
|
|
@@ -86548,7 +86862,7 @@ Claude runtime is unavailable.
|
|
|
86548
86862
|
|
|
86549
86863
|
${claudeRuntime.error ?? "Install Claude Code manually or use the bundled desktop runtime."}
|
|
86550
86864
|
|
|
86551
|
-
|
|
86865
|
+
Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUDE_EXECUTABLE to a valid Claude Code binary path, install Claude Code, or use AHChat Desktop with its bundled runtime.
|
|
86552
86866
|
`
|
|
86553
86867
|
);
|
|
86554
86868
|
process.exit(1);
|
|
@@ -86631,6 +86945,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86631
86945
|
onConnected: async () => {
|
|
86632
86946
|
await agentRegistry.refresh();
|
|
86633
86947
|
await groupRegistry.refresh();
|
|
86948
|
+
await subscriptionRegistry.refresh();
|
|
86634
86949
|
await agentManager.recoverFromRestart(agentRegistry.getAll());
|
|
86635
86950
|
},
|
|
86636
86951
|
onServerPush: async (msg) => {
|
|
@@ -86758,7 +87073,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86758
87073
|
const entries = await listDirectoryEntries(resolved.path);
|
|
86759
87074
|
connector?.send({
|
|
86760
87075
|
type: "bridge:list_dir_response",
|
|
86761
|
-
payload: { requestId, entries }
|
|
87076
|
+
payload: { requestId, entries, localPath: resolved.path }
|
|
86762
87077
|
});
|
|
86763
87078
|
logger29.info("list_dir response sent", { requestId, count: entries.length });
|
|
86764
87079
|
} catch (e) {
|
|
@@ -86795,6 +87110,7 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86795
87110
|
payload: {
|
|
86796
87111
|
requestId,
|
|
86797
87112
|
path: written.path,
|
|
87113
|
+
bridgePath: written.path,
|
|
86798
87114
|
relativePath: written.relativePath,
|
|
86799
87115
|
size: written.size
|
|
86800
87116
|
}
|
|
@@ -86889,7 +87205,9 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86889
87205
|
endIso: filter.endIso,
|
|
86890
87206
|
traceId: filter.traceId,
|
|
86891
87207
|
module: filter.module,
|
|
86892
|
-
levelMin: filter.levelMin
|
|
87208
|
+
levelMin: filter.levelMin,
|
|
87209
|
+
limit: filter.limit,
|
|
87210
|
+
offset: filter.offset
|
|
86893
87211
|
});
|
|
86894
87212
|
try {
|
|
86895
87213
|
const result = await scanBridgeLogs({ ...filter, source: "bridge" });
|
|
@@ -86899,13 +87217,17 @@ Bridge token (register this machine at Settings \u2192 \u5DF2\u8FDE\u63A5\u7684\
|
|
|
86899
87217
|
requestId,
|
|
86900
87218
|
entries: result.entries,
|
|
86901
87219
|
truncated: result.truncated,
|
|
86902
|
-
totalScanned: result.totalScanned
|
|
87220
|
+
totalScanned: result.totalScanned,
|
|
87221
|
+
totalMatched: result.totalMatched,
|
|
87222
|
+
nextOffset: result.nextOffset
|
|
86903
87223
|
}
|
|
86904
87224
|
});
|
|
86905
87225
|
logger29.info("fetch_logs response sent", {
|
|
86906
87226
|
requestId,
|
|
86907
87227
|
count: result.entries.length,
|
|
86908
|
-
truncated: result.truncated
|
|
87228
|
+
truncated: result.truncated,
|
|
87229
|
+
totalMatched: result.totalMatched,
|
|
87230
|
+
nextOffset: result.nextOffset
|
|
86909
87231
|
});
|
|
86910
87232
|
} catch (e) {
|
|
86911
87233
|
const err = e instanceof Error ? e.message : String(e);
|
|
@@ -87412,7 +87734,7 @@ Install Node.js ${MIN_NODE_MAJOR}+ first, then rerun the bridge command.`);
|
|
|
87412
87734
|
lines.push("\nNode is installed, but npm/npx is not available on PATH. Reinstall Node.js or fix PATH.");
|
|
87413
87735
|
} else if (!claudeRuntime.ok) {
|
|
87414
87736
|
lines.push(
|
|
87415
|
-
"\nClaude runtime is missing.
|
|
87737
|
+
"\nClaude runtime is missing. Reinstall @fangyb/ahchat-bridge with npm optional dependencies, set AHCHAT_CLAUDE_EXECUTABLE, install Claude Code manually, or use AHChat Desktop with its bundled runtime."
|
|
87416
87738
|
);
|
|
87417
87739
|
}
|
|
87418
87740
|
process.stdout.write(`${lines.join("\n")}
|
|
@@ -87434,7 +87756,7 @@ cli.command("run", "Start the bridge and connect to server").option("--server-ur
|
|
|
87434
87756
|
process.exit(1);
|
|
87435
87757
|
});
|
|
87436
87758
|
});
|
|
87437
|
-
cli.command("doctor", "Check Node, npm, Claude
|
|
87759
|
+
cli.command("doctor", "Check Node, npm, Claude runtime, PATH, and bridge launch options").option("--server-url <url>", "WebSocket URL of the AHChat server").option("--token <token>", "Auth token for server registration").option("--user <slug>", "User data-dir slug; derives ~/.ahchat/users/<slug>").option("--data-dir <dir>", "Data directory (default: ~/.ahchat)").option("--json", "Print machine-readable JSON").action((args) => {
|
|
87438
87760
|
doctor(args);
|
|
87439
87761
|
});
|
|
87440
87762
|
cli.command("launch", "Launch bridge from ahchat:// URL (called by OS)").option("--url <url>", "ahchat:// URL with server and token params").action((args) => {
|