@ganglion/xacpx 0.24.0 → 0.24.1-beta.0

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.
@@ -4381,9 +4381,9 @@ var init_recovery = __esm(() => {
4381
4381
  sessionInterrupted: (alias) => `Session "${alias}" was interrupted; no final reply received.`,
4382
4382
  sessionInterruptedHint: "Retry directly. If the session remains unresponsive, send /cancel first, then retry.",
4383
4383
  sessionInterruptedError: (summary) => `Error: ${summary}`,
4384
- queueOverflowWarning: "⚠️ Output too large",
4385
- queueOverflowHint: "Ask the agent to summarize or send in smaller chunks, then retry. The session is ready for your next message.",
4386
- queueOverflowUnconfirmedHint: "Automatic cleanup could not be confirmed. Please send /cancel first, then retry; if the issue persists, recreate the session (/session new ...).",
4384
+ queueOverflowWarning: "",
4385
+ queueOverflowHint: "Reply was truncated for size you can continue.",
4386
+ queueOverflowUnconfirmedHint: "Output was large and cleanup wasn't confirmed send /cancel, then continue.",
4387
4387
  autoInstallHeadlineFixed: "⚠️ Auto-install ran but could not fix the session startup problem",
4388
4388
  autoInstallHeadlineFailed: "❌ Auto-install failed",
4389
4389
  autoInstallOriginalError: "Original error:",
@@ -5512,9 +5512,9 @@ var init_recovery2 = __esm(() => {
5512
5512
  sessionInterrupted: (alias) => `当前会话「${alias}」执行中断,未收到最终回复。`,
5513
5513
  sessionInterruptedHint: "请直接重试;如果长时间无响应,可先发送 /cancel 后再重试。",
5514
5514
  sessionInterruptedError: (summary) => `错误信息:${summary}`,
5515
- queueOverflowWarning: "⚠️ 单次输出过大",
5516
- queueOverflowHint: "请让 agent 分步/摘要输出,或拆成多次发送;会话已就绪,可直接继续。",
5517
- queueOverflowUnconfirmedHint: "自动清理未能确认完成,请先发送 /cancel 后重试;若仍异常,请重建会话(/session new ...)或稍后重试。",
5515
+ queueOverflowWarning: "",
5516
+ queueOverflowHint: "部分回复因过长已收束,可直接继续。",
5517
+ queueOverflowUnconfirmedHint: "输出过长且清理未确认,请先发 /cancel 再继续。",
5518
5518
  autoInstallHeadlineFixed: "⚠️ 自动安装已执行但未能修复会话启动问题",
5519
5519
  autoInstallHeadlineFailed: "❌ 自动安装失败",
5520
5520
  autoInstallOriginalError: "原始错误:",
package/dist/cli.js CHANGED
@@ -302,9 +302,9 @@ var init_recovery = __esm(() => {
302
302
  sessionInterrupted: (alias) => `Session "${alias}" was interrupted; no final reply received.`,
303
303
  sessionInterruptedHint: "Retry directly. If the session remains unresponsive, send /cancel first, then retry.",
304
304
  sessionInterruptedError: (summary) => `Error: ${summary}`,
305
- queueOverflowWarning: "⚠️ Output too large",
306
- queueOverflowHint: "Ask the agent to summarize or send in smaller chunks, then retry. The session is ready for your next message.",
307
- queueOverflowUnconfirmedHint: "Automatic cleanup could not be confirmed. Please send /cancel first, then retry; if the issue persists, recreate the session (/session new ...).",
305
+ queueOverflowWarning: "",
306
+ queueOverflowHint: "Reply was truncated for size you can continue.",
307
+ queueOverflowUnconfirmedHint: "Output was large and cleanup wasn't confirmed send /cancel, then continue.",
308
308
  autoInstallHeadlineFixed: "⚠️ Auto-install ran but could not fix the session startup problem",
309
309
  autoInstallHeadlineFailed: "❌ Auto-install failed",
310
310
  autoInstallOriginalError: "Original error:",
@@ -1433,9 +1433,9 @@ var init_recovery2 = __esm(() => {
1433
1433
  sessionInterrupted: (alias) => `当前会话「${alias}」执行中断,未收到最终回复。`,
1434
1434
  sessionInterruptedHint: "请直接重试;如果长时间无响应,可先发送 /cancel 后再重试。",
1435
1435
  sessionInterruptedError: (summary) => `错误信息:${summary}`,
1436
- queueOverflowWarning: "⚠️ 单次输出过大",
1437
- queueOverflowHint: "请让 agent 分步/摘要输出,或拆成多次发送;会话已就绪,可直接继续。",
1438
- queueOverflowUnconfirmedHint: "自动清理未能确认完成,请先发送 /cancel 后重试;若仍异常,请重建会话(/session new ...)或稍后重试。",
1436
+ queueOverflowWarning: "",
1437
+ queueOverflowHint: "部分回复因过长已收束,可直接继续。",
1438
+ queueOverflowUnconfirmedHint: "输出过长且清理未确认,请先发 /cancel 再继续。",
1439
1439
  autoInstallHeadlineFixed: "⚠️ 自动安装已执行但未能修复会话启动问题",
1440
1440
  autoInstallHeadlineFailed: "❌ 自动安装失败",
1441
1441
  autoInstallOriginalError: "原始错误:",
@@ -34428,7 +34428,7 @@ async function executeChatTurn(params) {
34428
34428
  }
34429
34429
  });
34430
34430
  return {
34431
- text: response.text,
34431
+ text: response.silent ? undefined : response.text,
34432
34432
  media: response.media,
34433
34433
  usedReply
34434
34434
  };
@@ -41980,6 +41980,239 @@ var init_acpx_queue_overflow = __esm(() => {
41980
41980
  };
41981
41981
  });
41982
41982
 
41983
+ // src/commands/transport-diagnostics.ts
41984
+ function summarizeTransportError(message) {
41985
+ return message.replace(/\s+/g, " ").trim().slice(0, 200);
41986
+ }
41987
+ function summarizeTransportDiagnostic(output) {
41988
+ const trimmed = output.replace(/\s+/g, " ").trim();
41989
+ if (trimmed.length === 0) {
41990
+ return;
41991
+ }
41992
+ return trimmed.slice(0, 200);
41993
+ }
41994
+ function summarizeTransportDiagnosticTail(output) {
41995
+ const trimmed = output.replace(/\s+/g, " ").trim();
41996
+ if (trimmed.length === 0) {
41997
+ return;
41998
+ }
41999
+ return trimmed.slice(-200);
42000
+ }
42001
+ function summarizeTransportNdjson(output, prefix) {
42002
+ const lines = output.split(`
42003
+ `).map((line) => line.trim()).filter((line) => line.length > 0);
42004
+ if (lines.length === 0) {
42005
+ return {};
42006
+ }
42007
+ const methods = new Set;
42008
+ let agentMessageChunkCount = 0;
42009
+ let stopReason;
42010
+ for (const line of lines) {
42011
+ try {
42012
+ const payload = JSON.parse(line);
42013
+ if (typeof payload.method === "string" && payload.method.length > 0) {
42014
+ methods.add(payload.method);
42015
+ }
42016
+ if (payload.params?.update?.sessionUpdate === "agent_message_chunk") {
42017
+ agentMessageChunkCount += 1;
42018
+ }
42019
+ if (typeof payload.result?.stopReason === "string" && payload.result.stopReason.length > 0) {
42020
+ stopReason = payload.result.stopReason;
42021
+ }
42022
+ } catch {
42023
+ continue;
42024
+ }
42025
+ }
42026
+ const summary = {
42027
+ [`${prefix}LineCount`]: lines.length
42028
+ };
42029
+ if (methods.size > 0) {
42030
+ summary[`${prefix}Methods`] = [...methods].join(",");
42031
+ }
42032
+ if (agentMessageChunkCount > 0) {
42033
+ summary[`${prefix}AgentMessageChunkCount`] = agentMessageChunkCount;
42034
+ }
42035
+ if (stopReason) {
42036
+ summary[`${prefix}StopReason`] = stopReason;
42037
+ }
42038
+ return summary;
42039
+ }
42040
+ function isPartialPromptOutputError(message) {
42041
+ return message.includes(ACPX_PARTIAL_OUTPUT_SENTINEL);
42042
+ }
42043
+ var ACPX_PARTIAL_OUTPUT_SENTINEL = "未收到最终回复";
42044
+
42045
+ // src/recovery/errors.ts
42046
+ var MissingOptionalDepError, AutoInstallFailedError;
42047
+ var init_errors4 = __esm(() => {
42048
+ MissingOptionalDepError = class MissingOptionalDepError extends Error {
42049
+ kind = "missing_optional_dep";
42050
+ package;
42051
+ parentPackagePath;
42052
+ rawMessage;
42053
+ constructor(payload) {
42054
+ super(payload.rawMessage);
42055
+ this.name = "MissingOptionalDepError";
42056
+ this.package = payload.package;
42057
+ this.parentPackagePath = payload.parentPackagePath;
42058
+ this.rawMessage = payload.rawMessage;
42059
+ }
42060
+ };
42061
+ AutoInstallFailedError = class AutoInstallFailedError extends Error {
42062
+ kind = "auto_install_failed";
42063
+ original;
42064
+ steps;
42065
+ logPath;
42066
+ constructor(original, steps, logPath) {
42067
+ super(`auto-install failed: ${original.package}`);
42068
+ this.name = "AutoInstallFailedError";
42069
+ this.original = original;
42070
+ this.steps = steps;
42071
+ this.logPath = logPath;
42072
+ }
42073
+ };
42074
+ });
42075
+
42076
+ // src/commands/handlers/session-recovery-handler.ts
42077
+ function queueOverflowTipText(confirmed) {
42078
+ const r = t().recovery;
42079
+ return [r.queueOverflowWarning, confirmed ? r.queueOverflowHint : r.queueOverflowUnconfirmedHint].filter((line) => line.length > 0).join(`
42080
+ `);
42081
+ }
42082
+ function renderTransportError(session3, error2) {
42083
+ if (error2 instanceof AcpxQueueOverflowError) {
42084
+ return { silent: true };
42085
+ }
42086
+ const message = error2 instanceof Error ? error2.message : String(error2);
42087
+ const registryError = renderAdapterRegistryError(session3, message);
42088
+ if (registryError)
42089
+ return registryError;
42090
+ if (message.includes("No acpx session found")) {
42091
+ if (session3.transient) {
42092
+ return {
42093
+ text: [
42094
+ t().recovery.transientSessionFailed,
42095
+ t().recovery.transientSessionHint
42096
+ ].join(`
42097
+ `)
42098
+ };
42099
+ }
42100
+ const quotedWs = quoteWorkspaceNameIfNeeded(session3.workspace);
42101
+ return {
42102
+ text: [
42103
+ t().recovery.sessionUnavailable(session3.alias),
42104
+ t().recovery.sessionUnavailableRenewHint(session3.alias, session3.agent, quotedWs),
42105
+ t().recovery.sessionUnavailableAttachHint(session3.alias, session3.agent, quotedWs)
42106
+ ].join(`
42107
+ `)
42108
+ };
42109
+ }
42110
+ if (!isPartialPromptOutputError(message)) {
42111
+ throw error2;
42112
+ }
42113
+ return {
42114
+ text: [
42115
+ t().recovery.sessionInterrupted(session3.alias),
42116
+ t().recovery.sessionInterruptedHint,
42117
+ t().recovery.sessionInterruptedError(summarizeTransportError(message))
42118
+ ].join(`
42119
+ `)
42120
+ };
42121
+ }
42122
+ function renderSessionCreationError(session3, error2) {
42123
+ if (error2 instanceof AutoInstallFailedError) {
42124
+ const { original, steps, logPath } = error2;
42125
+ const r = t().recovery;
42126
+ const allVerifyFailed = steps.length > 0 && steps.every((s) => s.reason === "verify-failed");
42127
+ const headline = allVerifyFailed ? r.autoInstallHeadlineFixed : r.autoInstallHeadlineFailed;
42128
+ const stepLines = steps.map((s) => {
42129
+ const perStepPath = s.path ?? (s.scope === "precise" ? original.parentPackagePath : null);
42130
+ const label = s.scope === "precise" ? r.autoInstallScopePrecise(s.manager, perStepPath ?? undefined) : r.autoInstallScopeGlobal;
42131
+ if (s.reason === "verify-failed") {
42132
+ return r.autoInstallStepVerifyFailed(label);
42133
+ }
42134
+ return r.autoInstallStepError(label, s.stderrTail);
42135
+ }).join(`
42136
+
42137
+ `);
42138
+ return {
42139
+ text: [
42140
+ headline,
42141
+ ``,
42142
+ r.autoInstallOriginalError,
42143
+ original.rawMessage,
42144
+ ``,
42145
+ stepLines,
42146
+ ``,
42147
+ r.autoInstallManual(original.package),
42148
+ r.autoInstallLog(logPath)
42149
+ ].join(`
42150
+ `)
42151
+ };
42152
+ }
42153
+ const message = error2 instanceof Error ? error2.message : String(error2);
42154
+ const registryError = renderAdapterRegistryError(session3, message);
42155
+ if (registryError)
42156
+ return {
42157
+ text: [
42158
+ t().recovery.sessionCreationFailed,
42159
+ registryError.text
42160
+ ].join(`
42161
+ `)
42162
+ };
42163
+ if (message.includes("timed out") && message.includes("sessions new")) {
42164
+ return renderSessionCreationFailure(session3, message);
42165
+ }
42166
+ throw error2;
42167
+ }
42168
+ function renderAdapterRegistryError(session3, message) {
42169
+ const registry2 = managedAdapterRegistryFromCommand(session3.agentCommand);
42170
+ if (!registry2 || !isNpmAdapterRegistryNotFoundOutput(message))
42171
+ return null;
42172
+ return {
42173
+ text: t().recovery.adapterRegistryE404(registry2, DEFAULT_ADAPTER_REGISTRY)
42174
+ };
42175
+ }
42176
+ function renderSessionCreationVerificationError(session3) {
42177
+ return renderSessionCreationFailure(session3, t().recovery.sessionCreationVerificationDetail);
42178
+ }
42179
+ function renderSessionCreationFailure(session3, detail) {
42180
+ const r = t().recovery;
42181
+ return {
42182
+ text: [
42183
+ r.sessionCreationFailed,
42184
+ r.sessionCreationError(summarizeTransportError(detail)),
42185
+ r.sessionCreationAttachHint(session3.alias, session3.agent, quoteWorkspaceNameIfNeeded(session3.workspace))
42186
+ ].join(`
42187
+ `)
42188
+ };
42189
+ }
42190
+ async function tryRecoverMissingSession(ops, session3, error2) {
42191
+ if (error2 instanceof AcpxQueueOverflowError)
42192
+ return null;
42193
+ const message = error2 instanceof Error ? error2.message : String(error2);
42194
+ if (!message.includes("No acpx session found")) {
42195
+ return null;
42196
+ }
42197
+ if (session3.transient) {
42198
+ return null;
42199
+ }
42200
+ const transportAgentCommand = await ops.resolveSessionAgentCommand(session3);
42201
+ if (!transportAgentCommand || transportAgentCommand === session3.agentCommand) {
42202
+ return null;
42203
+ }
42204
+ await ops.setSessionTransportAgentCommand(session3.alias, transportAgentCommand);
42205
+ return await ops.getSession(session3.alias);
42206
+ }
42207
+ var init_session_recovery_handler = __esm(() => {
42208
+ init_errors4();
42209
+ init_workspace_name();
42210
+ init_i18n();
42211
+ init_adapter_registry();
42212
+ init_adapter_catalog();
42213
+ init_acpx_queue_overflow();
42214
+ });
42215
+
41983
42216
  // src/commands/handlers/session-handler.ts
41984
42217
  function sessionHelp() {
41985
42218
  const s = t().session;
@@ -42640,7 +42873,13 @@ async function handlePromptWithSession(context, session3, chatKey, text, reply,
42640
42873
  diagnostic: error2.cleanupDiagnostic ?? (error2 instanceof Error ? error2.message.slice(0, 512) : String(error2).slice(0, 512)),
42641
42874
  confirmed
42642
42875
  });
42643
- return context.recovery.renderTransportError(session3, error2);
42876
+ context.onQueueOverflowTip?.({
42877
+ chatKey,
42878
+ sessionAlias: session3.alias,
42879
+ confirmed,
42880
+ text: queueOverflowTipText(confirmed)
42881
+ });
42882
+ return { silent: true };
42644
42883
  }
42645
42884
  const recovered = await context.recovery.tryRecoverMissingSession(session3, error2);
42646
42885
  if (recovered) {
@@ -42739,6 +42978,7 @@ var init_session_handler = __esm(() => {
42739
42978
  init_workspace_name();
42740
42979
  init_i18n();
42741
42980
  init_acpx_queue_overflow();
42981
+ init_session_recovery_handler();
42742
42982
  });
42743
42983
 
42744
42984
  // src/formatting/render-text.ts
@@ -43756,37 +43996,6 @@ var init_help_handler = __esm(() => {
43756
43996
  init_i18n();
43757
43997
  });
43758
43998
 
43759
- // src/recovery/errors.ts
43760
- var MissingOptionalDepError, AutoInstallFailedError;
43761
- var init_errors4 = __esm(() => {
43762
- MissingOptionalDepError = class MissingOptionalDepError extends Error {
43763
- kind = "missing_optional_dep";
43764
- package;
43765
- parentPackagePath;
43766
- rawMessage;
43767
- constructor(payload) {
43768
- super(payload.rawMessage);
43769
- this.name = "MissingOptionalDepError";
43770
- this.package = payload.package;
43771
- this.parentPackagePath = payload.parentPackagePath;
43772
- this.rawMessage = payload.rawMessage;
43773
- }
43774
- };
43775
- AutoInstallFailedError = class AutoInstallFailedError extends Error {
43776
- kind = "auto_install_failed";
43777
- original;
43778
- steps;
43779
- logPath;
43780
- constructor(original, steps, logPath) {
43781
- super(`auto-install failed: ${original.package}`);
43782
- this.name = "AutoInstallFailedError";
43783
- this.original = original;
43784
- this.steps = steps;
43785
- this.logPath = logPath;
43786
- }
43787
- };
43788
- });
43789
-
43790
43999
  // src/commands/handlers/session-shortcut-handler.ts
43791
44000
  async function handleSessionShortcutCommand(context, ops, chatKey, agent3, target, createNew) {
43792
44001
  if (!context.config || !context.configStore) {
@@ -44384,213 +44593,6 @@ var init_native_session_handler = __esm(() => {
44384
44593
  NATIVE_SESSION_CACHE_TTL_MS = 10 * 60 * 1000;
44385
44594
  });
44386
44595
 
44387
- // src/commands/transport-diagnostics.ts
44388
- function summarizeTransportError(message) {
44389
- return message.replace(/\s+/g, " ").trim().slice(0, 200);
44390
- }
44391
- function summarizeTransportDiagnostic(output) {
44392
- const trimmed = output.replace(/\s+/g, " ").trim();
44393
- if (trimmed.length === 0) {
44394
- return;
44395
- }
44396
- return trimmed.slice(0, 200);
44397
- }
44398
- function summarizeTransportDiagnosticTail(output) {
44399
- const trimmed = output.replace(/\s+/g, " ").trim();
44400
- if (trimmed.length === 0) {
44401
- return;
44402
- }
44403
- return trimmed.slice(-200);
44404
- }
44405
- function summarizeTransportNdjson(output, prefix) {
44406
- const lines = output.split(`
44407
- `).map((line) => line.trim()).filter((line) => line.length > 0);
44408
- if (lines.length === 0) {
44409
- return {};
44410
- }
44411
- const methods = new Set;
44412
- let agentMessageChunkCount = 0;
44413
- let stopReason;
44414
- for (const line of lines) {
44415
- try {
44416
- const payload = JSON.parse(line);
44417
- if (typeof payload.method === "string" && payload.method.length > 0) {
44418
- methods.add(payload.method);
44419
- }
44420
- if (payload.params?.update?.sessionUpdate === "agent_message_chunk") {
44421
- agentMessageChunkCount += 1;
44422
- }
44423
- if (typeof payload.result?.stopReason === "string" && payload.result.stopReason.length > 0) {
44424
- stopReason = payload.result.stopReason;
44425
- }
44426
- } catch {
44427
- continue;
44428
- }
44429
- }
44430
- const summary = {
44431
- [`${prefix}LineCount`]: lines.length
44432
- };
44433
- if (methods.size > 0) {
44434
- summary[`${prefix}Methods`] = [...methods].join(",");
44435
- }
44436
- if (agentMessageChunkCount > 0) {
44437
- summary[`${prefix}AgentMessageChunkCount`] = agentMessageChunkCount;
44438
- }
44439
- if (stopReason) {
44440
- summary[`${prefix}StopReason`] = stopReason;
44441
- }
44442
- return summary;
44443
- }
44444
- function isPartialPromptOutputError(message) {
44445
- return message.includes(ACPX_PARTIAL_OUTPUT_SENTINEL);
44446
- }
44447
- var ACPX_PARTIAL_OUTPUT_SENTINEL = "未收到最终回复";
44448
-
44449
- // src/commands/handlers/session-recovery-handler.ts
44450
- function renderTransportError(session3, error2) {
44451
- if (error2 instanceof AcpxQueueOverflowError) {
44452
- const confirmed = error2.cleanup?.ownerTerminationSucceeded === true;
44453
- if (confirmed) {
44454
- return {
44455
- text: [t().recovery.queueOverflowWarning, t().recovery.queueOverflowHint].join(`
44456
- `)
44457
- };
44458
- }
44459
- return {
44460
- text: [t().recovery.queueOverflowWarning, t().recovery.queueOverflowUnconfirmedHint].join(`
44461
- `)
44462
- };
44463
- }
44464
- const message = error2 instanceof Error ? error2.message : String(error2);
44465
- const registryError = renderAdapterRegistryError(session3, message);
44466
- if (registryError)
44467
- return registryError;
44468
- if (message.includes("No acpx session found")) {
44469
- if (session3.transient) {
44470
- return {
44471
- text: [
44472
- t().recovery.transientSessionFailed,
44473
- t().recovery.transientSessionHint
44474
- ].join(`
44475
- `)
44476
- };
44477
- }
44478
- const quotedWs = quoteWorkspaceNameIfNeeded(session3.workspace);
44479
- return {
44480
- text: [
44481
- t().recovery.sessionUnavailable(session3.alias),
44482
- t().recovery.sessionUnavailableRenewHint(session3.alias, session3.agent, quotedWs),
44483
- t().recovery.sessionUnavailableAttachHint(session3.alias, session3.agent, quotedWs)
44484
- ].join(`
44485
- `)
44486
- };
44487
- }
44488
- if (!isPartialPromptOutputError(message)) {
44489
- throw error2;
44490
- }
44491
- return {
44492
- text: [
44493
- t().recovery.sessionInterrupted(session3.alias),
44494
- t().recovery.sessionInterruptedHint,
44495
- t().recovery.sessionInterruptedError(summarizeTransportError(message))
44496
- ].join(`
44497
- `)
44498
- };
44499
- }
44500
- function renderSessionCreationError(session3, error2) {
44501
- if (error2 instanceof AutoInstallFailedError) {
44502
- const { original, steps, logPath } = error2;
44503
- const r = t().recovery;
44504
- const allVerifyFailed = steps.length > 0 && steps.every((s) => s.reason === "verify-failed");
44505
- const headline = allVerifyFailed ? r.autoInstallHeadlineFixed : r.autoInstallHeadlineFailed;
44506
- const stepLines = steps.map((s) => {
44507
- const perStepPath = s.path ?? (s.scope === "precise" ? original.parentPackagePath : null);
44508
- const label = s.scope === "precise" ? r.autoInstallScopePrecise(s.manager, perStepPath ?? undefined) : r.autoInstallScopeGlobal;
44509
- if (s.reason === "verify-failed") {
44510
- return r.autoInstallStepVerifyFailed(label);
44511
- }
44512
- return r.autoInstallStepError(label, s.stderrTail);
44513
- }).join(`
44514
-
44515
- `);
44516
- return {
44517
- text: [
44518
- headline,
44519
- ``,
44520
- r.autoInstallOriginalError,
44521
- original.rawMessage,
44522
- ``,
44523
- stepLines,
44524
- ``,
44525
- r.autoInstallManual(original.package),
44526
- r.autoInstallLog(logPath)
44527
- ].join(`
44528
- `)
44529
- };
44530
- }
44531
- const message = error2 instanceof Error ? error2.message : String(error2);
44532
- const registryError = renderAdapterRegistryError(session3, message);
44533
- if (registryError)
44534
- return {
44535
- text: [
44536
- t().recovery.sessionCreationFailed,
44537
- registryError.text
44538
- ].join(`
44539
- `)
44540
- };
44541
- if (message.includes("timed out") && message.includes("sessions new")) {
44542
- return renderSessionCreationFailure(session3, message);
44543
- }
44544
- throw error2;
44545
- }
44546
- function renderAdapterRegistryError(session3, message) {
44547
- const registry2 = managedAdapterRegistryFromCommand(session3.agentCommand);
44548
- if (!registry2 || !isNpmAdapterRegistryNotFoundOutput(message))
44549
- return null;
44550
- return {
44551
- text: t().recovery.adapterRegistryE404(registry2, DEFAULT_ADAPTER_REGISTRY)
44552
- };
44553
- }
44554
- function renderSessionCreationVerificationError(session3) {
44555
- return renderSessionCreationFailure(session3, t().recovery.sessionCreationVerificationDetail);
44556
- }
44557
- function renderSessionCreationFailure(session3, detail) {
44558
- const r = t().recovery;
44559
- return {
44560
- text: [
44561
- r.sessionCreationFailed,
44562
- r.sessionCreationError(summarizeTransportError(detail)),
44563
- r.sessionCreationAttachHint(session3.alias, session3.agent, quoteWorkspaceNameIfNeeded(session3.workspace))
44564
- ].join(`
44565
- `)
44566
- };
44567
- }
44568
- async function tryRecoverMissingSession(ops, session3, error2) {
44569
- if (error2 instanceof AcpxQueueOverflowError)
44570
- return null;
44571
- const message = error2 instanceof Error ? error2.message : String(error2);
44572
- if (!message.includes("No acpx session found")) {
44573
- return null;
44574
- }
44575
- if (session3.transient) {
44576
- return null;
44577
- }
44578
- const transportAgentCommand = await ops.resolveSessionAgentCommand(session3);
44579
- if (!transportAgentCommand || transportAgentCommand === session3.agentCommand) {
44580
- return null;
44581
- }
44582
- await ops.setSessionTransportAgentCommand(session3.alias, transportAgentCommand);
44583
- return await ops.getSession(session3.alias);
44584
- }
44585
- var init_session_recovery_handler = __esm(() => {
44586
- init_errors4();
44587
- init_workspace_name();
44588
- init_i18n();
44589
- init_adapter_registry();
44590
- init_adapter_catalog();
44591
- init_acpx_queue_overflow();
44592
- });
44593
-
44594
44596
  // src/recovery/auto-install-optional-dep.ts
44595
44597
  import { spawn as spawn11 } from "node:child_process";
44596
44598
  import { createWriteStream } from "node:fs";
@@ -45595,6 +45597,7 @@ class CommandRouter {
45595
45597
  scheduled;
45596
45598
  scheduledDelivery;
45597
45599
  resolveNativeSessionListFormat;
45600
+ controlEvents;
45598
45601
  logger;
45599
45602
  autoInstall = autoInstallOptionalDep;
45600
45603
  discoverPaths = discoverParentPackagePaths;
@@ -45607,7 +45610,7 @@ class CommandRouter {
45607
45610
  activeTurns;
45608
45611
  transportInvoker;
45609
45612
  sessionControl;
45610
- constructor(sessions, transport, config4, configStore, logger, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration3, quota, scheduled, scheduledDelivery, resolveNativeSessionListFormat, activeTurns) {
45613
+ constructor(sessions, transport, config4, configStore, logger, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration3, quota, scheduled, scheduledDelivery, resolveNativeSessionListFormat, activeTurns, controlEvents) {
45611
45614
  this.sessions = sessions;
45612
45615
  this.transport = transport;
45613
45616
  this.config = config4;
@@ -45618,6 +45621,7 @@ class CommandRouter {
45618
45621
  this.scheduled = scheduled;
45619
45622
  this.scheduledDelivery = scheduledDelivery;
45620
45623
  this.resolveNativeSessionListFormat = resolveNativeSessionListFormat;
45624
+ this.controlEvents = controlEvents;
45621
45625
  this.logger = logger ?? createNoopAppLogger();
45622
45626
  this.activeTurns = activeTurns;
45623
45627
  this.transportInvoker = new TransportInvoker({
@@ -45836,7 +45840,18 @@ class CommandRouter {
45836
45840
  lifecycle: this.createSessionLifecycleOps(reply, perfSpan),
45837
45841
  interaction: this.createSessionInteractionOps(perfSpan),
45838
45842
  recovery: this.createSessionRenderRecoveryOps(),
45839
- ...this.activeTurns ? { activeTurns: this.activeTurns } : {}
45843
+ ...this.activeTurns ? { activeTurns: this.activeTurns } : {},
45844
+ ...this.controlEvents ? {
45845
+ onQueueOverflowTip: (info) => {
45846
+ this.controlEvents.emit({
45847
+ type: "queue-overflow-tip",
45848
+ chatKey: info.chatKey,
45849
+ sessionAlias: info.sessionAlias,
45850
+ confirmed: info.confirmed,
45851
+ text: info.text
45852
+ });
45853
+ }
45854
+ } : {}
45840
45855
  };
45841
45856
  }
45842
45857
  createSessionLifecycleOps(reply, perfSpan) {
@@ -60254,7 +60269,7 @@ ${envelope}` : envelope;
60254
60269
  });
60255
60270
  }
60256
60271
  });
60257
- if (response.text) {
60272
+ if (response.text && !response.silent) {
60258
60273
  emitChunk(response.text);
60259
60274
  }
60260
60275
  this.deps.events.emit({
@@ -60262,7 +60277,8 @@ ${envelope}` : envelope;
60262
60277
  chatKey: req.chatKey,
60263
60278
  sessionAlias: req.sessionAlias,
60264
60279
  ok: true,
60265
- text: finalText,
60280
+ ...finalText !== "" || !response.silent ? { text: finalText } : {},
60281
+ ...response.silent ? { silent: true } : {},
60266
60282
  ...req.peerOrigin ? { peerOrigin: req.peerOrigin } : {}
60267
60283
  });
60268
60284
  return {
@@ -63331,7 +63347,7 @@ async function buildApp(paths, deps = {}) {
63331
63347
  });
63332
63348
  const router3 = new CommandRouter(sessions, transport, config4, configStore, logger, undefined, orchestration3, quota, scheduledService, deps.channel?.supportsScheduledMessages ? {
63333
63349
  supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel)
63334
- } : undefined, deps.channel?.nativeSessionListFormat ? deps.channel.nativeSessionListFormat.bind(deps.channel) : undefined, activeTurns);
63350
+ } : undefined, deps.channel?.nativeSessionListFormat ? deps.channel.nativeSessionListFormat.bind(deps.channel) : undefined, activeTurns, controlEvents);
63335
63351
  const agent3 = new ConsoleAgent(router3, logger);
63336
63352
  const terminalService = createTerminalService({
63337
63353
  events: controlEvents,
@@ -9,6 +9,12 @@ export interface SessionHandlerContext extends CommandRouterContext {
9
9
  interaction: SessionInteractionOps;
10
10
  recovery: SessionRenderRecoveryOps;
11
11
  readonly activeTurns?: import("../../sessions/active-turn-registry.js").ActiveTurnRegistry;
12
+ onQueueOverflowTip?: (info: {
13
+ chatKey: string;
14
+ sessionAlias: string;
15
+ confirmed: boolean;
16
+ text: string;
17
+ }) => void;
12
18
  }
13
19
  export declare function sessionHelp(): HelpTopicMetadata;
14
20
  export declare function nativeSessionHelp(): HelpTopicMetadata;
@@ -0,0 +1,7 @@
1
+ import type { ResolvedSession } from "../../transport/types";
2
+ import type { RouterResponse, SessionRecoveryOps } from "../router-types";
3
+ export declare function queueOverflowTipText(confirmed: boolean): string;
4
+ export declare function renderTransportError(session: ResolvedSession, error: unknown): RouterResponse;
5
+ export declare function renderSessionCreationError(session: ResolvedSession, error: unknown): RouterResponse;
6
+ export declare function renderSessionCreationVerificationError(session: ResolvedSession): RouterResponse;
7
+ export declare function tryRecoverMissingSession(ops: SessionRecoveryOps, session: ResolvedSession, error: unknown): Promise<ResolvedSession | null>;
@@ -9,6 +9,8 @@ import type { PlanEntry, ToolUseEvent } from "../channels/types.js";
9
9
  import type { PerfSpan } from "../perf/perf-tracer";
10
10
  export interface RouterResponse {
11
11
  text?: string;
12
+ /** When true, channels must not deliver `text` (including an empty bubble). */
13
+ silent?: boolean;
12
14
  }
13
15
  export interface PromptRouteMetadata {
14
16
  chatKey: string;
@@ -0,0 +1,5 @@
1
+ export declare function summarizeTransportError(message: string): string;
2
+ export declare function summarizeTransportDiagnostic(output: string): string | undefined;
3
+ export declare function summarizeTransportDiagnosticTail(output: string): string | undefined;
4
+ export declare function summarizeTransportNdjson(output: string, prefix: "stdout" | "stderr"): Record<string, string | number>;
5
+ export declare function isPartialPromptOutputError(message: string): boolean;
@@ -73,7 +73,14 @@ export type ControlEvent = {
73
73
  errorMessage?: string;
74
74
  cancelled?: boolean;
75
75
  text?: string;
76
+ silent?: boolean;
76
77
  peerOrigin?: PeerTurnOrigin;
78
+ } | {
79
+ type: "queue-overflow-tip";
80
+ chatKey: string;
81
+ sessionAlias: string;
82
+ confirmed: boolean;
83
+ text: string;
77
84
  } | {
78
85
  type: "sessions-changed";
79
86
  } | {
@@ -317,9 +317,9 @@ var init_recovery = __esm(() => {
317
317
  sessionInterrupted: (alias) => `Session "${alias}" was interrupted; no final reply received.`,
318
318
  sessionInterruptedHint: "Retry directly. If the session remains unresponsive, send /cancel first, then retry.",
319
319
  sessionInterruptedError: (summary) => `Error: ${summary}`,
320
- queueOverflowWarning: "⚠️ Output too large",
321
- queueOverflowHint: "Ask the agent to summarize or send in smaller chunks, then retry. The session is ready for your next message.",
322
- queueOverflowUnconfirmedHint: "Automatic cleanup could not be confirmed. Please send /cancel first, then retry; if the issue persists, recreate the session (/session new ...).",
320
+ queueOverflowWarning: "",
321
+ queueOverflowHint: "Reply was truncated for size you can continue.",
322
+ queueOverflowUnconfirmedHint: "Output was large and cleanup wasn't confirmed send /cancel, then continue.",
323
323
  autoInstallHeadlineFixed: "⚠️ Auto-install ran but could not fix the session startup problem",
324
324
  autoInstallHeadlineFailed: "❌ Auto-install failed",
325
325
  autoInstallOriginalError: "Original error:",
@@ -1448,9 +1448,9 @@ var init_recovery2 = __esm(() => {
1448
1448
  sessionInterrupted: (alias) => `当前会话「${alias}」执行中断,未收到最终回复。`,
1449
1449
  sessionInterruptedHint: "请直接重试;如果长时间无响应,可先发送 /cancel 后再重试。",
1450
1450
  sessionInterruptedError: (summary) => `错误信息:${summary}`,
1451
- queueOverflowWarning: "⚠️ 单次输出过大",
1452
- queueOverflowHint: "请让 agent 分步/摘要输出,或拆成多次发送;会话已就绪,可直接继续。",
1453
- queueOverflowUnconfirmedHint: "自动清理未能确认完成,请先发送 /cancel 后重试;若仍异常,请重建会话(/session new ...)或稍后重试。",
1451
+ queueOverflowWarning: "",
1452
+ queueOverflowHint: "部分回复因过长已收束,可直接继续。",
1453
+ queueOverflowUnconfirmedHint: "输出过长且清理未确认,请先发 /cancel 再继续。",
1454
1454
  autoInstallHeadlineFixed: "⚠️ 自动安装已执行但未能修复会话启动问题",
1455
1455
  autoInstallHeadlineFailed: "❌ 自动安装失败",
1456
1456
  autoInstallOriginalError: "原始错误:",
@@ -0,0 +1,49 @@
1
+ export type PackageManager = "npm" | "bun" | "pnpm" | "yarn";
2
+ export interface DiscoveredParentPath {
3
+ /** Absolute directory containing the parent package's package.json. */
4
+ path: string;
5
+ /** Which package manager owns this directory — determines which CLI to install with. */
6
+ manager: PackageManager;
7
+ }
8
+ export interface DiscoverDeps {
9
+ env?: NodeJS.ProcessEnv;
10
+ home?: string;
11
+ platform?: NodeJS.Platform;
12
+ /**
13
+ * Working directory used as the anchor for `require.resolve` style lookups.
14
+ * In production this is typically the bridge / acpx cwd, not the daemon's cwd.
15
+ * Defaults to `process.cwd()` which is usually wrong for daemonized use.
16
+ */
17
+ cwd?: string;
18
+ fsExists?: (path: string) => Promise<boolean>;
19
+ /**
20
+ * Resolve `<name>/package.json` via Node.js resolution, anchored on the provided cwd.
21
+ * Returns the parent package dir (containing package.json) or null.
22
+ */
23
+ resolveFromCwd?: (parentName: string, cwd: string) => string | null;
24
+ /**
25
+ * Query a package manager root. Short timeout; null if the CLI is unavailable.
26
+ */
27
+ queryPackageManagerRoot?: (tool: "npm" | "pnpm" | "yarn") => Promise<string | null>;
28
+ }
29
+ /**
30
+ * Strip platform / arch / libc suffixes from an npm optional platform package name.
31
+ * Examples:
32
+ * "opencode-windows-x64" → "opencode"
33
+ * "@scope/pkg-linux-arm64-musl" → "@scope/pkg"
34
+ * "esbuild-darwin-x64" → "esbuild"
35
+ * "@next/swc-win32-x64-msvc" → "@next/swc"
36
+ * "@rollup/rollup-linux-x64-gnu" → "@rollup/rollup"
37
+ */
38
+ export declare function deriveParentPackageName(platformPackage: string): string;
39
+ /**
40
+ * Enumerate directories where the parent package might be installed across
41
+ * common package managers: npm (global), Bun (global), pnpm (global), Yarn (global),
42
+ * plus the local Node resolution tree. Each entry is tagged with its owning
43
+ * package manager so the installer can dispatch to the correct CLI — running
44
+ * `npm install` inside a Bun or pnpm tree would corrupt the managed store.
45
+ *
46
+ * Every returned path is guaranteed to exist and contain a package.json.
47
+ * Duplicates and non-existent paths are filtered out.
48
+ */
49
+ export declare function discoverParentPackagePaths(platformPackage: string, seedPath: string | null, deps?: DiscoverDeps): Promise<DiscoveredParentPath[]>;
@@ -0,0 +1,30 @@
1
+ export interface MissingOptionalDepPayload {
2
+ package: string;
3
+ parentPackagePath: string | null;
4
+ rawMessage: string;
5
+ }
6
+ export declare class MissingOptionalDepError extends Error {
7
+ readonly kind: "missing_optional_dep";
8
+ readonly package: string;
9
+ readonly parentPackagePath: string | null;
10
+ readonly rawMessage: string;
11
+ constructor(payload: MissingOptionalDepPayload);
12
+ }
13
+ import type { PackageManager } from "./discover-parent-package-paths";
14
+ export interface AutoInstallStepError {
15
+ scope: "precise" | "global";
16
+ stderrTail: string;
17
+ code: number | null;
18
+ reason?: "timeout" | "spawn" | "exit" | "verify-failed";
19
+ /** The parent package directory this precise install was run in (only set for scope === "precise"). */
20
+ path?: string;
21
+ /** The package manager used for this precise install (only set for scope === "precise"). */
22
+ manager?: PackageManager;
23
+ }
24
+ export declare class AutoInstallFailedError extends Error {
25
+ readonly kind: "auto_install_failed";
26
+ readonly original: MissingOptionalDepError;
27
+ readonly steps: AutoInstallStepError[];
28
+ readonly logPath: string;
29
+ constructor(original: MissingOptionalDepError, steps: AutoInstallStepError[], logPath: string);
30
+ }
@@ -86,6 +86,12 @@ export interface ChatResponse {
86
86
  * the same turn. May contain markdown and will be normalized before send.
87
87
  */
88
88
  text?: string;
89
+ /**
90
+ * When true, the channel must not post `text` as a chat/agent message
91
+ * (including a blank bubble). Used for queue-overflow tips that only
92
+ * surface as a relay-web toast.
93
+ */
94
+ silent?: boolean;
89
95
  /** Reply media file(s). */
90
96
  media?: OutboundChannelMedia | OutboundChannelMedia[];
91
97
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ganglion/xacpx",
3
- "version": "0.24.0",
3
+ "version": "0.24.1-beta.0",
4
4
  "description": "随时随地通过聊天频道(微信 / 飞书 / 元宝等)远程控制 `acpx` 上的 Claude Code、Codex 等 Agents。",
5
5
  "keywords": [
6
6
  "acpx",