@qwen-code/qwen-code 0.18.1 → 0.18.2

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 (74) hide show
  1. package/README.md +2 -1
  2. package/bundled/qc-helper/docs/common-workflow.md +4 -4
  3. package/bundled/qc-helper/docs/configuration/model-providers.md +1 -1
  4. package/bundled/qc-helper/docs/configuration/settings.md +77 -77
  5. package/bundled/qc-helper/docs/features/channels/feishu.md +16 -0
  6. package/bundled/qc-helper/docs/features/mcp.md +1 -1
  7. package/bundled/qc-helper/docs/features/sub-agents.md +3 -3
  8. package/bundled/qc-helper/docs/qwen-serve.md +24 -12
  9. package/bundled/qc-helper/docs/reference/keyboard-shortcuts.md +30 -30
  10. package/bundled/review/SKILL.md +10 -4
  11. package/bundled/simplify/SKILL.md +1 -1
  12. package/chunks/{agent-XT7NHZ5H.js → agent-P5U6QLWL.js} +5 -5
  13. package/chunks/{agent-headless-LNRE63ZL.js → agent-headless-24356DC7.js} +5 -5
  14. package/chunks/{anthropicContentGenerator-DCI26OQF.js → anthropicContentGenerator-KLBHYGH6.js} +1 -1
  15. package/chunks/{askUserQuestion-ITYUTWLR.js → askUserQuestion-QPZXR3UO.js} +1 -1
  16. package/chunks/{chunk-RON7LFNH.js → chunk-25FFAMED.js} +6 -6
  17. package/chunks/{chunk-7KPZFE5A.js → chunk-C64WAJOC.js} +1 -1
  18. package/chunks/{chunk-6T7Y7USE.js → chunk-EQ5NHJBY.js} +1354 -1028
  19. package/chunks/{chunk-IS7UA4W3.js → chunk-JZEKEWO5.js} +4 -4
  20. package/chunks/{chunk-XZTNBSMW.js → chunk-M7OBURJM.js} +1 -1
  21. package/chunks/{chunk-3NRO6NHX.js → chunk-MN5RAXVB.js} +3 -3
  22. package/chunks/{chunk-WJ3SND6W.js → chunk-NGDXHX3A.js} +2 -2
  23. package/chunks/{chunk-BXYRCW2C.js → chunk-QFJ67S5R.js} +10 -5
  24. package/chunks/{chunk-Y7KMDUEP.js → chunk-QP4R5FTG.js} +1 -1
  25. package/chunks/{chunk-QILTEBWS.js → chunk-RTTAC5VW.js} +1 -1
  26. package/chunks/{chunk-HQUWWSSP.js → chunk-VIEIRAK3.js} +1 -1
  27. package/chunks/{chunk-HED55F43.js → chunk-VU6A2OBJ.js} +15 -5
  28. package/chunks/{chunk-DHZREJTG.js → chunk-YJDVHAGL.js} +1 -1
  29. package/chunks/{chunk-A2ZIEEGJ.js → chunk-ZNUMXPNK.js} +592 -43
  30. package/chunks/{computer-use-4YX3JGBV.js → computer-use-EGW2I2HZ.js} +5 -5
  31. package/chunks/{contextCommand-KS2H7MW5.js → contextCommand-HI2X2Y7I.js} +7 -7
  32. package/chunks/{cron-create-CAPUKK7I.js → cron-create-DQKRQMCP.js} +1 -1
  33. package/chunks/{cron-delete-G3KAR26Q.js → cron-delete-DOFPHFTI.js} +1 -1
  34. package/chunks/{cron-list-ZA4ZIUS5.js → cron-list-RCVOO3CB.js} +1 -1
  35. package/chunks/{dist-VEGFONCF.js → dist-2UCAYOX7.js} +2 -2
  36. package/chunks/{dist-X4EXN7W6.js → dist-33LHH26D.js} +1 -1
  37. package/chunks/{dist-YLS6NI7H.js → dist-KF43SZZV.js} +1 -1
  38. package/chunks/{dist-7YWFWOCJ.js → dist-UH7CYT7F.js} +2 -2
  39. package/chunks/{edit-2ARPEO4B.js → edit-FJSOCDO2.js} +7 -9
  40. package/chunks/{enter-worktree-IXNXNAW5.js → enter-worktree-X6MVFDLR.js} +5 -5
  41. package/chunks/{enterPlanMode-TAKAGAYP.js → enterPlanMode-MZAEQZH3.js} +5 -5
  42. package/chunks/{exit-worktree-LHTRV7ML.js → exit-worktree-RM2UPOYQ.js} +5 -5
  43. package/chunks/{exitPlanMode-MK5UAITL.js → exitPlanMode-7BVY3CWJ.js} +7 -6
  44. package/chunks/{geminiContentGenerator-HFJIGO77.js → geminiContentGenerator-A6JHLUHK.js} +1 -1
  45. package/chunks/{glob-I2USLUSC.js → glob-L3AZLCV6.js} +5 -5
  46. package/chunks/{grep-WBIF7THR.js → grep-SNCPCXIP.js} +5 -5
  47. package/chunks/{ls-2R5RHLX5.js → ls-TRD77UTS.js} +1 -1
  48. package/chunks/{lsp-XKH6ZIAN.js → lsp-2VFWQPZS.js} +1 -1
  49. package/chunks/{monitor-WU7UFATU.js → monitor-TS6WL6DN.js} +5 -5
  50. package/chunks/{notebook-edit-KUHYPXEM.js → notebook-edit-26RNH24J.js} +6 -6
  51. package/chunks/{openaiContentGenerator-5PLHYJQL.js → openaiContentGenerator-7CA63X5G.js} +5 -5
  52. package/chunks/{qwenContentGenerator-TSKW73KY.js → qwenContentGenerator-4WJTJXFZ.js} +7 -7
  53. package/chunks/{read-file-VIPF2PS6.js → read-file-EUIHK6HD.js} +3 -3
  54. package/chunks/{ripGrep-XLIZTYE7.js → ripGrep-7J5B22W2.js} +5 -5
  55. package/chunks/{scheduler-O66SLJGU.js → scheduler-J3OUGTTS.js} +5 -5
  56. package/chunks/{send-message-CTME7DXD.js → send-message-QZOC5GA2.js} +1 -1
  57. package/chunks/{serve-BWOLYT62.js → serve-VF4ZNUJP.js} +709 -26
  58. package/chunks/{shell-XE7UYKOO.js → shell-G6XCJAG3.js} +5 -5
  59. package/chunks/{skill-RZWM6XMC.js → skill-7OVC6JIH.js} +3 -3
  60. package/chunks/{src-L5P7K4MH.js → src-XV5MLRND.js} +11 -5
  61. package/chunks/{syntheticOutput-ZJGSU7OQ.js → syntheticOutput-WJSUK4SZ.js} +2 -2
  62. package/chunks/{task-create-EE6JEM7G.js → task-create-GGSC27HO.js} +2 -2
  63. package/chunks/{task-list-EESYAC65.js → task-list-EDHHHSK4.js} +1 -1
  64. package/chunks/{task-stop-XZVCFFYY.js → task-stop-WR5PDVZY.js} +1 -1
  65. package/chunks/{task-update-EIO4HNE3.js → task-update-UR7NUHBV.js} +2 -2
  66. package/chunks/{team-create-R2H7Y3SG.js → team-create-JXSC7ROC.js} +5 -5
  67. package/chunks/{team-delete-A7LXPGV7.js → team-delete-FC33URJK.js} +1 -1
  68. package/chunks/{todoWrite-VRKSGAWM.js → todoWrite-GO2ME7ZV.js} +1 -1
  69. package/chunks/{tool-search-USSQMTMS.js → tool-search-YRWSWA2H.js} +3 -3
  70. package/chunks/{web-fetch-GHAZUA54.js → web-fetch-NLLATYIL.js} +2 -2
  71. package/chunks/{workflow-5LNNLNUR.js → workflow-ZN3DYFMU.js} +249 -24
  72. package/chunks/{write-file-2I7HP24C.js → write-file-355M4V7Z.js} +6 -6
  73. package/cli.js +1092 -491
  74. package/package.json +2 -2
