@coinseeker/opencode-telegram-plugin 1.0.14 → 1.1.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/README.md CHANGED
@@ -15,11 +15,11 @@ Configure the npm package in `~/.config/opencode/opencode.json`:
15
15
 
16
16
  ```json
17
17
  {
18
- "plugin": ["@coinseeker/opencode-telegram-plugin@1.0.14"]
18
+ "plugin": ["@coinseeker/opencode-telegram-plugin@1.1.0"]
19
19
  }
20
20
  ```
21
21
 
22
- Current stable version: `@coinseeker/opencode-telegram-plugin@1.0.14`.
22
+ Current stable version: `@coinseeker/opencode-telegram-plugin@1.1.0`.
23
23
 
24
24
  Restart OpenCode after editing the config. OpenCode resolves npm package plugins on startup.
25
25
 
@@ -923,6 +923,7 @@ function createQuestionDispatcher(ctx) {
923
923
  await expirePending2(ctx, shortHash, pending, messageId);
924
924
  return;
925
925
  }
926
+ pending.expiresAt = Date.now() + QUESTION_EXPIRY_MS;
926
927
  const question = pending.questions[questionIndex];
927
928
  if (!question) return;
928
929
  if (selection === "c") {
@@ -980,6 +981,7 @@ function createQuestionDispatcher(ctx) {
980
981
  await expirePending2(ctx, match.shortHash, match.data, match.data.telegramMessageIds[0]);
981
982
  return;
982
983
  }
984
+ match.data.expiresAt = Date.now() + QUESTION_EXPIRY_MS;
983
985
  const question = match.data.questions[awaiting.questionIndex];
984
986
  if (question?.multiple === true) {
985
987
  const current = selectedAnswers(match.data, awaiting.questionIndex);
@@ -1522,9 +1524,21 @@ Session: ${label}`
1522
1524
 
1523
1525
  // src/events/session-idle.ts
1524
1526
  var ROOT_IDLE_RECHECK_DELAY_MS = 2500;
1527
+ var DEFERRED_PARENT_CONFIRM_DELAY_MS = 2500;
1528
+ var deferredConfirmTimers = /* @__PURE__ */ new Map();
1525
1529
  function sleep(ms) {
1526
1530
  return new Promise((resolve) => setTimeout(resolve, ms));
1527
1531
  }
1532
+ function agentFinishedMessage(title, agent) {
1533
+ const base = title ? `Agent has finished: ${title}` : "Agent has finished.";
1534
+ return agent ? `${base} (${agent})` : base;
1535
+ }
1536
+ function cancelDeferredParentConfirm(sessionId) {
1537
+ const timer = deferredConfirmTimers.get(sessionId);
1538
+ if (timer === void 0) return;
1539
+ clearTimeout(timer);
1540
+ deferredConfirmTimers.delete(sessionId);
1541
+ }
1528
1542
  async function resolveParentID(sessionId, ctx) {
1529
1543
  const cachedParentID = ctx.sessionTitleService.getParentID(sessionId);
1530
1544
  if (cachedParentID !== void 0) return cachedParentID;
@@ -1576,8 +1590,9 @@ async function sendIdleNotification(sessionId, ctx) {
1576
1590
  });
1577
1591
  if (!claimed) return;
1578
1592
  const title = ctx.sessionTitleService.getSessionTitle(sessionId);
1579
- const isPlanSession = ctx.sessionTitleService.getSessionAgent(sessionId) === "plan";
1580
- const text = isPlanSession ? planCompleteMessage(title) : title ? `Agent has finished: ${title}` : "Agent has finished.";
1593
+ const agent = ctx.sessionTitleService.getSessionAgent(sessionId);
1594
+ const isPlanSession = agent === "plan";
1595
+ const text = isPlanSession ? planCompleteMessage(title) : agentFinishedMessage(title, agent);
1581
1596
  try {
1582
1597
  if (isPlanSession) {
1583
1598
  const shortHash = startWorkShortHash(sessionId);
@@ -1601,18 +1616,49 @@ async function flushDeferredParentIfReady(parentID, ctx) {
1601
1616
  if (!ctx.sessionTitleService.hasDeferredIdleNotification(parentID)) return;
1602
1617
  if (ctx.sessionTitleService.hasUnfinishedDescendants(parentID)) return;
1603
1618
  const parentStatus = ctx.sessionTitleService.getSessionStatus(parentID);
1604
- if (parentStatus === "idle") {
1605
- ctx.logger.info("keeping deferred parent idle notification - waiting for parent to resume", {
1619
+ if (parentStatus !== "idle") {
1620
+ if (parentStatus !== void 0) {
1621
+ cancelDeferredParentConfirm(parentID);
1622
+ ctx.sessionTitleService.clearDeferredIdleNotification(parentID);
1623
+ ctx.logger.info("clearing deferred parent idle notification - parent resumed", {
1624
+ sessionId: parentID
1625
+ });
1626
+ }
1627
+ return;
1628
+ }
1629
+ scheduleDeferredParentConfirm(parentID, ctx);
1630
+ }
1631
+ function scheduleDeferredParentConfirm(parentID, ctx) {
1632
+ if (deferredConfirmTimers.has(parentID)) return;
1633
+ const delay = ctx.deferredConfirmDelayMs ?? DEFERRED_PARENT_CONFIRM_DELAY_MS;
1634
+ const timer = setTimeout(() => {
1635
+ deferredConfirmTimers.delete(parentID);
1636
+ void confirmDeferredParentIdle(parentID, ctx);
1637
+ }, delay);
1638
+ timer.unref?.();
1639
+ deferredConfirmTimers.set(parentID, timer);
1640
+ ctx.logger.info("parent idle and descendants finished - confirming deferred notification", {
1641
+ sessionId: parentID
1642
+ });
1643
+ }
1644
+ async function confirmDeferredParentIdle(parentID, ctx) {
1645
+ if (!ctx.sessionTitleService.hasDeferredIdleNotification(parentID)) return;
1646
+ if (ctx.sessionTitleService.getSessionStatus(parentID) !== "idle") {
1647
+ ctx.sessionTitleService.clearDeferredIdleNotification(parentID);
1648
+ ctx.logger.info("clearing deferred parent idle notification - parent resumed during confirm", {
1606
1649
  sessionId: parentID
1607
1650
  });
1608
1651
  return;
1609
1652
  }
1610
- if (parentStatus !== void 0) {
1611
- ctx.sessionTitleService.clearDeferredIdleNotification(parentID);
1612
- ctx.logger.info("clearing deferred parent idle notification - parent resumed", {
1653
+ await hydrateDescendants(parentID, ctx);
1654
+ if (ctx.sessionTitleService.hasUnfinishedDescendants(parentID)) {
1655
+ ctx.logger.info("keeping deferred parent idle notification - descendants active again", {
1613
1656
  sessionId: parentID
1614
1657
  });
1658
+ return;
1615
1659
  }
1660
+ ctx.logger.info("sending deferred parent idle notification", { sessionId: parentID });
1661
+ await sendIdleNotification(parentID, ctx);
1616
1662
  }
1617
1663
  async function deferParentIdleIfDescendantsRunning(sessionId, ctx) {
1618
1664
  await hydrateDescendants(sessionId, ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinseeker/opencode-telegram-plugin",
3
- "version": "1.0.14",
3
+ "version": "1.1.0",
4
4
  "description": "Control and monitor OpenCode from Telegram with notifications, question replies, and subagent-aware completion.",
5
5
  "type": "module",
6
6
  "main": "dist/telegram-remote.js",