@threadbase-sh/streamer 1.69.5 → 1.70.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.
package/dist/cli.cjs CHANGED
@@ -116376,7 +116376,7 @@ var require_query = __commonJS({
116376
116376
  if (typeof this.text !== "string" && typeof this.name !== "string") {
116377
116377
  return new Error("A query must have either text or a name. Supplying neither is unsupported.");
116378
116378
  }
116379
- const previous = connection.parsedStatements[this.name];
116379
+ const previous = connection.parsedStatements[this.name] || connection.submittedNamedStatements[this.name];
116380
116380
  if (this.text && previous && this.text !== previous) {
116381
116381
  return new Error(`Prepared statements must be unique - '${this.name}' was used for a different statement`);
116382
116382
  }
@@ -116396,7 +116396,7 @@ var require_query = __commonJS({
116396
116396
  return null;
116397
116397
  }
116398
116398
  hasBeenParsed(connection) {
116399
- return this.name && connection.parsedStatements[this.name];
116399
+ return this.name && (connection.parsedStatements[this.name] || connection.submittedNamedStatements[this.name]);
116400
116400
  }
116401
116401
  handlePortalSuspended(connection) {
116402
116402
  this._getRows(connection, this.rows);
@@ -116420,6 +116420,9 @@ var require_query = __commonJS({
116420
116420
  name: this.name,
116421
116421
  types: this.types
116422
116422
  });
116423
+ if (this.name) {
116424
+ connection.submittedNamedStatements[this.name] = this.text;
116425
+ }
116423
116426
  }
116424
116427
  try {
116425
116428
  connection.bind({
@@ -117208,7 +117211,7 @@ var require_parser3 = __commonJS({
117208
117211
  const parameterCount = reader.int16();
117209
117212
  const message = new messages_1.ParameterDescriptionMessage(LATEINIT_LENGTH, parameterCount);
117210
117213
  for (let i = 0; i < parameterCount; i++) {
117211
- message.dataTypeIDs[i] = reader.int32();
117214
+ message.dataTypeIDs[i] = reader.uint32();
117212
117215
  }
117213
117216
  return message;
117214
117217
  };
@@ -117430,6 +117433,7 @@ var require_connection2 = __commonJS({
117430
117433
  this._keepAlive = config2.keepAlive;
117431
117434
  this._keepAliveInitialDelayMillis = config2.keepAliveInitialDelayMillis;
117432
117435
  this.parsedStatements = {};
117436
+ this.submittedNamedStatements = {};
117433
117437
  this.ssl = config2.ssl || false;
117434
117438
  this.sslNegotiation = config2.sslNegotiation || "postgres";
117435
117439
  this._ending = false;
@@ -117987,6 +117991,8 @@ var require_client3 = __commonJS({
117987
117991
  encoding: this.connectionParameters.client_encoding || "utf8"
117988
117992
  });
117989
117993
  this._queryQueue = [];
117994
+ this._sentQueryQueue = [];
117995
+ this.pipeline = Boolean(c.pipeline);
117990
117996
  this.binary = c.binary || defaults2.binary;
117991
117997
  this.processID = null;
117992
117998
  this.secretKey = null;
@@ -118021,6 +118027,8 @@ var require_client3 = __commonJS({
118021
118027
  enqueueError(activeQuery);
118022
118028
  this._activeQuery = null;
118023
118029
  }
118030
+ this._sentQueryQueue.forEach(enqueueError);
118031
+ this._sentQueryQueue.length = 0;
118024
118032
  this._queryQueue.forEach(enqueueError);
118025
118033
  this._queryQueue.length = 0;
118026
118034
  }
@@ -118263,6 +118271,9 @@ var require_client3 = __commonJS({
118263
118271
  return;
118264
118272
  }
118265
118273
  this._activeQuery = null;
118274
+ if (activeQuery.name) {
118275
+ delete this.connection.submittedNamedStatements[activeQuery.name];
118276
+ }
118266
118277
  activeQuery.handleError(msg, this.connection);
118267
118278
  }
118268
118279
  _handleRowDescription(msg) {
@@ -118319,6 +118330,7 @@ var require_client3 = __commonJS({
118319
118330
  }
118320
118331
  if (activeQuery.name) {
118321
118332
  this.connection.parsedStatements[activeQuery.name] = activeQuery.text;
118333
+ delete this.connection.submittedNamedStatements[activeQuery.name];
118322
118334
  }
118323
118335
  }
118324
118336
  _handleCopyInResponse(msg) {
@@ -118385,6 +118397,9 @@ var require_client3 = __commonJS({
118385
118397
  });
118386
118398
  } else if (client._queryQueue.indexOf(query) !== -1) {
118387
118399
  client._queryQueue.splice(client._queryQueue.indexOf(query), 1);
118400
+ } else if (client._sentQueryQueue.indexOf(query) !== -1) {
118401
+ query.callback = () => {
118402
+ };
118388
118403
  }
118389
118404
  }
118390
118405
  setTypeParser(oid, format, parseFn) {
@@ -118403,6 +118418,10 @@ var require_client3 = __commonJS({
118403
118418
  return utils.escapeLiteral(str);
118404
118419
  }
118405
118420
  _pulseQueryQueue() {
118421
+ if (this.pipeline) {
118422
+ this._pulsePipelinedQueryQueue();
118423
+ return;
118424
+ }
118406
118425
  if (this.readyForQuery === true) {
118407
118426
  this._activeQuery = this._queryQueue.shift();
118408
118427
  const activeQuery = this._getActiveQuery();
@@ -118423,6 +118442,30 @@ var require_client3 = __commonJS({
118423
118442
  }
118424
118443
  }
118425
118444
  }
118445
+ _pulsePipelinedQueryQueue() {
118446
+ if (!this._connected || !this._queryable) {
118447
+ return;
118448
+ }
118449
+ while (this._queryQueue.length > 0) {
118450
+ const query = this._queryQueue.shift();
118451
+ this.hasExecuted = true;
118452
+ const queryError = query.submit(this.connection);
118453
+ if (queryError) {
118454
+ process.nextTick(() => {
118455
+ query.handleError(queryError, this.connection);
118456
+ });
118457
+ continue;
118458
+ }
118459
+ this._sentQueryQueue.push(query);
118460
+ }
118461
+ if (this.readyForQuery && !this._activeQuery && this._sentQueryQueue.length > 0) {
118462
+ this._activeQuery = this._sentQueryQueue.shift();
118463
+ this.readyForQuery = false;
118464
+ }
118465
+ if (!this._activeQuery && this._sentQueryQueue.length === 0 && this._queryQueue.length === 0 && this.hasExecuted) {
118466
+ this.emit("drain");
118467
+ }
118468
+ }
118426
118469
  query(config2, values, callback) {
118427
118470
  let query;
118428
118471
  let result;
@@ -118466,6 +118509,9 @@ var require_client3 = __commonJS({
118466
118509
  const index = this._queryQueue.indexOf(query);
118467
118510
  if (index > -1) {
118468
118511
  this._queryQueue.splice(index, 1);
118512
+ } else if (this.pipeline) {
118513
+ this.connection.stream.destroy();
118514
+ return;
118469
118515
  }
118470
118516
  this._pulseQueryQueue();
118471
118517
  }, readTimeout);
@@ -118492,7 +118538,7 @@ var require_client3 = __commonJS({
118492
118538
  });
118493
118539
  return result;
118494
118540
  }
118495
- if (this._queryQueue.length > 0) {
118541
+ if (this._queryQueue.length > 0 && !this.pipeline) {
118496
118542
  queryQueueLengthDeprecationNotice();
118497
118543
  }
118498
118544
  this._queryQueue.push(query);
@@ -118518,7 +118564,11 @@ var require_client3 = __commonJS({
118518
118564
  return this._Promise.resolve();
118519
118565
  }
118520
118566
  }
118521
- if (this._getActiveQuery() || !this._queryable) {
118567
+ if (!this._queryable) {
118568
+ this.connection.stream.destroy();
118569
+ } else if (this.pipeline && (this._getActiveQuery() || this._sentQueryQueue.length > 0 || this._queryQueue.length > 0)) {
118570
+ this.once("drain", () => this.connection.end());
118571
+ } else if (this._getActiveQuery()) {
118522
118572
  this.connection.stream.destroy();
118523
118573
  } else {
118524
118574
  this.connection.end();
@@ -119008,7 +119058,7 @@ var require_query2 = __commonJS({
119008
119058
  sourceFunction: "routine"
119009
119059
  };
119010
119060
  NativeQuery.prototype.handleError = function(err) {
119011
- const fields = this.native.pq.resultErrorFields();
119061
+ const fields = this.native && this.native.pq.resultErrorFields();
119012
119062
  if (fields) {
119013
119063
  for (const key in fields) {
119014
119064
  const normalizedFieldName = errorFieldMap[key] || key;
@@ -119142,6 +119192,8 @@ var require_client4 = __commonJS({
119142
119192
  this._connecting = false;
119143
119193
  this._connected = false;
119144
119194
  this._queryable = true;
119195
+ this.pipeline = Boolean(config2.pipeline);
119196
+ this._pipelineInFlight = false;
119145
119197
  const cp = this.connectionParameters = new ConnectionParameters(config2);
119146
119198
  if (config2.nativeConnectionString) cp.nativeConnectionString = config2.nativeConnectionString;
119147
119199
  this.user = cp.user;
@@ -119285,7 +119337,7 @@ var require_client4 = __commonJS({
119285
119337
  });
119286
119338
  return result;
119287
119339
  }
119288
- if (this._queryQueue.length > 0) {
119340
+ if (this._queryQueue.length > 0 && !this.pipeline) {
119289
119341
  queryQueueLengthDeprecationNotice();
119290
119342
  }
119291
119343
  this._queryQueue.push(query);
@@ -119307,14 +119359,21 @@ var require_client4 = __commonJS({
119307
119359
  cb2 = (err) => err ? reject(err) : resolve4();
119308
119360
  });
119309
119361
  }
119310
- this.native.end(function() {
119311
- self2._connected = false;
119312
- self2._errorAllQueries(new Error("Connection terminated"));
119313
- process.nextTick(() => {
119314
- self2.emit("end");
119315
- if (cb2) cb2();
119362
+ const doEnd = function() {
119363
+ self2.native.end(function() {
119364
+ self2._connected = false;
119365
+ self2._errorAllQueries(new Error("Connection terminated"));
119366
+ process.nextTick(() => {
119367
+ self2.emit("end");
119368
+ if (cb2) cb2();
119369
+ });
119316
119370
  });
119317
- });
119371
+ };
119372
+ if (this.pipeline && (this._pipelineInFlight || this._queryQueue.length > 0)) {
119373
+ this.once("drain", doEnd);
119374
+ } else {
119375
+ doEnd();
119376
+ }
119318
119377
  return result;
119319
119378
  };
119320
119379
  Client2.prototype._hasActiveQuery = function() {
@@ -119324,6 +119383,9 @@ var require_client4 = __commonJS({
119324
119383
  if (!this._connected) {
119325
119384
  return;
119326
119385
  }
119386
+ if (this.pipeline && !initialConnection) {
119387
+ return this._pulsePipelinedQueryQueue();
119388
+ }
119327
119389
  if (this._hasActiveQuery()) {
119328
119390
  return;
119329
119391
  }
@@ -119341,6 +119403,69 @@ var require_client4 = __commonJS({
119341
119403
  self2._pulseQueryQueue();
119342
119404
  });
119343
119405
  };
119406
+ Client2.prototype._pulsePipelinedQueryQueue = function() {
119407
+ if (!this._connected || this._pipelineInFlight) {
119408
+ return;
119409
+ }
119410
+ if (this._queryQueue.length === 0) {
119411
+ if (this.hasExecuted) {
119412
+ this.emit("drain");
119413
+ }
119414
+ return;
119415
+ }
119416
+ this._pipelineInFlight = true;
119417
+ const self2 = this;
119418
+ const queries = [];
119419
+ const nativeQueries = [];
119420
+ const utils = require_utils5();
119421
+ while (this._queryQueue.length > 0) {
119422
+ const query = this._queryQueue.shift();
119423
+ this.hasExecuted = true;
119424
+ nativeQueries.push(query);
119425
+ const values = query.values ? query.values.map(utils.prepareValue) : null;
119426
+ const pipelineEntry = { text: query.text, name: query.name };
119427
+ if (values) {
119428
+ pipelineEntry.values = values;
119429
+ }
119430
+ if (query.name && this.namedQueries[query.name]) {
119431
+ pipelineEntry._alreadyPrepared = true;
119432
+ }
119433
+ queries.push(pipelineEntry);
119434
+ }
119435
+ this.native.pipeline(queries, function(err, results) {
119436
+ self2._pipelineInFlight = false;
119437
+ if (err) {
119438
+ for (let i = 0; i < nativeQueries.length; i++) {
119439
+ const q2 = nativeQueries[i];
119440
+ q2.native = self2.native;
119441
+ q2.handleError(err);
119442
+ }
119443
+ self2._pulsePipelinedQueryQueue();
119444
+ return;
119445
+ }
119446
+ for (let i = 0; i < nativeQueries.length; i++) {
119447
+ const q2 = nativeQueries[i];
119448
+ const r = results[i];
119449
+ q2.native = self2.native;
119450
+ if (r.err) {
119451
+ q2.handleError(r.err);
119452
+ } else {
119453
+ if (q2.name) {
119454
+ self2.namedQueries[q2.name] = q2.text;
119455
+ }
119456
+ q2.state = "end";
119457
+ q2.emit("end", r.result);
119458
+ if (q2.callback) {
119459
+ q2.callback(null, r.result);
119460
+ }
119461
+ }
119462
+ setImmediate(function() {
119463
+ q2.emit("_done");
119464
+ });
119465
+ }
119466
+ self2._pulsePipelinedQueryQueue();
119467
+ });
119468
+ };
119344
119469
  Client2.prototype.cancel = function(query) {
119345
119470
  if (this._activeQuery === query) {
119346
119471
  this.native.cancel(function() {
@@ -120610,7 +120735,7 @@ var PTY_HOST_PROTOCOL_VERSION, SESSION_DATE_FIELDS, LineDecoder;
120610
120735
  var init_protocol = __esm({
120611
120736
  "src/pty-host/protocol.ts"() {
120612
120737
  "use strict";
120613
- PTY_HOST_PROTOCOL_VERSION = 3;
120738
+ PTY_HOST_PROTOCOL_VERSION = 4;
120614
120739
  SESSION_DATE_FIELDS = [
120615
120740
  "startedAt",
120616
120741
  "completedAt",
@@ -120690,8 +120815,12 @@ var init_remote_session_runner = __esm({
120690
120815
  }
120691
120816
  throw new PtyHostProtocolMismatchError(status.protocolVersion, PTY_HOST_PROTOCOL_VERSION);
120692
120817
  }
120693
- await runner.request({ type: "subscribe" });
120818
+ const subscribed = await runner.request({ type: "subscribe" });
120694
120819
  runner.refreshMirror(status);
120820
+ runner.restorePromptSnapshots({
120821
+ ...status,
120822
+ promptSnapshots: subscribed.promptSnapshots ?? status.promptSnapshots
120823
+ });
120695
120824
  return runner;
120696
120825
  }
120697
120826
  constructor(transport, options) {
@@ -120784,6 +120913,19 @@ var init_remote_session_runner = __esm({
120784
120913
  this.pids.set(session.id, entry.pid);
120785
120914
  }
120786
120915
  }
120916
+ restorePromptSnapshots(status) {
120917
+ for (const snapshot of status.promptSnapshots ?? []) {
120918
+ if (snapshot.kind === "permission") {
120919
+ this.options.onPermissionChange?.(snapshot.sessionId, snapshot.gate, snapshot.occurrenceId);
120920
+ } else {
120921
+ this.options.onLiveQuestion?.(
120922
+ snapshot.sessionId,
120923
+ snapshot.questions,
120924
+ snapshot.occurrenceId
120925
+ );
120926
+ }
120927
+ }
120928
+ }
120787
120929
  async heartbeat(state, timeoutMs = HOST_HEARTBEAT_REQUEST_TIMEOUT_MS) {
120788
120930
  await this.request({ type: "heartbeat", ...state }, timeoutMs);
120789
120931
  }
@@ -120838,13 +120980,13 @@ var init_remote_session_runner = __esm({
120838
120980
  break;
120839
120981
  }
120840
120982
  case "permission-change":
120841
- this.options.onPermissionChange?.(event.sessionId, event.gate);
120983
+ this.options.onPermissionChange?.(event.sessionId, event.gate, event.occurrenceId);
120842
120984
  break;
120843
120985
  case "phase-change":
120844
120986
  this.options.onPhaseChange?.(event.sessionId, event.phase);
120845
120987
  break;
120846
120988
  case "live-question":
120847
- this.options.onLiveQuestion?.(event.sessionId, event.questions);
120989
+ this.options.onLiveQuestion?.(event.sessionId, event.questions, event.occurrenceId);
120848
120990
  break;
120849
120991
  case "live-question-gone":
120850
120992
  this.options.onLiveQuestionGone?.(event.sessionId);
@@ -128466,12 +128608,15 @@ __export(host_exports, {
128466
128608
  HOST_ORPHAN_SWEEP_MS: () => HOST_ORPHAN_SWEEP_MS,
128467
128609
  SessionHost: () => SessionHost
128468
128610
  });
128469
- var HOST_IDLE_SWEEP_MS, HOST_IDLE_AFTER_MS, HOST_HEARTBEAT_TIMEOUT_MS, HOST_ORPHAN_SWEEP_MS, SessionHost;
128611
+ var import_node_crypto8, HOST_IDLE_SWEEP_MS, HOST_IDLE_AFTER_MS, HOST_HEARTBEAT_TIMEOUT_MS, HOST_ORPHAN_SWEEP_MS, SessionHost;
128470
128612
  var init_host = __esm({
128471
128613
  "src/pty-host/host.ts"() {
128472
128614
  "use strict";
128615
+ import_node_crypto8 = require("crypto");
128473
128616
  init_live_session_manager();
128474
128617
  init_logger();
128618
+ init_detectPermissionGate();
128619
+ init_detectQuestionFromScreen();
128475
128620
  init_protocol();
128476
128621
  HOST_IDLE_SWEEP_MS = 5 * 60 * 1e3;
128477
128622
  HOST_IDLE_AFTER_MS = 6 * 60 * 60 * 1e3;
@@ -128493,6 +128638,7 @@ var init_host = __esm({
128493
128638
  orphanTimer = null;
128494
128639
  onOrphaned;
128495
128640
  orphaned = false;
128641
+ promptSnapshots = /* @__PURE__ */ new Map();
128496
128642
  constructor(options = {}) {
128497
128643
  this.log = options.logger ?? getLogger("pty-host");
128498
128644
  this.idleAfterMs = options.idleAfterMs ?? HOST_IDLE_AFTER_MS;
@@ -128505,12 +128651,55 @@ var init_host = __esm({
128505
128651
  this.lastAgentChunkAt.set(sessionId, Date.now());
128506
128652
  this.emit({ type: "event", event: "output", sessionId, data });
128507
128653
  },
128508
- onStatusChange: (session) => this.emit({ type: "event", event: "status-change", session }),
128654
+ onStatusChange: (session) => {
128655
+ if (session.status === "idle") this.promptSnapshots.delete(session.id);
128656
+ this.emit({ type: "event", event: "status-change", session });
128657
+ },
128509
128658
  onReady: (session) => this.emit({ type: "event", event: "ready", session }),
128510
- onPermissionChange: (sessionId, gate) => this.emit({ type: "event", event: "permission-change", sessionId, gate }),
128659
+ onPermissionChange: (sessionId, gate) => {
128660
+ const prior = this.promptSnapshots.get(sessionId);
128661
+ if (gate === null) {
128662
+ this.promptSnapshots.delete(sessionId);
128663
+ this.emit({
128664
+ type: "event",
128665
+ event: "permission-change",
128666
+ sessionId,
128667
+ gate,
128668
+ ...prior ? { occurrenceId: prior.occurrenceId } : {}
128669
+ });
128670
+ return;
128671
+ }
128672
+ const occurrenceId = prior?.kind === "permission" && permissionGateKey(prior.gate) === permissionGateKey(gate) ? prior.occurrenceId : (0, import_node_crypto8.randomUUID)();
128673
+ this.promptSnapshots.set(sessionId, {
128674
+ kind: "permission",
128675
+ sessionId,
128676
+ occurrenceId,
128677
+ gate
128678
+ });
128679
+ this.emit({
128680
+ type: "event",
128681
+ event: "permission-change",
128682
+ sessionId,
128683
+ gate,
128684
+ occurrenceId
128685
+ });
128686
+ },
128511
128687
  onPhaseChange: (sessionId, phase) => this.emit({ type: "event", event: "phase-change", sessionId, phase }),
128512
- onLiveQuestion: (sessionId, questions) => this.emit({ type: "event", event: "live-question", sessionId, questions }),
128513
- onLiveQuestionGone: (sessionId) => this.emit({ type: "event", event: "live-question-gone", sessionId }),
128688
+ onLiveQuestion: (sessionId, questions) => {
128689
+ const prior = this.promptSnapshots.get(sessionId);
128690
+ const occurrenceId = prior?.kind === "question" && questionContentKey(prior.questions) === questionContentKey(questions) ? prior.occurrenceId : (0, import_node_crypto8.randomUUID)();
128691
+ this.promptSnapshots.set(sessionId, {
128692
+ kind: "question",
128693
+ sessionId,
128694
+ occurrenceId,
128695
+ questions
128696
+ });
128697
+ this.emit({ type: "event", event: "live-question", sessionId, questions, occurrenceId });
128698
+ },
128699
+ onLiveQuestionGone: (sessionId) => {
128700
+ this.promptSnapshots.delete(sessionId);
128701
+ this.emit({ type: "event", event: "live-question-gone", sessionId });
128702
+ },
128514
128703
  onUserMessage: (sessionId, text, ts2) => this.emit({ type: "event", event: "user-message", sessionId, text, ts: ts2 })
128515
128704
  });
128516
128705
  this.idleTimer = setInterval(() => this.reapIdle(), options.idleSweepMs ?? HOST_IDLE_SWEEP_MS);
@@ -128579,11 +128768,12 @@ var init_host = __esm({
128579
128768
  event: "pty_host.streamer_subscribed",
128580
128769
  subscribers: this.subscribers.size
128581
128770
  });
128582
- return {};
128771
+ return { promptSnapshots: [...this.promptSnapshots.values()] };
128583
128772
  case "status":
128584
128773
  return {
128585
128774
  protocolVersion: PTY_HOST_PROTOCOL_VERSION,
128586
- sessions: this.runner.listSessions().map((session) => this.toHostSession(session))
128775
+ sessions: this.runner.listSessions().map((session) => this.toHostSession(session)),
128776
+ promptSnapshots: [...this.promptSnapshots.values()]
128587
128777
  };
128588
128778
  case "heartbeat":
128589
128779
  this.heartbeatLeases.set(transport, Date.now());
@@ -128641,6 +128831,7 @@ var init_host = __esm({
128641
128831
  }
128642
128832
  forget(sessionId) {
128643
128833
  this.lastAgentChunkAt.delete(sessionId);
128834
+ this.promptSnapshots.delete(sessionId);
128644
128835
  }
128645
128836
  /**
128646
128837
  * Release PTYs whose agent has been silent past the threshold.
@@ -132718,13 +132909,13 @@ var checkOptionalParameter = (path2) => {
132718
132909
  if (segment !== "" && !/\:/.test(segment)) {
132719
132910
  basePath += "/" + segment;
132720
132911
  } else if (/\:/.test(segment)) {
132721
- if (/\?/.test(segment)) {
132912
+ if (segment.charCodeAt(segment.length - 1) === 63) {
132722
132913
  if (results.length === 0 && basePath === "") {
132723
132914
  results.push("/");
132724
132915
  } else {
132725
132916
  results.push(basePath);
132726
132917
  }
132727
- const optionalSegment = segment.replace("?", "");
132918
+ const optionalSegment = segment.slice(0, -1);
132728
132919
  basePath += "/" + optionalSegment;
132729
132920
  results.push(basePath);
132730
132921
  } else {
@@ -132734,18 +132925,16 @@ var checkOptionalParameter = (path2) => {
132734
132925
  });
132735
132926
  return results.filter((v2, i, a) => a.indexOf(v2) === i);
132736
132927
  };
132928
+ var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
132737
132929
  var _decodeURI = (value) => {
132738
- if (!/[%+]/.test(value)) {
132739
- return value;
132740
- }
132741
132930
  if (value.indexOf("+") !== -1) {
132742
132931
  value = value.replace(/\+/g, " ");
132743
132932
  }
132744
- return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
132933
+ return tryDecodeURIComponent(value);
132745
132934
  };
132746
132935
  var _getQueryParam = (url2, key, multiple) => {
132747
132936
  let encoded;
132748
- if (!multiple && key && !/[%+]/.test(key)) {
132937
+ if (!multiple && key && key.indexOf("%") === -1 && key.indexOf("+") === -1) {
132749
132938
  let keyIndex2 = url2.indexOf("?", 8);
132750
132939
  if (keyIndex2 === -1) {
132751
132940
  return void 0;
@@ -132817,7 +133006,6 @@ var getQueryParams = (url2, key) => {
132817
133006
  var decodeURIComponent_ = decodeURIComponent;
132818
133007
 
132819
133008
  // node_modules/hono/dist/request.js
132820
- var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
132821
133009
  var HonoRequest = class {
132822
133010
  /**
132823
133011
  * `.raw` can get the raw Request object.
@@ -132856,7 +133044,6 @@ var HonoRequest = class {
132856
133044
  this.raw = request;
132857
133045
  this.path = path2;
132858
133046
  this.#matchResult = matchResult;
132859
- this.#validatedData = {};
132860
133047
  }
132861
133048
  param(key) {
132862
133049
  return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
@@ -132864,7 +133051,7 @@ var HonoRequest = class {
132864
133051
  #getDecodedParam(key) {
132865
133052
  const paramKey = this.#matchResult[0][this.routeIndex][1][key];
132866
133053
  const param = this.#getParamValue(paramKey);
132867
- return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param;
133054
+ return param && tryDecodeURIComponent(param);
132868
133055
  }
132869
133056
  #getAllDecodedParams() {
132870
133057
  const decoded = {};
@@ -132872,7 +133059,7 @@ var HonoRequest = class {
132872
133059
  for (const key of keys) {
132873
133060
  const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
132874
133061
  if (value !== void 0) {
132875
- decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
133062
+ decoded[key] = tryDecodeURIComponent(value);
132876
133063
  }
132877
133064
  }
132878
133065
  return decoded;
@@ -132905,8 +133092,7 @@ var HonoRequest = class {
132905
133092
  if (cachedBody) {
132906
133093
  return cachedBody;
132907
133094
  }
132908
- const anyCachedKey = Object.keys(bodyCache)[0];
132909
- if (anyCachedKey) {
133095
+ for (const anyCachedKey in bodyCache) {
132910
133096
  return bodyCache[anyCachedKey].then((body) => {
132911
133097
  if (anyCachedKey === "json") {
132912
133098
  body = JSON.stringify(body);
@@ -133009,10 +133195,11 @@ var HonoRequest = class {
133009
133195
  * @param data - The validated data to add.
133010
133196
  */
133011
133197
  addValidatedData(target, data) {
133012
- this.#validatedData[target] = data;
133198
+ ;
133199
+ (this.#validatedData ??= {})[target] = data;
133013
133200
  }
133014
133201
  valid(target) {
133015
- return this.#validatedData[target];
133202
+ return this.#validatedData?.[target];
133016
133203
  }
133017
133204
  /**
133018
133205
  * `.url()` can get the request url strings.
@@ -133343,6 +133530,10 @@ var Context = class {
133343
133530
  * c.header('X-Message', 'Hello!')
133344
133531
  * c.header('Content-Type', 'text/plain')
133345
133532
  *
133533
+ * // Append multiple headers using the append option (e.g. Vary)
133534
+ * c.header('Vary', 'Accept-Encoding', { append: true })
133535
+ * c.header('Vary', 'User-Agent', { append: true })
133536
+ *
133346
133537
  * return c.body('Thank you for coming')
133347
133538
  * })
133348
133539
  * ```
@@ -133414,11 +133605,11 @@ var Context = class {
133414
133605
  return Object.fromEntries(this.#var);
133415
133606
  }
133416
133607
  #newResponse(data, arg, headers) {
133417
- const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
133418
- if (typeof arg === "object" && "headers" in arg) {
133419
- const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
133420
- for (const [key, value] of argHeaders) {
133421
- if (key.toLowerCase() === "set-cookie") {
133608
+ let responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders;
133609
+ if (typeof arg === "object" && arg.headers) {
133610
+ responseHeaders ??= new Headers();
133611
+ for (const [key, value] of new Headers(arg.headers)) {
133612
+ if (key === "set-cookie") {
133422
133613
  responseHeaders.append(key, value);
133423
133614
  } else {
133424
133615
  responseHeaders.set(key, value);
@@ -133426,19 +133617,34 @@ var Context = class {
133426
133617
  }
133427
133618
  }
133428
133619
  if (headers) {
133429
- for (const [k2, v2] of Object.entries(headers)) {
133430
- if (typeof v2 === "string") {
133431
- responseHeaders.set(k2, v2);
133432
- } else {
133433
- responseHeaders.delete(k2);
133434
- for (const v22 of v2) {
133435
- responseHeaders.append(k2, v22);
133620
+ if (!responseHeaders) {
133621
+ let count = 0;
133622
+ for (const k2 in headers) {
133623
+ if (++count > 1 || typeof headers[k2] !== "string") {
133624
+ responseHeaders = new Headers();
133625
+ break;
133626
+ }
133627
+ }
133628
+ }
133629
+ if (responseHeaders) {
133630
+ for (const k2 in headers) {
133631
+ const v2 = headers[k2];
133632
+ if (typeof v2 === "string") {
133633
+ responseHeaders.set(k2, v2);
133634
+ } else {
133635
+ responseHeaders.delete(k2);
133636
+ for (const v22 of v2) {
133637
+ responseHeaders.append(k2, v22);
133638
+ }
133436
133639
  }
133437
133640
  }
133438
133641
  }
133439
133642
  }
133440
133643
  const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
133441
- return createResponseInstance(data, { status, headers: responseHeaders });
133644
+ return createResponseInstance(data, {
133645
+ status,
133646
+ headers: responseHeaders ?? headers
133647
+ });
133442
133648
  }
133443
133649
  newResponse = (...args) => this.#newResponse(...args);
133444
133650
  /**
@@ -133551,7 +133757,7 @@ var Context = class {
133551
133757
  // node_modules/hono/dist/router.js
133552
133758
  var METHOD_NAME_ALL = "ALL";
133553
133759
  var METHOD_NAME_ALL_LOWERCASE = "all";
133554
- var METHODS = ["get", "post", "put", "delete", "options", "patch"];
133760
+ var METHODS = ["get", "post", "put", "delete", "options", "patch", "query"];
133555
133761
  var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
133556
133762
  var UnsupportedPathError = class extends Error {
133557
133763
  };
@@ -133578,6 +133784,7 @@ var Hono = class _Hono {
133578
133784
  delete;
133579
133785
  options;
133580
133786
  patch;
133787
+ query;
133581
133788
  all;
133582
133789
  on;
133583
133790
  use;
@@ -133877,8 +134084,8 @@ var Hono = class _Hono {
133877
134084
  * @see {@link https://hono.dev/docs/api/hono#fetch}
133878
134085
  *
133879
134086
  * @param {Request} request - request Object of request
133880
- * @param {Env} Env - env Object
133881
- * @param {ExecutionContext} - context of execution
134087
+ * @param {Env} env - env Object
134088
+ * @param {ExecutionContext} executionCtx - context of execution
133882
134089
  * @returns {Response | Promise<Response>} response of request
133883
134090
  *
133884
134091
  */
@@ -133970,7 +134177,7 @@ function compareKey(a, b2) {
133970
134177
  return 1;
133971
134178
  }
133972
134179
  if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
133973
- return 1;
134180
+ return b2 === TAIL_WILDCARD_REG_EXP_STR ? -1 : 1;
133974
134181
  } else if (b2 === ONLY_WILDCARD_REG_EXP_STR || b2 === TAIL_WILDCARD_REG_EXP_STR) {
133975
134182
  return -1;
133976
134183
  }
@@ -133982,76 +134189,75 @@ function compareKey(a, b2) {
133982
134189
  return a.length === b2.length ? a < b2 ? -1 : 1 : b2.length - a.length;
133983
134190
  }
133984
134191
  var Node = class _Node {
134192
+ // handler index of a dynamic path, or -1 for a static path terminal
133985
134193
  #index;
133986
134194
  #varIndex;
133987
134195
  #children = /* @__PURE__ */ Object.create(null);
133988
- insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
133989
- if (tokens.length === 0) {
133990
- if (this.#index !== void 0) {
133991
- throw PATH_ERROR;
133992
- }
133993
- if (pathErrorCheckOnly) {
133994
- return;
133995
- }
133996
- this.#index = index;
133997
- return;
133998
- }
133999
- const [token, ...restTokens] = tokens;
134000
- const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
134001
- let node;
134002
- if (pattern) {
134003
- const name = pattern[1];
134004
- let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
134005
- if (name && pattern[2]) {
134006
- if (regexpStr === ".*") {
134007
- throw PATH_ERROR;
134008
- }
134009
- regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
134010
- if (/\((?!\?:)/.test(regexpStr)) {
134011
- throw PATH_ERROR;
134012
- }
134013
- }
134014
- node = this.#children[regexpStr];
134015
- if (!node) {
134016
- if (Object.keys(this.#children).some(
134017
- (k2) => k2 !== ONLY_WILDCARD_REG_EXP_STR && k2 !== TAIL_WILDCARD_REG_EXP_STR
134018
- )) {
134019
- throw PATH_ERROR;
134020
- }
134021
- if (pathErrorCheckOnly) {
134022
- return;
134196
+ insert(tokens, index, paramMap, context, isStatic) {
134197
+ let node = this;
134198
+ for (let i = 0, len = tokens.length; i < len; i++) {
134199
+ const token = tokens[i];
134200
+ const pattern = token.length === 1 ? token === "*" ? i === len - 1 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : null : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
134201
+ let nextNode;
134202
+ if (pattern) {
134203
+ const name = pattern[1];
134204
+ let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
134205
+ if (name && pattern[2]) {
134206
+ if (regexpStr === ".*") {
134207
+ throw PATH_ERROR;
134208
+ }
134209
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
134210
+ if (/\((?!\?:)/.test(regexpStr)) {
134211
+ throw PATH_ERROR;
134212
+ }
134213
+ if (regexpStr.length === 1 && regExpMetaChars.has(regexpStr)) {
134214
+ throw PATH_ERROR;
134215
+ }
134216
+ }
134217
+ nextNode = node.#children[regexpStr];
134218
+ if (!nextNode) {
134219
+ if (regexpStr !== ONLY_WILDCARD_REG_EXP_STR && regexpStr !== TAIL_WILDCARD_REG_EXP_STR) {
134220
+ for (const k2 in node.#children) {
134221
+ if (
134222
+ // a single-char pattern coexists with single-char literals as a literal does
134223
+ (regexpStr.length > 1 || k2.length > 1) && k2 !== ONLY_WILDCARD_REG_EXP_STR && k2 !== TAIL_WILDCARD_REG_EXP_STR
134224
+ ) {
134225
+ throw PATH_ERROR;
134226
+ }
134227
+ }
134228
+ }
134229
+ nextNode = node.#children[regexpStr] = new _Node();
134023
134230
  }
134024
- node = this.#children[regexpStr] = new _Node();
134025
134231
  if (name !== "") {
134026
- node.#varIndex = context.varIndex++;
134232
+ nextNode.#varIndex ??= context.varIndex++;
134233
+ paramMap.push([name, nextNode.#varIndex]);
134027
134234
  }
134028
- }
134029
- if (!pathErrorCheckOnly && name !== "") {
134030
- paramMap.push([name, node.#varIndex]);
134031
- }
134032
- } else {
134033
- node = this.#children[token];
134034
- if (!node) {
134035
- if (Object.keys(this.#children).some(
134036
- (k2) => k2.length > 1 && k2 !== ONLY_WILDCARD_REG_EXP_STR && k2 !== TAIL_WILDCARD_REG_EXP_STR
134037
- )) {
134038
- throw PATH_ERROR;
134039
- }
134040
- if (pathErrorCheckOnly) {
134041
- return;
134235
+ } else {
134236
+ nextNode = node.#children[token];
134237
+ if (!nextNode) {
134238
+ for (const k2 in node.#children) {
134239
+ if (k2.length > 1 && k2 !== ONLY_WILDCARD_REG_EXP_STR && k2 !== TAIL_WILDCARD_REG_EXP_STR) {
134240
+ throw PATH_ERROR;
134241
+ }
134242
+ }
134243
+ nextNode = node.#children[token] = new _Node();
134042
134244
  }
134043
- node = this.#children[token] = new _Node();
134044
134245
  }
134246
+ node = nextNode;
134247
+ }
134248
+ if (node.#index !== void 0) {
134249
+ throw PATH_ERROR;
134045
134250
  }
134046
- node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
134251
+ node.#index = isStatic ? -1 : index;
134047
134252
  }
134048
134253
  buildRegExpStr() {
134049
134254
  const childKeys = Object.keys(this.#children).sort(compareKey);
134050
134255
  const strList = childKeys.map((k2) => {
134051
134256
  const c = this.#children[k2];
134052
- return (typeof c.#varIndex === "number" ? `(${k2})@${c.#varIndex}` : regExpMetaChars.has(k2) ? `\\${k2}` : k2) + c.buildRegExpStr();
134053
- });
134054
- if (typeof this.#index === "number") {
134257
+ const childStr = c.buildRegExpStr();
134258
+ return childStr === "" ? "" : (typeof c.#varIndex === "number" ? `(${k2})@${c.#varIndex}` : regExpMetaChars.has(k2) ? `\\${k2}` : k2) + childStr;
134259
+ }).filter(Boolean);
134260
+ if (typeof this.#index === "number" && this.#index !== -1) {
134055
134261
  strList.unshift(`#${this.#index}`);
134056
134262
  }
134057
134263
  if (strList.length === 0) {
@@ -134068,12 +134274,20 @@ var Node = class _Node {
134068
134274
  var Trie = class {
134069
134275
  #context = { varIndex: 0 };
134070
134276
  #root = new Node();
134071
- insert(path2, index, pathErrorCheckOnly) {
134277
+ #index = 0;
134278
+ // dynamic path -> [handler index, param assoc]; static paths are not registered
134279
+ paths = /* @__PURE__ */ Object.create(null);
134280
+ insert(path2, isStatic) {
134281
+ if (isStatic) {
134282
+ this.#root.insert(path2.split(""), 0, [], this.#context, true);
134283
+ return;
134284
+ }
134072
134285
  const paramAssoc = [];
134073
134286
  const groups = [];
134287
+ let markedPath = path2;
134074
134288
  for (let i = 0; ; ) {
134075
134289
  let replaced = false;
134076
- path2 = path2.replace(/\{[^}]+\}/g, (m2) => {
134290
+ markedPath = markedPath.replace(/\{[^}]+\}/g, (m2) => {
134077
134291
  const mark = `@\\${i}`;
134078
134292
  groups[i] = [mark, m2];
134079
134293
  i++;
@@ -134084,7 +134298,7 @@ var Trie = class {
134084
134298
  break;
134085
134299
  }
134086
134300
  }
134087
- const tokens = path2.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
134301
+ const tokens = markedPath.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
134088
134302
  for (let i = groups.length - 1; i >= 0; i--) {
134089
134303
  const [mark] = groups[i];
134090
134304
  for (let j2 = tokens.length - 1; j2 >= 0; j2--) {
@@ -134094,8 +134308,8 @@ var Trie = class {
134094
134308
  }
134095
134309
  }
134096
134310
  }
134097
- this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly);
134098
- return paramAssoc;
134311
+ this.#root.insert(tokens, this.#index, paramAssoc, this.#context, false);
134312
+ this.paths[path2] = [this.#index++, paramAssoc];
134099
134313
  }
134100
134314
  buildRegExp() {
134101
134315
  let regexp = this.#root.buildRegExpStr();
@@ -134121,7 +134335,6 @@ var Trie = class {
134121
134335
  };
134122
134336
 
134123
134337
  // node_modules/hono/dist/router/reg-exp-router/router.js
134124
- var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
134125
134338
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
134126
134339
  function buildWildcardRegExp(path2) {
134127
134340
  return wildcardRegExpCache[path2] ??= new RegExp(
@@ -134134,63 +134347,6 @@ function buildWildcardRegExp(path2) {
134134
134347
  function clearWildcardRegExpCache() {
134135
134348
  wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
134136
134349
  }
134137
- function buildMatcherFromPreprocessedRoutes(routes) {
134138
- const trie = new Trie();
134139
- const handlerData = [];
134140
- if (routes.length === 0) {
134141
- return nullMatcher;
134142
- }
134143
- const routesWithStaticPathFlag = routes.map(
134144
- (route) => [!/\*|\/:/.test(route[0]), ...route]
134145
- ).sort(
134146
- ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length
134147
- );
134148
- const staticMap = /* @__PURE__ */ Object.create(null);
134149
- for (let i = 0, j2 = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
134150
- const [pathErrorCheckOnly, path2, handlers] = routesWithStaticPathFlag[i];
134151
- if (pathErrorCheckOnly) {
134152
- staticMap[path2] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
134153
- } else {
134154
- j2++;
134155
- }
134156
- let paramAssoc;
134157
- try {
134158
- paramAssoc = trie.insert(path2, j2, pathErrorCheckOnly);
134159
- } catch (e) {
134160
- throw e === PATH_ERROR ? new UnsupportedPathError(path2) : e;
134161
- }
134162
- if (pathErrorCheckOnly) {
134163
- continue;
134164
- }
134165
- handlerData[j2] = handlers.map(([h, paramCount]) => {
134166
- const paramIndexMap = /* @__PURE__ */ Object.create(null);
134167
- paramCount -= 1;
134168
- for (; paramCount >= 0; paramCount--) {
134169
- const [key, value] = paramAssoc[paramCount];
134170
- paramIndexMap[key] = value;
134171
- }
134172
- return [h, paramIndexMap];
134173
- });
134174
- }
134175
- const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
134176
- for (let i = 0, len = handlerData.length; i < len; i++) {
134177
- for (let j2 = 0, len2 = handlerData[i].length; j2 < len2; j2++) {
134178
- const map2 = handlerData[i][j2]?.[1];
134179
- if (!map2) {
134180
- continue;
134181
- }
134182
- const keys = Object.keys(map2);
134183
- for (let k2 = 0, len3 = keys.length; k2 < len3; k2++) {
134184
- map2[keys[k2]] = paramReplacementMap[map2[keys[k2]]];
134185
- }
134186
- }
134187
- }
134188
- const handlerMap = [];
134189
- for (const i in indexReplacementMap) {
134190
- handlerMap[i] = handlerData[indexReplacementMap[i]];
134191
- }
134192
- return [regexp, handlerMap, staticMap];
134193
- }
134194
134350
  function findMiddleware(middleware, path2) {
134195
134351
  if (!middleware) {
134196
134352
  return void 0;
@@ -134206,9 +134362,18 @@ var RegExpRouter = class {
134206
134362
  name = "RegExpRouter";
134207
134363
  #middleware;
134208
134364
  #routes;
134365
+ #tries;
134209
134366
  constructor() {
134210
134367
  this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
134211
134368
  this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
134369
+ this.#tries = { [METHOD_NAME_ALL]: new Trie() };
134370
+ }
134371
+ #insertPath(method, path2) {
134372
+ try {
134373
+ this.#tries[method].insert(path2, !/\*|\/:/.test(path2));
134374
+ } catch (e) {
134375
+ throw e === PATH_ERROR ? new UnsupportedPathError(path2) : e;
134376
+ }
134212
134377
  }
134213
134378
  add(method, path2, handler) {
134214
134379
  const middleware = this.#middleware;
@@ -134217,11 +134382,12 @@ var RegExpRouter = class {
134217
134382
  throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
134218
134383
  }
134219
134384
  if (!middleware[method]) {
134220
- ;
134385
+ this.#tries[method] = new Trie();
134221
134386
  [middleware, routes].forEach((handlerMap) => {
134222
134387
  handlerMap[method] = /* @__PURE__ */ Object.create(null);
134223
134388
  Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p2) => {
134224
134389
  handlerMap[method][p2] = [...handlerMap[METHOD_NAME_ALL][p2]];
134390
+ this.#insertPath(method, p2);
134225
134391
  });
134226
134392
  });
134227
134393
  }
@@ -134231,13 +134397,12 @@ var RegExpRouter = class {
134231
134397
  const paramCount = (path2.match(/\/:/g) || []).length;
134232
134398
  if (/\*$/.test(path2)) {
134233
134399
  const re2 = buildWildcardRegExp(path2);
134234
- if (method === METHOD_NAME_ALL) {
134235
- Object.keys(middleware).forEach((m2) => {
134236
- middleware[m2][path2] ||= findMiddleware(middleware[m2], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || [];
134237
- });
134238
- } else {
134239
- middleware[method][path2] ||= findMiddleware(middleware[method], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || [];
134240
- }
134400
+ Object.keys(middleware).forEach((m2) => {
134401
+ if ((method === METHOD_NAME_ALL || method === m2) && !middleware[m2][path2]) {
134402
+ this.#insertPath(m2, path2);
134403
+ middleware[m2][path2] = findMiddleware(middleware[m2], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || [];
134404
+ }
134405
+ });
134241
134406
  Object.keys(middleware).forEach((m2) => {
134242
134407
  if (method === METHOD_NAME_ALL || method === m2) {
134243
134408
  Object.keys(middleware[m2]).forEach((p2) => {
@@ -134259,9 +134424,12 @@ var RegExpRouter = class {
134259
134424
  const path22 = paths[i];
134260
134425
  Object.keys(routes).forEach((m2) => {
134261
134426
  if (method === METHOD_NAME_ALL || method === m2) {
134262
- routes[m2][path22] ||= [
134263
- ...findMiddleware(middleware[m2], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || []
134264
- ];
134427
+ if (!routes[m2][path22]) {
134428
+ this.#insertPath(m2, path22);
134429
+ routes[m2][path22] = [
134430
+ ...findMiddleware(middleware[m2], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || []
134431
+ ];
134432
+ }
134265
134433
  routes[m2][path22].push([handler, paramCount - len + i + 1]);
134266
134434
  }
134267
134435
  });
@@ -134273,29 +134441,54 @@ var RegExpRouter = class {
134273
134441
  Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
134274
134442
  matchers[method] ||= this.#buildMatcher(method);
134275
134443
  });
134276
- this.#middleware = this.#routes = void 0;
134444
+ this.#middleware = this.#routes = this.#tries = void 0;
134277
134445
  clearWildcardRegExpCache();
134278
134446
  return matchers;
134279
134447
  }
134280
134448
  #buildMatcher(method) {
134281
- const routes = [];
134282
- let hasOwnRoute = method === METHOD_NAME_ALL;
134283
- [this.#middleware, this.#routes].forEach((r) => {
134284
- const ownRoute = r[method] ? Object.keys(r[method]).map((path2) => [path2, r[method][path2]]) : [];
134285
- if (ownRoute.length !== 0) {
134286
- hasOwnRoute ||= true;
134287
- routes.push(...ownRoute);
134288
- } else if (method !== METHOD_NAME_ALL) {
134289
- routes.push(
134290
- ...Object.keys(r[METHOD_NAME_ALL]).map((path2) => [path2, r[METHOD_NAME_ALL][path2]])
134291
- );
134449
+ const middleware = this.#middleware[method];
134450
+ const routes = this.#routes[method];
134451
+ const trie = this.#tries[method];
134452
+ const staticMap = /* @__PURE__ */ Object.create(null);
134453
+ const handlerData = [];
134454
+ [middleware, routes].forEach((r) => {
134455
+ for (const path2 in r) {
134456
+ const handlers = r[path2];
134457
+ const pathData = trie.paths[path2];
134458
+ if (!pathData) {
134459
+ staticMap[path2] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
134460
+ continue;
134461
+ }
134462
+ const paramAssoc = pathData[1];
134463
+ handlerData[pathData[0]] = handlers.map(([h, paramCount]) => {
134464
+ const paramIndexMap = /* @__PURE__ */ Object.create(null);
134465
+ paramCount -= 1;
134466
+ for (; paramCount >= 0; paramCount--) {
134467
+ const [key, value] = paramAssoc[paramCount];
134468
+ paramIndexMap[key] = value;
134469
+ }
134470
+ return [h, paramIndexMap];
134471
+ });
134292
134472
  }
134293
134473
  });
134294
- if (!hasOwnRoute) {
134295
- return null;
134296
- } else {
134297
- return buildMatcherFromPreprocessedRoutes(routes);
134474
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
134475
+ for (let i = 0, len = handlerData.length; i < len; i++) {
134476
+ for (let j2 = 0, len2 = handlerData[i].length; j2 < len2; j2++) {
134477
+ const map2 = handlerData[i][j2]?.[1];
134478
+ if (!map2) {
134479
+ continue;
134480
+ }
134481
+ const keys = Object.keys(map2);
134482
+ for (let k2 = 0, len3 = keys.length; k2 < len3; k2++) {
134483
+ map2[keys[k2]] = paramReplacementMap[map2[keys[k2]]];
134484
+ }
134485
+ }
134486
+ }
134487
+ const handlerMap = [];
134488
+ for (const i in indexReplacementMap) {
134489
+ handlerMap[i] = handlerData[indexReplacementMap[i]];
134298
134490
  }
134491
+ return [regexp, handlerMap, staticMap];
134299
134492
  }
134300
134493
  };
134301
134494
 
@@ -134356,76 +134549,51 @@ var SmartRouter = class {
134356
134549
 
134357
134550
  // node_modules/hono/dist/router/trie-router/node.js
134358
134551
  var emptyParams = /* @__PURE__ */ Object.create(null);
134359
- var hasChildren = (children) => {
134360
- for (const _2 in children) {
134361
- return true;
134362
- }
134363
- return false;
134364
- };
134552
+ var order = 0;
134365
134553
  var Node2 = class _Node2 {
134366
- #methods;
134367
- #children;
134368
- #patterns;
134369
- #order = 0;
134554
+ #methods = [];
134555
+ #children = /* @__PURE__ */ Object.create(null);
134556
+ #patterns = [];
134557
+ #pattern;
134370
134558
  #params = emptyParams;
134371
- constructor(method, handler, children) {
134372
- this.#children = children || /* @__PURE__ */ Object.create(null);
134373
- this.#methods = [];
134374
- if (method && handler) {
134375
- const m2 = /* @__PURE__ */ Object.create(null);
134376
- m2[method] = { handler, possibleKeys: [], score: 0 };
134377
- this.#methods = [m2];
134378
- }
134379
- this.#patterns = [];
134380
- }
134381
134559
  insert(method, path2, handler) {
134382
- this.#order = ++this.#order;
134383
134560
  let curNode = this;
134384
134561
  const parts = splitRoutingPath(path2);
134385
- const possibleKeys = [];
134386
- for (let i = 0, len = parts.length; i < len; i++) {
134387
- const p2 = parts[i];
134388
- const nextP = parts[i + 1];
134389
- const pattern = getPattern(p2, nextP);
134390
- const key = Array.isArray(pattern) ? pattern[0] : p2;
134391
- if (key in curNode.#children) {
134392
- curNode = curNode.#children[key];
134393
- if (pattern) {
134394
- possibleKeys.push(pattern[1]);
134395
- }
134396
- continue;
134562
+ const possibleKeys = /* @__PURE__ */ new Set();
134563
+ let i = 0;
134564
+ for (const p2 of parts) {
134565
+ const nextP = parts[++i];
134566
+ const pattern = getPattern(p2, nextP) || (nextP === void 0 && p2 && p2.indexOf("*") === p2.length - 1 ? p2 : null);
134567
+ const isParam = Array.isArray(pattern);
134568
+ const key = isParam ? pattern[0] : pattern || p2;
134569
+ const child = curNode.#children[key] ||= new _Node2();
134570
+ if (pattern && !child.#pattern) {
134571
+ child.#pattern = pattern;
134572
+ curNode.#patterns.push(child);
134397
134573
  }
134398
- curNode.#children[key] = new _Node2();
134399
- if (pattern) {
134400
- curNode.#patterns.push(pattern);
134401
- possibleKeys.push(pattern[1]);
134574
+ curNode = child;
134575
+ if (isParam) {
134576
+ possibleKeys.add(pattern[1]);
134402
134577
  }
134403
- curNode = curNode.#children[key];
134404
134578
  }
134405
134579
  curNode.#methods.push({
134406
134580
  [method]: {
134407
134581
  handler,
134408
- possibleKeys: possibleKeys.filter((v2, i, a) => a.indexOf(v2) === i),
134409
- score: this.#order
134582
+ possibleKeys: [...possibleKeys],
134583
+ score: ++order
134410
134584
  }
134411
134585
  });
134412
- return curNode;
134413
134586
  }
134414
134587
  #pushHandlerSets(handlerSets, node, method, nodeParams, params) {
134415
134588
  for (let i = 0, len = node.#methods.length; i < len; i++) {
134416
134589
  const m2 = node.#methods[i];
134417
134590
  const handlerSet = m2[method] || m2[METHOD_NAME_ALL];
134418
- const processedSet = {};
134419
- if (handlerSet !== void 0) {
134591
+ if (handlerSet) {
134420
134592
  handlerSet.params = /* @__PURE__ */ Object.create(null);
134421
134593
  handlerSets.push(handlerSet);
134422
- if (nodeParams !== emptyParams || params && params !== emptyParams) {
134423
- for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
134424
- const key = handlerSet.possibleKeys[i2];
134425
- const processed = processedSet[handlerSet.score];
134426
- handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key];
134427
- processedSet[handlerSet.score] = true;
134428
- }
134594
+ for (let i2 = 0, len2 = handlerSet.possibleKeys.length; i2 < len2; i2++) {
134595
+ const key = handlerSet.possibleKeys[i2];
134596
+ handlerSet.params[key] = params?.[key] && !i2 ? params[key] : nodeParams[key] ?? params?.[key];
134429
134597
  }
134430
134598
  }
134431
134599
  }
@@ -134457,33 +134625,33 @@ var Node2 = class _Node2 {
134457
134625
  tempNodes.push(nextNode);
134458
134626
  }
134459
134627
  }
134460
- for (let k2 = 0, len3 = node.#patterns.length; k2 < len3; k2++) {
134461
- const pattern = node.#patterns[k2];
134628
+ for (const child of node.#patterns) {
134629
+ const pattern = child.#pattern;
134462
134630
  const params = node.#params === emptyParams ? {} : { ...node.#params };
134463
- if (pattern === "*") {
134464
- const astNode = node.#children["*"];
134465
- if (astNode) {
134466
- this.#pushHandlerSets(handlerSets, astNode, method, node.#params);
134467
- astNode.#params = params;
134468
- tempNodes.push(astNode);
134631
+ if (typeof pattern === "string") {
134632
+ if (pattern === "*" || part.startsWith(pattern.slice(0, -1))) {
134633
+ this.#pushHandlerSets(handlerSets, child, method, node.#params);
134634
+ if (pattern === "*") {
134635
+ child.#params = params;
134636
+ tempNodes.push(child);
134637
+ }
134469
134638
  }
134470
134639
  continue;
134471
134640
  }
134472
- const [key, name, matcher] = pattern;
134473
- if (!part && !(matcher instanceof RegExp)) {
134641
+ const [, name, matcher] = pattern;
134642
+ if (!part && matcher === true) {
134474
134643
  continue;
134475
134644
  }
134476
- const child = node.#children[key];
134477
- if (matcher instanceof RegExp) {
134478
- if (partOffsets === null) {
134479
- partOffsets = new Array(len);
134645
+ if (matcher !== true) {
134646
+ if (!partOffsets) {
134647
+ partOffsets = [];
134480
134648
  let offset = path2[0] === "/" ? 1 : 0;
134481
134649
  for (let p2 = 0; p2 < len; p2++) {
134482
134650
  partOffsets[p2] = offset;
134483
134651
  offset += parts[p2].length + 1;
134484
134652
  }
134485
134653
  }
134486
- const restPathString = path2.substring(partOffsets[i]);
134654
+ const restPathString = path2.slice(partOffsets[i]);
134487
134655
  const m2 = matcher.exec(restPathString);
134488
134656
  if (m2) {
134489
134657
  params[name] = m2[0];
@@ -134497,11 +134665,12 @@ var Node2 = class _Node2 {
134497
134665
  params
134498
134666
  );
134499
134667
  }
134500
- if (hasChildren(child.#children)) {
134668
+ for (const _2 in child.#children) {
134501
134669
  child.#params = params;
134502
- const componentCount = m2[0].match(/\//)?.length ?? 0;
134670
+ const componentCount = m2[0].match(/\//g)?.length ?? 0;
134503
134671
  const targetCurNodes = curNodesQueue[componentCount] ||= [];
134504
134672
  targetCurNodes.push(child);
134673
+ break;
134505
134674
  }
134506
134675
  continue;
134507
134676
  }
@@ -134529,7 +134698,7 @@ var Node2 = class _Node2 {
134529
134698
  const shifted = curNodesQueue.shift();
134530
134699
  curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
134531
134700
  }
134532
- if (handlerSets.length > 1) {
134701
+ if (handlerSets[1]) {
134533
134702
  handlerSets.sort((a, b2) => {
134534
134703
  return a.score - b2.score;
134535
134704
  });
@@ -134541,19 +134710,11 @@ var Node2 = class _Node2 {
134541
134710
  // node_modules/hono/dist/router/trie-router/router.js
134542
134711
  var TrieRouter = class {
134543
134712
  name = "TrieRouter";
134544
- #node;
134545
- constructor() {
134546
- this.#node = new Node2();
134547
- }
134713
+ #node = new Node2();
134548
134714
  add(method, path2, handler) {
134549
- const results = checkOptionalParameter(path2);
134550
- if (results) {
134551
- for (let i = 0, len = results.length; i < len; i++) {
134552
- this.#node.insert(method, results[i], handler);
134553
- }
134554
- return;
134715
+ for (const result of checkOptionalParameter(path2) || [path2]) {
134716
+ this.#node.insert(method, result, handler);
134555
134717
  }
134556
- this.#node.insert(method, path2, handler);
134557
134718
  }
134558
134719
  match(method, path2) {
134559
134720
  return this.#node.search(method, path2);
@@ -136057,7 +136218,13 @@ var createMiscRoutes = (deps) => {
136057
136218
  // the box is starved. Additive capability flag only — live readings stay
136058
136219
  // off this polled endpoint. Absent means an older server that never
136059
136220
  // samples. Informational: pressure never holds, kills, or refuses sessions.
136060
- hostPressure: true
136221
+ hostPressure: true,
136222
+ // Provider-neutral prompt contract: normalized prompt events, opaque ids
136223
+ // and the atomic /prompt/answer route. A prompt_snapshot on subscribe
136224
+ // carries RETAINED prompts, terminal ones included — render on `state`,
136225
+ // not on presence — and an answer retry after that retention window is
136226
+ // answered 404 prompt_not_found rather than the recorded outcome.
136227
+ promptContract: { schemaVersion: 1, atomicAnswer: true }
136061
136228
  });
136062
136229
  });
136063
136230
  app.get("/api/profiles", (c) => c.json([]));
@@ -136555,6 +136722,10 @@ var createSessionRoutes = (deps) => {
136555
136722
  await deps.handleSendAnswer(c.req.param("id"), c.env.incoming, c.env.outgoing);
136556
136723
  return alreadyHandled6();
136557
136724
  });
136725
+ app.post("/:id/prompt/answer", async (c) => {
136726
+ await deps.handlePromptAnswer(c.req.param("id"), c.env.incoming, c.env.outgoing);
136727
+ return alreadyHandled6();
136728
+ });
136558
136729
  app.post("/:id/permission/answer", async (c) => {
136559
136730
  await deps.handlePermissionAnswer(c.req.param("id"), c.env.incoming, c.env.outgoing);
136560
136731
  return alreadyHandled6();
@@ -140738,10 +140909,10 @@ function watch(paths, options = {}) {
140738
140909
  var chokidar_default = { watch, FSWatcher };
140739
140910
 
140740
140911
  // node_modules/@threadbase-sh/scanner/dist/index.js
140741
- function applySort(metas, order) {
140912
+ function applySort(metas, order2) {
140742
140913
  const out = [...metas];
140743
140914
  const tie = (a, b2) => a.id.localeCompare(b2.id);
140744
- switch (order) {
140915
+ switch (order2) {
140745
140916
  case "recent":
140746
140917
  out.sort((a, b2) => b2.timestamp.localeCompare(a.timestamp) || tie(a, b2));
140747
140918
  break;
@@ -146251,7 +146422,7 @@ function parseSessionListQuery(url2) {
146251
146422
  if (!VALID_ORDERS.includes(orderRaw)) {
146252
146423
  return { error: `order must be asc or desc` };
146253
146424
  }
146254
- const order = orderRaw;
146425
+ const order2 = orderRaw;
146255
146426
  const statusRaw = url2.searchParams.get("status");
146256
146427
  let status;
146257
146428
  if (statusRaw) {
@@ -146264,7 +146435,7 @@ function parseSessionListQuery(url2) {
146264
146435
  status = parts;
146265
146436
  }
146266
146437
  const cursor = url2.searchParams.get("cursor") ?? void 0;
146267
- return { query: { limit, sortBy, order, status, cursor } };
146438
+ return { query: { limit, sortBy, order: order2, status, cursor } };
146268
146439
  }
146269
146440
  function readBody2(req) {
146270
146441
  return new Promise((resolve4, reject) => {
@@ -147672,6 +147843,522 @@ async function readGitBranch2(dir) {
147672
147843
  // src/api/handlers/sessions.handlers.ts
147673
147844
  init_providers();
147674
147845
  init_pty_shared();
147846
+
147847
+ // src/schemas/prompt.schema.ts
147848
+ init_zod();
147849
+ var PROMPT_SCHEMA_VERSION = 1;
147850
+ var OpaqueIdSchema = external_exports.string().trim().min(1).max(200);
147851
+ var MeaningfulStringSchema = external_exports.string().trim().min(1);
147852
+ var PromptOptionSchema = external_exports.object({
147853
+ optionId: OpaqueIdSchema,
147854
+ label: MeaningfulStringSchema,
147855
+ description: external_exports.string().optional(),
147856
+ preview: external_exports.string().optional()
147857
+ });
147858
+ var PromptQuestionSchema = external_exports.object({
147859
+ questionId: OpaqueIdSchema,
147860
+ text: MeaningfulStringSchema,
147861
+ header: external_exports.string().optional(),
147862
+ inputMode: external_exports.enum(["single", "multi", "text"]),
147863
+ options: external_exports.array(PromptOptionSchema),
147864
+ allowOther: external_exports.boolean(),
147865
+ secret: external_exports.union([external_exports.boolean(), external_exports.literal("unknown")])
147866
+ }).superRefine((question, ctx) => {
147867
+ const optionIds = question.options.map((option) => option.optionId);
147868
+ if (new Set(optionIds).size !== optionIds.length) {
147869
+ ctx.addIssue({
147870
+ code: "custom",
147871
+ message: "optionId values must be unique",
147872
+ path: ["options"]
147873
+ });
147874
+ }
147875
+ if (question.inputMode === "text" && question.options.length !== 0) {
147876
+ ctx.addIssue({
147877
+ code: "custom",
147878
+ message: "text questions cannot carry options",
147879
+ path: ["options"]
147880
+ });
147881
+ }
147882
+ if (question.inputMode !== "text" && question.options.length === 0) {
147883
+ ctx.addIssue({
147884
+ code: "custom",
147885
+ message: "select questions require options",
147886
+ path: ["options"]
147887
+ });
147888
+ }
147889
+ });
147890
+ var TERMINAL_PROMPT_STATES = /* @__PURE__ */ new Set(["resolved", "cancelled", "expired", "unavailable"]);
147891
+ var PromptSchema = external_exports.object({
147892
+ schemaVersion: external_exports.literal(PROMPT_SCHEMA_VERSION),
147893
+ sessionId: OpaqueIdSchema,
147894
+ promptId: OpaqueIdSchema,
147895
+ revision: external_exports.number().int().positive(),
147896
+ state: external_exports.enum(["open", "updated", "resolved", "cancelled", "expired", "unavailable"]),
147897
+ terminalReason: MeaningfulStringSchema.optional(),
147898
+ intent: external_exports.enum(["approval", "question"]),
147899
+ title: external_exports.string().optional(),
147900
+ message: external_exports.string().optional(),
147901
+ detail: external_exports.string().optional(),
147902
+ questions: external_exports.array(PromptQuestionSchema).min(1),
147903
+ answerRequirement: external_exports.enum(["blocking", "non_blocking", "unknown"]),
147904
+ expiresAt: external_exports.string().datetime({ offset: true }).nullable(),
147905
+ provenance: external_exports.object({
147906
+ source: external_exports.enum(["provider", "screen", "transcript", "synthetic"]),
147907
+ confidence: external_exports.enum(["authoritative", "inferred"])
147908
+ })
147909
+ }).superRefine((prompt, ctx) => {
147910
+ if (![prompt.title, prompt.message, prompt.detail].some((value) => value?.trim())) {
147911
+ ctx.addIssue({
147912
+ code: "custom",
147913
+ message: "prompt requires a meaningful title, message, or detail",
147914
+ path: ["message"]
147915
+ });
147916
+ }
147917
+ const questionIds = prompt.questions.map((question) => question.questionId);
147918
+ if (new Set(questionIds).size !== questionIds.length) {
147919
+ ctx.addIssue({
147920
+ code: "custom",
147921
+ message: "questionId values must be unique",
147922
+ path: ["questions"]
147923
+ });
147924
+ }
147925
+ const optionIds = prompt.questions.flatMap(
147926
+ (question) => question.options.map((option) => option.optionId)
147927
+ );
147928
+ if (new Set(optionIds).size !== optionIds.length) {
147929
+ ctx.addIssue({
147930
+ code: "custom",
147931
+ message: "optionId values must be unique within a prompt",
147932
+ path: ["questions"]
147933
+ });
147934
+ }
147935
+ const terminal = TERMINAL_PROMPT_STATES.has(prompt.state);
147936
+ if (terminal !== (prompt.terminalReason !== void 0)) {
147937
+ ctx.addIssue({
147938
+ code: "custom",
147939
+ message: terminal ? "terminal prompts require terminalReason" : "actionable prompts cannot carry terminalReason",
147940
+ path: ["terminalReason"]
147941
+ });
147942
+ }
147943
+ });
147944
+ var OptionResponseSchema = external_exports.object({
147945
+ questionId: OpaqueIdSchema,
147946
+ optionIds: external_exports.array(OpaqueIdSchema).min(1).refine((ids) => new Set(ids).size === ids.length, "optionIds must be unique"),
147947
+ text: external_exports.never().optional()
147948
+ });
147949
+ var TextResponseSchema = external_exports.object({
147950
+ questionId: OpaqueIdSchema,
147951
+ text: external_exports.string(),
147952
+ optionIds: external_exports.never().optional()
147953
+ });
147954
+ var PromptResponseSchema = external_exports.union([OptionResponseSchema, TextResponseSchema]);
147955
+ var PromptAnswerSchema = external_exports.object({
147956
+ promptId: OpaqueIdSchema,
147957
+ revision: external_exports.number().int().positive(),
147958
+ responses: external_exports.array(PromptResponseSchema).min(1),
147959
+ idempotencyKey: OpaqueIdSchema
147960
+ }).superRefine((answer, ctx) => {
147961
+ const questionIds = answer.responses.map((response) => response.questionId);
147962
+ if (new Set(questionIds).size !== questionIds.length) {
147963
+ ctx.addIssue({
147964
+ code: "custom",
147965
+ message: "each questionId can be answered only once",
147966
+ path: ["responses"]
147967
+ });
147968
+ }
147969
+ });
147970
+
147971
+ // src/services/prompts/promptRegistry.ts
147972
+ var import_node_crypto5 = require("crypto");
147973
+ var PROMPT_TERMINAL_RETENTION_MS = 10 * 60 * 1e3;
147974
+ var PROMPT_MAX_RECORDS_PER_SESSION = 200;
147975
+ var MAX_TIMEOUT_MS = 2147483647;
147976
+ function copyPrompt(prompt) {
147977
+ return {
147978
+ ...prompt,
147979
+ questions: prompt.questions.map((question) => ({
147980
+ ...question,
147981
+ options: question.options.map((option) => ({ ...option }))
147982
+ })),
147983
+ provenance: { ...prompt.provenance }
147984
+ };
147985
+ }
147986
+ function terminalError(state) {
147987
+ switch (state) {
147988
+ case "resolved":
147989
+ return "already_resolved";
147990
+ case "expired":
147991
+ return "prompt_expired";
147992
+ case "cancelled":
147993
+ return "prompt_cancelled";
147994
+ case "unavailable":
147995
+ return "prompt_unavailable";
147996
+ }
147997
+ }
147998
+ var PromptRegistry = class {
147999
+ bySession = /* @__PURE__ */ new Map();
148000
+ byId = /* @__PURE__ */ new Map();
148001
+ sequences = /* @__PURE__ */ new Map();
148002
+ createId;
148003
+ emit;
148004
+ onExpire;
148005
+ now;
148006
+ terminalRetentionMs;
148007
+ maxRecordsPerSession;
148008
+ constructor(options = {}) {
148009
+ this.createId = options.createId ?? import_node_crypto5.randomUUID;
148010
+ this.emit = options.emit;
148011
+ this.onExpire = options.onExpire;
148012
+ this.now = options.now ?? Date.now;
148013
+ this.terminalRetentionMs = options.terminalRetentionMs ?? PROMPT_TERMINAL_RETENTION_MS;
148014
+ this.maxRecordsPerSession = options.maxRecordsPerSession ?? PROMPT_MAX_RECORDS_PER_SESSION;
148015
+ }
148016
+ open(draft, adapter, promptId = this.createId()) {
148017
+ this.prune(draft.sessionId);
148018
+ const held = this.byId.get(promptId);
148019
+ if (held && (held.prompt.state === "open" || held.prompt.state === "updated")) {
148020
+ throw new Error(`Prompt id already exists: ${promptId}`);
148021
+ }
148022
+ const id = held ? this.createId() : promptId;
148023
+ const prompt = PromptSchema.parse({
148024
+ ...draft,
148025
+ schemaVersion: PROMPT_SCHEMA_VERSION,
148026
+ promptId: id,
148027
+ revision: 1,
148028
+ state: "open",
148029
+ questions: draft.questions.map((question) => ({
148030
+ ...question,
148031
+ questionId: this.createId(),
148032
+ options: question.options.map((option) => ({ ...option, optionId: this.createId() }))
148033
+ })),
148034
+ provenance: { ...draft.provenance }
148035
+ });
148036
+ const entry = {
148037
+ prompt,
148038
+ adapter,
148039
+ queue: Promise.resolve(),
148040
+ inFlight: /* @__PURE__ */ new Map(),
148041
+ outcomes: /* @__PURE__ */ new Map()
148042
+ };
148043
+ const session = this.bySession.get(prompt.sessionId) ?? /* @__PURE__ */ new Map();
148044
+ session.set(prompt.promptId, entry);
148045
+ this.bySession.set(prompt.sessionId, session);
148046
+ this.byId.set(prompt.promptId, entry);
148047
+ this.publish(entry);
148048
+ this.scheduleExpiration(entry);
148049
+ this.enforceCap(prompt.sessionId);
148050
+ return copyPrompt(prompt);
148051
+ }
148052
+ update(promptId, draft, adapter) {
148053
+ const entry = this.requireEntry(promptId);
148054
+ this.expireIfDue(entry, this.now());
148055
+ if (entry.prompt.sessionId !== draft.sessionId) throw new Error("Prompt session cannot change");
148056
+ if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") {
148057
+ throw new Error(`Cannot update terminal prompt ${promptId}`);
148058
+ }
148059
+ if (entry.prompt.questions.length !== draft.questions.length) {
148060
+ throw new Error("Prompt question cardinality cannot change during an update");
148061
+ }
148062
+ const questions = draft.questions.map((question, questionIndex) => {
148063
+ const prior = entry.prompt.questions[questionIndex];
148064
+ if (prior.options.length !== question.options.length) {
148065
+ throw new Error("Prompt option cardinality cannot change during an update");
148066
+ }
148067
+ return {
148068
+ ...question,
148069
+ questionId: prior.questionId,
148070
+ options: question.options.map((option, optionIndex) => ({
148071
+ ...option,
148072
+ optionId: prior.options[optionIndex].optionId
148073
+ }))
148074
+ };
148075
+ });
148076
+ const prompt = PromptSchema.parse({
148077
+ ...draft,
148078
+ schemaVersion: PROMPT_SCHEMA_VERSION,
148079
+ promptId,
148080
+ revision: entry.prompt.revision + 1,
148081
+ state: "updated",
148082
+ questions,
148083
+ provenance: { ...draft.provenance }
148084
+ });
148085
+ entry.prompt = prompt;
148086
+ if (adapter) entry.adapter = adapter;
148087
+ this.publish(entry);
148088
+ this.scheduleExpiration(entry);
148089
+ return copyPrompt(entry.prompt);
148090
+ }
148091
+ transition(promptId, state, reason) {
148092
+ const entry = this.requireEntry(promptId);
148093
+ if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") {
148094
+ throw new Error(`Cannot transition terminal prompt ${promptId}`);
148095
+ }
148096
+ entry.prompt = {
148097
+ ...entry.prompt,
148098
+ revision: entry.prompt.revision + 1,
148099
+ state,
148100
+ terminalReason: reason
148101
+ };
148102
+ entry.terminalAt = this.now();
148103
+ this.clearExpiration(entry);
148104
+ this.publish(entry);
148105
+ return copyPrompt(entry.prompt);
148106
+ }
148107
+ invalidateSession(sessionId, reason = "session_ended") {
148108
+ const transitioned = [];
148109
+ for (const entry of this.bySession.get(sessionId)?.values() ?? []) {
148110
+ if (entry.prompt.state === "open" || entry.prompt.state === "updated") {
148111
+ transitioned.push(this.transition(entry.prompt.promptId, "unavailable", reason));
148112
+ }
148113
+ }
148114
+ return transitioned;
148115
+ }
148116
+ get(promptId) {
148117
+ const entry = this.byId.get(promptId);
148118
+ if (!entry) return null;
148119
+ this.prune(entry.prompt.sessionId);
148120
+ return this.byId.has(promptId) ? copyPrompt(entry.prompt) : null;
148121
+ }
148122
+ hasActionable(sessionId) {
148123
+ this.prune(sessionId);
148124
+ return [...this.bySession.get(sessionId)?.values() ?? []].some(
148125
+ (entry) => entry.prompt.state === "open" || entry.prompt.state === "updated"
148126
+ );
148127
+ }
148128
+ snapshot(sessionId) {
148129
+ this.prune(sessionId);
148130
+ return {
148131
+ type: "prompt_snapshot",
148132
+ schemaVersion: PROMPT_SCHEMA_VERSION,
148133
+ sessionId,
148134
+ sequence: this.sequences.get(sessionId) ?? 0,
148135
+ prompts: [...this.bySession.get(sessionId)?.values() ?? []].map(
148136
+ (entry) => copyPrompt(entry.prompt)
148137
+ )
148138
+ };
148139
+ }
148140
+ dispose() {
148141
+ for (const entry of this.byId.values()) this.clearExpiration(entry);
148142
+ }
148143
+ answer(sessionId, answer) {
148144
+ this.prune(sessionId);
148145
+ const entry = this.byId.get(answer.promptId);
148146
+ if (!entry || entry.prompt.sessionId !== sessionId) {
148147
+ return Promise.resolve({ ok: false, code: "prompt_not_found" });
148148
+ }
148149
+ this.pruneOutcomes(entry);
148150
+ const recorded = entry.outcomes.get(answer.idempotencyKey);
148151
+ if (recorded) return Promise.resolve(recorded.outcome);
148152
+ const pending = entry.inFlight.get(answer.idempotencyKey);
148153
+ if (pending) return pending;
148154
+ const task = entry.queue.then(() => this.performAnswer(entry, answer));
148155
+ entry.queue = task.then(
148156
+ () => void 0,
148157
+ () => void 0
148158
+ );
148159
+ entry.inFlight.set(answer.idempotencyKey, task);
148160
+ void task.then((outcome) => {
148161
+ entry.inFlight.delete(answer.idempotencyKey);
148162
+ entry.outcomes.set(answer.idempotencyKey, { at: this.now(), outcome });
148163
+ });
148164
+ return task;
148165
+ }
148166
+ async performAnswer(entry, answer) {
148167
+ const prompt = entry.prompt;
148168
+ if (prompt.state !== "open" && prompt.state !== "updated") {
148169
+ return { ok: false, code: terminalError(prompt.state) };
148170
+ }
148171
+ if (this.expireIfDue(entry, this.now())) {
148172
+ return { ok: false, code: "prompt_expired" };
148173
+ }
148174
+ if (prompt.revision !== answer.revision) {
148175
+ return {
148176
+ ok: false,
148177
+ code: "prompt_revision_mismatch",
148178
+ currentRevision: prompt.revision
148179
+ };
148180
+ }
148181
+ const responseError = this.validateResponses(prompt, answer);
148182
+ if (responseError) return { ok: false, code: responseError };
148183
+ if (!entry.adapter) return { ok: false, code: "prompt_unavailable" };
148184
+ let adapterResult;
148185
+ try {
148186
+ adapterResult = await entry.adapter({ prompt: copyPrompt(prompt), answer });
148187
+ } catch {
148188
+ return { ok: false, code: "provider_error" };
148189
+ }
148190
+ if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") {
148191
+ return { ok: false, code: terminalError(entry.prompt.state) };
148192
+ }
148193
+ if (entry.prompt.revision !== answer.revision) {
148194
+ return {
148195
+ ok: false,
148196
+ code: "prompt_revision_mismatch",
148197
+ currentRevision: entry.prompt.revision
148198
+ };
148199
+ }
148200
+ if (!adapterResult.ok) {
148201
+ if (adapterResult.terminal) {
148202
+ this.transition(
148203
+ prompt.promptId,
148204
+ adapterResult.terminal.state,
148205
+ adapterResult.terminal.reason
148206
+ );
148207
+ }
148208
+ return { ok: false, code: adapterResult.code };
148209
+ }
148210
+ return { ok: true, prompt: this.transition(prompt.promptId, "resolved", "answered") };
148211
+ }
148212
+ validateResponses(prompt, answer) {
148213
+ const questions = new Map(prompt.questions.map((question) => [question.questionId, question]));
148214
+ for (const response of answer.responses) {
148215
+ if (!questions.has(response.questionId)) return "unknown_question";
148216
+ }
148217
+ if (answer.responses.length !== prompt.questions.length) return "incomplete_answer";
148218
+ const responses = new Map(answer.responses.map((response) => [response.questionId, response]));
148219
+ for (const question of prompt.questions) {
148220
+ const response = responses.get(question.questionId);
148221
+ if (!response) return "incomplete_answer";
148222
+ if (question.inputMode === "text") {
148223
+ if (typeof response.text !== "string") return "incomplete_answer";
148224
+ continue;
148225
+ }
148226
+ const optionIds = response.optionIds;
148227
+ if (!optionIds) return "incomplete_answer";
148228
+ if (question.inputMode === "single" && optionIds.length !== 1) {
148229
+ return "unsupported_prompt_shape";
148230
+ }
148231
+ const known = new Set(question.options.map((option) => option.optionId));
148232
+ if (optionIds.some((optionId) => !known.has(optionId))) return "unknown_option";
148233
+ }
148234
+ return null;
148235
+ }
148236
+ publish(entry) {
148237
+ const sessionId = entry.prompt.sessionId;
148238
+ const sequence = (this.sequences.get(sessionId) ?? 0) + 1;
148239
+ this.sequences.set(sessionId, sequence);
148240
+ this.emit?.({
148241
+ type: "prompt_event",
148242
+ sessionId,
148243
+ sequence,
148244
+ prompt: copyPrompt(entry.prompt)
148245
+ });
148246
+ }
148247
+ scheduleExpiration(entry) {
148248
+ this.clearExpiration(entry);
148249
+ const expiresAt = entry.prompt.expiresAt;
148250
+ if (expiresAt === null) return;
148251
+ const delay = Math.min(MAX_TIMEOUT_MS, Math.max(0, Date.parse(expiresAt) - this.now()));
148252
+ entry.expiryTimer = setTimeout(() => {
148253
+ entry.expiryTimer = void 0;
148254
+ if (!this.expireIfDue(entry, this.now())) this.scheduleExpiration(entry);
148255
+ }, delay);
148256
+ entry.expiryTimer.unref?.();
148257
+ }
148258
+ clearExpiration(entry) {
148259
+ if (entry.expiryTimer) clearTimeout(entry.expiryTimer);
148260
+ entry.expiryTimer = void 0;
148261
+ }
148262
+ expireIfDue(entry, now) {
148263
+ if (entry.prompt.state !== "open" && entry.prompt.state !== "updated") return false;
148264
+ if (entry.prompt.expiresAt === null || now < Date.parse(entry.prompt.expiresAt)) return false;
148265
+ const expired = this.transition(entry.prompt.promptId, "expired", "deadline_elapsed");
148266
+ this.onExpire?.(expired);
148267
+ return true;
148268
+ }
148269
+ requireEntry(promptId) {
148270
+ const entry = this.byId.get(promptId);
148271
+ if (!entry) throw new Error(`Unknown prompt: ${promptId}`);
148272
+ return entry;
148273
+ }
148274
+ prune(sessionId) {
148275
+ const now = this.now();
148276
+ const session = this.bySession.get(sessionId);
148277
+ if (!session) return;
148278
+ for (const [promptId, entry] of session) {
148279
+ this.expireIfDue(entry, now);
148280
+ if (entry.terminalAt !== void 0 && now - entry.terminalAt > this.terminalRetentionMs) {
148281
+ this.clearExpiration(entry);
148282
+ session.delete(promptId);
148283
+ this.byId.delete(promptId);
148284
+ }
148285
+ }
148286
+ if (session.size === 0) this.bySession.delete(sessionId);
148287
+ }
148288
+ enforceCap(sessionId) {
148289
+ const session = this.bySession.get(sessionId);
148290
+ if (!session || session.size <= this.maxRecordsPerSession) return;
148291
+ const terminal = [...session.entries()].filter(([, entry]) => entry.terminalAt !== void 0).sort((a, b2) => (a[1].terminalAt ?? 0) - (b2[1].terminalAt ?? 0));
148292
+ while (session.size > this.maxRecordsPerSession && terminal.length > 0) {
148293
+ const [promptId, entry] = terminal.shift();
148294
+ this.clearExpiration(entry);
148295
+ session.delete(promptId);
148296
+ this.byId.delete(promptId);
148297
+ }
148298
+ }
148299
+ pruneOutcomes(entry) {
148300
+ const now = this.now();
148301
+ for (const [key, recorded] of entry.outcomes) {
148302
+ if (now - recorded.at > this.terminalRetentionMs) entry.outcomes.delete(key);
148303
+ }
148304
+ }
148305
+ };
148306
+
148307
+ // src/services/prompts/ptyPromptAdapter.ts
148308
+ function permissionPromptDraft(sessionId, gate) {
148309
+ if (!gate) throw new Error("Cannot normalize an absent permission gate");
148310
+ const message = gate.prompt?.trim() || "Approval required";
148311
+ return {
148312
+ sessionId,
148313
+ intent: "approval",
148314
+ title: "Approval",
148315
+ message,
148316
+ ...gate.detail?.trim() ? { detail: gate.detail } : {},
148317
+ questions: [
148318
+ {
148319
+ text: message,
148320
+ header: "Approval",
148321
+ inputMode: "single",
148322
+ options: gate.options.map((option) => ({ label: option.label })),
148323
+ allowOther: false,
148324
+ secret: "unknown"
148325
+ }
148326
+ ],
148327
+ answerRequirement: "unknown",
148328
+ expiresAt: null,
148329
+ provenance: { source: "screen", confidence: "inferred" }
148330
+ };
148331
+ }
148332
+ function questionPromptDraft(sessionId, questions, source) {
148333
+ const first = questions[0];
148334
+ if (!first) throw new Error("Cannot normalize an empty question list");
148335
+ return {
148336
+ sessionId,
148337
+ intent: "question",
148338
+ ...first.header.trim() ? { title: first.header } : {},
148339
+ message: first.question,
148340
+ questions: questions.map((question) => ({
148341
+ text: question.question,
148342
+ ...question.header.trim() ? { header: question.header } : {},
148343
+ inputMode: question.multiSelect ? "multi" : "single",
148344
+ options: question.options.map((option) => ({
148345
+ label: option.label,
148346
+ ...option.description ? { description: option.description } : {},
148347
+ ...option.preview ? { preview: option.preview } : {}
148348
+ })),
148349
+ allowOther: false,
148350
+ secret: "unknown"
148351
+ })),
148352
+ answerRequirement: "unknown",
148353
+ expiresAt: null,
148354
+ provenance: {
148355
+ source,
148356
+ confidence: source === "transcript" ? "authoritative" : "inferred"
148357
+ }
148358
+ };
148359
+ }
148360
+
148361
+ // src/api/handlers/sessions.handlers.ts
147675
148362
  init_codexScreen();
147676
148363
  init_detectPermissionGate();
147677
148364
  init_detectQuestionFromScreen();
@@ -148041,6 +148728,21 @@ function codexSessionActiveBody(outcome) {
148041
148728
  ...outcome.ownerSource != null && { ownerSource: outcome.ownerSource }
148042
148729
  };
148043
148730
  }
148731
+ function promptAnswerStatus(code) {
148732
+ switch (code) {
148733
+ case "prompt_not_found":
148734
+ return 404;
148735
+ case "provider_error":
148736
+ return 502;
148737
+ case "unknown_question":
148738
+ case "unknown_option":
148739
+ case "incomplete_answer":
148740
+ case "unsupported_prompt_shape":
148741
+ return 400;
148742
+ default:
148743
+ return 409;
148744
+ }
148745
+ }
148044
148746
  var SessionHandlers = class {
148045
148747
  constructor(deps) {
148046
148748
  this.deps = deps;
@@ -148079,6 +148781,10 @@ var SessionHandlers = class {
148079
148781
  get pendingQuestions() {
148080
148782
  return this.deps.pendingQuestions;
148081
148783
  }
148784
+ get promptRegistry() {
148785
+ if (!this.deps.promptRegistry) this.deps.promptRegistry = new PromptRegistry();
148786
+ return this.deps.promptRegistry;
148787
+ }
148082
148788
  get pendingQuestionKey() {
148083
148789
  return this.deps.pendingQuestionKey;
148084
148790
  }
@@ -148097,6 +148803,13 @@ var SessionHandlers = class {
148097
148803
  get sessionSubscribers() {
148098
148804
  return this.deps.sessionSubscribers;
148099
148805
  }
148806
+ // Prompt lifecycle events (question / permission and their cancellations)
148807
+ // carry prompt content and go ONLY to the session's subscribers — never to
148808
+ // every connected socket. A client that subscribes after a prompt opened
148809
+ // gets it from the subscribe replay (server-wiring), not from a broadcast.
148810
+ broadcastToSession(sessionId, message) {
148811
+ this.wsHub.broadcastToClients(this.sessionSubscribers.get(sessionId) ?? [], message);
148812
+ }
148100
148813
  get agentConfig() {
148101
148814
  return this.deps.agentConfig;
148102
148815
  }
@@ -148590,6 +149303,7 @@ var SessionHandlers = class {
148590
149303
  json2(res, 400, { error: "Missing input field" });
148591
149304
  return;
148592
149305
  }
149306
+ this.promptRegistry.hasActionable(sessionId);
148593
149307
  const openPrompt = this.pendingPermission.has(sessionId) ? "permission" : this.pendingQuestions.has(sessionId) ? "question" : null;
148594
149308
  if (openPrompt) {
148595
149309
  this.log.info(`[input.prompt_pending] ${sessionId.slice(0, 8)} kind=${openPrompt}`, {
@@ -148645,37 +149359,106 @@ var SessionHandlers = class {
148645
149359
  // the later JSONL flush of the same question is de-duped. We synthesize a
148646
149360
  // screen-scoped toolUseId; the JSONL path overwrites pendingQuestions with the
148647
149361
  // real toolUseId when it lands, so answering works once JSONL catches up.
148648
- handleLiveQuestion(sessionId, questions) {
149362
+ handleLiveQuestion(sessionId, questions, occurrenceId) {
148649
149363
  const key = questionContentKey(questions);
148650
149364
  if (this.pendingQuestionKey.get(sessionId) === key) return;
148651
149365
  const toolUseId = `screen:${sessionId}:${key.length}`;
148652
- this.pendingQuestions.set(sessionId, { toolUseId, questions, origin: "pty" });
149366
+ const prior = this.pendingQuestions.get(sessionId);
149367
+ const priorPrompt = prior ? this.promptRegistry.get(prior.promptId) : null;
149368
+ if (priorPrompt?.state === "open" || priorPrompt?.state === "updated") {
149369
+ this.promptRegistry.transition(priorPrompt.promptId, "cancelled", "replaced");
149370
+ }
149371
+ const prompt = this.promptRegistry.open(
149372
+ questionPromptDraft(sessionId, questions, "screen"),
149373
+ this.questionAnswerAdapter(sessionId),
149374
+ occurrenceId
149375
+ );
149376
+ this.pendingQuestions.set(sessionId, {
149377
+ toolUseId,
149378
+ questions,
149379
+ origin: "pty",
149380
+ promptId: prompt.promptId
149381
+ });
148653
149382
  this.pendingQuestionKey.set(sessionId, key);
148654
- this.wsHub.broadcast({ type: "question", sessionId, toolUseId, questions });
149383
+ this.broadcastToSession(sessionId, { type: "question", sessionId, toolUseId, questions });
149384
+ }
149385
+ handleJsonlQuestion(sessionId, toolUseId, questions, origin) {
149386
+ const prior = this.pendingQuestions.get(sessionId);
149387
+ const sameQuestion = prior !== void 0 && questionContentKey(prior.questions) === questionContentKey(questions);
149388
+ let prompt;
149389
+ if (sameQuestion) {
149390
+ const current = this.promptRegistry.get(prior.promptId);
149391
+ prompt = current?.provenance.source === "transcript" ? current : this.promptRegistry.update(
149392
+ prior.promptId,
149393
+ questionPromptDraft(sessionId, questions, "transcript"),
149394
+ this.questionAnswerAdapter(sessionId)
149395
+ );
149396
+ } else {
149397
+ const priorPrompt = prior ? this.promptRegistry.get(prior.promptId) : null;
149398
+ if (priorPrompt?.state === "open" || priorPrompt?.state === "updated") {
149399
+ this.promptRegistry.transition(priorPrompt.promptId, "cancelled", "replaced");
149400
+ }
149401
+ prompt = this.promptRegistry.open(
149402
+ questionPromptDraft(sessionId, questions, "transcript"),
149403
+ this.questionAnswerAdapter(sessionId)
149404
+ );
149405
+ }
149406
+ this.pendingQuestions.set(sessionId, {
149407
+ toolUseId,
149408
+ questions,
149409
+ origin,
149410
+ promptId: prompt.promptId
149411
+ });
148655
149412
  }
148656
149413
  // Permission gate opened/closed (OSC 777 + scraped options). Broadcasts the
148657
149414
  // additive `permission` / `permission_cancelled` events. Mobile answers by
148658
149415
  // sending the chosen option index via /input { keys } (e.g. "2\r").
148659
- handlePermissionChange(sessionId, gate) {
149416
+ handlePermissionChange(sessionId, gate, occurrenceId) {
148660
149417
  if (gate === null) {
148661
- if (!this.pendingPermission.has(sessionId)) return;
149418
+ const prior2 = this.pendingPermission.get(sessionId);
149419
+ if (!prior2) return;
149420
+ const prompt2 = prior2.promptId ? this.promptRegistry.get(prior2.promptId) : null;
149421
+ if (prompt2?.state === "open" || prompt2?.state === "updated") {
149422
+ this.promptRegistry.transition(prompt2.promptId, "cancelled", "provider_closed");
149423
+ }
148662
149424
  this.pendingPermission.delete(sessionId);
148663
149425
  this.pendingPermissionKey.delete(sessionId);
148664
- this.wsHub.broadcast({ type: "permission_cancelled", sessionId });
149426
+ this.broadcastToSession(sessionId, { type: "permission_cancelled", sessionId });
148665
149427
  return;
148666
149428
  }
148667
149429
  const key = permissionContentKey(gate);
148668
- if (this.pendingPermissionKey.get(sessionId) === key) return;
148669
149430
  const prior = this.pendingPermission.get(sessionId);
148670
- const gateId = prior && permissionGateKey(prior) === permissionGateKey(gate) ? prior.gateId : (0, import_crypto9.randomUUID)();
148671
- this.pendingPermission.set(sessionId, { ...gate, gateId });
149431
+ const priorPromptId = prior?.promptId;
149432
+ if (this.pendingPermissionKey.get(sessionId) === key && (occurrenceId === void 0 || prior?.occurrenceId === occurrenceId)) {
149433
+ return;
149434
+ }
149435
+ const samePrompt = prior && priorPromptId !== void 0 && permissionGateKey(prior) === permissionGateKey(gate) && (occurrenceId === void 0 || prior.occurrenceId === occurrenceId);
149436
+ if (prior && !samePrompt) {
149437
+ const priorPrompt = prior.promptId ? this.promptRegistry.get(prior.promptId) : null;
149438
+ if (priorPrompt?.state === "open" || priorPrompt?.state === "updated") {
149439
+ this.promptRegistry.transition(priorPrompt.promptId, "cancelled", "replaced");
149440
+ }
149441
+ }
149442
+ const prompt = gate.options.length === 0 ? null : samePrompt ? this.promptRegistry.get(priorPromptId) : this.promptRegistry.open(
149443
+ permissionPromptDraft(sessionId, gate),
149444
+ this.permissionAnswerAdapter(sessionId),
149445
+ occurrenceId
149446
+ );
149447
+ if (samePrompt && !prompt) throw new Error("Pending permission prompt disappeared");
149448
+ const gateId = prompt?.promptId ?? occurrenceId ?? prior?.gateId ?? (0, import_crypto9.randomUUID)();
149449
+ this.pendingPermission.set(sessionId, {
149450
+ ...gate,
149451
+ gateId,
149452
+ ...prompt ? { promptId: prompt.promptId } : {},
149453
+ ...occurrenceId !== void 0 ? { occurrenceId } : {}
149454
+ });
148672
149455
  this.pendingPermissionKey.set(sessionId, key);
148673
149456
  const subscriberCount = this.sessionSubscribers.get(sessionId)?.size ?? 0;
148674
149457
  this.log.info(
148675
149458
  `[ws.broadcast_permission] ${sessionId.slice(0, 8)} subscribers=${subscriberCount}`,
148676
149459
  { event: "ws.broadcast_permission", sessionId, subscriberCount }
148677
149460
  );
148678
- this.wsHub.broadcast({
149461
+ this.broadcastToSession(sessionId, {
148679
149462
  type: "permission",
148680
149463
  sessionId,
148681
149464
  ...gate.prompt ? { prompt: gate.prompt } : {},
@@ -148686,6 +149469,107 @@ var SessionHandlers = class {
148686
149469
  gateId
148687
149470
  });
148688
149471
  }
149472
+ permissionAnswerAdapter(sessionId) {
149473
+ return async ({ prompt, answer }) => {
149474
+ const gate = this.pendingPermission.get(sessionId);
149475
+ if (!gate || gate.promptId !== prompt.promptId) {
149476
+ return {
149477
+ ok: false,
149478
+ code: "prompt_unavailable",
149479
+ terminal: { state: "unavailable", reason: "provider_prompt_missing" }
149480
+ };
149481
+ }
149482
+ const response = answer.responses[0];
149483
+ const selectedId = response?.optionIds?.[0];
149484
+ const selectedIndex = prompt.questions[0]?.options.findIndex(
149485
+ (option2) => option2.optionId === selectedId
149486
+ );
149487
+ if (selectedIndex === void 0 || selectedIndex < 0) {
149488
+ return { ok: false, code: "unknown_option" };
149489
+ }
149490
+ const option = gate.options[selectedIndex];
149491
+ if (!option) return { ok: false, code: "unknown_option" };
149492
+ const provider = this.sessionStore.getManaged(sessionId)?.provider;
149493
+ if (provider !== CODEX_CLI_PROVIDER && !await this.permissionGateStillOpen(sessionId, permissionGateKey(gate))) {
149494
+ return {
149495
+ ok: false,
149496
+ code: "prompt_cancelled",
149497
+ terminal: { state: "cancelled", reason: "provider_closed" }
149498
+ };
149499
+ }
149500
+ if (this.pendingPermission.get(sessionId)?.promptId !== prompt.promptId) {
149501
+ return { ok: false, code: "prompt_cancelled" };
149502
+ }
149503
+ try {
149504
+ this.ptyManager.sendKeys(
149505
+ sessionId,
149506
+ option.answerKeys ?? permissionAnswerKeys(option.index)
149507
+ );
149508
+ } catch {
149509
+ return { ok: false, code: "provider_error" };
149510
+ }
149511
+ return { ok: true };
149512
+ };
149513
+ }
149514
+ questionAnswerAdapter(sessionId) {
149515
+ return async ({ prompt, answer }) => {
149516
+ const pending = this.pendingQuestions.get(sessionId);
149517
+ if (!pending || pending.promptId !== prompt.promptId) {
149518
+ return {
149519
+ ok: false,
149520
+ code: "prompt_unavailable",
149521
+ terminal: { state: "unavailable", reason: "provider_prompt_missing" }
149522
+ };
149523
+ }
149524
+ const answers = {};
149525
+ for (const question of prompt.questions) {
149526
+ const response = answer.responses.find((item) => item.questionId === question.questionId);
149527
+ if (!response?.optionIds) return { ok: false, code: "unsupported_prompt_shape" };
149528
+ answers[question.text] = response.optionIds.map((optionId) => {
149529
+ const option = question.options.find((item) => item.optionId === optionId);
149530
+ return option?.label ?? "";
149531
+ });
149532
+ }
149533
+ const resolution = resolveAnswer(pending, {
149534
+ toolUseId: pending.toolUseId,
149535
+ answers
149536
+ });
149537
+ if (!resolution.ok) {
149538
+ const code = resolution.reason === "unknown_option" || resolution.reason === "incomplete_answer" || resolution.reason === "unsupported_prompt_shape" ? resolution.reason : "prompt_unavailable";
149539
+ return { ok: false, code };
149540
+ }
149541
+ if (!await this.questionMenuStillOpen(sessionId)) {
149542
+ this.pendingQuestions.delete(sessionId);
149543
+ this.pendingQuestionKey.delete(sessionId);
149544
+ this.broadcastToSession(sessionId, {
149545
+ type: "question_cancelled",
149546
+ sessionId,
149547
+ toolUseId: pending.toolUseId
149548
+ });
149549
+ return {
149550
+ ok: false,
149551
+ code: "prompt_cancelled",
149552
+ terminal: { state: "cancelled", reason: "provider_closed" }
149553
+ };
149554
+ }
149555
+ if (this.pendingQuestions.get(sessionId)?.promptId !== prompt.promptId) {
149556
+ return { ok: false, code: "prompt_cancelled" };
149557
+ }
149558
+ try {
149559
+ this.ptyManager.sendKeys(sessionId, resolution.keys);
149560
+ } catch {
149561
+ return { ok: false, code: "provider_error" };
149562
+ }
149563
+ this.pendingQuestions.delete(sessionId);
149564
+ this.pendingQuestionKey.delete(sessionId);
149565
+ this.broadcastToSession(sessionId, {
149566
+ type: "question_cancelled",
149567
+ sessionId,
149568
+ toolUseId: pending.toolUseId
149569
+ });
149570
+ return { ok: true };
149571
+ };
149572
+ }
148689
149573
  /**
148690
149574
  * Answer a permission gate — the validated counterpart of POST /:id/input.
148691
149575
  *
@@ -148721,9 +149605,14 @@ var SessionHandlers = class {
148721
149605
  return;
148722
149606
  }
148723
149607
  const gateClosed = () => {
149608
+ const pending = this.pendingPermission.get(sessionId);
149609
+ const prompt = pending?.promptId ? this.promptRegistry.get(pending.promptId) : null;
149610
+ if (prompt?.state === "open" || prompt?.state === "updated") {
149611
+ this.promptRegistry.transition(prompt.promptId, "cancelled", "provider_closed");
149612
+ }
148724
149613
  this.pendingPermission.delete(sessionId);
148725
149614
  this.pendingPermissionKey.delete(sessionId);
148726
- this.wsHub.broadcast({ type: "permission_cancelled", sessionId });
149615
+ this.broadcastToSession(sessionId, { type: "permission_cancelled", sessionId });
148727
149616
  json2(res, 409, { ok: false, reason: "gate_closed" });
148728
149617
  };
148729
149618
  const gate = this.pendingPermission.get(sessionId);
@@ -148762,6 +149651,10 @@ var SessionHandlers = class {
148762
149651
  json2(res, 400, { ok: false, reason: message });
148763
149652
  return;
148764
149653
  }
149654
+ const normalized = gate.promptId ? this.promptRegistry.get(gate.promptId) : null;
149655
+ if (normalized?.state === "open" || normalized?.state === "updated") {
149656
+ this.promptRegistry.transition(normalized.promptId, "resolved", "answered_legacy");
149657
+ }
148765
149658
  json2(res, 200, { ok: true });
148766
149659
  }
148767
149660
  /**
@@ -148807,9 +149700,13 @@ var SessionHandlers = class {
148807
149700
  }
148808
149701
  const toolUseId = pending?.toolUseId ?? "";
148809
149702
  if (!await this.questionMenuStillOpen(sessionId)) {
149703
+ const prompt = this.promptRegistry.get(pending?.promptId ?? "");
149704
+ if (prompt?.state === "open" || prompt?.state === "updated") {
149705
+ this.promptRegistry.transition(prompt.promptId, "cancelled", "provider_closed");
149706
+ }
148810
149707
  this.pendingQuestions.delete(sessionId);
148811
149708
  this.pendingQuestionKey.delete(sessionId);
148812
- this.wsHub.broadcast({ type: "question_cancelled", sessionId, toolUseId });
149709
+ this.broadcastToSession(sessionId, { type: "question_cancelled", sessionId, toolUseId });
148813
149710
  json2(res, 409, { ok: false, reason: "question_gone" });
148814
149711
  return;
148815
149712
  }
@@ -148820,10 +149717,41 @@ var SessionHandlers = class {
148820
149717
  json2(res, 400, { ok: false, reason: message });
148821
149718
  return;
148822
149719
  }
149720
+ const normalized = this.promptRegistry.get(pending?.promptId ?? "");
149721
+ if (normalized?.state === "open" || normalized?.state === "updated") {
149722
+ this.promptRegistry.transition(normalized.promptId, "resolved", "answered_legacy");
149723
+ }
148823
149724
  this.pendingQuestions.delete(sessionId);
148824
- this.wsHub.broadcast({ type: "question_cancelled", sessionId, toolUseId });
149725
+ this.broadcastToSession(sessionId, { type: "question_cancelled", sessionId, toolUseId });
148825
149726
  json2(res, 200, { ok: true });
148826
149727
  }
149728
+ /**
149729
+ * Answer a normalized prompt by its opaque ids.
149730
+ *
149731
+ * Refusals are keyed by `code` — the stable machine taxonomy of the prompt
149732
+ * contract. The released legacy routes (`/answer`, `/permission/answer`) key
149733
+ * theirs by `reason` and keep doing so; a client reads whichever key belongs
149734
+ * to the route it called, and the two vocabularies are not merged.
149735
+ *
149736
+ * Status follows the same split as the legacy routes: a malformed or
149737
+ * unanswerable *request* is 400, a prompt whose *state* refuses the answer is
149738
+ * 409. A retry after PROMPT_TERMINAL_RETENTION_MS answers 404
149739
+ * `prompt_not_found`, not the recorded outcome — the record it would replay
149740
+ * is gone by then.
149741
+ */
149742
+ async handlePromptAnswer(sessionId, req, res) {
149743
+ const parsed = PromptAnswerSchema.safeParse(await readBody2(req));
149744
+ if (!parsed.success) {
149745
+ json2(res, 400, { ok: false, code: "invalid_prompt_answer" });
149746
+ return;
149747
+ }
149748
+ const outcome = await this.promptRegistry.answer(sessionId, parsed.data);
149749
+ if (outcome.ok) {
149750
+ json2(res, 200, outcome);
149751
+ return;
149752
+ }
149753
+ json2(res, promptAnswerStatus(outcome.code), outcome);
149754
+ }
148827
149755
  // Best-effort: a session we don't own a PTY for, or one that raced away
148828
149756
  // mid-read, is not ours to veto — say yes and let the write decide.
148829
149757
  async questionMenuStillOpen(sessionId) {
@@ -151168,6 +152096,27 @@ init_capabilities();
151168
152096
  function wsAllows(principal, required2) {
151169
152097
  return principal === null || hasCapability(principal, required2);
151170
152098
  }
152099
+ function clearExpiredPendingPrompt(deps, prompt) {
152100
+ const permission = deps.pendingPermission.get(prompt.sessionId);
152101
+ if (permission?.promptId === prompt.promptId) {
152102
+ deps.pendingPermission.delete(prompt.sessionId);
152103
+ deps.pendingPermissionKey.delete(prompt.sessionId);
152104
+ deps.wsHub.broadcastToClients(deps.sessionSubscribers.get(prompt.sessionId) ?? [], {
152105
+ type: "permission_cancelled",
152106
+ sessionId: prompt.sessionId
152107
+ });
152108
+ }
152109
+ const question = deps.pendingQuestions.get(prompt.sessionId);
152110
+ if (question?.promptId === prompt.promptId) {
152111
+ deps.pendingQuestions.delete(prompt.sessionId);
152112
+ deps.pendingQuestionKey.delete(prompt.sessionId);
152113
+ deps.wsHub.broadcastToClients(deps.sessionSubscribers.get(prompt.sessionId) ?? [], {
152114
+ type: "question_cancelled",
152115
+ sessionId: prompt.sessionId,
152116
+ toolUseId: question.toolUseId
152117
+ });
152118
+ }
152119
+ }
151171
152120
  function createConversationWatcherEvents(deps) {
151172
152121
  return {
151173
152122
  onNewLineSpans: (filePath, spans, readFrom, endOffset) => {
@@ -151290,11 +152239,11 @@ function createLiveSessionOptions(deps) {
151290
152239
  ts: ts2
151291
152240
  });
151292
152241
  },
151293
- onPermissionChange: (sessionId, gate) => {
151294
- deps.sessionHandlers().handlePermissionChange(sessionId, gate);
152242
+ onPermissionChange: (sessionId, gate, occurrenceId) => {
152243
+ deps.sessionHandlers().handlePermissionChange(sessionId, gate, occurrenceId);
151295
152244
  },
151296
- onLiveQuestion: (sessionId, questions) => {
151297
- deps.sessionHandlers().handleLiveQuestion(sessionId, questions);
152245
+ onLiveQuestion: (sessionId, questions, occurrenceId) => {
152246
+ deps.sessionHandlers().handleLiveQuestion(sessionId, questions, occurrenceId);
151298
152247
  },
151299
152248
  onLiveQuestionGone: (sessionId) => {
151300
152249
  deps.pendingQuestionKey.delete(sessionId);
@@ -151375,10 +152324,11 @@ function createLiveSessionOptions(deps) {
151375
152324
  if (filePath) {
151376
152325
  deps.fileWatcher.unwatch(filePath);
151377
152326
  deps.sessionFileMap.delete(session.id);
151378
- deps.cancelPendingQuestion(session.id);
151379
152327
  }
152328
+ deps.cancelPendingQuestion(session.id);
151380
152329
  deps.pendingPermission.delete(session.id);
151381
152330
  deps.pendingPermissionKey.delete(session.id);
152331
+ deps.promptRegistry.invalidateSession(session.id, "session_ended");
151382
152332
  deps.contendedSessions.delete(session.id);
151383
152333
  deps.rememberSelfPtyEnded(session.id);
151384
152334
  }
@@ -151433,6 +152383,7 @@ function createApiDeps(deps) {
151433
152383
  handleGetOutput: (id, res) => deps.sessionHandlers.handleGetOutput(id, res),
151434
152384
  handleSendInput: (id, req, res) => deps.sessionHandlers.handleSendInput(id, req, res),
151435
152385
  handleSendAnswer: (id, req, res) => deps.sessionHandlers.handleSendAnswer(id, req, res),
152386
+ handlePromptAnswer: (id, req, res) => deps.sessionHandlers.handlePromptAnswer(id, req, res),
151436
152387
  handlePermissionAnswer: (id, req, res) => deps.sessionHandlers.handlePermissionAnswer(id, req, res),
151437
152388
  handleCancel: (id, res) => deps.sessionHandlers.handleCancel(id, res),
151438
152389
  handleStopSession: (id, res) => deps.sessionHandlers.handleStopSession(id, res),
@@ -151491,6 +152442,9 @@ function createApiDeps(deps) {
151491
152442
  return;
151492
152443
  }
151493
152444
  deps.addSessionSubscriber(msg.sessionId, ws2);
152445
+ if (deps.promptRegistry) {
152446
+ ws2.send(JSON.stringify(deps.promptRegistry.snapshot(msg.sessionId)));
152447
+ }
151494
152448
  if (deps.ptyManager.hasSession(msg.sessionId)) {
151495
152449
  const lines = await deps.ptyManager.getOutputLines(msg.sessionId, REPLAY_MAX_LINES);
151496
152450
  const userMessages = deps.ptyManager.getInputHistory(msg.sessionId);
@@ -153720,16 +154674,16 @@ function compareValues(a, b2) {
153720
154674
  if (typeof a === "number" && typeof b2 === "number") return a - b2;
153721
154675
  return String(a).localeCompare(String(b2));
153722
154676
  }
153723
- function makeComparator(key, order) {
153724
- const dir = order === "asc" ? 1 : -1;
154677
+ function makeComparator(key, order2) {
154678
+ const dir = order2 === "asc" ? 1 : -1;
153725
154679
  return (a, b2) => {
153726
154680
  const cmp = compareValues(getSortValue(a, key), getSortValue(b2, key)) * dir;
153727
154681
  if (cmp !== 0) return cmp;
153728
154682
  return a.id.localeCompare(b2.id);
153729
154683
  };
153730
154684
  }
153731
- function findCursorBoundary(sorted, cursor, key, order) {
153732
- const dir = order === "asc" ? 1 : -1;
154685
+ function findCursorBoundary(sorted, cursor, key, order2) {
154686
+ const dir = order2 === "asc" ? 1 : -1;
153733
154687
  for (let i = 0; i < sorted.length; i++) {
153734
154688
  const item = sorted[i];
153735
154689
  const cmp = compareValues(getSortValue(item, key), cursor.k) * dir;
@@ -154305,6 +155259,7 @@ var StreamerServer = class {
154305
155259
  // repaint of the same gate doesn't re-broadcast on every tick. Cleared
154306
155260
  // alongside pendingPermission.
154307
155261
  pendingPermissionKey = /* @__PURE__ */ new Map();
155262
+ promptRegistry;
154308
155263
  // Scanner lifecycle, freshness state and the cache↔disk reconcile.
154309
155264
  scannerManager;
154310
155265
  // Binds a live session to the JSONL/rollout its provider writes.
@@ -154557,6 +155512,20 @@ var StreamerServer = class {
154557
155512
  this.browserCors = config2.browserCors ?? loadBrowserCors();
154558
155513
  this.sessionStore = new SessionStore();
154559
155514
  this.wsHub = new WSHub();
155515
+ this.promptRegistry = new PromptRegistry({
155516
+ emit: (event) => this.wsHub.broadcastToClients(this.sessionSubscribers.get(event.sessionId) ?? [], event),
155517
+ onExpire: (prompt) => clearExpiredPendingPrompt(
155518
+ {
155519
+ pendingPermission: this.pendingPermission,
155520
+ pendingPermissionKey: this.pendingPermissionKey,
155521
+ pendingQuestions: this.pendingQuestions,
155522
+ pendingQuestionKey: this.pendingQuestionKey,
155523
+ sessionSubscribers: this.sessionSubscribers,
155524
+ wsHub: this.wsHub
155525
+ },
155526
+ prompt
155527
+ )
155528
+ });
154560
155529
  this.fileWatcher = new ConversationWatcher(
154561
155530
  createConversationWatcherEvents({
154562
155531
  sessionFileMap: this.sessionFileMap,
@@ -154600,6 +155569,7 @@ var StreamerServer = class {
154600
155569
  pendingQuestionKey: this.pendingQuestionKey,
154601
155570
  pendingPermission: this.pendingPermission,
154602
155571
  pendingPermissionKey: this.pendingPermissionKey,
155572
+ promptRegistry: this.promptRegistry,
154603
155573
  contendedSessions: this.contendedSessions,
154604
155574
  // Thunks, not values: sessionHandlers is constructed below, the
154605
155575
  // registry repo and the push notifiers are bound during listen(), and
@@ -154690,6 +155660,7 @@ var StreamerServer = class {
154690
155660
  sessionStatusBus: this.sessionStatusBus,
154691
155661
  sessionFileMap: this.sessionFileMap,
154692
155662
  pendingQuestions: this.pendingQuestions,
155663
+ promptRegistry: this.promptRegistry,
154693
155664
  pendingQuestionKey: this.pendingQuestionKey,
154694
155665
  pendingPermission: this.pendingPermission,
154695
155666
  pendingPermissionKey: this.pendingPermissionKey,
@@ -154790,6 +155761,7 @@ var StreamerServer = class {
154790
155761
  terminalSeq: this.terminalSeq,
154791
155762
  pendingPermission: this.pendingPermission,
154792
155763
  pendingQuestions: this.pendingQuestions,
155764
+ promptRegistry: this.promptRegistry,
154793
155765
  agentClient,
154794
155766
  conversationWriter,
154795
155767
  agentConfig
@@ -155570,6 +156542,7 @@ var StreamerServer = class {
155570
156542
  if (!this.ptyManager.isRemote()) this.ptyManager.dispose();
155571
156543
  this.fileWatcher.dispose();
155572
156544
  this.externalTails.clear();
156545
+ this.promptRegistry.dispose();
155573
156546
  this.wsHub.dispose();
155574
156547
  this.pairTokens.dispose();
155575
156548
  this.liveActivityRenewal?.stop();
@@ -156158,7 +157131,7 @@ var StreamerServer = class {
156158
157131
  for (const p2 of pending) {
156159
157132
  if (contended || foreignVsPty(p2.questions)) continue;
156160
157133
  const origin = priorPtyKey !== null && questionContentKey(p2.questions) === priorPtyKey ? "pty" : "jsonl";
156161
- this.pendingQuestions.set(sessionId, { ...p2, origin });
157134
+ this.sessionHandlers.handleJsonlQuestion(sessionId, p2.toolUseId, p2.questions, origin);
156162
157135
  const t = setTimeout(() => {
156163
157136
  if (this.pendingQuestions.get(sessionId)?.toolUseId === p2.toolUseId) {
156164
157137
  this.cancelPendingQuestion(sessionId);
@@ -156176,7 +157149,7 @@ var StreamerServer = class {
156176
157149
  priorToolUseId
156177
157150
  });
156178
157151
  this.pendingQuestionKey.set(sessionId, key);
156179
- if (broadcast2) this.wsHub.broadcast(m2);
157152
+ if (broadcast2) this.wsHub.broadcastToClients(this.sessionSubscribers.get(sessionId) ?? [], m2);
156180
157153
  }
156181
157154
  }
156182
157155
  cancelPendingQuestion(sessionId) {
@@ -156184,7 +157157,15 @@ var StreamerServer = class {
156184
157157
  if (!pq) return;
156185
157158
  this.pendingQuestions.delete(sessionId);
156186
157159
  this.pendingQuestionKey.delete(sessionId);
156187
- this.wsHub.broadcast({ type: "question_cancelled", sessionId, toolUseId: pq.toolUseId });
157160
+ const prompt = this.promptRegistry.get(pq.promptId);
157161
+ if (prompt?.state === "open" || prompt?.state === "updated") {
157162
+ this.promptRegistry.transition(pq.promptId, "cancelled", "provider_closed");
157163
+ }
157164
+ this.wsHub.broadcastToClients(this.sessionSubscribers.get(sessionId) ?? [], {
157165
+ type: "question_cancelled",
157166
+ sessionId,
157167
+ toolUseId: pq.toolUseId
157168
+ });
156188
157169
  }
156189
157170
  async handleBrowse(url2, res) {
156190
157171
  if (!this.browseRoot) {
@@ -156515,7 +157496,7 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
156515
157496
  }
156516
157497
 
156517
157498
  // src/updater/download.ts
156518
- var import_node_crypto5 = require("crypto");
157499
+ var import_node_crypto6 = require("crypto");
156519
157500
  var import_node_fs10 = require("fs");
156520
157501
  var import_node_path11 = require("path");
156521
157502
  var import_promises17 = require("stream/promises");
@@ -156582,7 +157563,7 @@ async function downloadAndVerify(opts) {
156582
157563
  if (!res.ok || !res.body) {
156583
157564
  throw new Error(`Failed to download ${artifact.filename}: ${res.status} ${res.statusText}`);
156584
157565
  }
156585
- const hash2 = (0, import_node_crypto5.createHash)("sha256");
157566
+ const hash2 = (0, import_node_crypto6.createHash)("sha256");
156586
157567
  const out = (0, import_node_fs10.createWriteStream)(targetPath);
156587
157568
  let bytes = 0;
156588
157569
  const measured = new TransformStream({
@@ -156887,7 +157868,7 @@ var import_node_path18 = require("path");
156887
157868
  var import_path38 = __toESM(require("path"), 1);
156888
157869
  var import_node_fs14 = __toESM(require("fs"), 1);
156889
157870
  var import_node_assert = __toESM(require("assert"), 1);
156890
- var import_node_crypto6 = require("crypto");
157871
+ var import_node_crypto7 = require("crypto");
156891
157872
  var import_node_fs15 = __toESM(require("fs"), 1);
156892
157873
  var import_node_path19 = __toESM(require("path"), 1);
156893
157874
  var import_fs43 = __toESM(require("fs"), 1);
@@ -159302,7 +160283,7 @@ var Te = fo === "win32";
159302
160283
  var uo = 1024;
159303
160284
  var mo = (s3, t) => {
159304
160285
  if (!Te) return import_node_fs15.default.unlink(s3, t);
159305
- let e = s3 + ".DELETE." + (0, import_node_crypto6.randomBytes)(16).toString("hex");
160286
+ let e = s3 + ".DELETE." + (0, import_node_crypto7.randomBytes)(16).toString("hex");
159306
160287
  import_node_fs15.default.rename(s3, e, (i) => {
159307
160288
  if (i) return t(i);
159308
160289
  import_node_fs15.default.unlink(e, t);
@@ -159310,7 +160291,7 @@ var mo = (s3, t) => {
159310
160291
  };
159311
160292
  var po = (s3) => {
159312
160293
  if (!Te) return import_node_fs15.default.unlinkSync(s3);
159313
- let t = s3 + ".DELETE." + (0, import_node_crypto6.randomBytes)(16).toString("hex");
160294
+ let t = s3 + ".DELETE." + (0, import_node_crypto7.randomBytes)(16).toString("hex");
159314
160295
  import_node_fs15.default.renameSync(s3, t), import_node_fs15.default.unlinkSync(t);
159315
160296
  };
159316
160297
  var vr = (s3, t, e) => s3 !== void 0 && s3 === s3 >>> 0 ? s3 : t !== void 0 && t === t >>> 0 ? t : e;