@@ -22,6 +22,7 @@ import {
22
22
  InvalidSessionMetadataError,
23
23
  InvalidSessionScopeError,
24
24
  MAX_WORKSPACE_PATH_LENGTH,
25
+ MID_TURN_QUEUE_DRAIN_METHOD,
25
26
  McpServerNotFoundError,
26
27
  McpServerRestartFailedError,
27
28
  MissingCliEntryError,
@@ -65,7 +66,7 @@ import {
65
66
  loadSettings,
66
67
  mapDomainErrorToErrorKind,
67
68
  reloadEnvironment
68
- } from "./chunk-BXYRCW2C.js";
69
+ } from "./chunk-QFJ67S5R.js";
69
70
  import {
70
71
  ClientSideConnection,
71
72
  PROTOCOL_VERSION,
@@ -76,7 +77,7 @@ import {
76
77
  SUPPORTED_LANGUAGES,
77
78
  writeStderrLine,
78
79
  writeStdoutLine
79
- } from "./chunk-XZTNBSMW.js";
80
+ } from "./chunk-M7OBURJM.js";
80
81
  import {
81
82
  ALL_PROVIDERS,
82
83
  APPROVAL_MODES,
@@ -107,9 +108,9 @@ import {
107
108
  resolveBaseUrl,
108
109
  shouldShowStep,
109
110
  writeWorkspaceContextFile
110
- } from "./chunk-6T7Y7USE.js";
111
+ } from "./chunk-EQ5NHJBY.js";
111
112
  import "./chunk-K5PGHDBN.js";
112
- import "./chunk-HQUWWSSP.js";
113
+ import "./chunk-VIEIRAK3.js";
113
114
  import "./chunk-O4PICXES.js";
114
115
  import "./chunk-TW522KN6.js";
115
116
  import "./chunk-BJ5HQ23U.js";
@@ -153,14 +154,14 @@ import {
153
154
  resolveTelemetrySettings,
154
155
  shutdownTelemetry,
155
156
  withDaemonRequestSpan
156
- } from "./chunk-RON7LFNH.js";
157
+ } from "./chunk-25FFAMED.js";
157
158
  import "./chunk-3PJXIDKI.js";
158
159
  import "./chunk-UWCTAVOD.js";
159
160
  import "./chunk-OFEVLU4C.js";
160
161
  import "./chunk-IQHSD7K5.js";
161
162
  import "./chunk-LYRSMKLS.js";
162
- import "./chunk-QILTEBWS.js";
163
- import "./chunk-A2ZIEEGJ.js";
163
+ import "./chunk-RTTAC5VW.js";
164
+ import "./chunk-ZNUMXPNK.js";
164
165
  import {
165
166
  QwenOAuth2Client,
166
167
  QwenOAuthPollError,
@@ -17129,9 +17130,6 @@ var MultiClientPermissionMediator = class {
17129
17130
  }
17130
17131
  };
17131
17132
 
17132
- // packages/acp-bridge/src/bridgeTypes.ts
17133
- init_esbuild_shims();
17134
-
17135
17133
  // packages/acp-bridge/src/bridgeOptions.ts
17136
17134
  init_esbuild_shims();
17137
17135
 
@@ -17409,6 +17407,7 @@ function sliceLineRange(content, startLine, endLine) {
17409
17407
  return content.slice(offset, end > offset ? end - 1 : end);
17410
17408
  }
17411
17409
  __name(sliceLineRange, "sliceLineRange");
