@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.
Files changed (3) hide show
  1. package/dist/cli.cjs +382 -60
  2. package/dist/index.js +376 -52
  3. 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 require2 = process.getBuiltinModule("module").createRequire(importMetaUrl);
27111
- const polyfill = require2("node-readable-to-web-readable-stream");
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 require2 = process.getBuiltinModule("module").createRequire(importMetaUrl);
35777
- const canvas = require2("@napi-rs/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. Install Claude Code manually or use the bundled desktop runtime.";
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
- return attempts.map((attempt) => {
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\u5347\u5E8F\u6392\u5217\u3002\u6BCF\u884C\u5E26 file / lineNum\uFF0C\u5F15\u7528\u65E5\u5FD7\u65F6\u5FC5\u987B\u7CBE\u786E\u5199 [<file>:L<lineNum>]\u3002
79334
- \u6CE8\u610F\uFF1A\u5982\u679C\u7ED3\u679C\u8FC7\u957F\u4F1A\u88AB\u622A\u65AD\uFF0Cheader \u4F1A\u6807\u6CE8"\u5DF2\u622A\u65AD"\u2014\u2014\u6B64\u65F6\u7F29\u5C0F\u65F6\u95F4\u7A97\u6216\u52A0 module/traceId \u8FC7\u6EE4\u518D\u67E5\u3002`,
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.truncated ? "\n\uFF08\u5DF2\u622A\u65AD\uFF0C\u8BF7\u7F29\u5C0F\u65F6\u95F4\u7A97\u6216\u52A0\u8FC7\u6EE4\u6761\u4EF6\u518D\u67E5\uFF09" : "");
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 tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === preferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
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 tierConfig = tiers.find((t) => t.tier === tier && t.subscriptionId === preferredSubscriptionId) ?? tiers.find((t) => t.tier === tier);
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 !== "AskUserQuestion") {
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 === "AskUserQuestion") {
81388
+ if (isAskUserQuestionToolName(proc.currentToolName)) {
81142
81389
  const last = proc.contentBlocks[proc.contentBlocks.length - 1];
81143
- if (last?.type === "tool_use" && last.toolName === "AskUserQuestion") {
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 === "AskUserQuestion") {
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
- return cfg;
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; falling back to system OAuth", {
82214
+ logger12.warn("Subscription not found; refusing native OAuth fallback", {
81932
82215
  agentId: agent.id,
81933
82216
  subscriptionId: cfg.subscriptionId
81934
82217
  });
81935
- return { ...cfg, subscriptionType: "system" };
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(task.content, runtime.ccSessionId ?? "", onYielded);
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 = task.content.trim() || "\u8BF7\u67E5\u770B\u6211\u53D1\u9001\u7684\u9644\u4EF6\u3002";
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
- if (typeof workspacePath !== "string" || !workspacePath.trim()) return null;
83187
- const candidate = import_node_path11.default.resolve(workspacePath);
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 BRIDGE_TOKEN_HEADER = "X-AHChat-Bridge-Token";
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(BRIDGE_TOKEN_HEADER)) {
84425
- headers.set(BRIDGE_TOKEN_HEADER, token);
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, limit, state) {
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 ?? DEFAULT_LIMIT, 1), MAX_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, limit, state);
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) => a.ts.localeCompare(b.ts));
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: state.hits,
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
- Set AHCHAT_CLAUDE_EXECUTABLE to a valid Claude Code binary path, install Claude Code, or use AHChat Desktop with its bundled runtime.
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. Install Claude Code manually, set AHCHAT_CLAUDE_EXECUTABLE, or use AHChat Desktop with its bundled runtime."
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 CLI, PATH, and bridge launch options").option("--server-url <url>", "WebSocket URL of the AHChat server").option("--token <token>", "Auth token for server registration").option("--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) => {
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) => {