@coinseeker/opencode-telegram-plugin 1.1.6 → 1.1.7
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 +3 -3
- package/dist/telegram-remote.js +44 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,15 +15,15 @@ Configure the npm package in `~/.config/opencode/opencode.json`:
|
|
|
15
15
|
|
|
16
16
|
```json
|
|
17
17
|
{
|
|
18
|
-
"plugin": ["@coinseeker/opencode-telegram-plugin@1.1.
|
|
18
|
+
"plugin": ["@coinseeker/opencode-telegram-plugin@1.1.7"]
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Current stable version: `@coinseeker/opencode-telegram-plugin@1.1.
|
|
22
|
+
Current stable version: `@coinseeker/opencode-telegram-plugin@1.1.7`.
|
|
23
23
|
|
|
24
24
|
Restart OpenCode after editing the config. OpenCode resolves npm package plugins on startup.
|
|
25
25
|
|
|
26
|
-
To update an existing install, replace the previous pinned package entry with `@coinseeker/opencode-telegram-plugin@1.1.
|
|
26
|
+
To update an existing install, replace the previous pinned package entry with `@coinseeker/opencode-telegram-plugin@1.1.7`, keep the rest of the `plugin` array unchanged, and restart OpenCode.
|
|
27
27
|
|
|
28
28
|
## Configure Telegram
|
|
29
29
|
|
package/dist/telegram-remote.js
CHANGED
|
@@ -1655,6 +1655,8 @@ function createStartWorkDispatcher(ctx) {
|
|
|
1655
1655
|
// src/events/session-idle.ts
|
|
1656
1656
|
var ROOT_IDLE_RECHECK_DELAY_MS = 2500;
|
|
1657
1657
|
var DEFERRED_PARENT_CONFIRM_DELAY_MS = 2500;
|
|
1658
|
+
var PLAN_COMPLETION_MESSAGE_LIMIT = 5;
|
|
1659
|
+
var START_WORK_COMMAND_RE = /(?:^|[\s`"'(])\/?start[_-]work(?:$|[\s`"').,!?])/i;
|
|
1658
1660
|
var deferredConfirmTimers = /* @__PURE__ */ new Map();
|
|
1659
1661
|
function sleep(ms) {
|
|
1660
1662
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
@@ -1666,6 +1668,42 @@ function agentFinishedMessage(title, agent) {
|
|
|
1666
1668
|
function selectPlanSessionAgent(candidates) {
|
|
1667
1669
|
return candidates.find(isPlanSessionAgent) ?? candidates.find((agent) => agent !== void 0);
|
|
1668
1670
|
}
|
|
1671
|
+
function extractTextFromParts(parts) {
|
|
1672
|
+
const pieces = [];
|
|
1673
|
+
for (const part of parts) {
|
|
1674
|
+
if (part.type === "text" && typeof part.text === "string") pieces.push(part.text);
|
|
1675
|
+
}
|
|
1676
|
+
return pieces.join(" ");
|
|
1677
|
+
}
|
|
1678
|
+
function findLatestAssistantMessage(messages) {
|
|
1679
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
1680
|
+
const message = messages[i];
|
|
1681
|
+
if (message?.info.role === "assistant") return message;
|
|
1682
|
+
}
|
|
1683
|
+
return void 0;
|
|
1684
|
+
}
|
|
1685
|
+
function hasStartWorkCommandInstruction(text) {
|
|
1686
|
+
return START_WORK_COMMAND_RE.test(text);
|
|
1687
|
+
}
|
|
1688
|
+
async function latestAssistantText(sessionId, ctx) {
|
|
1689
|
+
try {
|
|
1690
|
+
const result = await ctx.client.session.messages({
|
|
1691
|
+
path: { id: sessionId },
|
|
1692
|
+
query: { limit: PLAN_COMPLETION_MESSAGE_LIMIT }
|
|
1693
|
+
});
|
|
1694
|
+
const message = findLatestAssistantMessage(normalizeMessages(result.data));
|
|
1695
|
+
return message ? extractTextFromParts(message.parts) : void 0;
|
|
1696
|
+
} catch (err) {
|
|
1697
|
+
ctx.logger.warn("plan completion message lookup failed", { sessionId, error: String(err) });
|
|
1698
|
+
return void 0;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
async function shouldSendPlanCompletion(sessionId, ctx) {
|
|
1702
|
+
const text = await latestAssistantText(sessionId, ctx);
|
|
1703
|
+
if (text !== void 0 && hasStartWorkCommandInstruction(text)) return true;
|
|
1704
|
+
ctx.logger.info("skipping plan completion notice - no start-work instruction", { sessionId });
|
|
1705
|
+
return false;
|
|
1706
|
+
}
|
|
1669
1707
|
async function resolveSessionAgent(sessionId, ctx) {
|
|
1670
1708
|
const candidates = [
|
|
1671
1709
|
ctx.sessionTitleService.getSessionAgent(sessionId)
|
|
@@ -1745,15 +1783,16 @@ async function sendIdleNotification(sessionId, ctx) {
|
|
|
1745
1783
|
ctx.logger.info("idle suppressed - session was aborted", { sessionId });
|
|
1746
1784
|
return;
|
|
1747
1785
|
}
|
|
1786
|
+
const title = ctx.sessionTitleService.getSessionTitle(sessionId);
|
|
1787
|
+
const agent = await resolveSessionAgent(sessionId, ctx);
|
|
1788
|
+
const isPlanSession = isPlanSessionAgent(agent);
|
|
1789
|
+
if (isPlanSession && !await shouldSendPlanCompletion(sessionId, ctx)) return;
|
|
1748
1790
|
const claimed = await claimOnce({
|
|
1749
1791
|
claimsDir: ctx.claimsDir,
|
|
1750
1792
|
key: `session.idle:${sessionId}`,
|
|
1751
1793
|
ttlMs: 5e3
|
|
1752
1794
|
});
|
|
1753
1795
|
if (!claimed) return;
|
|
1754
|
-
const title = ctx.sessionTitleService.getSessionTitle(sessionId);
|
|
1755
|
-
const agent = await resolveSessionAgent(sessionId, ctx);
|
|
1756
|
-
const isPlanSession = isPlanSessionAgent(agent);
|
|
1757
1796
|
const text = isPlanSession ? planCompleteMessage(title) : agentFinishedMessage(title, agent);
|
|
1758
1797
|
try {
|
|
1759
1798
|
if (isPlanSession) {
|
|
@@ -2352,7 +2391,7 @@ function resolveProjectRoot(session) {
|
|
|
2352
2391
|
if (!session.directory) throw new Error("session directory missing");
|
|
2353
2392
|
return session.directory;
|
|
2354
2393
|
}
|
|
2355
|
-
function
|
|
2394
|
+
function extractTextFromParts2(parts) {
|
|
2356
2395
|
const pieces = [];
|
|
2357
2396
|
for (const part of parts) {
|
|
2358
2397
|
if (part.type === "text" && typeof part.text === "string") {
|
|
@@ -2364,7 +2403,7 @@ function extractTextFromParts(parts) {
|
|
|
2364
2403
|
function buildSnippet(envelope) {
|
|
2365
2404
|
if (!envelope) return EMPTY_MESSAGE;
|
|
2366
2405
|
try {
|
|
2367
|
-
const raw =
|
|
2406
|
+
const raw = extractTextFromParts2(envelope.parts);
|
|
2368
2407
|
const cleaned = stripCodeFences(raw);
|
|
2369
2408
|
const truncated = truncateForTelegram(cleaned, SNIPPET_MAX_CHARS);
|
|
2370
2409
|
if (!truncated) return EMPTY_MESSAGE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinseeker/opencode-telegram-plugin",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7",
|
|
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",
|