17410
+ var MID_TURN_MESSAGE_INJECTED_EVENT = "mid_turn_message_injected";
17412
17411
  var BridgeClient = class {
17413
17412
  constructor(resolveEntry, resolvePendingRestoreEvents, mediator, permissionTimeoutMs, maxPendingPerSession, fileSystem, onModelPromoted, onModePromoted) {
17414
17413
  this.resolveEntry = resolveEntry;
@@ -17551,6 +17550,49 @@ var BridgeClient = class {
17551
17550
  * call and exits on settle (success or failure).
17552
17551
  */
17553
17552
  inFlightRestoreIds = /* @__PURE__ */ new Set();
17553
+ /**
17554
+ * Handle child->bridge ACP `extMethod` requests (calls that expect a
17555
+ * response, unlike `extNotification`). The only method served today is
17556
+ * `craft/drainMidTurnQueue`: the ACP child calls it between tool batches to
17557
+ * pull any messages the browser queued mid-turn. We splice the per-session
17558
+ * queue, return them to the child as the response, and — when non-empty —
17559
+ * publish a `mid_turn_message_injected` SSE frame so the browser can move
17560
+ * those messages out of its pending queue (a dedupe signal, not a transcript
17561
+ * render). Unknown methods reject with ACP `methodNotFound` (-32601), matching
17562
+ * the SDK's
17563
+ * default for an unimplemented client surface; the child's drain caller
17564
+ * treats that as "drain unsupported" and stops asking.
17565
+ */
17566
+ async extMethod(method, params) {
17567
+ if (method !== MID_TURN_QUEUE_DRAIN_METHOD) {
17568
+ throw RequestError.methodNotFound(method);
17569
+ }
17570
+ const sessionId = typeof params["sessionId"] === "string" ? params["sessionId"] : void 0;
17571
+ if (!sessionId) return { messages: [] };
17572
+ const entry = this.resolveEntry(sessionId);
17573
+ if (!entry) return { messages: [] };
17574
+ const drained = entry.midTurnMessageQueue.splice(0);
17575
+ const messages = drained.map((item) => item.text);
17576
+ if (drained.length > 0) {
17577
+ const byOriginator = /* @__PURE__ */ new Map();
17578
+ for (const item of drained) {
17579
+ const group = byOriginator.get(item.originatorClientId);
17580
+ if (group) group.push(item.text);
17581
+ else byOriginator.set(item.originatorClientId, [item.text]);
17582
+ }
17583
+ for (const [originatorClientId, texts] of byOriginator) {
17584
+ const published = entry.events.publish({
17585
+ type: MID_TURN_MESSAGE_INJECTED_EVENT,
17586
+ data: { sessionId: entry.sessionId, messages: texts },
17587
+ ...originatorClientId ? { originatorClientId } : {}
17588
+ });
17589
+ writeStderrLine2(
17590
+ published ? `[mid-turn] session=${entry.sessionId} drained=${texts.length}${originatorClientId ? ` originator=${originatorClientId}` : ""} injected into running turn` : `[mid-turn] session=${entry.sessionId} drained=${texts.length} echo frame dropped (bus closed); browser may resend next turn`
17591
+ );
17592
+ }
17593
+ }
17594
+ return { messages };
17595
+ }
17554
17596
  /**
17555
17597
  * Handle child->bridge ACP `extNotification` calls. Six methods are
17556
17598
  * recognized — `qwen/notify/session/model-update`,
@@ -18540,6 +18582,7 @@ var SESSION_RECAP_TIMEOUT_MS = 6e4;
18540
18582
  var SESSION_BTW_TIMEOUT_MS = 6e4;
18541
18583
  var SHELL_COMMAND_TIMEOUT_MS = 12e4;
18542
18584
  var MAX_SHELL_OUTPUT_FOR_HISTORY = 1e4;
18585
+ var MAX_MID_TURN_QUEUE_DEPTH = 20;
18543
18586
  var DEFAULT_MAX_SESSIONS = 20;
18544
18587
  var DEFAULT_MAX_PENDING_PROMPTS_PER_SESSION = 5;
18545
18588
  var MAX_EVENT_RING_SIZE = 1e6;
@@ -19263,6 +19306,7 @@ function createAcpSessionBridge(opts) {
19263
19306
  events,
19264
19307
  promptQueue: Promise.resolve(),
19265
19308
  pendingPromptCount: 0,
19309
+ midTurnMessageQueue: [],
19266
19310
  modelChangeQueue: Promise.resolve(),
19267
19311
  approvalModeQueue: Promise.resolve(),
19268
19312
  modelPublishGeneration: 0,
@@ -19566,6 +19610,37 @@ function createAcpSessionBridge(opts) {
19566
19610
  __name(closeSessionImpl, "closeSessionImpl");
19567
19611
  startSessionReaper();
19568
19612
  return {
19613
+ getDaemonStatusSnapshot() {
19614
+ return {
19615
+ limits: {
19616
+ maxSessions: maxSessions === Infinity ? null : maxSessions,
19617
+ maxPendingPromptsPerSession: maxPendingPromptsPerSession === Infinity ? null : maxPendingPromptsPerSession,
19618
+ eventRingSize,
19619
+ channelIdleTimeoutMs: resolvedChannelIdleTimeoutMs(),
19620
+ sessionIdleTimeoutMs
19621
+ },
19622
+ sessionCount: byId.size,
19623
+ pendingPermissionCount: permissionMediator.pendingCount,
19624
+ channelLive: !!liveChannelInfo(),
19625
+ permissionPolicy: permissionMediator.policy,
19626
+ sessions: [...byId.values()].map((entry) => ({
19627
+ sessionId: entry.sessionId,
19628
+ workspaceCwd: entry.workspaceCwd,
19629
+ createdAt: entry.createdAt,
19630
+ ...entry.displayName ? { displayName: entry.displayName } : {},
19631
+ clientCount: entry.clientIds.size,
19632
+ subscriberCount: entry.events.subscriberCount,
19633
+ attachCount: entry.attachCount,
19634
+ pendingPromptCount: entry.pendingPromptCount,
19635
+ pendingPermissionCount: entry.pendingPermissionIds.size,
19636
+ hasActivePrompt: entry.promptActive,
19637
+ lastEventId: entry.events.lastEventId,
19638
+ ...entry.sessionLastSeenAt !== void 0 ? { lastSeenAt: entry.sessionLastSeenAt } : {},
19639
+ ...entry.currentModelId ? { currentModelId: entry.currentModelId } : {},
19640
+ ...entry.currentApprovalMode ? { currentApprovalMode: entry.currentApprovalMode } : {}
19641
+ }))
19642
+ };
19643
+ },
19569
19644
  get sessionCount() {
19570
19645
  return byId.size;
19571
19646
  },
@@ -19840,7 +19915,15 @@ function createAcpSessionBridge(opts) {
19840
19915
  () => void 0,
19841
19916
  () => void 0
19842
19917
  );
19843
- result.finally(releasePromptSlot).catch(() => {
19918
+ result.finally(() => {
19919
+ releasePromptSlot();
19920
+ if (entry.pendingPromptCount === 0 && entry.midTurnMessageQueue.length > 0) {
19921
+ writeStderrLine2(
19922
+ `[mid-turn] session=${entry.sessionId} dropped ${entry.midTurnMessageQueue.length} undrained message(s) at idle; browser resends next turn`
19923
+ );
19924
+ entry.midTurnMessageQueue.length = 0;
19925
+ }
19926
+ }).catch(() => {
19844
19927
  });
19845
19928
  return result;
19846
19929
  },
@@ -20545,6 +20628,29 @@ function createAcpSessionBridge(opts) {
20545
20628
  recap: response.recap ?? null
20546
20629
  };
20547
20630
  },
20631
+ enqueueMidTurnMessage(sessionId, message, context) {
20632
+ const entry = byId.get(sessionId);
20633
+ if (!entry) throw new SessionNotFoundError(sessionId);
20634
+ const originatorClientId = resolveTrustedClientId(
20635
+ entry,
20636
+ context?.clientId
20637
+ );
20638
+ const trimmed = message.trim();
20639
+ if (trimmed.length === 0 || entry.pendingPromptCount === 0) {
20640
+ writeStderrLine2(
20641
+ `[mid-turn] session=${entry.sessionId} rejected: ${trimmed.length === 0 ? "empty message" : "session idle"}; browser keeps it for next turn`
20642
+ );
20643
+ return { accepted: false };
20644
+ }
20645
+ if (entry.midTurnMessageQueue.length >= MAX_MID_TURN_QUEUE_DEPTH) {
20646
+ writeStderrLine2(
20647
+ `[mid-turn] session=${entry.sessionId} rejected: queue full (depth ${entry.midTurnMessageQueue.length} >= ${MAX_MID_TURN_QUEUE_DEPTH}); browser keeps it for next turn`
20648
+ );
20649
+ return { accepted: false };
20650
+ }
20651
+ entry.midTurnMessageQueue.push({ text: trimmed, originatorClientId });
20652
+ return { accepted: true };
20653
+ },
20548
20654
  async generateSessionBtw(sessionId, question, signal, _context) {
20549
20655
  const entry = byId.get(sessionId);
20550
20656
  if (!entry) throw new SessionNotFoundError(sessionId);
@@ -25222,6 +25328,43 @@ var AcpConnection = class {
25222
25328
  }
25223
25329
  return binding;
25224
25330
  }
25331
+ getDiagnostic() {
25332
+ const liveStreams = /* @__PURE__ */ new Set();
25333
+ if (this.connStream && !this.connStream.isClosed) {
25334
+ liveStreams.add(this.connStream);
25335
+ }
25336
+ let sessionStreams = 0;
25337
+ let bufferedSessionFrames = 0;
25338
+ for (const binding of this.sessions.values()) {
25339
+ bufferedSessionFrames += binding.buffer.length;
25340
+ if (binding.stream && !binding.stream.isClosed) {
25341
+ sessionStreams += 1;
25342
+ liveStreams.add(binding.stream);
25343
+ }
25344
+ }
25345
+ let sseStreams = 0;
25346
+ let wsStreams = 0;
25347
+ for (const stream of liveStreams) {
25348
+ if (stream.kind === "sse") sseStreams += 1;
25349
+ if (stream.kind === "ws") wsStreams += 1;
25350
+ }
25351
+ return {
25352
+ connectionIdPrefix: this.connectionId.slice(0, 8),
25353
+ fromLoopback: this.fromLoopback,
25354
+ destroyed: this.destroyed,
25355
+ lastActiveMs: this.lastActiveMs,
25356
+ ownedSessionCount: this.ownedSessions.size,
25357
+ sessionBindingCount: this.sessions.size,
25358
+ closingSessionCount: this.closingSessions.size,
25359
+ pendingClientRequests: this.pending.size,
25360
+ connectionStreamOpen: this.connStream !== void 0 && !this.connStream.isClosed,
25361
+ sessionStreams,
25362
+ sseStreams,
25363
+ wsStreams,
25364
+ bufferedConnectionFrames: this.connBuffer.length,
25365
+ bufferedSessionFrames
25366
+ };
25367
+ }
25225
25368
  /** Send a frame on the connection-scoped stream (buffer until it attaches). */
25226
25369
  sendConn(frame) {
25227
25370
  if (this.connStream && !this.connStream.isClosed) {
@@ -25403,6 +25546,24 @@ var ConnectionRegistry = class {
25403
25546
  get connectionCap() {
25404
25547
  return this.maxConnections;
25405
25548
  }
25549
+ getSnapshot() {
25550
+ const connections = [...this.byId.values()].map(
25551
+ (conn) => conn.getDiagnostic()
25552
+ );
25553
+ return {
25554
+ connectionCount: this.byId.size,
25555
+ connectionCap: this.maxConnections > 0 && Number.isFinite(this.maxConnections) ? this.maxConnections : null,
25556
+ connectionStreams: connections.filter((conn) => conn.connectionStreamOpen).length,
25557
+ sessionStreams: sumBy(connections, (conn) => conn.sessionStreams),
25558
+ sseStreams: sumBy(connections, (conn) => conn.sseStreams),
25559
+ wsStreams: sumBy(connections, (conn) => conn.wsStreams),
25560
+ pendingClientRequests: sumBy(
25561
+ connections,
25562
+ (conn) => conn.pendingClientRequests
25563
+ ),
25564
+ connections
25565
+ };
25566
+ }
25406
25567
  dispose() {
25407
25568
  clearInterval(this.sweepTimer);
25408
25569
  for (const id of [...this.byId.keys()]) this.delete(id);
@@ -25418,6 +25579,12 @@ var ConnectionRegistry = class {
25418
25579
  }
25419
25580
  }
25420
25581
  };
25582
+ function sumBy(values, select) {
25583
+ let total = 0;
25584
+ for (const value of values) total += select(value);
25585
+ return total;
25586
+ }
25587
+ __name(sumBy, "sumBy");
25421
25588
 
25422
25589
  // packages/cli/src/serve/acpHttp/sseStream.ts
25423
25590
  init_esbuild_shims();
@@ -25430,6 +25597,7 @@ var SseStream = class {
25430
25597
  static {
25431
25598
  __name(this, "SseStream");
25432
25599
  }
25600
+ kind = "sse";
25433
25601
  writeChain = Promise.resolve();
25434
25602
  heartbeat;
25435
25603
  closed = false;
@@ -25576,6 +25744,7 @@ var WsStream = class {
25576
25744
  static {
25577
25745
  __name(this, "WsStream");
25578
25746
  }
25747
+ kind = "ws";
25579
25748
  writeChain = Promise.resolve();
25580
25749
  _closed = false;
25581
25750
  heartbeat;
@@ -26170,6 +26339,439 @@ function isLoopbackReq(req) {
26170
26339
  }
26171
26340
  __name(isLoopbackReq, "isLoopbackReq");
26172
26341
 
26342
+ // packages/cli/src/serve/daemonStatus.ts
26343
+ init_esbuild_shims();
26344
+ var DEFAULT_LISTENER_MAX_CONNECTIONS = 256;
26345
+ var SECTION_TIMEOUT_MS = 1e3;
26346
+ var CAPACITY_WARNING_RATIO = 0.8;
26347
+ var SectionTimeoutError = class extends Error {
26348
+ constructor(section, timeoutMs) {
26349
+ super(`${section} status timed out after ${timeoutMs}ms`);
26350
+ this.section = section;
26351
+ this.timeoutMs = timeoutMs;
26352
+ this.name = "SectionTimeoutError";
26353
+ }
26354
+ static {
26355
+ __name(this, "SectionTimeoutError");
26356
+ }
26357
+ };
26358
+ function parseDaemonStatusDetail(raw) {
26359
+ if (raw === void 0) return { ok: true, detail: "summary" };
26360
+ if (raw === "summary" || raw === "full") {
26361
+ return { ok: true, detail: raw };
26362
+ }
26363
+ return { ok: false };
26364
+ }
26365
+ __name(parseDaemonStatusDetail, "parseDaemonStatusDetail");
26366
+ async function buildDaemonStatusResponse(detail, input) {
26367
+ const bridgeSnapshot = input.bridge.getDaemonStatusSnapshot();
26368
+ const acpSnapshot = input.acpHandle?.registry.getSnapshot();
26369
+ const rateLimitHits = input.rateLimiter?.getHitCounts() ?? zeroRateHits();
26370
+ const issues = [];
26371
+ let full;
26372
+ pushRuntimeIssues(issues, bridgeSnapshot, acpSnapshot, rateLimitHits, input);
26373
+ if (detail === "full") {
26374
+ full = await buildFullStatus(input, bridgeSnapshot, acpSnapshot);
26375
+ pushFullIssues(issues, full);
26376
+ }
26377
+ return {
26378
+ v: 1,
26379
+ detail,
26380
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
26381
+ status: rollupStatus(issues),
26382
+ issues,
26383
+ daemon: {
26384
+ pid: process.pid,
26385
+ uptimeMs: Math.round(process.uptime() * 1e3),
26386
+ mode: input.opts.mode,
26387
+ workspaceCwd: input.boundWorkspace,
26388
+ ...input.qwenCodeVersion ? { qwenCodeVersion: input.qwenCodeVersion } : {},
26389
+ ...input.daemonLog?.getDaemonId() ? { daemonId: input.daemonLog.getDaemonId() } : {},
26390
+ ...detail === "full" && input.daemonLog?.getLogPath() ? { logPath: input.daemonLog.getLogPath() } : {}
26391
+ },
26392
+ security: {
26393
+ tokenConfigured: Boolean(input.opts.token),
26394
+ requireAuth: input.opts.requireAuth === true,
26395
+ loopbackBind: isLoopbackBind(input.opts.hostname),
26396
+ allowOriginConfigured: input.opts.allowOrigins !== void 0 && input.opts.allowOrigins.length > 0,
26397
+ allowOriginMode: allowOriginMode(input.opts.allowOrigins),
26398
+ sessionShellCommandEnabled: input.sessionShellCommandEnabled
26399
+ },
26400
+ limits: {
26401
+ maxSessions: bridgeSnapshot.limits.maxSessions,
26402
+ maxPendingPromptsPerSession: bridgeSnapshot.limits.maxPendingPromptsPerSession,
26403
+ listenerMaxConnections: listenerMaxConnections(input.opts.maxConnections),
26404
+ eventRingSize: bridgeSnapshot.limits.eventRingSize,
26405
+ promptDeadlineMs: positiveFiniteOrNull(input.opts.promptDeadlineMs),
26406
+ writerIdleTimeoutMs: positiveFiniteOrNull(input.opts.writerIdleTimeoutMs),
26407
+ channelIdleTimeoutMs: bridgeSnapshot.limits.channelIdleTimeoutMs,
26408
+ sessionIdleTimeoutMs: bridgeSnapshot.limits.sessionIdleTimeoutMs,
26409
+ acpConnectionCap: acpSnapshot?.connectionCap ?? null
26410
+ },
26411
+ capabilities: {
26412
+ protocolVersions: input.protocolVersions,
26413
+ features: [...input.features]
26414
+ },
26415
+ runtime: {
26416
+ sessions: { active: bridgeSnapshot.sessionCount },
26417
+ permissions: {
26418
+ pending: bridgeSnapshot.pendingPermissionCount,
26419
+ policy: bridgeSnapshot.permissionPolicy
26420
+ },
26421
+ channel: { live: bridgeSnapshot.channelLive },
26422
+ transport: {
26423
+ restSseActive: input.getRestSseActive(),
26424
+ acp: {
26425
+ enabled: acpSnapshot !== void 0,
26426
+ connections: acpSnapshot?.connectionCount ?? 0,
26427
+ connectionStreams: acpSnapshot?.connectionStreams ?? 0,
26428
+ sessionStreams: acpSnapshot?.sessionStreams ?? 0,
26429
+ sseStreams: acpSnapshot?.sseStreams ?? 0,
26430
+ wsStreams: acpSnapshot?.wsStreams ?? 0,
26431
+ pendingClientRequests: acpSnapshot?.pendingClientRequests ?? 0
26432
+ }
26433
+ },
26434
+ rateLimit: {
26435
+ enabled: input.opts.rateLimit === true,
26436
+ rejectedSinceStart: rateLimitHits
26437
+ },
26438
+ process: process.memoryUsage()
26439
+ },
26440
+ ...full ? { full } : {}
26441
+ };
26442
+ }
26443
+ __name(buildDaemonStatusResponse, "buildDaemonStatusResponse");
26444
+ async function buildFullStatus(input, bridgeSnapshot, acpSnapshot) {
26445
+ const ctx = {
26446
+ route: "GET /daemon/status",
26447
+ workspaceCwd: input.boundWorkspace
26448
+ };
26449
+ const [mcp, skills, tools, providers, env, preflight, hooks, extensions] = await Promise.all([
26450
+ collectSection(
26451
+ "workspace.mcp",
26452
+ () => input.workspace.getWorkspaceMcpStatus(ctx)
26453
+ ),
26454
+ collectSection(
26455
+ "workspace.skills",
26456
+ () => input.workspace.getWorkspaceSkillsStatus(ctx)
26457
+ ),
26458
+ collectSection(
26459
+ "workspace.tools",
26460
+ () => input.bridge.getWorkspaceToolsStatus()
26461
+ ),
26462
+ collectSection(
26463
+ "workspace.providers",
26464
+ () => input.workspace.getWorkspaceProvidersStatus(ctx)
26465
+ ),
26466
+ collectSection(
26467
+ "workspace.env",
26468
+ () => input.workspace.getWorkspaceEnvStatus(ctx)
26469
+ ),
26470
+ collectSection(
26471
+ "workspace.preflight",
26472
+ () => input.workspace.getWorkspacePreflightStatus(ctx)
26473
+ ),
26474
+ collectSection(
26475
+ "workspace.hooks",
26476
+ () => input.workspace.getWorkspaceHooksStatus(ctx)
26477
+ ),
26478
+ collectSection(
26479
+ "workspace.extensions",
26480
+ () => input.workspace.getWorkspaceExtensionsStatus(ctx)
26481
+ )
26482
+ ]);
26483
+ return {
26484
+ sessions: bridgeSnapshot.sessions,
26485
+ acpConnections: acpSnapshot?.connections ?? [],
26486
+ workspace: {
26487
+ mcp,
26488
+ skills,
26489
+ tools,
26490
+ providers,
26491
+ env,
26492
+ preflight,
26493
+ hooks,
26494
+ extensions
26495
+ },
26496
+ auth: {
26497
+ supportedDeviceFlowProviders: [...input.supportedDeviceFlowProviders],
26498
+ pendingDeviceFlowCount: input.deviceFlowRegistry.listPending().length
26499
+ }
26500
+ };
26501
+ }
26502
+ __name(buildFullStatus, "buildFullStatus");
26503
+ async function collectSection(name, read) {
26504
+ const startMs = Date.now();
26505
+ try {
26506
+ const data = await withTimeout2(read(), name, SECTION_TIMEOUT_MS);
26507
+ return {
26508
+ status: inferSectionStatus(data),
26509
+ durationMs: Date.now() - startMs,
26510
+ summary: summarizeStatusData(data),
26511
+ data
26512
+ };
26513
+ } catch (err) {
26514
+ return {
26515
+ status: "unavailable",
26516
+ durationMs: Date.now() - startMs,
26517
+ error: {
26518
+ kind: err instanceof SectionTimeoutError ? "timeout" : "error",
26519
+ message: err instanceof Error ? err.message : String(err)
26520
+ }
26521
+ };
26522
+ }
26523
+ }
26524
+ __name(collectSection, "collectSection");
26525
+ async function withTimeout2(promise, section, timeoutMs) {
26526
+ let timer;
26527
+ try {
26528
+ return await Promise.race([
26529
+ promise,
26530
+ new Promise((_resolve, reject) => {
26531
+ timer = setTimeout(
26532
+ () => reject(new SectionTimeoutError(section, timeoutMs)),
26533
+ timeoutMs
26534
+ );
26535
+ })
26536
+ ]);
26537
+ } finally {
26538
+ if (timer) clearTimeout(timer);
26539
+ }
26540
+ }
26541
+ __name(withTimeout2, "withTimeout");
26542
+ function pushRuntimeIssues(issues, bridgeSnapshot, acpSnapshot, rateLimitHits, input) {
26543
+ if (bridgeSnapshot.limits.maxSessions !== null && bridgeSnapshot.limits.maxSessions > 0 && bridgeSnapshot.sessionCount / bridgeSnapshot.limits.maxSessions >= CAPACITY_WARNING_RATIO) {
26544
+ issues.push({
26545
+ code: "session_capacity_high",
26546
+ severity: "warning",
26547
+ message: `Active sessions are at ${bridgeSnapshot.sessionCount}/${bridgeSnapshot.limits.maxSessions}.`
26548
+ });
26549
+ }
26550
+ if (acpSnapshot !== void 0 && acpSnapshot.connectionCap !== null && acpSnapshot.connectionCap > 0 && acpSnapshot.connectionCount / acpSnapshot.connectionCap >= CAPACITY_WARNING_RATIO) {
26551
+ issues.push({
26552
+ code: "connection_capacity_high",
26553
+ severity: "warning",
26554
+ message: `ACP connections are at ${acpSnapshot.connectionCount}/${acpSnapshot.connectionCap}.`
26555
+ });
26556
+ }
26557
+ if (bridgeSnapshot.pendingPermissionCount > 0) {
26558
+ issues.push({
26559
+ code: "pending_permissions",
26560
+ severity: "warning",
26561
+ message: `${bridgeSnapshot.pendingPermissionCount} permission request(s) are pending.`
26562
+ });
26563
+ }
26564
+ if (bridgeSnapshot.sessionCount > 0 && !bridgeSnapshot.channelLive) {
26565
+ issues.push({
26566
+ code: "acp_channel_down",
26567
+ severity: "error",
26568
+ message: "Active sessions exist but the ACP channel is not live."
26569
+ });
26570
+ }
26571
+ if (input.opts.rateLimit === true && sumRateHits(rateLimitHits) > 0) {
26572
+ issues.push({
26573
+ code: "rate_limit_hits",
26574
+ severity: "warning",
26575
+ message: `${sumRateHits(rateLimitHits)} request(s) have been rejected by rate limiting since start.`
26576
+ });
26577
+ }
26578
+ }
26579
+ __name(pushRuntimeIssues, "pushRuntimeIssues");
26580
+ function pushFullIssues(issues, full) {
26581
+ for (const [name, section] of Object.entries(full.workspace)) {
26582
+ if (section.status === "unavailable") {
26583
+ issues.push({
26584
+ code: "workspace_status_unavailable",
26585
+ severity: "warning",
26586
+ section: name,
26587
+ message: `${name} status is unavailable.`
26588
+ });
26589
+ }
26590
+ }
26591
+ const preflight = full.workspace["preflight"];
26592
+ if (preflight && sectionHasStatus(preflight, "error")) {
26593
+ issues.push({
26594
+ code: "preflight_error",
26595
+ severity: "error",
26596
+ section: "preflight",
26597
+ message: "Workspace preflight reports an error."
26598
+ });
26599
+ }
26600
+ const mcp = full.workspace["mcp"];
26601
+ const mcpBudget = mcp ? inspectMcpBudget(mcp) : void 0;
26602
+ if (mcpBudget === "exhausted") {
26603
+ issues.push({
26604
+ code: "mcp_budget_exhausted",
26605
+ severity: "error",
26606
+ section: "mcp",
26607
+ message: "MCP client budget is exhausted."
26608
+ });
26609
+ } else if (mcpBudget === "warning") {
26610
+ issues.push({
26611
+ code: "mcp_budget_warning",
26612
+ severity: "warning",
26613
+ section: "mcp",
26614
+ message: "MCP client budget is near capacity."
26615
+ });
26616
+ }
26617
+ }
26618
+ __name(pushFullIssues, "pushFullIssues");
26619
+ function inferSectionStatus(data) {
26620
+ const statuses = collectStatuses(data);
26621
+ if (statuses.includes("error")) return "error";
26622
+ if (statuses.includes("warning")) return "warning";
26623
+ return "ok";
26624
+ }
26625
+ __name(inferSectionStatus, "inferSectionStatus");
26626
+ function summarizeStatusData(data) {
26627
+ const summary = {};
26628
+ if (!isRecord(data)) return summary;
26629
+ copyBoolean(data, summary, "initialized");
26630
+ copyBoolean(data, summary, "acpChannelLive");
26631
+ copyString(data, summary, "discoveryState");
26632
+ copyString(data, summary, "budgetMode");
26633
+ copyNumber(data, summary, "clientCount");
26634
+ copyNumber(data, summary, "clientBudget");
26635
+ for (const key of [
26636
+ "cells",
26637
+ "errors",
26638
+ "servers",
26639
+ "budgets",
26640
+ "skills",
26641
+ "tools",
26642
+ "providers",
26643
+ "hooks",
26644
+ "extensions"
26645
+ ]) {
26646
+ const value = data[key];
26647
+ if (Array.isArray(value)) {
26648
+ summary[`${key}Count`] = value.length;
26649
+ }
26650
+ }
26651
+ return summary;
26652
+ }
26653
+ __name(summarizeStatusData, "summarizeStatusData");
26654
+ function collectStatuses(data) {
26655
+ const statuses = [];
26656
+ visitStatusContainers(data, (record) => {
26657
+ const status = record["status"];
26658
+ if (typeof status === "string") statuses.push(status);
26659
+ });
26660
+ return statuses;
26661
+ }
26662
+ __name(collectStatuses, "collectStatuses");
26663
+ function sectionHasStatus(section, status) {
26664
+ return collectStatuses(section.data).includes(status);
26665
+ }
26666
+ __name(sectionHasStatus, "sectionHasStatus");
26667
+ function inspectMcpBudget(section) {
26668
+ const data = section.data;
26669
+ if (!isRecord(data)) return void 0;
26670
+ const budgetIssue = inspectBudgetContainers(data);
26671
+ if (budgetIssue) return budgetIssue;
26672
+ const clientCount = numberValue(data["clientCount"]);
26673
+ const clientBudget = numberValue(data["clientBudget"]);
26674
+ if (clientCount !== void 0 && clientBudget !== void 0 && clientBudget > 0) {
26675
+ const ratio = clientCount / clientBudget;
26676
+ if (ratio >= 1) return "exhausted";
26677
+ if (ratio >= 0.75) return "warning";
26678
+ }
26679
+ return void 0;
26680
+ }
26681
+ __name(inspectMcpBudget, "inspectMcpBudget");
26682
+ function inspectBudgetContainers(data) {
26683
+ let result;
26684
+ visitStatusContainers(data, (record) => {
26685
+ if (result === "exhausted") return;
26686
+ const errorKind = record["errorKind"];
26687
+ const disabledReason = record["disabledReason"];
26688
+ const status = record["status"];
26689
+ const kind = record["kind"];
26690
+ const refusedCount = numberValue(record["refusedCount"]);
26691
+ if (errorKind === "budget_exhausted" || disabledReason === "budget" || kind === "mcp_budget" && status === "error" || refusedCount !== void 0 && refusedCount > 0) {
26692
+ result = "exhausted";
26693
+ return;
26694
+ }
26695
+ if (kind === "mcp_budget" && status === "warning") {
26696
+ result = "warning";
26697
+ }
26698
+ });
26699
+ return result;
26700
+ }
26701
+ __name(inspectBudgetContainers, "inspectBudgetContainers");
26702
+ function visitStatusContainers(data, visit) {
26703
+ if (!isRecord(data)) return;
26704
+ visit(data);
26705
+ for (const key of [
26706
+ "cells",
26707
+ "errors",
26708
+ "servers",
26709
+ "budgets",
26710
+ "skills",
26711
+ "tools",
26712
+ "providers",
26713
+ "hooks",
26714
+ "extensions"
26715
+ ]) {
26716
+ const value = data[key];
26717
+ if (!Array.isArray(value)) continue;
26718
+ for (const item of value) visitStatusContainers(item, visit);
26719
+ }
26720
+ }
26721
+ __name(visitStatusContainers, "visitStatusContainers");
26722
+ function rollupStatus(issues) {
26723
+ if (issues.some((issue) => issue.severity === "error")) return "error";
26724
+ if (issues.length > 0) return "warning";
26725
+ return "ok";
26726
+ }
26727
+ __name(rollupStatus, "rollupStatus");
26728
+ function allowOriginMode(allowOrigins) {
26729
+ if (!allowOrigins || allowOrigins.length === 0) return "none";
26730
+ return allowOrigins.includes("*") ? "any" : "specific";
26731
+ }
26732
+ __name(allowOriginMode, "allowOriginMode");
26733
+ function listenerMaxConnections(value) {
26734
+ if (value === void 0) return DEFAULT_LISTENER_MAX_CONNECTIONS;
26735
+ if (value === 0 || value === Infinity) return null;
26736
+ return Number.isFinite(value) && value > 0 ? value : null;
26737
+ }
26738
+ __name(listenerMaxConnections, "listenerMaxConnections");
26739
+ function positiveFiniteOrNull(value) {
26740
+ return value !== void 0 && Number.isFinite(value) && value > 0 ? value : null;
26741
+ }
26742
+ __name(positiveFiniteOrNull, "positiveFiniteOrNull");
26743
+ function zeroRateHits() {
26744
+ return { prompt: 0, mutation: 0, read: 0 };
26745
+ }
26746
+ __name(zeroRateHits, "zeroRateHits");
26747
+ function sumRateHits(hits) {
26748
+ return hits.prompt + hits.mutation + hits.read;
26749
+ }
26750
+ __name(sumRateHits, "sumRateHits");
26751
+ function isRecord(value) {
26752
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26753
+ }
26754
+ __name(isRecord, "isRecord");
26755
+ function numberValue(value) {
26756
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
26757
+ }
26758
+ __name(numberValue, "numberValue");
26759
+ function copyBoolean(from, to, key) {
26760
+ const value = from[key];
26761
+ if (typeof value === "boolean") to[key] = value;
26762
+ }
26763
+ __name(copyBoolean, "copyBoolean");
26764
+ function copyString(from, to, key) {
26765
+ const value = from[key];
26766
+ if (typeof value === "string") to[key] = value;
26767
+ }
26768
+ __name(copyString, "copyString");
26769
+ function copyNumber(from, to, key) {
26770
+ const value = numberValue(from[key]);
26771
+ if (value !== void 0) to[key] = value;
26772
+ }
26773
+ __name(copyNumber, "copyNumber");
26774
+
26173
26775
  // packages/cli/src/serve/capabilities.ts
26174
26776
  init_esbuild_shims();
26175
26777
  var SERVE_PROTOCOL_VERSION = "v1";
@@ -26178,6 +26780,7 @@ var SUPPORTED_SERVE_PROTOCOL_VERSIONS = [
26178
26780
  ];
26179
26781
  var SERVE_CAPABILITY_REGISTRY = {
26180
26782
  health: { since: "v1" },
26783
+ daemon_status: { since: "v1" },
26181
26784
  capabilities: { since: "v1" },
26182
26785
  session_create: { since: "v1" },
26183
26786
  session_scope_override: { since: "v1" },
@@ -30408,8 +31011,11 @@ function resolveDaemonTelemetryRoute(req) {
30408
31011
  if (req.method === "POST" && path14 === "/sessions/delete") {
30409
31012
  return { route: "POST /sessions/delete" };
30410
31013
  }
31014
+ if (req.method === "GET" && path14 === "/daemon/status") {
31015
+ return { route: "GET /daemon/status" };
31016
+ }
30411
31017
  const sessionAction = path14.match(
30412
- /^\/session\/([^/]+)\/(load|resume|prompt|cancel|recap|btw|model|shell|detach|rewind|approval-mode|language|a2ui-action)$/
31018
+ /^\/session\/([^/]+)\/(load|resume|prompt|cancel|recap|btw|mid-turn-message|model|shell|detach|rewind|approval-mode|language|a2ui-action)$/
30413
31019
  );
30414
31020
  const sessionActionId = sessionAction?.[1];
30415
31021
  const sessionActionName = sessionAction?.[2];
@@ -30815,23 +31421,65 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
30815
31421
  }
30816
31422
  __name(buildWorkspaceCtx, "buildWorkspaceCtx");
30817
31423
  const LANGUAGE_CODES = [...SUPPORTED_LANGUAGES.map((l) => l.code), "auto"];
31424
+ const currentServeFeatures = /* @__PURE__ */ __name(() => getAdvertisedServeFeatures(void 0, {
31425
+ requireAuth: opts.requireAuth === true,
31426
+ mcpPoolActive: opts.mcpPoolActive !== false,
31427
+ allowOriginActive: opts.allowOrigins !== void 0 && opts.allowOrigins.length > 0,
31428
+ ...opts.promptDeadlineMs !== void 0 ? { promptDeadlineMs: opts.promptDeadlineMs } : {},
31429
+ ...opts.writerIdleTimeoutMs !== void 0 ? { writerIdleTimeoutMs: opts.writerIdleTimeoutMs } : {},
31430
+ persistSettingAvailable: deps.persistSetting !== void 0,
31431
+ sessionShellCommandEnabled,
31432
+ rateLimit: opts.rateLimit === true,
31433
+ reloadAvailable: deps.workspace !== void 0
31434
+ }), "currentServeFeatures");
31435
+ const acpHandleRef = {};
31436
+ app.get("/daemon/status", async (req, res) => {
31437
+ const detail = parseDaemonStatusDetail(req.query["detail"]);
31438
+ if (!detail.ok || !detail.detail) {
31439
+ res.status(400).json({
31440
+ error: "detail must be one of: summary, full",
31441
+ code: "invalid_detail"
31442
+ });
31443
+ return;
31444
+ }
31445
+ try {
31446
+ res.status(200).json(
31447
+ await buildDaemonStatusResponse(detail.detail, {
31448
+ opts,
31449
+ boundWorkspace,
31450
+ bridge,
31451
+ workspace,
31452
+ daemonLog,
31453
+ qwenCodeVersion: deps.qwenCodeVersion,
31454
+ acpHandle: acpHandleRef.current,
31455
+ rateLimiter,
31456
+ getRestSseActive: getActiveSseCount,
31457
+ features: currentServeFeatures(),
31458
+ protocolVersions: getServeProtocolVersions(),
31459
+ supportedDeviceFlowProviders: Array.from(
31460
+ deviceFlowProviderMap.keys()
31461
+ ),
31462
+ deviceFlowRegistry,
31463
+ sessionShellCommandEnabled
31464
+ })
31465
+ );
31466
+ } catch (err) {
31467
+ writeStderrLine(
31468
+ `qwen serve: /daemon/status failed: ${err instanceof Error ? err.message : String(err)}`
31469
+ );
31470
+ res.status(500).json({
31471
+ error: "Failed to build daemon status",
31472
+ code: "daemon_status_failed"
31473
+ });
31474
+ }
31475
+ });
30818
31476
  app.get("/capabilities", (_req, res) => {
30819
31477
  const envelope = {
30820
31478
  v: CAPABILITIES_SCHEMA_VERSION,
30821
31479
  protocolVersions: getServeProtocolVersions(),
30822
31480
  ...deps.qwenCodeVersion ? { qwenCodeVersion: deps.qwenCodeVersion } : {},
30823
31481
  mode: opts.mode,
30824
- features: getAdvertisedServeFeatures(void 0, {
30825
- requireAuth: opts.requireAuth === true,
30826
- mcpPoolActive: opts.mcpPoolActive !== false,
30827
- allowOriginActive: opts.allowOrigins !== void 0 && opts.allowOrigins.length > 0,
30828
- ...opts.promptDeadlineMs !== void 0 ? { promptDeadlineMs: opts.promptDeadlineMs } : {},
30829
- ...opts.writerIdleTimeoutMs !== void 0 ? { writerIdleTimeoutMs: opts.writerIdleTimeoutMs } : {},
30830
- persistSettingAvailable: deps.persistSetting !== void 0,
30831
- sessionShellCommandEnabled,
30832
- rateLimit: opts.rateLimit === true,
30833
- reloadAvailable: deps.workspace !== void 0
30834
- }),
31482
+ features: currentServeFeatures(),
30835
31483
  modelServices: [],
30836
31484
  // Surface the bound workspace so clients can detect mismatch
30837
31485
  // pre-flight and omit `cwd` on `POST /session`.
@@ -31882,6 +32530,41 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
31882
32530
  res.off("close", onResClose);
31883
32531
  }
31884
32532
  });
32533
+ const MID_TURN_MESSAGE_MAX_LENGTH = 16 * 1024;
32534
+ app.post("/session/:id/mid-turn-message", mutate(), (req, res) => {
32535
+ const sessionId = requireSessionId(req, res);
32536
+ if (sessionId === null) return;
32537
+ const body = safeBody(req);
32538
+ const message = body["message"];
32539
+ const trimmed = typeof message === "string" ? message.trim() : "";
32540
+ if (trimmed.length === 0) {
32541
+ res.status(400).json({
32542
+ error: "`message` is required and must be a non-empty string"
32543
+ });
32544
+ return;
32545
+ }
32546
+ if (trimmed.length > MID_TURN_MESSAGE_MAX_LENGTH) {
32547
+ res.status(400).json({
32548
+ error: `\`message\` must be at most ${MID_TURN_MESSAGE_MAX_LENGTH} characters`
32549
+ });
32550
+ return;
32551
+ }
32552
+ const clientId = parseClientIdHeader(req, res);
32553
+ if (clientId === null) return;
32554
+ try {
32555
+ const result = bridge.enqueueMidTurnMessage(
32556
+ sessionId,
32557
+ trimmed,
32558
+ clientId !== void 0 ? { clientId } : void 0
32559
+ );
32560
+ res.status(200).json(result);
32561
+ } catch (err) {
32562
+ sendBridgeError(res, err, {
32563
+ route: "POST /session/:id/mid-turn-message",
32564
+ sessionId
32565
+ });
32566
+ }
32567
+ });
31885
32568
  app.post("/session/:id/shell", mutate({ strict: true }), async (req, res) => {
31886
32569
  const sessionId = req.params["id"];
31887
32570
  if (!sessionShellCommandEnabled) {
@@ -32594,7 +33277,7 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
32594
33277
  }
32595
33278
  })();
32596
33279
  });
32597
- const acpHandle = mountAcpHttp(app, bridge, {
33280
+ acpHandleRef.current = mountAcpHttp(app, bridge, {
32598
33281
  boundWorkspace,
32599
33282
  workspace,
32600
33283
  fsFactory,
@@ -32603,8 +33286,8 @@ function createServeApp(opts, getPort = () => opts.port, deps = {}) {
32603
33286
  sessionShellCommandEnabled,
32604
33287
  checkRate: rateLimiter?.checkRate
32605
33288
  });
32606
- if (acpHandle) {
32607
- app.locals["acpHandle"] = acpHandle;
33289
+ if (acpHandleRef.current) {
33290
+ app.locals["acpHandle"] = acpHandleRef.current;
32608
33291
  }
32609
33292
  app.use(
32610
33293
  (err, _req, res, _next) => {