@ashx-j/lunr 0.2.24 → 0.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/gateway/adapters/discord.d.ts.map +1 -1
  3. package/dist/gateway/adapters/discord.js +2 -7
  4. package/dist/gateway/adapters/discord.js.map +1 -1
  5. package/dist/gateway/adapters/telegram.d.ts.map +1 -1
  6. package/dist/gateway/adapters/telegram.js +7 -0
  7. package/dist/gateway/adapters/telegram.js.map +1 -1
  8. package/dist/gateway/agent-bridge.d.ts +4 -1
  9. package/dist/gateway/agent-bridge.d.ts.map +1 -1
  10. package/dist/gateway/agent-bridge.js +57 -17
  11. package/dist/gateway/agent-bridge.js.map +1 -1
  12. package/dist/gateway/buttons.d.ts.map +1 -1
  13. package/dist/gateway/buttons.js +29 -19
  14. package/dist/gateway/buttons.js.map +1 -1
  15. package/dist/gateway/commands.d.ts +2 -0
  16. package/dist/gateway/commands.d.ts.map +1 -1
  17. package/dist/gateway/commands.js +39 -18
  18. package/dist/gateway/commands.js.map +1 -1
  19. package/dist/gateway/config.d.ts +1 -0
  20. package/dist/gateway/config.d.ts.map +1 -1
  21. package/dist/gateway/config.js +2 -0
  22. package/dist/gateway/config.js.map +1 -1
  23. package/dist/gateway/cron.d.ts +1 -1
  24. package/dist/gateway/cron.d.ts.map +1 -1
  25. package/dist/gateway/cron.js +2 -2
  26. package/dist/gateway/cron.js.map +1 -1
  27. package/dist/gateway/index.d.ts.map +1 -1
  28. package/dist/gateway/index.js +26 -26
  29. package/dist/gateway/index.js.map +1 -1
  30. package/dist/gateway/mobile-commands.d.ts.map +1 -1
  31. package/dist/gateway/mobile-commands.js +3 -3
  32. package/dist/gateway/mobile-commands.js.map +1 -1
  33. package/dist/gateway/presenter.d.ts +12 -1
  34. package/dist/gateway/presenter.d.ts.map +1 -1
  35. package/dist/gateway/presenter.js +146 -48
  36. package/dist/gateway/presenter.js.map +1 -1
  37. package/dist/gateway/router.d.ts +5 -5
  38. package/dist/gateway/router.d.ts.map +1 -1
  39. package/dist/gateway/router.js +95 -41
  40. package/dist/gateway/router.js.map +1 -1
  41. package/dist/gateway/service.d.ts.map +1 -1
  42. package/dist/gateway/service.js +13 -4
  43. package/dist/gateway/service.js.map +1 -1
  44. package/dist/gateway/setup.d.ts +5 -0
  45. package/dist/gateway/setup.d.ts.map +1 -1
  46. package/dist/gateway/setup.js +98 -42
  47. package/dist/gateway/setup.js.map +1 -1
  48. package/dist/gateway/stream.d.ts +6 -5
  49. package/dist/gateway/stream.d.ts.map +1 -1
  50. package/dist/gateway/stream.js +24 -11
  51. package/dist/gateway/stream.js.map +1 -1
  52. package/dist/node-runtime/{agent-session-services-IEF7LQWD.js → agent-session-services-YXXFCP5J.js} +7 -6
  53. package/dist/node-runtime/{builtin-extensions-EBAWTH4M.js → builtin-extensions-ZLAX7TUH.js} +1 -1
  54. package/dist/node-runtime/{chunk-OF7PWMG4.js → chunk-2HHLJWGD.js} +3 -87
  55. package/dist/node-runtime/{chunk-VWCE2HSZ.js → chunk-2HMIRK7W.js} +4 -4
  56. package/dist/node-runtime/{chunk-K5AGHH57.js → chunk-3XPLBUEM.js} +1 -1
  57. package/dist/node-runtime/{chunk-RORY2HMJ.js → chunk-6XL67VVY.js} +1 -1
  58. package/dist/node-runtime/chunk-7S3T6YEA.js +97 -0
  59. package/dist/node-runtime/{chunk-R3K2F5GI.js → chunk-B4HP6ZWM.js} +2 -0
  60. package/dist/node-runtime/{chunk-YVI6L6LU.js → chunk-E4D3IGP2.js} +38 -22
  61. package/dist/node-runtime/{chunk-5Q3EHOHI.js → chunk-IJIFHRTB.js} +14 -12
  62. package/dist/node-runtime/{chunk-Y73WPE6S.js → chunk-KWIYUUZK.js} +63 -37
  63. package/dist/node-runtime/{chunk-F4FLTQKV.js → chunk-LQP3RB67.js} +184 -1527
  64. package/dist/node-runtime/{chunk-FU6OODRZ.js → chunk-NRKGMJYU.js} +1 -1
  65. package/dist/node-runtime/{chunk-IGV54Q5V.js → chunk-QTU6AKNJ.js} +128 -63
  66. package/dist/node-runtime/{chunk-L3LX4SNR.js → chunk-RC7DMV45.js} +5 -5
  67. package/dist/node-runtime/{chunk-UWPJL22I.js → chunk-SLVOAQOY.js} +15 -4
  68. package/dist/node-runtime/{chunk-WHLRAGUQ.js → chunk-TORR5XBV.js} +6 -6
  69. package/dist/node-runtime/{chunk-UP2XBVH5.js → chunk-UOEDI7RP.js} +1 -1
  70. package/dist/node-runtime/{chunk-DE2JB6J5.js → chunk-VQFSUJJG.js} +2 -2
  71. package/dist/node-runtime/{chunk-QM43FEAE.js → chunk-WF7PGWRZ.js} +3 -3
  72. package/dist/node-runtime/chunk-YCUZEGJG.js +1361 -0
  73. package/dist/node-runtime/{command-7BG7VVTS.js → command-6WDOYKS6.js} +5 -5
  74. package/dist/node-runtime/{commands-QFDKNQTL.js → commands-QC6VUZJQ.js} +5 -5
  75. package/dist/node-runtime/{config-RORQUQFG.js → config-D4QUPAHX.js} +1 -1
  76. package/dist/node-runtime/{gateway-TWR3N65G.js → gateway-INAYBF4Q.js} +134 -78
  77. package/dist/node-runtime/index.js +15 -12
  78. package/dist/node-runtime/{install-cli-VAP6KBFN.js → install-cli-KL4UDDAD.js} +3 -3
  79. package/dist/node-runtime/{interactive-mode-6J5VZ2TT.js → interactive-mode-Z5M7WYYZ.js} +8 -7
  80. package/dist/node-runtime/{lunr-browser-J5ZZYVGM.js → lunr-browser-IR7TL3J7.js} +3 -3
  81. package/dist/node-runtime/{lunr-cron-CXOL37AL.js → lunr-cron-LWIZJM2N.js} +5 -5
  82. package/dist/node-runtime/main.js +12 -10
  83. package/dist/node-runtime/{mobile-commands-VTBM5DSZ.js → mobile-commands-J7OJEKFO.js} +4 -4
  84. package/dist/node-runtime/{package-manager-cli-ZLW5DZXF.js → package-manager-cli-VYZM5WHN.js} +10 -7
  85. package/dist/node-runtime/{pi-subagents-XPCLLKIM.js → pi-subagents-DNY7EAIG.js} +6 -6
  86. package/dist/node-runtime/rpc-entry.js +12 -10
  87. package/dist/node-runtime/{runtime-bridges-QYXUX2TG.js → runtime-bridges-VRDDR73P.js} +5 -5
  88. package/dist/node-runtime/{service-ISSP6VHE.js → service-MDQIPQ26.js} +1 -1
  89. package/dist/node-runtime/{settings-manager-WCQDUVQB.js → settings-manager-J4SPQPDJ.js} +4 -4
  90. package/dist/node-runtime/setup-CQ2NLVK5.js +214 -0
  91. package/dist/node-runtime/{subagent-executor-OTNISDQU.js → subagent-executor-KZZQGAKV.js} +5 -5
  92. package/dist/node-runtime/{update-cli-VBR2777K.js → update-cli-GTFJC7XK.js} +4 -4
  93. package/docs/features.md +4 -4
  94. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  95. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  96. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  97. package/examples/extensions/gondolin/package-lock.json +2 -2
  98. package/examples/extensions/gondolin/package.json +1 -1
  99. package/examples/extensions/sandbox/package-lock.json +2 -2
  100. package/examples/extensions/sandbox/package.json +1 -1
  101. package/examples/extensions/with-deps/package-lock.json +2 -2
  102. package/examples/extensions/with-deps/package.json +1 -1
  103. package/package.json +4 -4
  104. package/dist/node-runtime/setup-YRBKH2LD.js +0 -155
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
2
  import {
3
3
  bindSubagentCommunicationSetting
4
- } from "./chunk-RORY2HMJ.js";
4
+ } from "./chunk-6XL67VVY.js";
5
5
  import {
6
6
  registerCustomizeBridge
7
7
  } from "./chunk-4EULYYR4.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-RMQZU2YU.js";
