@coinseeker/opencode-telegram-plugin 1.0.8 → 1.0.9
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 +2 -2
- package/dist/telegram-remote.js +3 -132
- package/package.json +1 -1
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.
|
|
18
|
+
"plugin": ["@coinseeker/opencode-telegram-plugin@1.0.9"]
|
|
19
19
|
}
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Current stable version: `@coinseeker/opencode-telegram-plugin@1.0.
|
|
22
|
+
Current stable version: `@coinseeker/opencode-telegram-plugin@1.0.9`.
|
|
23
23
|
|
|
24
24
|
Restart OpenCode after editing the config. OpenCode resolves npm package plugins on startup.
|
|
25
25
|
|
package/dist/telegram-remote.js
CHANGED
|
@@ -45,7 +45,6 @@ function createTelegramBot(opts) {
|
|
|
45
45
|
let activeChatId = opts.initialChatId;
|
|
46
46
|
let questionDispatcher;
|
|
47
47
|
let permissionDispatcher;
|
|
48
|
-
let startWorkDispatcher;
|
|
49
48
|
if (polling) {
|
|
50
49
|
bot.use(async (ctx, next) => {
|
|
51
50
|
const userId = ctx.from?.id;
|
|
@@ -98,13 +97,6 @@ This chat is now active for OpenCode notifications.`
|
|
|
98
97
|
if (!permissionDispatcher || messageId === void 0) return;
|
|
99
98
|
await permissionDispatcher.handleCallbackQuery(data, messageId);
|
|
100
99
|
});
|
|
101
|
-
bot.callbackQuery(/^sw:(.+)$/, async (ctx) => {
|
|
102
|
-
await ctx.answerCallbackQuery();
|
|
103
|
-
const data = ctx.callbackQuery.data;
|
|
104
|
-
const messageId = ctx.callbackQuery.message?.message_id;
|
|
105
|
-
if (!startWorkDispatcher || messageId === void 0) return;
|
|
106
|
-
await startWorkDispatcher.handleCallbackQuery(data, messageId);
|
|
107
|
-
});
|
|
108
100
|
bot.on("message:text", async (ctx) => {
|
|
109
101
|
const replyToMessageId = ctx.message.reply_to_message?.message_id;
|
|
110
102
|
const chatId = ctx.chat.id;
|
|
@@ -198,9 +190,6 @@ This chat is now active for OpenCode notifications.`
|
|
|
198
190
|
},
|
|
199
191
|
setPermissionDispatcher(dispatcher) {
|
|
200
192
|
permissionDispatcher = dispatcher;
|
|
201
|
-
},
|
|
202
|
-
setStartWorkDispatcher(dispatcher) {
|
|
203
|
-
startWorkDispatcher = dispatcher;
|
|
204
193
|
}
|
|
205
194
|
};
|
|
206
195
|
}
|
|
@@ -953,84 +942,6 @@ async function handleSessionError(event, ctx) {
|
|
|
953
942
|
ctx.logger.info("session abort recorded", { sessionId: event.properties.sessionID ?? "global" });
|
|
954
943
|
}
|
|
955
944
|
|
|
956
|
-
// src/events/start-work.ts
|
|
957
|
-
var CALLBACK_RE3 = /^sw:(.+)$/;
|
|
958
|
-
var START_WORK_COMMAND = "start-work";
|
|
959
|
-
var START_WORK_RE = /(?:^|[\s`])\/start-work(?:\s+([^\n`]+))?/g;
|
|
960
|
-
var StartWorkCommandStore = class {
|
|
961
|
-
commands = /* @__PURE__ */ new Map();
|
|
962
|
-
updateFromText(sessionID, text) {
|
|
963
|
-
const command = extractStartWorkCommand(sessionID, text);
|
|
964
|
-
if (!command) return void 0;
|
|
965
|
-
this.commands.set(sessionID, command.arguments);
|
|
966
|
-
return command;
|
|
967
|
-
}
|
|
968
|
-
get(sessionID) {
|
|
969
|
-
const args = this.commands.get(sessionID);
|
|
970
|
-
if (args === void 0) return void 0;
|
|
971
|
-
return { sessionID, arguments: args };
|
|
972
|
-
}
|
|
973
|
-
delete(sessionID) {
|
|
974
|
-
this.commands.delete(sessionID);
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
function extractStartWorkCommand(sessionID, text) {
|
|
978
|
-
let latestArgs;
|
|
979
|
-
for (const match of text.matchAll(START_WORK_RE)) {
|
|
980
|
-
const args = (match[1] ?? "").trim();
|
|
981
|
-
if (args) latestArgs = args;
|
|
982
|
-
}
|
|
983
|
-
if (latestArgs === void 0) return void 0;
|
|
984
|
-
return { sessionID, arguments: latestArgs };
|
|
985
|
-
}
|
|
986
|
-
function startWorkCallbackData(sessionID) {
|
|
987
|
-
const data = `sw:${encodeURIComponent(sessionID)}`;
|
|
988
|
-
return Buffer.byteLength(data, "utf8") <= 64 ? data : void 0;
|
|
989
|
-
}
|
|
990
|
-
function startWorkKeyboard(sessionID) {
|
|
991
|
-
const callbackData = startWorkCallbackData(sessionID);
|
|
992
|
-
if (!callbackData) return void 0;
|
|
993
|
-
return [[{ text: "\u25B6\uFE0F Run /start-work", callback_data: callbackData }]];
|
|
994
|
-
}
|
|
995
|
-
function createStartWorkDispatcher(ctx) {
|
|
996
|
-
return {
|
|
997
|
-
async handleCallbackQuery(data, messageId) {
|
|
998
|
-
const match = CALLBACK_RE3.exec(data);
|
|
999
|
-
if (!match) return;
|
|
1000
|
-
const sessionID = decodeURIComponent(match[1]);
|
|
1001
|
-
const command = ctx.startWorkCommands.get(sessionID);
|
|
1002
|
-
if (!command) {
|
|
1003
|
-
await ctx.bot.editMessageRemoveKeyboard(
|
|
1004
|
-
messageId,
|
|
1005
|
-
`\u26A0\uFE0F No /start-work command was detected for this session.
|
|
1006
|
-
|
|
1007
|
-
Session: ${sessionID}`
|
|
1008
|
-
);
|
|
1009
|
-
return;
|
|
1010
|
-
}
|
|
1011
|
-
try {
|
|
1012
|
-
await ctx.runSessionCommand(sessionID, START_WORK_COMMAND, command.arguments);
|
|
1013
|
-
await ctx.bot.editMessageRemoveKeyboard(
|
|
1014
|
-
messageId,
|
|
1015
|
-
`\u25B6\uFE0F Sent /start-work ${command.arguments} to opencode.
|
|
1016
|
-
|
|
1017
|
-
Session: ${sessionID}`
|
|
1018
|
-
);
|
|
1019
|
-
ctx.startWorkCommands.delete(sessionID);
|
|
1020
|
-
ctx.logger.info("start-work command sent", { sessionID });
|
|
1021
|
-
} catch (err) {
|
|
1022
|
-
await ctx.bot.editMessageRemoveKeyboard(
|
|
1023
|
-
messageId,
|
|
1024
|
-
`\u26A0\uFE0F Failed to send /start-work to opencode.
|
|
1025
|
-
|
|
1026
|
-
Session: ${sessionID}`
|
|
1027
|
-
);
|
|
1028
|
-
ctx.logger.error("failed to send start-work command", { sessionID, error: String(err) });
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
945
|
// src/events/session-idle.ts
|
|
1035
946
|
var ROOT_IDLE_RECHECK_DELAY_MS = 2500;
|
|
1036
947
|
function sleep(ms) {
|
|
@@ -1077,17 +988,9 @@ async function sendIdleNotification(sessionId, ctx) {
|
|
|
1077
988
|
});
|
|
1078
989
|
if (!claimed) return;
|
|
1079
990
|
const title = ctx.sessionTitleService.getSessionTitle(sessionId);
|
|
1080
|
-
const
|
|
1081
|
-
const message = title ? `Agent has finished: ${title}` : "Agent has finished.";
|
|
1082
|
-
const keyboard = startWorkCommand ? startWorkKeyboard(sessionId) : void 0;
|
|
1083
|
-
const text = startWorkCommand ? `${message}
|
|
1084
|
-
|
|
1085
|
-
Plan is ready. Tap below to run /start-work ${startWorkCommand.arguments}.` : message;
|
|
991
|
+
const text = title ? `Agent has finished: ${title}` : "Agent has finished.";
|
|
1086
992
|
try {
|
|
1087
|
-
await ctx.bot.sendMessage(
|
|
1088
|
-
text,
|
|
1089
|
-
keyboard ? { reply_markup: { inline_keyboard: keyboard } } : void 0
|
|
1090
|
-
);
|
|
993
|
+
await ctx.bot.sendMessage(text);
|
|
1091
994
|
ctx.sessionTitleService.clearDeferredIdleNotification(sessionId);
|
|
1092
995
|
ctx.logger.info("idle notification sent", { sessionId, title });
|
|
1093
996
|
} catch (err) {
|
|
@@ -1467,16 +1370,6 @@ var SessionTitleService = class {
|
|
|
1467
1370
|
|
|
1468
1371
|
// src/telegram-remote.ts
|
|
1469
1372
|
var pluginDir = dirname4(fileURLToPath(import.meta.url));
|
|
1470
|
-
function getTextPartFromMessagePartUpdated(event) {
|
|
1471
|
-
if (event.type !== "message.part.updated") return void 0;
|
|
1472
|
-
const part = event.properties?.part;
|
|
1473
|
-
if (!part || typeof part !== "object") return void 0;
|
|
1474
|
-
const candidate = part;
|
|
1475
|
-
if (candidate.type !== "text" || typeof candidate.sessionID !== "string" || typeof candidate.text !== "string") {
|
|
1476
|
-
return void 0;
|
|
1477
|
-
}
|
|
1478
|
-
return { type: "text", sessionID: candidate.sessionID, text: candidate.text };
|
|
1479
|
-
}
|
|
1480
1373
|
var TelegramRemote = async (input) => {
|
|
1481
1374
|
const logger = createLogger({ namespace: "telegram" });
|
|
1482
1375
|
try {
|
|
@@ -1490,7 +1383,6 @@ var TelegramRemote = async (input) => {
|
|
|
1490
1383
|
const claimsDir = join6(tmpdir4(), `opencoder-telegram-claims-${tokenHash}`);
|
|
1491
1384
|
const pendingQuestions = createPendingQuestionStore({ tokenHash });
|
|
1492
1385
|
const pendingPermissions = createPendingPermissionStore({ tokenHash });
|
|
1493
|
-
const startWorkCommands = new StartWorkCommandStore();
|
|
1494
1386
|
const lockResult = await acquireLock({ lockPath });
|
|
1495
1387
|
const isLeader = lockResult.acquired;
|
|
1496
1388
|
logger.info(
|
|
@@ -1529,13 +1421,6 @@ var TelegramRemote = async (input) => {
|
|
|
1529
1421
|
throwOnError: true
|
|
1530
1422
|
});
|
|
1531
1423
|
};
|
|
1532
|
-
const runSessionCommand = async (sessionID, command, args) => {
|
|
1533
|
-
await input.client.session.command({
|
|
1534
|
-
path: { id: sessionID },
|
|
1535
|
-
body: { command, arguments: args },
|
|
1536
|
-
throwOnError: true
|
|
1537
|
-
});
|
|
1538
|
-
};
|
|
1539
1424
|
const bot = createTelegramBot({
|
|
1540
1425
|
config,
|
|
1541
1426
|
stateStore,
|
|
@@ -1580,15 +1465,12 @@ var TelegramRemote = async (input) => {
|
|
|
1580
1465
|
tokenHash,
|
|
1581
1466
|
pendingQuestions,
|
|
1582
1467
|
pendingPermissions,
|
|
1583
|
-
startWorkCommands,
|
|
1584
1468
|
replyToQuestion,
|
|
1585
|
-
replyToPermission
|
|
1586
|
-
runSessionCommand
|
|
1469
|
+
replyToPermission
|
|
1587
1470
|
};
|
|
1588
1471
|
if (isLeader) {
|
|
1589
1472
|
bot.setQuestionDispatcher(createQuestionDispatcher(ctx));
|
|
1590
1473
|
bot.setPermissionDispatcher(createPermissionDispatcher(ctx));
|
|
1591
|
-
bot.setStartWorkDispatcher(createStartWorkDispatcher(ctx));
|
|
1592
1474
|
}
|
|
1593
1475
|
return {
|
|
1594
1476
|
event: async ({ event }) => {
|
|
@@ -1606,17 +1488,6 @@ var TelegramRemote = async (input) => {
|
|
|
1606
1488
|
case "permission.updated":
|
|
1607
1489
|
return handlePermissionUpdated(event, ctx);
|
|
1608
1490
|
default: {
|
|
1609
|
-
const textPart = getTextPartFromMessagePartUpdated(extEvent);
|
|
1610
|
-
if (textPart) {
|
|
1611
|
-
const command = startWorkCommands.updateFromText(textPart.sessionID, textPart.text);
|
|
1612
|
-
if (command) {
|
|
1613
|
-
logger.info("start-work command detected", {
|
|
1614
|
-
sessionID: command.sessionID,
|
|
1615
|
-
arguments: command.arguments
|
|
1616
|
-
});
|
|
1617
|
-
}
|
|
1618
|
-
return;
|
|
1619
|
-
}
|
|
1620
1491
|
if (isEventPermissionAsked(extEvent)) {
|
|
1621
1492
|
if (!isLeader) return;
|
|
1622
1493
|
return handlePermissionAsked(extEvent, ctx);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinseeker/opencode-telegram-plugin",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
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",
|