@ganglion/xacpx 0.13.0 → 0.14.1

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.js CHANGED
@@ -1075,6 +1075,7 @@ var init_misc = __esm(() => {
1075
1075
  defaultHomeWorkspaceDescription: "Home directory",
1076
1076
  pluginChannelFeishu: "Feishu channel",
1077
1077
  pluginChannelYuanbao: "Tencent Yuanbao channel",
1078
+ pluginChannelRelay: "Relay hub connector (drive this instance from a self-hosted relay hub)",
1078
1079
  pluginChannelInstallHint: (channelType, packageName) => `Channel ${channelType} requires a plugin: xacpx plugin add ${packageName}`,
1079
1080
  orchestrationSuggestion1: "Run /tasks --stuck to locate stuck tasks",
1080
1081
  orchestrationSuggestion2: "/task <id> shows the full timeline to locate errors",
@@ -2171,6 +2172,7 @@ var init_misc2 = __esm(() => {
2171
2172
  defaultHomeWorkspaceDescription: "用户主目录",
2172
2173
  pluginChannelFeishu: "飞书频道",
2173
2174
  pluginChannelYuanbao: "腾讯元宝频道",
2175
+ pluginChannelRelay: "Relay hub 连接器(从自托管 relay hub 遥控这台实例)",
2174
2176
  pluginChannelInstallHint: (channelType, packageName) => `频道 ${channelType} 需要安装插件:xacpx plugin add ${packageName}`,
2175
2177
  orchestrationSuggestion1: "查看 /tasks --stuck 定位卡住的任务",
2176
2178
  orchestrationSuggestion2: "/task <id> 可看完整时间线定位错误点",
@@ -19512,6 +19514,12 @@ var init_known_plugins = __esm(() => {
19512
19514
  channels: ["yuanbao"],
19513
19515
  descriptionKey: "pluginChannelYuanbao",
19514
19516
  official: true
19517
+ },
19518
+ {
19519
+ packageName: "@ganglion/xacpx-channel-relay",
19520
+ channels: ["relay"],
19521
+ descriptionKey: "pluginChannelRelay",
19522
+ official: true
19515
19523
  }
19516
19524
  ];
19517
19525
  });
@@ -21780,8 +21788,9 @@ async function buildCoordinatorPrompt(input) {
21780
21788
  `));
21781
21789
  }
21782
21790
  if (input.userText) {
21783
- sections.push([t().coordinatorPrompt.userMessageLabel, input.userText].join(`
21784
- `));
21791
+ const hasOrchestrationContext = sections.length > 0;
21792
+ sections.push(hasOrchestrationContext ? [t().coordinatorPrompt.userMessageLabel, input.userText].join(`
21793
+ `) : input.userText);
21785
21794
  }
21786
21795
  const claimHumanReply = shouldBind && input.chatKey && activePackage?.awaitingReplyMessageId ? {
21787
21796
  coordinatorSession: input.coordinatorSession,
@@ -22377,7 +22386,7 @@ async function handleSessionArchive(context, chatKey, alias, archive) {
22377
22386
  await archive(internalAlias);
22378
22387
  return { text: t().session.sessionArchived(alias) };
22379
22388
  }
22380
- async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
22389
+ async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands) {
22381
22390
  if (session3.archived) {
22382
22391
  await context.sessions.setArchived(session3.alias, false);
22383
22392
  }
@@ -22412,7 +22421,7 @@ async function promptWithSession(context, session3, chatKey, text, reply, replyC
22412
22421
  const { promptText, taskIds, groupIds, claimHumanReply } = await preparePromptWithFallback(context, session3, chatKey, text, replyContextToken, accountId);
22413
22422
  try {
22414
22423
  const replyContext = transportReply && context.quota && getChannelIdFromChatKey(chatKey) === "weixin" ? { chatKey, quota: context.quota } : undefined;
22415
- const result = await context.interaction.promptTransportSession(session3, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage);
22424
+ const result = await context.interaction.promptTransportSession(session3, promptText, transportReply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage, onCommands);
22416
22425
  if (claimHumanReply) {
22417
22426
  try {
22418
22427
  await context.orchestration?.claimActiveHumanReply?.(claimHumanReply);
@@ -22432,23 +22441,23 @@ async function promptWithSession(context, session3, chatKey, text, reply, replyC
22432
22441
  throw error2;
22433
22442
  }
22434
22443
  }
22435
- async function handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
22444
+ async function handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands) {
22436
22445
  try {
22437
- return await promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
22446
+ return await promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
22438
22447
  } catch (error2) {
22439
22448
  const recovered = await context.recovery.tryRecoverMissingSession(session3, error2);
22440
22449
  if (recovered) {
22441
- return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
22450
+ return await promptWithSession(context, recovered, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
22442
22451
  }
22443
22452
  return context.recovery.renderTransportError(session3, error2);
22444
22453
  }
22445
22454
  }
22446
- async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
22455
+ async function handlePrompt(context, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands) {
22447
22456
  const session3 = metadata?.boundSessionAlias ? context.sessions.getResolvedSessionByInternalAlias(metadata.boundSessionAlias) : await context.sessions.getCurrentSession(chatKey);
22448
22457
  if (!session3) {
22449
22458
  return { text: t().session.noCurrent };
22450
22459
  }
22451
- return await handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
22460
+ return await handlePromptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
22452
22461
  }
22453
22462
  function toCoordinatorRouteChatMetadata(metadata) {
22454
22463
  if (!metadata) {
@@ -24707,7 +24716,7 @@ class CommandRouter {
24707
24716
  this.logger = logger2 ?? createNoopAppLogger();
24708
24717
  this.activeTurns = activeTurns;
24709
24718
  }
24710
- async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage) {
24719
+ async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage, onCommands) {
24711
24720
  const startedAt = Date.now();
24712
24721
  let command = parseCommand(input);
24713
24722
  if (metadata?.channel === "control" && command.kind !== "prompt") {
@@ -24869,16 +24878,16 @@ class CommandRouter {
24869
24878
  ...this.sessions.resolveSession(descriptor.alias, descriptor.agent, descriptor.workspace, descriptor.transportSession),
24870
24879
  transient: true
24871
24880
  };
24872
- return await handlePromptWithSession(sessionContext, transientSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
24881
+ return await handlePromptWithSession(sessionContext, transientSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
24873
24882
  }
24874
24883
  if (metadata?.scheduledSessionAlias) {
24875
24884
  const scheduledSession = await this.sessions.getSession(metadata.scheduledSessionAlias);
24876
24885
  if (!scheduledSession) {
24877
24886
  throw new Error(`session "${metadata.scheduledSessionAlias}" not found for scheduled prompt`);
24878
24887
  }
24879
- return await handlePromptWithSession(sessionContext, scheduledSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
24888
+ return await handlePromptWithSession(sessionContext, scheduledSession, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
24880
24889
  }
24881
- return await handlePrompt(sessionContext, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage);
24890
+ return await handlePrompt(sessionContext, chatKey, command.text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage, onCommands);
24882
24891
  }
24883
24892
  }
24884
24893
  });
@@ -25102,7 +25111,7 @@ class CommandRouter {
25102
25111
  setModelTransportSession: (session3, modelId) => this.setModelTransportSession(session3, modelId),
25103
25112
  getModelTransportSession: (session3) => this.getModelTransportSession(session3),
25104
25113
  cancelTransportSession: (session3) => this.cancelTransportSession(session3),
25105
- promptTransportSession: (session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride, onPlan, onUsage) => this.promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride ?? perfSpan, onPlan, onUsage)
25114
+ promptTransportSession: (session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride, onPlan, onUsage, onCommands) => this.promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpanOverride ?? perfSpan, onPlan, onUsage, onCommands)
25106
25115
  };
25107
25116
  }
25108
25117
  createSessionRenderRecoveryOps() {
@@ -25281,7 +25290,7 @@ class CommandRouter {
25281
25290
  async checkTransportSession(session3) {
25282
25291
  return await this.measureTransportCall("has_session", session3, () => this.transport.hasSession(session3));
25283
25292
  }
25284
- async promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage) {
25293
+ async promptTransportSession(session3, text, reply, replyContext, media, abortSignal, onToolEvent, onThought, perfSpan, onPlan, onUsage, onCommands) {
25285
25294
  session3.mcpCoordinatorSession ??= stableCoordinatorSession(session3.transportSession);
25286
25295
  let done = false;
25287
25296
  let abortRequested = false;
@@ -25340,7 +25349,8 @@ class CommandRouter {
25340
25349
  ...onToolEvent ? { onToolEvent } : {},
25341
25350
  ...onThought ? { onThought } : {},
25342
25351
  ...onPlan ? { onPlan } : {},
25343
- ...onUsage ? { onUsage } : {}
25352
+ ...onUsage ? { onUsage } : {},
25353
+ ...onCommands ? { onCommands } : {}
25344
25354
  }));
25345
25355
  } catch (error2) {
25346
25356
  localOutcome = isAbortError2(error2) || abortRequested ? "aborted" : "error";
@@ -25526,7 +25536,7 @@ class ConsoleAgent {
25526
25536
  ...m.fileName ? { fileName: m.fileName } : {}
25527
25537
  })) : undefined;
25528
25538
  request.perfSpan?.mark("agent.dispatched");
25529
- return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan, request.onPlan, request.onUsage);
25539
+ return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan, request.onPlan, request.onUsage, request.onCommands);
25530
25540
  }
25531
25541
  isKnownCommand(text) {
25532
25542
  return isKnownXacpxCommandText(text);
@@ -30607,6 +30617,10 @@ function encodeBridgePromptUsageEvent(event) {
30607
30617
  return `${JSON.stringify(event)}
30608
30618
  `;
30609
30619
  }
30620
+ function encodeBridgePromptCommandsEvent(event) {
30621
+ return `${JSON.stringify(event)}
30622
+ `;
30623
+ }
30610
30624
  function encodeBridgeSessionProgressEvent(event) {
30611
30625
  return `${JSON.stringify(event)}
30612
30626
  `;
@@ -30913,7 +30927,14 @@ class AcpxBridgeClient {
30913
30927
  pending.onEvent?.({
30914
30928
  type: "prompt.usage",
30915
30929
  used: message.used,
30916
- size: message.size
30930
+ size: message.size,
30931
+ ...message.cost ? { cost: message.cost } : {},
30932
+ ...message.breakdown ? { breakdown: message.breakdown } : {}
30933
+ });
30934
+ } else if (message.event === "prompt.commands") {
30935
+ pending.onEvent?.({
30936
+ type: "prompt.commands",
30937
+ commands: message.commands
30917
30938
  });
30918
30939
  } else if (message.event === "session.progress") {
30919
30940
  pending.onEvent?.({
@@ -31376,6 +31397,8 @@ class AcpxBridgeTransport {
31376
31397
  let planChain = Promise.resolve();
31377
31398
  let usageError;
31378
31399
  let usageChain = Promise.resolve();
31400
+ let commandsError;
31401
+ let commandsChain = Promise.resolve();
31379
31402
  let toolEventMode = resolveToolEventMode(options);
31380
31403
  if ((toolEventMode === "structured" || toolEventMode === "both") && !options?.onToolEvent) {
31381
31404
  toolEventMode = "text";
@@ -31431,19 +31454,30 @@ class AcpxBridgeTransport {
31431
31454
  if (event.type === "prompt.usage") {
31432
31455
  const onUsage = options?.onUsage;
31433
31456
  if (onUsage) {
31434
- const usage = { used: event.used, size: event.size };
31457
+ const usage = { used: event.used, size: event.size, ...event.cost ? { cost: event.cost } : {}, ...event.breakdown ? { breakdown: event.breakdown } : {} };
31435
31458
  usageChain = usageChain.then(() => onUsage(usage)).catch((error2) => {
31436
31459
  usageError ??= error2;
31437
31460
  });
31438
31461
  }
31439
31462
  return;
31440
31463
  }
31464
+ if (event.type === "prompt.commands") {
31465
+ const onCommands = options?.onCommands;
31466
+ if (onCommands) {
31467
+ const commands = event.commands;
31468
+ commandsChain = commandsChain.then(() => onCommands(commands)).catch((error2) => {
31469
+ commandsError ??= error2;
31470
+ });
31471
+ }
31472
+ return;
31473
+ }
31441
31474
  });
31442
31475
  await segmentChain;
31443
31476
  await toolEventChain;
31444
31477
  await thoughtChain;
31445
31478
  await planChain;
31446
31479
  await usageChain;
31480
+ await commandsChain;
31447
31481
  if (sink) {
31448
31482
  const { overflowCount } = sink.finalize();
31449
31483
  await sink.drain({ timeoutMs: 30000 });
@@ -31467,6 +31501,9 @@ class AcpxBridgeTransport {
31467
31501
  if (usageError) {
31468
31502
  throw usageError;
31469
31503
  }
31504
+ if (commandsError) {
31505
+ throw commandsError;
31506
+ }
31470
31507
  return { text: summary ? `${summary}
31471
31508
 
31472
31509
  ${result.text}` : "" };
@@ -31486,6 +31523,9 @@ ${result.text}` : "" };
31486
31523
  if (usageError) {
31487
31524
  throw usageError;
31488
31525
  }
31526
+ if (commandsError) {
31527
+ throw commandsError;
31528
+ }
31489
31529
  return result;
31490
31530
  }
31491
31531
  async setMode(session3, modeId) {
@@ -31695,6 +31735,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
31695
31735
  let onThought;
31696
31736
  let onPlan;
31697
31737
  let onUsage;
31738
+ let onCommands;
31698
31739
  let rawStream = false;
31699
31740
  if (options === undefined) {
31700
31741
  toolEventMode = "text";
@@ -31707,6 +31748,7 @@ function createStreamingPromptState(formatToolCalls = false, options) {
31707
31748
  onThought = options.onThought;
31708
31749
  onPlan = options.onPlan;
31709
31750
  onUsage = options.onUsage;
31751
+ onCommands = options.onCommands;
31710
31752
  rawStream = options.rawStream ?? false;
31711
31753
  toolEventMode = resolveToolEventMode({
31712
31754
  toolEventMode: options.mode,
@@ -31720,12 +31762,14 @@ function createStreamingPromptState(formatToolCalls = false, options) {
31720
31762
  pendingLine: "",
31721
31763
  formatToolCalls,
31722
31764
  emittedToolCallIds: new Set,
31765
+ toolCalls: new Map,
31723
31766
  toolEventMode,
31724
31767
  rawStream,
31725
31768
  onToolEvent,
31726
31769
  onThought,
31727
31770
  onPlan,
31728
31771
  onUsage,
31772
+ onCommands,
31729
31773
  finalize() {
31730
31774
  if (this.pendingLine.trim().length > 0) {
31731
31775
  parseStreamingChunks(this, this.pendingLine);
@@ -31766,7 +31810,8 @@ function parseStreamingChunks(state, line) {
31766
31810
  const wantsStructured = state.toolEventMode === "structured" || state.toolEventMode === "both";
31767
31811
  const wantsText = (state.toolEventMode === "text" || state.toolEventMode === "both") && state.formatToolCalls;
31768
31812
  if (wantsStructured && state.onToolEvent) {
31769
- const toolEvent = buildToolUseEvent(update);
31813
+ const merged = update.toolCallId ? mergeToolCallUpdate(state, update.toolCallId, update) : update;
31814
+ const toolEvent = buildToolUseEvent(merged);
31770
31815
  if (toolEvent)
31771
31816
  state.onToolEvent(toolEvent);
31772
31817
  }
@@ -31793,8 +31838,17 @@ function parseStreamingChunks(state, line) {
31793
31838
  if (update.sessionUpdate === "usage_update") {
31794
31839
  const used = typeof update.used === "number" && Number.isFinite(update.used) ? update.used : undefined;
31795
31840
  const size = typeof update.size === "number" && Number.isFinite(update.size) ? update.size : undefined;
31796
- if (used !== undefined && size !== undefined && size > 0)
31797
- state.onUsage?.({ used, size });
31841
+ if (used !== undefined && size !== undefined && size > 0) {
31842
+ const cost = normalizeUsageCost(update.cost);
31843
+ const breakdown = normalizeUsageBreakdown(update._meta?.usage);
31844
+ state.onUsage?.({ used, size, ...cost ? { cost } : {}, ...breakdown ? { breakdown } : {} });
31845
+ }
31846
+ return;
31847
+ }
31848
+ if (update.sessionUpdate === "available_commands_update") {
31849
+ if (Array.isArray(update.availableCommands)) {
31850
+ state.onCommands?.(normalizeAgentCommands(update.availableCommands));
31851
+ }
31798
31852
  return;
31799
31853
  }
31800
31854
  const isThoughtChunk = update.sessionUpdate === "agent_thought_chunk" && update.content?.type === "text" && typeof update.content.text === "string";
@@ -31844,6 +31898,29 @@ function formatToolCallEvent(update, sessionUpdate) {
31844
31898
  const statusText = status ? ` (${status})` : "";
31845
31899
  return `${emoji2} ${title}${statusText}${summaryText}`;
31846
31900
  }
31901
+ function isEmptyToolField(v) {
31902
+ if (v === undefined || v === null)
31903
+ return true;
31904
+ if (typeof v === "string")
31905
+ return v.trim().length === 0;
31906
+ if (Array.isArray(v))
31907
+ return v.length === 0;
31908
+ if (typeof v === "object")
31909
+ return Object.keys(v).length === 0;
31910
+ return false;
31911
+ }
31912
+ function mergeToolCallUpdate(state, toolCallId, update) {
31913
+ const prev = state.toolCalls.get(toolCallId) ?? { toolCallId };
31914
+ const merged = { ...prev };
31915
+ for (const key of ["kind", "title", "rawInput", "content", "rawOutput", "locations", "status"]) {
31916
+ const next = update[key];
31917
+ if (!isEmptyToolField(next))
31918
+ merged[key] = next;
31919
+ }
31920
+ merged.toolCallId = toolCallId;
31921
+ state.toolCalls.set(toolCallId, merged);
31922
+ return merged;
31923
+ }
31847
31924
  function buildToolUseEvent(update) {
31848
31925
  if (!update)
31849
31926
  return null;
@@ -31961,6 +32038,52 @@ function readFirstStringArray(record3, keys) {
31961
32038
  }
31962
32039
  return;
31963
32040
  }
32041
+ function asFiniteNumber(value) {
32042
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
32043
+ }
32044
+ function firstFiniteNumber(record3, keys) {
32045
+ for (const key of keys) {
32046
+ const n = asFiniteNumber(record3[key]);
32047
+ if (n !== undefined)
32048
+ return n;
32049
+ }
32050
+ return;
32051
+ }
32052
+ function normalizeUsageBreakdown(value) {
32053
+ if (!isRecord3(value))
32054
+ return;
32055
+ const out = {};
32056
+ for (const [key, aliases] of USAGE_BREAKDOWN_FIELDS) {
32057
+ const n = firstFiniteNumber(value, aliases);
32058
+ if (n !== undefined)
32059
+ out[key] = n;
32060
+ }
32061
+ return Object.keys(out).length > 0 ? out : undefined;
32062
+ }
32063
+ function normalizeUsageCost(value) {
32064
+ if (!isRecord3(value))
32065
+ return;
32066
+ const amount = asFiniteNumber(value.amount);
32067
+ const currency = readString(value, "currency");
32068
+ if (amount === undefined && !currency)
32069
+ return;
32070
+ return { ...amount !== undefined ? { amount } : {}, ...currency ? { currency } : {} };
32071
+ }
32072
+ function normalizeAgentCommands(value) {
32073
+ if (!Array.isArray(value))
32074
+ return [];
32075
+ const out = [];
32076
+ for (const entry of value) {
32077
+ if (!isRecord3(entry))
32078
+ continue;
32079
+ const name = readString(entry, "name");
32080
+ if (!name)
32081
+ continue;
32082
+ const description = readString(entry, "description");
32083
+ out.push({ name, ...description ? { description } : {}, hasInput: entry.input != null });
32084
+ }
32085
+ return out;
32086
+ }
31964
32087
  function isRecord3(value) {
31965
32088
  return typeof value === "object" && value !== null && !Array.isArray(value);
31966
32089
  }
@@ -31986,8 +32109,17 @@ function isGenericToolTitle(kind, title) {
31986
32109
  }
31987
32110
  return false;
31988
32111
  }
32112
+ var USAGE_BREAKDOWN_FIELDS;
31989
32113
  var init_streaming_prompt = __esm(() => {
31990
32114
  init_tool_kind_emoji();
32115
+ USAGE_BREAKDOWN_FIELDS = [
32116
+ ["inputTokens", ["inputTokens", "input_tokens"]],
32117
+ ["outputTokens", ["outputTokens", "output_tokens"]],
32118
+ ["cachedReadTokens", ["cachedReadTokens", "cacheReadInputTokens", "cache_read_input_tokens"]],
32119
+ ["cachedWriteTokens", ["cachedWriteTokens", "cacheCreationInputTokens", "cache_creation_input_tokens"]],
32120
+ ["thoughtTokens", ["thoughtTokens", "thought_tokens"]],
32121
+ ["totalTokens", ["totalTokens", "total_tokens"]]
32122
+ ];
31991
32123
  });
31992
32124
 
31993
32125
  // src/transport/acpx-cli/node-pty-helper.ts
@@ -33497,24 +33629,29 @@ var init_workspace_fs = __esm(() => {
33497
33629
  });
33498
33630
 
33499
33631
  // src/control/control-service.ts
33632
+ import path15 from "node:path";
33633
+
33500
33634
  class ControlService {
33501
33635
  deps;
33502
33636
  constructor(deps) {
33503
33637
  this.deps = deps;
33504
33638
  }
33505
33639
  workspaceFs = new WorkspaceFs(() => this.deps.workspaces.list().map((w) => ({ name: w.name, cwd: w.cwd })));
33506
- listDirectory(workspace3, path15) {
33507
- return this.workspaceFs.listDirectory(workspace3, path15);
33640
+ listDirectory(workspace3, path16) {
33641
+ return this.workspaceFs.listDirectory(workspace3, path16);
33508
33642
  }
33509
- readWorkspaceFile(workspace3, path15) {
33510
- return this.workspaceFs.readFile(workspace3, path15);
33643
+ readWorkspaceFile(workspace3, path16) {
33644
+ return this.workspaceFs.readFile(workspace3, path16);
33511
33645
  }
33512
- workspaceGitDiff(workspace3, path15) {
33513
- return this.workspaceFs.gitDiff(workspace3, path15);
33646
+ workspaceGitDiff(workspace3, path16) {
33647
+ return this.workspaceFs.gitDiff(workspace3, path16);
33514
33648
  }
33515
33649
  searchWorkspace(workspace3, query) {
33516
33650
  return this.workspaceFs.search(workspace3, query);
33517
33651
  }
33652
+ async uploadFile(input) {
33653
+ return this.deps.uploadStore.save(input.filename, input.content, input.mimeType);
33654
+ }
33518
33655
  async getSessionModel(chatKey, alias) {
33519
33656
  const session3 = await this.resolveControlSession(chatKey, alias);
33520
33657
  if (!session3)
@@ -33658,7 +33795,8 @@ class ControlService {
33658
33795
  text: input.text,
33659
33796
  senderId: input.senderId,
33660
33797
  ...input.isOwner !== undefined ? { isOwner: input.isOwner } : {},
33661
- ...input.accountId !== undefined ? { accountId: input.accountId } : {}
33798
+ ...input.accountId !== undefined ? { accountId: input.accountId } : {},
33799
+ ...input.media !== undefined ? { media: input.media } : {}
33662
33800
  });
33663
33801
  }
33664
33802
  async runScheduledTurn(input) {
@@ -33730,6 +33868,32 @@ ${chunk}` : chunk
33730
33868
  });
33731
33869
  emittedChunk = true;
33732
33870
  };
33871
+ const incomingMedia = params.media ?? [];
33872
+ const sandboxedMedia = incomingMedia.length ? (() => {
33873
+ const uploadRoot = path15.resolve(this.deps.uploadStore.root);
33874
+ const kept = incomingMedia.filter((ref) => {
33875
+ const resolved = path15.resolve(ref.filePath);
33876
+ return resolved === uploadRoot || resolved.startsWith(uploadRoot + path15.sep);
33877
+ });
33878
+ const dropped = incomingMedia.length - kept.length;
33879
+ if (dropped > 0) {
33880
+ console.warn(`[control] dropped ${dropped} media ref(s) with filePath outside the upload sandbox`);
33881
+ }
33882
+ return kept;
33883
+ })() : incomingMedia;
33884
+ const chatMedia = sandboxedMedia.map((ref) => ({
33885
+ kind: ref.kind,
33886
+ filePath: ref.filePath,
33887
+ mimeType: ref.mimeType,
33888
+ ...ref.fileName ? { fileName: ref.fileName } : {},
33889
+ sizeBytes: ref.size,
33890
+ source: {
33891
+ channelId: "relay",
33892
+ accountId: params.accountId ?? "control",
33893
+ chatKey: params.chatKey,
33894
+ messageId: ref.id
33895
+ }
33896
+ }));
33733
33897
  try {
33734
33898
  const response = await this.deps.agent.chat({
33735
33899
  accountId: params.accountId ?? "control",
@@ -33737,6 +33901,7 @@ ${chunk}` : chunk
33737
33901
  text: params.text,
33738
33902
  metadata: buildControlMetadata(params.senderId, params.isOwner),
33739
33903
  abortSignal: controller.signal,
33904
+ ...chatMedia.length > 0 ? { media: chatMedia } : {},
33740
33905
  reply: async (chunk) => {
33741
33906
  emitChunk(chunk);
33742
33907
  },
@@ -33770,7 +33935,17 @@ ${chunk}` : chunk
33770
33935
  chatKey: params.chatKey,
33771
33936
  sessionAlias: params.sessionAlias,
33772
33937
  used: usage.used,
33773
- size: usage.size
33938
+ size: usage.size,
33939
+ ...usage.cost ? { cost: usage.cost } : {},
33940
+ ...usage.breakdown ? { breakdown: usage.breakdown } : {}
33941
+ });
33942
+ },
33943
+ onCommands: (commands) => {
33944
+ this.deps.events.emit({
33945
+ type: "agent-commands",
33946
+ chatKey: params.chatKey,
33947
+ sessionAlias: params.sessionAlias,
33948
+ commands
33774
33949
  });
33775
33950
  }
33776
33951
  });
@@ -33859,13 +34034,92 @@ var init_control_service = __esm(() => {
33859
34034
  init_workspace_fs();
33860
34035
  });
33861
34036
 
34037
+ // src/control/upload-store.ts
34038
+ import { mkdtemp as mkdtemp2, readdir as readdir5, rm as rm10, stat as stat4, writeFile as writeFile8 } from "node:fs/promises";
34039
+ import { homedir as homedir12 } from "node:os";
34040
+ import path16 from "node:path";
34041
+ function defaultRootDir() {
34042
+ const home = process.env.HOME ?? homedir12();
34043
+ return path16.join(coreHomeDir(home), "runtime", "uploads");
34044
+ }
34045
+ function sanitizeUploadFilename(raw) {
34046
+ const base = path16.basename(raw).replace(/[/\\]/g, "").replace(/^\.+/, "");
34047
+ const cleaned = base.trim();
34048
+ return cleaned.length > 0 ? cleaned : "file";
34049
+ }
34050
+
34051
+ class UploadStore {
34052
+ rootDir;
34053
+ maxBytes;
34054
+ ttlMs;
34055
+ now;
34056
+ constructor(opts = {}) {
34057
+ this.rootDir = opts.rootDir ?? defaultRootDir();
34058
+ this.maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
34059
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
34060
+ this.now = opts.now ?? (() => new Date);
34061
+ }
34062
+ get root() {
34063
+ return this.rootDir;
34064
+ }
34065
+ async save(filename, base642, mimeType) {
34066
+ if (base642.length > Math.ceil(this.maxBytes * 4 / 3) + 4)
34067
+ throw new Error("file-too-large");
34068
+ const bytes = Buffer.from(base642, "base64");
34069
+ if (bytes.byteLength === 0)
34070
+ throw new Error("empty-file");
34071
+ if (bytes.byteLength > this.maxBytes)
34072
+ throw new Error("file-too-large");
34073
+ const safeName = sanitizeUploadFilename(filename);
34074
+ const { mkdir: mkdir9 } = await import("node:fs/promises");
34075
+ await mkdir9(this.rootDir, { recursive: true });
34076
+ const dir = await mkdtemp2(path16.join(this.rootDir, "u-"));
34077
+ const filePath = path16.join(dir, safeName);
34078
+ await writeFile8(filePath, bytes);
34079
+ return {
34080
+ id: path16.basename(dir),
34081
+ path: filePath,
34082
+ filename: safeName,
34083
+ mimeType,
34084
+ size: bytes.byteLength
34085
+ };
34086
+ }
34087
+ async cleanup() {
34088
+ let entries;
34089
+ try {
34090
+ entries = await readdir5(this.rootDir);
34091
+ } catch {
34092
+ return 0;
34093
+ }
34094
+ const cutoff = this.now().getTime() - this.ttlMs;
34095
+ let removed = 0;
34096
+ for (const name of entries) {
34097
+ const dir = path16.join(this.rootDir, name);
34098
+ try {
34099
+ const info = await stat4(dir);
34100
+ if (info.mtimeMs < cutoff) {
34101
+ await rm10(dir, { recursive: true, force: true });
34102
+ removed += 1;
34103
+ }
34104
+ } catch {}
34105
+ }
34106
+ return removed;
34107
+ }
34108
+ }
34109
+ var DEFAULT_MAX_BYTES, DEFAULT_TTL_MS;
34110
+ var init_upload_store = __esm(() => {
34111
+ init_core_home();
34112
+ DEFAULT_MAX_BYTES = 10 * 1024 * 1024;
34113
+ DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
34114
+ });
34115
+
33862
34116
  // src/config/agent-catalog.ts
33863
34117
  import { existsSync as existsSync3 } from "node:fs";
33864
34118
  import { delimiter as delimiter2, join as join21 } from "node:path";
33865
34119
  function isBinaryOnPath(binary) {
33866
- const path15 = process.env.PATH ?? "";
34120
+ const path17 = process.env.PATH ?? "";
33867
34121
  const exts = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
33868
- for (const dir of path15.split(delimiter2)) {
34122
+ for (const dir of path17.split(delimiter2)) {
33869
34123
  if (!dir)
33870
34124
  continue;
33871
34125
  for (const ext of exts) {
@@ -33900,6 +34154,57 @@ var init_agent_catalog = __esm(() => {
33900
34154
  };
33901
34155
  });
33902
34156
 
34157
+ // src/config/config-watcher.ts
34158
+ import { watch } from "node:fs";
34159
+ import { basename as basename3, dirname as dirname12 } from "node:path";
34160
+ function startConfigWatcher(options) {
34161
+ const { configPath, onChange, debounceMs = 250, logger: logger2 } = options;
34162
+ const watchFactory = options.watchFactory ?? watch;
34163
+ const dir = dirname12(configPath);
34164
+ const target = basename3(configPath);
34165
+ let timer;
34166
+ let watcher;
34167
+ const fire = () => {
34168
+ timer = undefined;
34169
+ try {
34170
+ onChange();
34171
+ } catch (error2) {
34172
+ logger2?.error("config.watch.callback_failed", "config watch callback threw", {
34173
+ error: error2 instanceof Error ? error2.message : String(error2)
34174
+ });
34175
+ }
34176
+ };
34177
+ try {
34178
+ watcher = watchFactory(dir, { persistent: false }, (_event, filename) => {
34179
+ if (filename !== null && basename3(filename.toString()) !== target)
34180
+ return;
34181
+ if (timer)
34182
+ clearTimeout(timer);
34183
+ timer = setTimeout(fire, debounceMs);
34184
+ });
34185
+ watcher.on("error", (error2) => {
34186
+ logger2?.error("config.watch.error", "config watcher errored", {
34187
+ error: error2 instanceof Error ? error2.message : String(error2)
34188
+ });
34189
+ });
34190
+ } catch (error2) {
34191
+ logger2?.error("config.watch.start_failed", "could not start config watcher", {
34192
+ error: error2 instanceof Error ? error2.message : String(error2)
34193
+ });
34194
+ }
34195
+ return {
34196
+ close: () => {
34197
+ if (timer) {
34198
+ clearTimeout(timer);
34199
+ timer = undefined;
34200
+ }
34201
+ watcher?.close();
34202
+ watcher = undefined;
34203
+ }
34204
+ };
34205
+ }
34206
+ var init_config_watcher = () => {};
34207
+
33903
34208
  // src/main.ts
33904
34209
  var exports_main = {};
33905
34210
  __export(exports_main, {
@@ -33910,8 +34215,8 @@ __export(exports_main, {
33910
34215
  buildApp: () => buildApp
33911
34216
  });
33912
34217
  import { randomUUID as randomUUID3 } from "node:crypto";
33913
- import { homedir as homedir12 } from "node:os";
33914
- import { dirname as dirname12, join as join22 } from "node:path";
34218
+ import { homedir as homedir13 } from "node:os";
34219
+ import { dirname as dirname13, join as join22 } from "node:path";
33915
34220
  import { fileURLToPath as fileURLToPath5 } from "node:url";
33916
34221
  function startProgressHeartbeat(orchestration3, config4, logger2, channel) {
33917
34222
  const thresholdSeconds = config4.orchestration.progressHeartbeatSeconds;
@@ -34402,6 +34707,9 @@ async function buildApp(paths, deps = {}) {
34402
34707
  const router3 = new CommandRouter(sessions, transport, config4, configStore, logger2, undefined, orchestration3, quota, scheduledService, deps.channel?.supportsScheduledMessages ? { supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel) } : undefined, deps.channel?.nativeSessionListFormat ? deps.channel.nativeSessionListFormat.bind(deps.channel) : undefined, activeTurns);
34403
34708
  const agent3 = new ConsoleAgent(router3, logger2);
34404
34709
  const controlEvents = createControlEventBus(logger2);
34710
+ const uploadStore = new UploadStore;
34711
+ uploadStore.cleanup();
34712
+ const uploadCleanupInterval = setInterval(() => void uploadStore.cleanup().catch(() => {}), 60 * 60 * 1000);
34405
34713
  const control = new ControlService({
34406
34714
  agent: agent3,
34407
34715
  sessions,
@@ -34438,12 +34746,35 @@ async function buildApp(paths, deps = {}) {
34438
34746
  create: async (name, cwd, description) => {
34439
34747
  const updated = await configStore.upsertWorkspace(name, cwd, description);
34440
34748
  replaceRuntimeConfig(config4, updated);
34749
+ controlEvents.emit({ type: "workspaces-changed" });
34441
34750
  return { name, cwd, ...description ? { description } : {} };
34442
34751
  },
34443
34752
  remove: async (name) => {
34444
34753
  const updated = await configStore.removeWorkspace(name);
34445
34754
  replaceRuntimeConfig(config4, updated);
34755
+ controlEvents.emit({ type: "workspaces-changed" });
34446
34756
  }
34757
+ },
34758
+ uploadStore
34759
+ });
34760
+ const workspaceSignature = (cfg) => JSON.stringify(Object.keys(cfg.workspaces).sort().map((name) => {
34761
+ const ws = cfg.workspaces[name];
34762
+ return [name, ws.cwd, ws.description ?? ""];
34763
+ }));
34764
+ const configWatcher = startConfigWatcher({
34765
+ configPath: paths.configPath,
34766
+ logger: logger2,
34767
+ onChange: () => {
34768
+ const before = workspaceSignature(config4);
34769
+ reloadRuntimeConfig().then(() => {
34770
+ if (workspaceSignature(config4) !== before) {
34771
+ controlEvents.emit({ type: "workspaces-changed" });
34772
+ }
34773
+ }).catch((error2) => {
34774
+ logger2.error("config.reload_failed", "failed to reload config after file change", {
34775
+ error: error2 instanceof Error ? error2.message : String(error2)
34776
+ });
34777
+ });
34447
34778
  }
34448
34779
  });
34449
34780
  const scheduledScheduler = new ScheduledTaskScheduler(scheduledService, {
@@ -34514,6 +34845,8 @@ async function buildApp(paths, deps = {}) {
34514
34845
  reapStaleQueueOwners: () => reapWarmQueueOwners("startup"),
34515
34846
  dispose: async () => {
34516
34847
  scheduledScheduler.stop();
34848
+ configWatcher.close();
34849
+ clearInterval(uploadCleanupInterval);
34517
34850
  if (progressHeartbeatInterval !== undefined) {
34518
34851
  clearInterval(progressHeartbeatInterval);
34519
34852
  }
@@ -34574,7 +34907,7 @@ async function main() {
34574
34907
  }
34575
34908
  }
34576
34909
  async function prepareChannelMedia(configPath, config4) {
34577
- const runtimeDir = join22(dirname12(configPath), "runtime");
34910
+ const runtimeDir = join22(dirname13(configPath), "runtime");
34578
34911
  const mediaRootDir = join22(runtimeDir, "media");
34579
34912
  const mediaStore = new RuntimeMediaStore({ rootDir: mediaRootDir });
34580
34913
  await mediaStore.cleanupExpired().catch((error2) => {
@@ -34584,12 +34917,12 @@ async function prepareChannelMedia(configPath, config4) {
34584
34917
  return { mediaStore, channelDeps: { mediaStore, allowedMediaRoots } };
34585
34918
  }
34586
34919
  function resolveRuntimePaths() {
34587
- const home = process.env.HOME ?? homedir12();
34920
+ const home = process.env.HOME ?? homedir13();
34588
34921
  if (!home) {
34589
34922
  throw new Error("Unable to resolve the current user home directory");
34590
34923
  }
34591
34924
  const configPath = coreEnv("CONFIG") ?? join22(coreHomeDir(home), "config.json");
34592
- const runtimeDir = join22(dirname12(configPath), "runtime");
34925
+ const runtimeDir = join22(dirname13(configPath), "runtime");
34593
34926
  return {
34594
34927
  configPath,
34595
34928
  statePath: coreEnv("STATE") ?? join22(coreHomeDir(home), "state.json"),
@@ -34604,12 +34937,12 @@ function resolveBridgeEntryPath() {
34604
34937
  return fileURLToPath5(new URL("./bridge/bridge-main.ts", import.meta.url));
34605
34938
  }
34606
34939
  function resolveAppLogPath(configPath) {
34607
- const rootDir = dirname12(configPath);
34940
+ const rootDir = dirname13(configPath);
34608
34941
  const runtimeDir = join22(rootDir, "runtime");
34609
34942
  return join22(runtimeDir, "app.log");
34610
34943
  }
34611
34944
  function resolvePerfLogPath(configPath) {
34612
- const rootDir = dirname12(configPath);
34945
+ const rootDir = dirname13(configPath);
34613
34946
  const runtimeDir = join22(rootDir, "runtime");
34614
34947
  return join22(runtimeDir, "perf.log");
34615
34948
  }
@@ -34656,7 +34989,9 @@ var init_main = __esm(async () => {
34656
34989
  init_render_text();
34657
34990
  init_quota_manager();
34658
34991
  init_control_service();
34992
+ init_upload_store();
34659
34993
  init_agent_catalog();
34994
+ init_config_watcher();
34660
34995
  init_perf_tracer();
34661
34996
  init_bootstrap();
34662
34997
  init_i18n();
@@ -34849,12 +35184,12 @@ var init_config_check = __esm(async () => {
34849
35184
  });
34850
35185
 
34851
35186
  // src/doctor/checks/daemon-check.ts
34852
- import { readdir as readdir5, readFile as readFile15, rm as rm10 } from "node:fs/promises";
35187
+ import { readdir as readdir6, readFile as readFile15, rm as rm11 } from "node:fs/promises";
34853
35188
  import { fileURLToPath as fileURLToPath6 } from "node:url";
34854
- import { homedir as homedir13 } from "node:os";
35189
+ import { homedir as homedir14 } from "node:os";
34855
35190
  import { join as join23 } from "node:path";
34856
35191
  async function checkDaemon(options = {}) {
34857
- const home = options.home ?? process.env.HOME ?? homedir13();
35192
+ const home = options.home ?? process.env.HOME ?? homedir14();
34858
35193
  const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
34859
35194
  const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
34860
35195
  home,
@@ -34988,22 +35323,22 @@ async function detectStaleConsumerLockFix(runtimeDir, deps) {
34988
35323
  }
34989
35324
  async function defaultListConsumerLocks(runtimeDir) {
34990
35325
  try {
34991
- return await readdir5(runtimeDir);
35326
+ return await readdir6(runtimeDir);
34992
35327
  } catch {
34993
35328
  return [];
34994
35329
  }
34995
35330
  }
34996
- async function defaultReadConsumerLock(path15) {
35331
+ async function defaultReadConsumerLock(path17) {
34997
35332
  try {
34998
- const raw = await readFile15(path15, "utf8");
35333
+ const raw = await readFile15(path17, "utf8");
34999
35334
  const parsed = JSON.parse(raw);
35000
35335
  return typeof parsed.pid === "number" ? { pid: parsed.pid } : null;
35001
35336
  } catch {
35002
35337
  return null;
35003
35338
  }
35004
35339
  }
35005
- async function defaultRemoveConsumerLock(path15) {
35006
- await rm10(path15, { force: true });
35340
+ async function defaultRemoveConsumerLock(path17) {
35341
+ await rm11(path17, { force: true });
35007
35342
  }
35008
35343
  function resolveCliEntryPath() {
35009
35344
  return process.argv[1] ?? fileURLToPath6(import.meta.url);
@@ -35018,11 +35353,11 @@ var init_daemon_check = __esm(() => {
35018
35353
  });
35019
35354
 
35020
35355
  // src/doctor/checks/logs-check.ts
35021
- import { stat as stat4, readdir as readdir6 } from "node:fs/promises";
35022
- import { basename as basename3, join as join24 } from "node:path";
35023
- import { homedir as homedir14 } from "node:os";
35356
+ import { stat as stat5, readdir as readdir7 } from "node:fs/promises";
35357
+ import { basename as basename4, join as join24 } from "node:path";
35358
+ import { homedir as homedir15 } from "node:os";
35024
35359
  async function checkLogs(options = {}) {
35025
- const home = options.home ?? process.env.HOME ?? homedir14();
35360
+ const home = options.home ?? process.env.HOME ?? homedir15();
35026
35361
  const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
35027
35362
  const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
35028
35363
  home,
@@ -35049,18 +35384,18 @@ async function checkLogs(options = {}) {
35049
35384
  `error: ${formatError6(error2)}`
35050
35385
  ]);
35051
35386
  }
35052
- const baseNames = [basename3(paths.appLog), basename3(paths.stdoutLog), basename3(paths.stderrLog)];
35387
+ const baseNames = [basename4(paths.appLog), basename4(paths.stdoutLog), basename4(paths.stderrLog)];
35053
35388
  const tracked = new Set(baseNames);
35054
35389
  const matched = entries.filter((entry) => isTrackedLogName(entry, tracked));
35055
35390
  const files = [];
35056
35391
  for (const name of matched) {
35057
- const path15 = join24(paths.runtimeDir, name);
35392
+ const path17 = join24(paths.runtimeDir, name);
35058
35393
  try {
35059
- const fileStat = await probe.stat(path15);
35394
+ const fileStat = await probe.stat(path17);
35060
35395
  if (fileStat.isDirectory()) {
35061
35396
  continue;
35062
35397
  }
35063
- files.push({ name, path: path15, size: fileStat.size });
35398
+ files.push({ name, path: path17, size: fileStat.size });
35064
35399
  } catch {
35065
35400
  continue;
35066
35401
  }
@@ -35134,8 +35469,8 @@ function formatBytes(bytes) {
35134
35469
  }
35135
35470
  function createLogsFsProbe() {
35136
35471
  return {
35137
- stat: async (path15) => await stat4(path15),
35138
- readdir: async (path15) => await readdir6(path15)
35472
+ stat: async (path17) => await stat5(path17),
35473
+ readdir: async (path17) => await readdir7(path17)
35139
35474
  };
35140
35475
  }
35141
35476
  function formatError6(error2) {
@@ -35204,9 +35539,9 @@ var init_orchestration_health = __esm(() => {
35204
35539
  });
35205
35540
 
35206
35541
  // src/doctor/checks/orchestration-socket-check.ts
35207
- import { homedir as homedir15 } from "node:os";
35542
+ import { homedir as homedir16 } from "node:os";
35208
35543
  async function checkOrchestrationSocket(options = {}) {
35209
- const home = options.home ?? process.env.HOME ?? homedir15();
35544
+ const home = options.home ?? process.env.HOME ?? homedir16();
35210
35545
  const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
35211
35546
  const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
35212
35547
  home,
@@ -35379,11 +35714,11 @@ var init_plugin_check = __esm(async () => {
35379
35714
 
35380
35715
  // src/doctor/checks/runtime-check.ts
35381
35716
  import { constants } from "node:fs";
35382
- import { access as access4, stat as stat5 } from "node:fs/promises";
35383
- import { dirname as dirname13 } from "node:path";
35384
- import { homedir as homedir16 } from "node:os";
35717
+ import { access as access4, stat as stat6 } from "node:fs/promises";
35718
+ import { dirname as dirname14 } from "node:path";
35719
+ import { homedir as homedir17 } from "node:os";
35385
35720
  async function checkRuntime(options = {}) {
35386
- const home = options.home ?? process.env.HOME ?? homedir16();
35721
+ const home = options.home ?? process.env.HOME ?? homedir17();
35387
35722
  const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
35388
35723
  const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
35389
35724
  home,
@@ -35477,107 +35812,107 @@ function formatMode(mode) {
35477
35812
  }
35478
35813
  function createRuntimeFsProbe() {
35479
35814
  return {
35480
- stat: async (path15) => await stat5(path15),
35481
- access: async (path15, mode) => await access4(path15, mode)
35815
+ stat: async (path17) => await stat6(path17),
35816
+ access: async (path17, mode) => await access4(path17, mode)
35482
35817
  };
35483
35818
  }
35484
- async function checkDirectoryCreatable(label, path15, probe, platform) {
35819
+ async function checkDirectoryCreatable(label, path17, probe, platform) {
35485
35820
  try {
35486
- const stats = await probe.stat(path15);
35821
+ const stats = await probe.stat(path17);
35487
35822
  if (!stats.isDirectory()) {
35488
35823
  return {
35489
35824
  ok: false,
35490
- detail: `${label}: ${path15} (exists but is not a directory)`
35825
+ detail: `${label}: ${path17} (exists but is not a directory)`
35491
35826
  };
35492
35827
  }
35493
- await probe.access(path15, directoryAccessMode(platform));
35828
+ await probe.access(path17, directoryAccessMode(platform));
35494
35829
  return {
35495
35830
  ok: true,
35496
- detail: `${label}: ${path15} (writable)`
35831
+ detail: `${label}: ${path17} (writable)`
35497
35832
  };
35498
35833
  } catch (error2) {
35499
35834
  if (!isMissingPathError2(error2)) {
35500
35835
  return {
35501
35836
  ok: false,
35502
- detail: `${label}: ${path15} (unusable: ${formatError9(error2)})`
35837
+ detail: `${label}: ${path17} (unusable: ${formatError9(error2)})`
35503
35838
  };
35504
35839
  }
35505
- const parentCheck = await checkCreatableAncestorDirectory(path15, probe, platform);
35840
+ const parentCheck = await checkCreatableAncestorDirectory(path17, probe, platform);
35506
35841
  if (!parentCheck.ok) {
35507
35842
  return {
35508
35843
  ok: false,
35509
- detail: `${label}: ${path15} (parent not writable: ${parentCheck.blockingPath})`
35844
+ detail: `${label}: ${path17} (parent not writable: ${parentCheck.blockingPath})`
35510
35845
  };
35511
35846
  }
35512
35847
  return {
35513
35848
  ok: true,
35514
- detail: `${label}: ${path15} (creatable via ${parentCheck.creatableFrom})`
35849
+ detail: `${label}: ${path17} (creatable via ${parentCheck.creatableFrom})`
35515
35850
  };
35516
35851
  }
35517
35852
  }
35518
- async function checkFileCreatable(label, path15, probe, platform) {
35853
+ async function checkFileCreatable(label, path17, probe, platform) {
35519
35854
  try {
35520
- const stats = await probe.stat(path15);
35855
+ const stats = await probe.stat(path17);
35521
35856
  if (stats.isDirectory()) {
35522
35857
  return {
35523
35858
  ok: false,
35524
- detail: `${label}: ${path15} (exists but is a directory)`
35859
+ detail: `${label}: ${path17} (exists but is a directory)`
35525
35860
  };
35526
35861
  }
35527
- await probe.access(path15, constants.W_OK);
35862
+ await probe.access(path17, constants.W_OK);
35528
35863
  return {
35529
35864
  ok: true,
35530
- detail: `${label}: ${path15} (writable)`
35865
+ detail: `${label}: ${path17} (writable)`
35531
35866
  };
35532
35867
  } catch (error2) {
35533
35868
  if (!isMissingPathError2(error2)) {
35534
35869
  return {
35535
35870
  ok: false,
35536
- detail: `${label}: ${path15} (unusable: ${formatError9(error2)})`
35871
+ detail: `${label}: ${path17} (unusable: ${formatError9(error2)})`
35537
35872
  };
35538
35873
  }
35539
- const parentCheck = await checkCreatableAncestorDirectory(dirname13(path15), probe, platform);
35874
+ const parentCheck = await checkCreatableAncestorDirectory(dirname14(path17), probe, platform);
35540
35875
  if (!parentCheck.ok) {
35541
35876
  return {
35542
35877
  ok: false,
35543
- detail: `${label}: ${path15} (parent not writable: ${parentCheck.blockingPath})`
35878
+ detail: `${label}: ${path17} (parent not writable: ${parentCheck.blockingPath})`
35544
35879
  };
35545
35880
  }
35546
35881
  return {
35547
35882
  ok: true,
35548
- detail: `${label}: ${path15} (creatable via ${parentCheck.creatableFrom})`
35883
+ detail: `${label}: ${path17} (creatable via ${parentCheck.creatableFrom})`
35549
35884
  };
35550
35885
  }
35551
35886
  }
35552
- async function checkCreatableAncestorDirectory(path15, probe, platform) {
35887
+ async function checkCreatableAncestorDirectory(path17, probe, platform) {
35553
35888
  try {
35554
- const stats = await probe.stat(path15);
35889
+ const stats = await probe.stat(path17);
35555
35890
  if (!stats.isDirectory()) {
35556
35891
  return {
35557
35892
  ok: false,
35558
- creatableFrom: path15,
35559
- blockingPath: path15
35893
+ creatableFrom: path17,
35894
+ blockingPath: path17
35560
35895
  };
35561
35896
  }
35562
- await probe.access(path15, directoryAccessMode(platform));
35897
+ await probe.access(path17, directoryAccessMode(platform));
35563
35898
  return {
35564
35899
  ok: true,
35565
- creatableFrom: path15
35900
+ creatableFrom: path17
35566
35901
  };
35567
35902
  } catch (error2) {
35568
35903
  if (!isMissingPathError2(error2)) {
35569
35904
  return {
35570
35905
  ok: false,
35571
- creatableFrom: path15,
35572
- blockingPath: path15
35906
+ creatableFrom: path17,
35907
+ blockingPath: path17
35573
35908
  };
35574
35909
  }
35575
- const parent = dirname13(path15);
35576
- if (parent === path15) {
35910
+ const parent = dirname14(path17);
35911
+ if (parent === path17) {
35577
35912
  return {
35578
35913
  ok: false,
35579
- creatableFrom: path15,
35580
- blockingPath: path15
35914
+ creatableFrom: path17,
35915
+ blockingPath: path17
35581
35916
  };
35582
35917
  }
35583
35918
  const parentCheck = await checkCreatableAncestorDirectory(parent, probe, platform);
@@ -36016,10 +36351,10 @@ var init_render_doctor = __esm(() => {
36016
36351
  });
36017
36352
 
36018
36353
  // src/doctor/doctor.ts
36019
- import { homedir as homedir17 } from "node:os";
36354
+ import { homedir as homedir18 } from "node:os";
36020
36355
  import { join as join25 } from "node:path";
36021
36356
  async function runDoctor(options = {}, deps = {}) {
36022
- const home = deps.home ?? process.env.HOME ?? homedir17();
36357
+ const home = deps.home ?? process.env.HOME ?? homedir18();
36023
36358
  const runtimePaths = resolveDoctorRuntimePaths(home, deps.resolveRuntimePaths);
36024
36359
  const sharedLoadConfig = createSharedLoadConfig(runtimePaths, deps.loadConfig ?? loadConfig);
36025
36360
  const runners = [
@@ -36356,8 +36691,8 @@ var init_doctor2 = __esm(async () => {
36356
36691
  // src/cli.ts
36357
36692
  init_core_home();
36358
36693
  import { randomUUID as randomUUID4 } from "node:crypto";
36359
- import { homedir as homedir18 } from "node:os";
36360
- import { dirname as dirname14, join as join26, sep as sep2 } from "node:path";
36694
+ import { homedir as homedir19 } from "node:os";
36695
+ import { dirname as dirname15, join as join26, sep as sep2 } from "node:path";
36361
36696
  import { fileURLToPath as fileURLToPath7 } from "node:url";
36362
36697
 
36363
36698
  // src/runtime/migrate-core-home.ts
@@ -52962,7 +53297,7 @@ function decodeFirstRunOnboarding(raw) {
52962
53297
  return null;
52963
53298
  }
52964
53299
  function requireHome2() {
52965
- const home = process.env.HOME ?? homedir18();
53300
+ const home = process.env.HOME ?? homedir19();
52966
53301
  if (!home) {
52967
53302
  throw new Error("Unable to resolve the current user home directory");
52968
53303
  }
@@ -52986,7 +53321,7 @@ function safeDaemonLogPaths() {
52986
53321
  const configPath = resolveConfigPathForCurrentEnv();
52987
53322
  const paths = resolveDaemonPathsForCurrentConfig();
52988
53323
  return {
52989
- appLog: join26(dirname14(configPath), "runtime", "app.log"),
53324
+ appLog: join26(dirname15(configPath), "runtime", "app.log"),
52990
53325
  stderrLog: paths.stderrLog
52991
53326
  };
52992
53327
  } catch {