5
5
  import {
6
6
  atomicJson
7
- } from "./chunk-UWPJL22I.js";
7
+ } from "./chunk-SLVOAQOY.js";
8
8
  import {
9
9
  noOpUIContext
10
10
  } from "./chunk-GJ2RDBRL.js";
@@ -14,10 +14,11 @@ import {
14
14
  setPermissionMode
15
15
  } from "./chunk-ZXSGTGJ6.js";
16
16
  import {
17
+ gatewayConfigPath,
17
18
  loadGatewayConfig,
18
19
  platformConfigFor,
19
20
  saveGatewayConfig
20
- } from "./chunk-R3K2F5GI.js";
21
+ } from "./chunk-B4HP6ZWM.js";
21
22
  import {
22
23
  getAgentDir
23
24
  } from "./chunk-FQMM2EZ2.js";
@@ -341,12 +342,12 @@ async function handleCallback(cb, deps) {
341
342
  await answerExpired(adapter, cb);
342
343
  return;
343
344
  }
344
- if (picker.validate && !picker.validate()) {
345
+ if (!picker.completed && picker.validate && !picker.validate()) {
345
346
  registry.delete(parsed.id), picker.onCancel?.(), await answerExpired(adapter, cb);
346
347
  return;
347
348
  }
348
349
  if (Date.now() > picker.createdAt + PICKER_TTL_MS) {
349
- picker.onCancel?.(), registry.delete(parsed.id);
350
+ picker.completed || picker.onCancel?.(), registry.delete(parsed.id);
350
351
  try {
351
352
  await picker.adapter.editMessage(picker.chatId, picker.messageId, "\u23F1 Expired \u2014 run the command again.", []);
352
353
  } catch {
@@ -366,6 +367,11 @@ async function handleCallback(cb, deps) {
366
367
  await answerUnauthorized(adapter, cb);
367
368
  return;
368
369
  }
370
+ if (picker.completed !== void 0) {
371
+ await adapter.answerCallback(cb.id, "Already completed.").catch(() => {
372
+ });
373
+ return;
374
+ }
369
375
  if (parsed.action === "cancel") {
370
376
  registry.delete(parsed.id), picker.onCancel?.();
371
377
  try {
@@ -417,33 +423,25 @@ async function handleCallback(cb, deps) {
417
423
  }
418
424
  return;
419
425
  }
420
- registry.delete(parsed.id);
421
- try {
422
- await picker.adapter.editMessage(picker.chatId, picker.messageId, result.text, []);
423
- } catch {
424
- }
426
+ picker.completed = result.text, await confirmPicker(picker, result.text);
425
427
  } catch (err) {
426
- registry.delete(parsed.id);
427
428
  let message = err instanceof Error ? err.message : String(err);
428
- try {
429
- await picker.adapter.editMessage(picker.chatId, picker.messageId, `\u26A0 ${message}`, []);
430
- } catch {
431
- }
429
+ picker.completed = `\u26A0 ${message}`, await confirmPicker(picker, picker.completed);
432
430
  } finally {
433
431
  picker.resolving = !1;
434
432
  }
435
433
  }
434
+ async function confirmPicker(picker, text) {
435
+ if ((await picker.adapter.editMessage(picker.chatId, picker.messageId, text, []).catch(() => ({ success: !1 }))).success)
436
+ return;
437
+ (await picker.adapter.send(picker.chatId, text, { threadId: picker.source.threadId }).catch(() => ({ success: !1 }))).success || console.error(`[gateway] picker confirmation failed on ${picker.adapter.platform}`);
438
+ }
436
439
  function startButtonSweeper() {
437
440
  sweeper || (sweeper = setInterval(() => {
438
441
  let cutoff = Date.now() - PICKER_TTL_MS;
439
442
  for (let [id, entry] of registry)
440
- if (!(entry.createdAt > cutoff)) {
441
- registry.delete(id), entry.onCancel?.();
442
- try {
443
- entry.adapter.editMessage(entry.chatId, entry.messageId, "\u23F1 Expired \u2014 run the command again.", []);
444
- } catch {
445
- }
446
- }
443
+ entry.createdAt > cutoff || (registry.delete(id), !entry.completed && (entry.onCancel?.(), entry.adapter.editMessage(entry.chatId, entry.messageId, "\u23F1 Expired \u2014 run the command again.", []).catch(() => {
444
+ })));
447
445
  }, SWEEP_INTERVAL_MS), sweeper.unref?.());
448
446
  }
449
447
  function stopButtonSweeper() {
@@ -530,13 +528,23 @@ function splitMessage(text, max) {
530
528
  }
531
529
 
532
530
  // packages/coding-agent/dist/gateway/presenter.js
533
- var epochs = /* @__PURE__ */ new Map(), inputs = /* @__PURE__ */ new Map(), dialogs = /* @__PURE__ */ new Map(), adapters = /* @__PURE__ */ new Map(), timer, sending = !1, path2 = () => join3(getAgentDir(), "gateway-outbox.json"), outbox = [];
531
+ var epochs = /* @__PURE__ */ new Map(), inputs = /* @__PURE__ */ new Map(), dialogs = /* @__PURE__ */ new Map(), adapters = /* @__PURE__ */ new Map(), deliveryConfigs = /* @__PURE__ */ new Map(), roleGrants = /* @__PURE__ */ new Map(), timer, activeDeliveries = /* @__PURE__ */ new Map(), MAX_ATTEMPTS = 5, path2 = () => join3(getAgentDir(), "gateway-outbox.json"), outbox = [];
532
+ function sourceWithCurrentRole(key, source) {
533
+ let grant = roleGrants.get(key);
534
+ return {
535
+ ...source,
536
+ roleAuthorized: grant?.userId === source.userId && grant.chatId === source.chatId && grant.threadId === source.threadId
537
+ };
538
+ }
539
+ function rememberGatewayRole(key, source) {
540
+ source.roleAuthorized === !0 ? roleGrants.set(key, { userId: source.userId, chatId: source.chatId, threadId: source.threadId }) : roleGrants.delete(key);
541
+ }
534
542
  function canDeliver(key) {
535
543
  let binding = conversationBinding(key);
536
544
  if (!binding)
537
545
  return !1;
538
546
  let cfg = loadGatewayConfig();
539
- return binding.owner && (binding.owner !== binding.source.userId || !isGatewayOwner(binding.source, cfg)) ? !1 : isAuthorized(binding.source, cfg, createPairingStore());
547
+ return binding.owner && (binding.owner !== binding.source.userId || !isGatewayOwner(binding.source, cfg)) ? !1 : isAuthorized(sourceWithCurrentRole(key, binding.source), cfg, createPairingStore());
540
548
  }
541
549
  function gatewayDestination(key) {
542
550
  let binding = conversationBinding(key), adapter = binding && adapters.get(binding.source.platform);
@@ -551,56 +559,106 @@ function withGatewayPresentation(key, run) {
551
559
  function startGatewayPresenter(connected) {
552
560
  if (adapters = connected, existsSync3(path2()))
553
561
  try {
554
- outbox = JSON.parse(readFileSync3(path2(), "utf8"));
562
+ let raw = JSON.parse(readFileSync3(path2(), "utf8"));
563
+ if (!Array.isArray(raw) || !raw.every((item) => item && typeof item.id == "string" && typeof item.key == "string" && typeof item.text == "string"))
564
+ throw new Error("Invalid outbox");
565
+ outbox = raw;
555
566
  } catch {
556
567
  throw new Error("Gateway outbox is invalid. Restore it before starting.");
557
568
  }
569
+ else
570
+ outbox = [];
571
+ for (let item of outbox)
572
+ item.kind === "notice" && epochs.set(item.key, Math.max(epochs.get(item.key) ?? 0, item.epoch ?? 0));
558
573
  timer && clearInterval(timer), timer = setInterval(() => {
559
- flushOutbox();
560
- }, 3e3), timer.unref(), flushOutbox();
574
+ flushOutbox().catch((error) => console.error("[gateway] outbox flush failed:", error));
575
+ }, 3e3), timer.unref(), flushOutbox().catch((error) => console.error("[gateway] outbox flush failed:", error));
561
576
  }
562
577
  function stopGatewayPresenter() {
563
578
  timer && clearInterval(timer), timer = void 0;
564
579
  for (let key of dialogs.keys())
565
580
  invalidateGatewayDialogs(key);
566
- adapters = /* @__PURE__ */ new Map();
581
+ adapters = /* @__PURE__ */ new Map(), deliveryConfigs.clear(), roleGrants.clear();
582
+ }
583
+ function gatewayEpoch(key) {
584
+ return epochs.get(key) ?? 0;
567
585
  }
568
- async function sendGatewayNotice(key, text) {
586
+ async function sendGatewayNotice(key, text, kind = "notice", epoch = gatewayEpoch(key)) {
569
587
  let clean = text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").trim();
570
588
  if (!clean || !canDeliver(key))
571
589
  return;
572
- let { adapter } = gatewayDestination(key);
573
- for (let chunk of splitMessage(clean, adapter.maxMessageLength))
574
- outbox.push({ id: randomUUID(), key, epoch: epochs.get(key) ?? 0, text: chunk });
575
- atomicJson(path2(), outbox), await flushOutbox();
576
- }
577
- async function flushOutbox() {
578
- if (!sending) {
579
- sending = !0;
580
- try {
581
- for (let item of [...outbox]) {
582
- if (!canDeliver(item.key)) {
583
- outbox = outbox.filter((v) => v.id !== item.id), atomicJson(path2(), outbox);
584
- continue;
585
- }
586
- let target;
587
- try {
588
- target = gatewayDestination(item.key);
589
- } catch {
590
- continue;
591
- }
592
- if ((await target.adapter.send(target.source.chatId, item.text, { threadId: target.source.threadId }).catch(() => ({ success: !1 }))).success)
593
- outbox = outbox.filter((v) => v.id !== item.id), atomicJson(path2(), outbox);
594
- else
595
- break;
590
+ let { adapter, source } = gatewayDestination(key);
591
+ await queueGatewayText(key, source, adapter, clean, { kind, epoch });
592
+ }
593
+ async function queueGatewayText(key, source, adapter, text, options) {
594
+ if (!text || options.kind === "notice" && options.epoch !== void 0 && options.epoch !== gatewayEpoch(key))
595
+ return;
596
+ adapters.set(source.platform, adapter), options.cfg && deliveryConfigs.set(key, options.cfg);
597
+ let chunks = options.chunks ?? splitMessage(text, adapter.maxMessageLength), batchId = randomUUID();
598
+ for (let [index, chunk] of chunks.entries())
599
+ outbox.push({
600
+ id: randomUUID(),
601
+ batchId,
602
+ key,
603
+ source: { ...source, roleAuthorized: void 0 },
604
+ epoch: options.epoch ?? gatewayEpoch(key),
605
+ text: chunk,
606
+ kind: options.kind,
607
+ replyTo: index === 0 ? options.replyTo : void 0
608
+ });
609
+ atomicJson(path2(), outbox), activeDeliveries.has(key) && await activeDeliveries.get(key), await flushKey(key);
610
+ }
611
+ function flushOutbox() {
612
+ return Promise.all([...new Set(outbox.map((item) => item.key))].map(flushKey)).then(() => {
613
+ });
614
+ }
615
+ function flushKey(key) {
616
+ let current = activeDeliveries.get(key);
617
+ if (current)
618
+ return current;
619
+ let running = drainKey(key).finally(() => {
620
+ activeDeliveries.delete(key);
621
+ });
622
+ return activeDeliveries.set(key, running), running;
623
+ }
624
+ async function drainKey(key) {
625
+ let failedBatches = new Set(outbox.filter((item) => item.failed && item.batchId).map((item) => item.batchId));
626
+ for (let item of [...outbox].filter((item2) => item2.key === key)) {
627
+ if (item.failed || item.batchId && failedBatches.has(item.batchId))
628
+ continue;
629
+ if (item.kind === "notice" && item.epoch !== (epochs.get(item.key) ?? 0)) {
630
+ outbox = outbox.filter((v) => v.id !== item.id), atomicJson(path2(), outbox);
631
+ continue;
632
+ }
633
+ let binding = conversationBinding(item.key), source = item.source ?? binding?.source;
634
+ if (!source)
635
+ break;
636
+ let cfg = existsSync3(gatewayConfigPath()) ? loadGatewayConfig() : deliveryConfigs.get(item.key) ?? loadGatewayConfig();
637
+ if (binding && (binding.source.platform !== source.platform || binding.source.chatId !== source.chatId || binding.source.userId !== source.userId || binding.source.threadId !== source.threadId) || !isAuthorized(sourceWithCurrentRole(key, source), cfg, createPairingStore()) || binding?.owner && (binding.owner !== source.userId || !isGatewayOwner(source, cfg))) {
638
+ outbox = outbox.filter((v) => v.id !== item.id), atomicJson(path2(), outbox);
639
+ continue;
640
+ }
641
+ let adapter = adapters.get(source.platform);
642
+ if (!adapter || (item.nextAttempt ?? 0) > Date.now())
643
+ break;
644
+ let opts = { threadId: source.threadId, replyTo: item.replyTo }, result = await adapter.send(source.chatId, item.text, opts).catch((error) => ({ success: !1, error: String(error), retryable: !0 }));
645
+ if (result.success)
646
+ outbox = outbox.filter((v) => v.id !== item.id), atomicJson(path2(), outbox);
647
+ else {
648
+ if (item.attempts = (item.attempts ?? 0) + 1, item.failed = result.retryable === !1 || item.attempts >= MAX_ATTEMPTS, item.nextAttempt = Date.now() + Math.min(6e4, 3e3 * 2 ** (item.attempts - 1)), item.failed && item.batchId) {
649
+ failedBatches.add(item.batchId);
650
+ for (let pending2 of outbox)
651
+ pending2.batchId === item.batchId && (pending2.failed = !0);
596
652
  }
597
- } finally {
598
- sending = !1;
653
+ atomicJson(path2(), outbox), console.error(`[gateway] delivery ${item.failed ? "failed permanently" : "retry scheduled"} for ${source.platform}: ${result.error ?? "unknown error"}`);
654
+ break;
599
655
  }
600
656
  }
601
657
  }
602
658
  function invalidateGatewayDialogs(key) {
603
659
  epochs.set(key, (epochs.get(key) ?? 0) + 1);
660
+ let remaining = outbox.filter((item) => item.key !== key || item.kind !== "notice");
661
+ remaining.length !== outbox.length && (outbox = remaining, atomicJson(path2(), outbox));
604
662
  for (let cancel of dialogs.get(key) ?? [])
605
663
  cancel();
606
664
  dialogs.delete(key), inputs.delete(key);
@@ -642,34 +700,38 @@ ${item.value}` })
642
700
  });
643
701
  }
644
702
  function gatewayInput(key, title, placeholder, opts) {
645
- return inputs.has(key) ? Promise.reject(new Error("Answer or cancel the existing question first.")) : dialog(key, opts, async (done) => {
703
+ if (inputs.has(key))
704
+ return Promise.reject(new Error("Answer or cancel the existing question first."));
705
+ let epoch = gatewayEpoch(key);
706
+ return dialog(key, opts, async (done) => {
646
707
  let { source } = gatewayDestination(key);
647
708
  inputs.set(key, { userId: source.userId, resolve: done }), await sendGatewayNotice(key, `${title}${placeholder ? `
648
709
  ${placeholder}` : ""}
649
- Reply with text, or /cancel.`);
710
+ Reply with text, or /cancel.`, "notice", epoch);
650
711
  });
651
712
  }
652
713
  function createGatewayUI(key) {
714
+ let epoch = gatewayEpoch(key);
653
715
  return {
654
716
  ...noOpUIContext,
655
- select: (title, options, opts) => gatewaySelect(key, title, options, opts),
656
- confirm: async (title, message, opts) => await gatewaySelect(key, `${title}
717
+ select: (title, options, opts) => gatewayEpoch(key) === epoch ? gatewaySelect(key, title, options, opts) : Promise.resolve(void 0),
718
+ confirm: async (title, message, opts) => gatewayEpoch(key) === epoch && await gatewaySelect(key, `${title}
657
719
  ${message}`, ["Approve", "Decline"], opts) === "Approve",
658
- input: (title, placeholder, opts) => gatewayInput(key, title, placeholder, opts),
659
- editor: (title, prefill) => gatewayInput(key, title, prefill),
720
+ input: (title, placeholder, opts) => gatewayEpoch(key) === epoch ? gatewayInput(key, title, placeholder, opts) : Promise.resolve(void 0),
721
+ editor: (title, prefill) => gatewayEpoch(key) === epoch ? gatewayInput(key, title, prefill) : Promise.resolve(void 0),
660
722
  notify: (message) => {
661
- sendGatewayNotice(key, message).catch(() => {
723
+ sendGatewayNotice(key, message, "notice", epoch).catch(() => {
662
724
  });
663
725
  },
664
726
  custom: async () => {
665
727
  throw new Error("This command requires the terminal interface. Use the gateway's text commands or button pickers.");
666
728
  },
667
729
  pasteToEditor: (text) => {
668
- sendGatewayNotice(key, text).catch(() => {
730
+ sendGatewayNotice(key, text, "notice", epoch).catch(() => {
669
731
  });
670
732
  },
671
733
  setEditorText: (text) => {
672
- sendGatewayNotice(key, text).catch(() => {
734
+ sendGatewayNotice(key, text, "notice", epoch).catch(() => {
673
735
  });
674
736
  }
675
737
  };
@@ -696,10 +758,13 @@ export {
696
758
  startButtonSweeper,
697
759
  stopButtonSweeper,
698
760
  splitMessage,
761
+ rememberGatewayRole,
699
762
  withGatewayPresentation,
700
763
  startGatewayPresenter,
701
764
  stopGatewayPresenter,
765
+ gatewayEpoch,
702
766
  sendGatewayNotice,
767
+ queueGatewayText,
703
768
  invalidateGatewayDialogs,
704
769
  acceptGatewayInput,
705
770
  gatewaySelect,
@@ -45,13 +45,13 @@ import {
45
45
  peekRollbackTurnsConsumed,
46
46
  rollbackLastTurn,
47
47
  setRollbackWarningHandler
48
- } from "./chunk-DE2JB6J5.js";
48
+ } from "./chunk-VQFSUJJG.js";
49
49
  import {
50
50
  notifyTodosEnabledChanged
51
51
  } from "./chunk-CCCN2UCX.js";
52
52
  import {
53
53
  parseGitUrl
54
- } from "./chunk-F4FLTQKV.js";
54
+ } from "./chunk-LQP3RB67.js";
55
55
  import {
56
56
  createAllToolDefinitions,
57
57
  ensureTool,
@@ -88,7 +88,7 @@ import {
88
88
  SUBAGENT_SPINNER_NAMES,
89
89
  configureHttpDispatcher,
90
90
  formatHttpIdleTimeoutMs
91
- } from "./chunk-RORY2HMJ.js";
91
+ } from "./chunk-6XL67VVY.js";
92
92
  import {
93
93
  ProjectTrustStore,
94
94
  getProjectTrustOptions,
@@ -8217,7 +8217,7 @@ Pi will resume when the editor exits.
8217
8217
  return;
8218
8218
  }
8219
8219
  if (action === "status") {
8220
- this.showStatus((await import("./service-ISSP6VHE.js")).serviceStatusText());
8220
+ this.showStatus((await import("./service-MDQIPQ26.js")).serviceStatusText());
8221
8221
  return;
8222
8222
  }
8223
8223
  this.ui.stop();
@@ -8232,7 +8232,7 @@ Pi will resume when the editor exits.
8232
8232
  } finally {
8233
8233
  this.ui.start(), this.ui.requestRender(!0);
8234
8234
  }
8235
- this.showStatus((await import("./service-ISSP6VHE.js")).serviceStatusText());
8235
+ this.showStatus((await import("./service-MDQIPQ26.js")).serviceStatusText());
8236
8236
  })().catch((error) => this.showStatus(error instanceof Error ? error.message : String(error)));
8237
8237
  },
8238
8238
  onDefaultPermissionModeChange: (mode) => {
@@ -90,6 +90,11 @@ function claimGateway(onStop) {
90
90
  }, 500);
91
91
  return {
92
92
  update(platforms, state = "ready") {
93
+ if (stopping && state !== "stopping") {
94
+ stopping = !1;
95
+ let control = readJson(controlPath());
96
+ control && typeof control == "object" && "instance" in control && control.instance === status.instance && rmSync(controlPath(), { force: !0 });
97
+ }
93
98
  status.platforms = { ...platforms }, status.state = state, save();
94
99
  },
95
100
  release() {
@@ -103,8 +108,12 @@ function cliPath() {
103
108
  }
104
109
  var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
105
110
  async function startGatewayService() {
106
- if (gatewayIsRunning())
107
- return "Gateway is already running.";
111
+ if (gatewayIsRunning()) {
112
+ if (readGatewayStatus()?.state === "ready")
113
+ return "Gateway is already running.";
114
+ throw new Error(`Gateway process is running but no bot is connected. ${serviceStatusText()}
115
+ Inspect ${gatewayLogPath()}`);
116
+ }
108
117
  mkdirSync(serviceDirectory(), { recursive: !0, mode: 448 });
109
118
  let startup = loadServiceSettings().startup;
110
119
  if (startup !== "off") {
@@ -122,7 +131,8 @@ async function startGatewayService() {
122
131
  return "Gateway started.";
123
132
  await sleep(200);
124
133
  }
125
- throw new Error(`Startup service did not become ready. Run lunr gateway doctor and inspect ${gatewayLogPath()}`);
134
+ throw new Error(`Startup service did not connect within 20 seconds. ${serviceStatusText()}
135
+ Run lunr gateway doctor and inspect ${gatewayLogPath()}`);
126
136
  }
127
137
  let { openSync, closeSync } = await import("node:fs"), log = openSync(gatewayLogPath(), "a", 384), child = spawn(process.execPath, [cliPath(), "gateway", "run"], {
128
138
  cwd: homedir(),
@@ -146,7 +156,8 @@ async function startGatewayService() {
146
156
  throw new Error(`Gateway exited with code ${child.exitCode}. See ${gatewayLogPath()}`);
147
157
  await sleep(200);
148
158
  }
149
- throw new Error(`Gateway did not become ready within 20 seconds. Check lunr gateway status and ${gatewayLogPath()}`);
159
+ throw new Error(`Gateway did not connect within 20 seconds. ${serviceStatusText()}
160
+ Check lunr gateway status and ${gatewayLogPath()}`);
150
161
  }
151
162
  async function stopGatewayService() {
152
163
  let status = readGatewayStatus();
@@ -7,7 +7,7 @@ import {
7
7
  gatewaySelect,
8
8
  isGatewayOwner,
9
9
  requireGatewayOwner
10
- } from "./chunk-IGV54Q5V.js";
10
+ } from "./chunk-QTU6AKNJ.js";
11
11
  import {
12
12
  getSubagentCancellation
13
13
  } from "./chunk-BBUVIEZB.js";
@@ -21,7 +21,7 @@ import {
21
21
  } from "./chunk-2KIPT4HJ.js";
22
22
  import {
23
23
  loadGatewayConfig
24
- } from "./chunk-R3K2F5GI.js";
24
+ } from "./chunk-B4HP6ZWM.js";
25
25
 
26
26
  // packages/coding-agent/dist/gateway/mobile-commands.js
27
27
  import { mkdirSync, readdirSync, realpathSync, statSync } from "node:fs";
@@ -148,7 +148,7 @@ async function continueSession(ctx, file) {
148
148
  async function performContinue(ctx, file, signal) {
149
149
  requireGatewayOwner(ctx.event.source);
150
150
  let { requestSessionTransfer, SessionTransferError } = await import("./session-handoff-GWARVEWT.js"), { key, bridge } = ctx;
151
- if ((await bridge.getSession(key))?.sessionManager?.getSessionFile() === file) {
151
+ if (bridge.peekSession?.(key)?.sessionManager?.getSessionFile() === file) {
152
152
  await ctx.adapter.send(ctx.event.source.chatId, "This session is already open here.");
153
153
  return;
154
154
  }
@@ -157,7 +157,7 @@ async function performContinue(ctx, file, signal) {
157
157
  try {
158
158
  await requestSessionTransfer(file, { timeoutMs: 3e3, signal });
159
159
  } catch (error) {
160
- if (!(error instanceof SessionTransferError) || error.code !== "busy")
160
+ if (!(error instanceof SessionTransferError) || !["busy", "timeout"].includes(error.code))
161
161
  throw error;
162
162
  let choice = await gatewaySelect(key, `${error instanceof Error ? error.message : "Session is in use"}
163
163
  How should lunR continue?`, ["Wait until idle", "Stop and continue", "Cancel"], { signal });
@@ -173,7 +173,7 @@ How should lunR continue?`, ["Wait until idle", "Stop and continue", "Cancel"],
173
173
  await requestSessionTransfer(file, { timeoutMs: 3e3, signal });
174
174
  break;
175
175
  } catch (retryError) {
176
- if (!(retryError instanceof SessionTransferError) || retryError.code !== "busy" || Date.now() >= deadline)
176
+ if (!(retryError instanceof SessionTransferError) || !["busy", "timeout"].includes(retryError.code) || Date.now() >= deadline)
177
177
  throw retryError;
178
178
  }
179
179
  await new Promise((resolve2) => setTimeout(resolve2, 500));
@@ -325,7 +325,7 @@ async function handleMobileCommand(ctx, command, args) {
325
325
  if (command === "settings") {
326
326
  let choice = await gatewaySelect(ctx.key, "Session settings", ["Model", "Thinking", "Permissions"]);
327
327
  if (choice === "Model" || choice === "Thinking") {
328
- let { CHAT_COMMANDS, runChatCommand } = await import("./commands-QFDKNQTL.js"), cmd = CHAT_COMMANDS.find((c) => c.name === choice.toLowerCase());
328
+ let { CHAT_COMMANDS, runChatCommand } = await import("./commands-QC6VUZJQ.js"), cmd = CHAT_COMMANDS.find((c) => c.name === choice.toLowerCase());
329
329
  return cmd && await runChatCommand(cmd, {
330
330
  ...ctx,
331
331
  args: "",
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __lunrRequire } from "node:module"; const require = __lunrRequire(import.meta.url);
2
2
  import {
3
3
  loadInstallFeatures
4
- } from "./chunk-VWCE2HSZ.js";
4
+ } from "./chunk-2HMIRK7W.js";
5
5
  import {
6
6
  getAgentDir
7
7
  } from "./chunk-FQMM2EZ2.js";
@@ -7,7 +7,7 @@ import {
7
7
  createSyntheticSourceInfo,
8
8
  expandPromptTemplate,
9
9
  formatSkillsForPrompt
10
- } from "./chunk-F4FLTQKV.js";
10
+ } from "./chunk-YCUZEGJG.js";
11
11
  import {
12
12
  stripFrontmatter
13
13
  } from "./chunk-QFWG2RVL.js";
@@ -31,7 +31,7 @@ import {
31
31
  } from "./chunk-KJ6DWS3K.js";
32
32
  import {
33
33
  SettingsManager
34
- } from "./chunk-RORY2HMJ.js";
34
+ } from "./chunk-6XL67VVY.js";
35
35
  import {
36
36
  DEFAULT_THINKING_LEVEL,
37
37
  calculateContextTokens,
@@ -925,12 +925,12 @@ var lightBuiltinExtensions = [
925
925
  ], DEFERRED_BUILTIN_LOADERS = [
926
926
  { name: "pi-ollama-cloud", load: () => import("./pi-ollama-cloud-2F3Y2QNM.js") },
927
927
  { name: "narumiruna-pi-goal", load: () => import("./goal-NJEE5CTU.js") },
928
- { name: "lunr-cron", load: () => import("./lunr-cron-CXOL37AL.js") },
928
+ { name: "lunr-cron", load: () => import("./lunr-cron-LWIZJM2N.js") },
929
929
  { name: "pi-intercom", load: () => import("./pi-intercom-QM53RLTS.js") },
930
930
  { name: "pi-prompt-template-model", load: () => import("./pi-prompt-template-model-QWTCGLJU.js") },
931
- { name: "pi-subagents", load: () => import("./pi-subagents-XPCLLKIM.js") },
931
+ { name: "pi-subagents", load: () => import("./pi-subagents-DNY7EAIG.js") },
932
932
  { name: "pi-web-access", load: () => import("./pi-web-access-WTGMNZ32.js") },
933
- { name: "lunr-browser", load: () => import("./lunr-browser-J5ZZYVGM.js") },
933
+ { name: "lunr-browser", load: () => import("./lunr-browser-IR7TL3J7.js") },
934
934
  { name: "pi-lsp-extension", load: () => import("./src-IVPNZ2BX.js") },
935
935
  { name: "pi-mcp-adapter", load: () => import("./pi-mcp-adapter-5UKBZP44.js") }
936
936
  ], DEFERRED_BUILTIN_EXTENSION_NAMES = DEFERRED_BUILTIN_LOADERS.map((entry) => entry.name), DEFERRED_BUILTIN_FLAGS = ["mcp-config"];