@inetafrica/open-claudia 1.10.1 → 1.12.1
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/CHANGELOG.md +12 -0
- package/README.md +4 -2
- package/bot-agent.js +72 -4
- package/bot.js +73 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v1.12.0
|
|
4
|
+
- Cursor Agent tool progress: Shell, Read, Edit, Write, Grep, Glob calls now show in real-time Telegram updates
|
|
5
|
+
- Plan output surfaced to Telegram: when Cursor creates a plan (`--mode plan`), the full plan markdown and task list are sent to the user
|
|
6
|
+
- Handles all Cursor tool_call event types with fallback for unknown tools
|
|
7
|
+
|
|
8
|
+
## v1.11.0
|
|
9
|
+
- Backend-aware plan mode: /plan passes `--mode plan` to Cursor Agent, `--permission-mode plan` to Claude
|
|
10
|
+
- New /ask command: read-only Q&A mode (Cursor Agent only, `--mode ask`)
|
|
11
|
+
- /effort and /budget now warn when on Cursor backend (unsupported flags)
|
|
12
|
+
- Worktree flag (`--worktree`) wired into Cursor Agent args
|
|
13
|
+
- buildCursorArgs now forwards plan/ask/worktree settings
|
|
14
|
+
|
|
3
15
|
## v1.10.0
|
|
4
16
|
- Cursor Agent backend: switch between Claude Code and Cursor Agent CLI
|
|
5
17
|
- New commands: /cursor, /claude, /backend with inline keyboard
|
package/README.md
CHANGED
|
@@ -126,7 +126,8 @@ When you select a project, the last conversation is automatically resumed. Tap "
|
|
|
126
126
|
| `/model` | Switch model (opus / sonnet / haiku for Claude; any model flag for Cursor) |
|
|
127
127
|
| `/effort` | Set effort level (low / medium / high / max) |
|
|
128
128
|
| `/budget` | Set max spend for next task (e.g. `/budget 0.50`) — Claude only |
|
|
129
|
-
| `/plan` | Toggle plan mode — Claude
|
|
129
|
+
| `/plan` | Toggle plan mode — `--permission-mode plan` (Claude) / `--mode plan` (Cursor) |
|
|
130
|
+
| `/ask` | Toggle ask mode — read-only Q&A, no edits (Cursor Agent only) |
|
|
130
131
|
| `/compact` | Summarize conversation context |
|
|
131
132
|
| `/worktree` | Toggle isolated git branch — Claude only |
|
|
132
133
|
| `/mode` | Switch between direct and agent bot modes |
|
|
@@ -158,9 +159,10 @@ When you select a project, the last conversation is automatically resumed. Tap "
|
|
|
158
159
|
| Session flag | `--resume <id>` | `--resume <id>` |
|
|
159
160
|
| Auth | `claude auth` | `agent login` |
|
|
160
161
|
| Plan mode | Yes (`--permission-mode plan`) | Yes (`--mode plan`) |
|
|
162
|
+
| Ask mode | No | Yes (`--mode ask`) |
|
|
161
163
|
| Budget control | Yes (`--max-budget-usd`) | No |
|
|
162
164
|
| Effort levels | Yes | No |
|
|
163
|
-
| Worktree | Yes |
|
|
165
|
+
| Worktree | Yes (`--worktree`) | Yes (`--worktree`) |
|
|
164
166
|
| Model switching | Yes | Yes |
|
|
165
167
|
| Dangerously skip permissions | Yes | Yes (`--trust`) |
|
|
166
168
|
|
package/bot-agent.js
CHANGED
|
@@ -178,6 +178,7 @@ bot.setMyCommands([
|
|
|
178
178
|
{ command: "effort", description: "Set effort level" },
|
|
179
179
|
{ command: "budget", description: "Set max spend for next task" },
|
|
180
180
|
{ command: "plan", description: "Toggle plan mode" },
|
|
181
|
+
{ command: "ask", description: "Toggle ask mode (Cursor only)" },
|
|
181
182
|
{ command: "sessions", description: "List conversations for this project" },
|
|
182
183
|
{ command: "compact", description: "Summarize conversation context" },
|
|
183
184
|
{ command: "continue", description: "Resume last conversation" },
|
|
@@ -696,6 +697,9 @@ function buildCursorArgs(prompt, opts = {}) {
|
|
|
696
697
|
if (opts.continueSession) args.push("--continue");
|
|
697
698
|
else if (cursorSessionId && !opts.fresh) args.push("--resume", cursorSessionId);
|
|
698
699
|
if (settings.model) args.push("--model", settings.model);
|
|
700
|
+
if (settings.permissionMode === "plan") args.push("--mode", "plan");
|
|
701
|
+
else if (settings.permissionMode === "ask") args.push("--mode", "ask");
|
|
702
|
+
if (settings.worktree) args.push("--worktree");
|
|
699
703
|
args.push(prompt);
|
|
700
704
|
return args;
|
|
701
705
|
}
|
|
@@ -841,7 +845,6 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
|
|
|
841
845
|
else if (block.type === "tool_use") {
|
|
842
846
|
currentTool = block.name;
|
|
843
847
|
toolUses.push(block.name);
|
|
844
|
-
// Extract useful detail from tool input
|
|
845
848
|
const input = block.input || {};
|
|
846
849
|
if (block.name === "Bash" && input.command) currentToolDetail = input.command.slice(0, 80);
|
|
847
850
|
else if (block.name === "Read" && input.file_path) currentToolDetail = input.file_path.split("/").slice(-2).join("/");
|
|
@@ -853,6 +856,48 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
|
|
|
853
856
|
}
|
|
854
857
|
}
|
|
855
858
|
}
|
|
859
|
+
// Cursor Agent tool_call events (different format from Claude's tool_use blocks)
|
|
860
|
+
if (evt.type === "tool_call" && evt.subtype === "started" && evt.tool_call) {
|
|
861
|
+
const tc = evt.tool_call;
|
|
862
|
+
if (tc.shellToolCall) {
|
|
863
|
+
const a = tc.shellToolCall.args || {};
|
|
864
|
+
currentTool = "Shell"; toolUses.push("Shell");
|
|
865
|
+
currentToolDetail = (a.description || a.command || "").slice(0, 80);
|
|
866
|
+
} else if (tc.readToolCall) {
|
|
867
|
+
currentTool = "Read"; toolUses.push("Read");
|
|
868
|
+
currentToolDetail = (tc.readToolCall.args?.path || "").split("/").slice(-2).join("/");
|
|
869
|
+
} else if (tc.editToolCall) {
|
|
870
|
+
currentTool = "Edit"; toolUses.push("Edit");
|
|
871
|
+
currentToolDetail = (tc.editToolCall.args?.filePath || "").split("/").slice(-2).join("/");
|
|
872
|
+
} else if (tc.writeToolCall) {
|
|
873
|
+
currentTool = "Write"; toolUses.push("Write");
|
|
874
|
+
currentToolDetail = (tc.writeToolCall.args?.filePath || "").split("/").slice(-2).join("/");
|
|
875
|
+
} else if (tc.grepToolCall) {
|
|
876
|
+
currentTool = "Grep"; toolUses.push("Grep");
|
|
877
|
+
currentToolDetail = (tc.grepToolCall.args?.pattern || "").slice(0, 40);
|
|
878
|
+
} else if (tc.globToolCall) {
|
|
879
|
+
currentTool = "Glob"; toolUses.push("Glob");
|
|
880
|
+
currentToolDetail = (tc.globToolCall.args?.globPattern || "").slice(0, 40);
|
|
881
|
+
} else if (tc.createPlanToolCall) {
|
|
882
|
+
currentTool = "Plan"; toolUses.push("Plan");
|
|
883
|
+
const plan = tc.createPlanToolCall.args || {};
|
|
884
|
+
let planText = "";
|
|
885
|
+
if (plan.name) planText += `**${plan.name}**\n\n`;
|
|
886
|
+
if (plan.plan) planText += plan.plan + "\n";
|
|
887
|
+
if (plan.todos && plan.todos.length) {
|
|
888
|
+
planText += "\n**Tasks:**\n";
|
|
889
|
+
for (const todo of plan.todos) {
|
|
890
|
+
planText += `• ${todo.content || todo.id}\n`;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
if (planText) assistantText = planText;
|
|
894
|
+
currentToolDetail = plan.name || "creating plan";
|
|
895
|
+
} else {
|
|
896
|
+
const toolKey = Object.keys(tc)[0] || "unknown";
|
|
897
|
+
currentTool = toolKey.replace("ToolCall", ""); toolUses.push(currentTool);
|
|
898
|
+
currentToolDetail = "";
|
|
899
|
+
}
|
|
900
|
+
}
|
|
856
901
|
if (evt.type === "result" && evt.session_id) {
|
|
857
902
|
if (settings.backend === "cursor") { cursorSessionId = evt.session_id; }
|
|
858
903
|
else { lastSessionId = evt.session_id; }
|
|
@@ -1126,23 +1171,46 @@ bot.onText(/\/model (.+)/, (msg, match) => { if (!isAuthorized(msg)) return; set
|
|
|
1126
1171
|
|
|
1127
1172
|
bot.onText(/\/effort$/, (msg) => {
|
|
1128
1173
|
if (!isAuthorized(msg)) return;
|
|
1174
|
+
if (settings.backend === "cursor") return send("Effort levels are not supported on Cursor Agent.\nSwitch to Claude with /claude to use this.");
|
|
1129
1175
|
send(`Effort: ${settings.effort || "default"}`, { keyboard: { inline_keyboard: [
|
|
1130
1176
|
[{ text: "Low", callback_data: "e:low" }, { text: "Med", callback_data: "e:medium" }, { text: "High", callback_data: "e:high" }, { text: "Max", callback_data: "e:max" }],
|
|
1131
1177
|
[{ text: "Default", callback_data: "e:default" }],
|
|
1132
1178
|
] } });
|
|
1133
1179
|
});
|
|
1134
|
-
bot.onText(/\/effort (.+)/, (msg, match) => {
|
|
1180
|
+
bot.onText(/\/effort (.+)/, (msg, match) => {
|
|
1181
|
+
if (!isAuthorized(msg)) return;
|
|
1182
|
+
if (settings.backend === "cursor") return send("Effort levels are not supported on Cursor Agent.");
|
|
1183
|
+
const e = match[1].trim().toLowerCase(); settings.effort = ["low","medium","high","max"].includes(e) ? e : null; send(`Effort: ${settings.effort || "default"}`);
|
|
1184
|
+
});
|
|
1135
1185
|
|
|
1136
1186
|
bot.onText(/\/budget$/, (msg) => {
|
|
1137
1187
|
if (!isAuthorized(msg)) return;
|
|
1188
|
+
if (settings.backend === "cursor") return send("Budget limits are not supported on Cursor Agent.\nSwitch to Claude with /claude to use this.");
|
|
1138
1189
|
send(`Budget: ${settings.budget ? "$" + settings.budget : "none"}`, { keyboard: { inline_keyboard: [
|
|
1139
1190
|
[{ text: "$1", callback_data: "b:1" }, { text: "$5", callback_data: "b:5" }, { text: "$10", callback_data: "b:10" }, { text: "$25", callback_data: "b:25" }],
|
|
1140
1191
|
[{ text: "No limit", callback_data: "b:none" }],
|
|
1141
1192
|
] } });
|
|
1142
1193
|
});
|
|
1143
|
-
bot.onText(/\/budget (.+)/, (msg, match) => {
|
|
1194
|
+
bot.onText(/\/budget (.+)/, (msg, match) => {
|
|
1195
|
+
if (!isAuthorized(msg)) return;
|
|
1196
|
+
if (settings.backend === "cursor") return send("Budget limits are not supported on Cursor Agent.");
|
|
1197
|
+
const v = parseFloat(match[1].replace("$","")); settings.budget = v > 0 ? v : null; send(`Budget: ${settings.budget ? "$"+settings.budget : "none"}`);
|
|
1198
|
+
});
|
|
1144
1199
|
|
|
1145
|
-
bot.onText(/\/plan$/, (msg) => {
|
|
1200
|
+
bot.onText(/\/plan$/, (msg) => {
|
|
1201
|
+
if (!isAuthorized(msg)) return;
|
|
1202
|
+
const p = settings.permissionMode === "plan";
|
|
1203
|
+
settings.permissionMode = p ? null : "plan";
|
|
1204
|
+
const label = settings.backend === "cursor" ? "read-only planning, no edits" : "plan permission mode";
|
|
1205
|
+
send(p ? "Plan mode off." : `Plan mode on (${label}).`);
|
|
1206
|
+
});
|
|
1207
|
+
bot.onText(/\/ask$/, (msg) => {
|
|
1208
|
+
if (!isAuthorized(msg)) return;
|
|
1209
|
+
if (settings.backend !== "cursor") return send("Ask mode is only available on Cursor Agent.\nUse /cursor to switch.");
|
|
1210
|
+
const a = settings.permissionMode === "ask";
|
|
1211
|
+
settings.permissionMode = a ? null : "ask";
|
|
1212
|
+
send(a ? "Ask mode off." : "Ask mode on (read-only Q&A, no edits).");
|
|
1213
|
+
});
|
|
1146
1214
|
bot.onText(/\/compact/, async (msg) => { if (!isAuthorized(msg)) return; if (!requireSession(msg)) return; if (!getActiveSessionId()) return send("No conversation."); await runClaude("Summarize: key decisions, code state, next steps.", currentSession.dir, msg.message_id); });
|
|
1147
1215
|
bot.onText(/\/continue$/, async (msg) => { if (!isAuthorized(msg)) return; if (!requireSession(msg)) return; await runClaude("continue where we left off", currentSession.dir, msg.message_id, { continueSession: true }); });
|
|
1148
1216
|
bot.onText(/\/worktree$/, (msg) => { if (!isAuthorized(msg)) return; settings.worktree = !settings.worktree; send(settings.worktree ? "Worktree on." : "Worktree off."); });
|
package/bot.js
CHANGED
|
@@ -236,6 +236,7 @@ bot.setMyCommands([
|
|
|
236
236
|
{ command: "effort", description: "Set effort level" },
|
|
237
237
|
{ command: "budget", description: "Set max spend for next task" },
|
|
238
238
|
{ command: "plan", description: "Toggle plan mode" },
|
|
239
|
+
{ command: "ask", description: "Toggle ask mode (Cursor only)" },
|
|
239
240
|
{ command: "sessions", description: "List conversations for this project" },
|
|
240
241
|
{ command: "compact", description: "Summarize conversation context" },
|
|
241
242
|
{ command: "continue", description: "Resume last conversation" },
|
|
@@ -757,6 +758,9 @@ function buildCursorArgs(prompt, opts = {}) {
|
|
|
757
758
|
if (opts.continueSession) args.push("--continue");
|
|
758
759
|
else if (cursorSessionId && !opts.fresh) args.push("--resume", cursorSessionId);
|
|
759
760
|
if (settings.model) args.push("--model", settings.model);
|
|
761
|
+
if (settings.permissionMode === "plan") args.push("--mode", "plan");
|
|
762
|
+
else if (settings.permissionMode === "ask") args.push("--mode", "ask");
|
|
763
|
+
if (settings.worktree) args.push("--worktree");
|
|
760
764
|
args.push(prompt);
|
|
761
765
|
return args;
|
|
762
766
|
}
|
|
@@ -857,7 +861,6 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
|
|
|
857
861
|
else if (block.type === "tool_use") {
|
|
858
862
|
currentTool = block.name;
|
|
859
863
|
toolUses.push(block.name);
|
|
860
|
-
// Extract useful detail from tool input
|
|
861
864
|
const input = block.input || {};
|
|
862
865
|
if (block.name === "Bash" && input.command) currentToolDetail = input.command.slice(0, 80);
|
|
863
866
|
else if (block.name === "Read" && input.file_path) currentToolDetail = input.file_path.split("/").slice(-2).join("/");
|
|
@@ -869,6 +872,48 @@ async function runClaude(prompt, cwd, replyToMsgId, opts = {}) {
|
|
|
869
872
|
}
|
|
870
873
|
}
|
|
871
874
|
}
|
|
875
|
+
// Cursor Agent tool_call events (different format from Claude's tool_use blocks)
|
|
876
|
+
if (evt.type === "tool_call" && evt.subtype === "started" && evt.tool_call) {
|
|
877
|
+
const tc = evt.tool_call;
|
|
878
|
+
if (tc.shellToolCall) {
|
|
879
|
+
const a = tc.shellToolCall.args || {};
|
|
880
|
+
currentTool = "Shell"; toolUses.push("Shell");
|
|
881
|
+
currentToolDetail = (a.description || a.command || "").slice(0, 80);
|
|
882
|
+
} else if (tc.readToolCall) {
|
|
883
|
+
currentTool = "Read"; toolUses.push("Read");
|
|
884
|
+
currentToolDetail = (tc.readToolCall.args?.path || "").split("/").slice(-2).join("/");
|
|
885
|
+
} else if (tc.editToolCall) {
|
|
886
|
+
currentTool = "Edit"; toolUses.push("Edit");
|
|
887
|
+
currentToolDetail = (tc.editToolCall.args?.filePath || "").split("/").slice(-2).join("/");
|
|
888
|
+
} else if (tc.writeToolCall) {
|
|
889
|
+
currentTool = "Write"; toolUses.push("Write");
|
|
890
|
+
currentToolDetail = (tc.writeToolCall.args?.filePath || "").split("/").slice(-2).join("/");
|
|
891
|
+
} else if (tc.grepToolCall) {
|
|
892
|
+
currentTool = "Grep"; toolUses.push("Grep");
|
|
893
|
+
currentToolDetail = (tc.grepToolCall.args?.pattern || "").slice(0, 40);
|
|
894
|
+
} else if (tc.globToolCall) {
|
|
895
|
+
currentTool = "Glob"; toolUses.push("Glob");
|
|
896
|
+
currentToolDetail = (tc.globToolCall.args?.globPattern || "").slice(0, 40);
|
|
897
|
+
} else if (tc.createPlanToolCall) {
|
|
898
|
+
currentTool = "Plan"; toolUses.push("Plan");
|
|
899
|
+
const plan = tc.createPlanToolCall.args || {};
|
|
900
|
+
let planText = "";
|
|
901
|
+
if (plan.name) planText += `**${plan.name}**\n\n`;
|
|
902
|
+
if (plan.plan) planText += plan.plan + "\n";
|
|
903
|
+
if (plan.todos && plan.todos.length) {
|
|
904
|
+
planText += "\n**Tasks:**\n";
|
|
905
|
+
for (const todo of plan.todos) {
|
|
906
|
+
planText += `• ${todo.content || todo.id}\n`;
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
if (planText) assistantText = planText;
|
|
910
|
+
currentToolDetail = plan.name || "creating plan";
|
|
911
|
+
} else {
|
|
912
|
+
const toolKey = Object.keys(tc)[0] || "unknown";
|
|
913
|
+
currentTool = toolKey.replace("ToolCall", ""); toolUses.push(currentTool);
|
|
914
|
+
currentToolDetail = "";
|
|
915
|
+
}
|
|
916
|
+
}
|
|
872
917
|
if (evt.type === "result" && evt.session_id) {
|
|
873
918
|
if (settings.backend === "cursor") { cursorSessionId = evt.session_id; }
|
|
874
919
|
else { lastSessionId = evt.session_id; }
|
|
@@ -1169,23 +1214,47 @@ bot.onText(/\/model (.+)/, (msg, match) => { if (!isAuthorized(msg)) return; set
|
|
|
1169
1214
|
|
|
1170
1215
|
bot.onText(/\/effort$/, (msg) => {
|
|
1171
1216
|
if (!isAuthorized(msg)) return;
|
|
1217
|
+
if (settings.backend === "cursor") return send("Effort levels are not supported on Cursor Agent.\nSwitch to Claude with /claude to use this.");
|
|
1172
1218
|
send(`Effort: ${settings.effort || "default"}`, { keyboard: { inline_keyboard: [
|
|
1173
1219
|
[{ text: "Low", callback_data: "e:low" }, { text: "Med", callback_data: "e:medium" }, { text: "High", callback_data: "e:high" }, { text: "Max", callback_data: "e:max" }],
|
|
1174
1220
|
[{ text: "Default", callback_data: "e:default" }],
|
|
1175
1221
|
] } });
|
|
1176
1222
|
});
|
|
1177
|
-
bot.onText(/\/effort (.+)/, (msg, match) => {
|
|
1223
|
+
bot.onText(/\/effort (.+)/, (msg, match) => {
|
|
1224
|
+
if (!isAuthorized(msg)) return;
|
|
1225
|
+
if (settings.backend === "cursor") return send("Effort levels are not supported on Cursor Agent.");
|
|
1226
|
+
const e = match[1].trim().toLowerCase(); settings.effort = ["low","medium","high","max"].includes(e) ? e : null; send(`Effort: ${settings.effort || "default"}`);
|
|
1227
|
+
});
|
|
1178
1228
|
|
|
1179
1229
|
bot.onText(/\/budget$/, (msg) => {
|
|
1180
1230
|
if (!isAuthorized(msg)) return;
|
|
1231
|
+
if (settings.backend === "cursor") return send("Budget limits are not supported on Cursor Agent.\nSwitch to Claude with /claude to use this.");
|
|
1181
1232
|
send(`Budget: ${settings.budget ? "$" + settings.budget : "none"}`, { keyboard: { inline_keyboard: [
|
|
1182
1233
|
[{ text: "$1", callback_data: "b:1" }, { text: "$5", callback_data: "b:5" }, { text: "$10", callback_data: "b:10" }, { text: "$25", callback_data: "b:25" }],
|
|
1183
1234
|
[{ text: "No limit", callback_data: "b:none" }],
|
|
1184
1235
|
] } });
|
|
1185
1236
|
});
|
|
1186
|
-
bot.onText(/\/budget (.+)/, (msg, match) => {
|
|
1237
|
+
bot.onText(/\/budget (.+)/, (msg, match) => {
|
|
1238
|
+
if (!isAuthorized(msg)) return;
|
|
1239
|
+
if (settings.backend === "cursor") return send("Budget limits are not supported on Cursor Agent.");
|
|
1240
|
+
const v = parseFloat(match[1].replace("$","")); settings.budget = v > 0 ? v : null; send(`Budget: ${settings.budget ? "$"+settings.budget : "none"}`);
|
|
1241
|
+
});
|
|
1187
1242
|
|
|
1188
|
-
bot.onText(/\/plan$/, (msg) => {
|
|
1243
|
+
bot.onText(/\/plan$/, (msg) => {
|
|
1244
|
+
if (!isAuthorized(msg)) return;
|
|
1245
|
+
const p = settings.permissionMode === "plan";
|
|
1246
|
+
settings.permissionMode = p ? null : "plan";
|
|
1247
|
+
const label = settings.backend === "cursor" ? "read-only planning, no edits" : "plan permission mode";
|
|
1248
|
+
if (p) cursorSessionId = null; // reset session so next message doesn't resume plan-mode session
|
|
1249
|
+
send(p ? "Plan mode off (session reset)." : `Plan mode on (${label}).`);
|
|
1250
|
+
});
|
|
1251
|
+
bot.onText(/\/ask$/, (msg) => {
|
|
1252
|
+
if (!isAuthorized(msg)) return;
|
|
1253
|
+
if (settings.backend !== "cursor") return send("Ask mode is only available on Cursor Agent.\nUse /cursor to switch.");
|
|
1254
|
+
const a = settings.permissionMode === "ask";
|
|
1255
|
+
settings.permissionMode = a ? null : "ask";
|
|
1256
|
+
send(a ? "Ask mode off." : "Ask mode on (read-only Q&A, no edits).");
|
|
1257
|
+
});
|
|
1189
1258
|
bot.onText(/\/compact/, async (msg) => { if (!isAuthorized(msg)) return; if (!requireSession(msg)) return; if (!getActiveSessionId()) return send("No conversation."); await runClaude("Summarize: key decisions, code state, next steps.", currentSession.dir, msg.message_id); });
|
|
1190
1259
|
bot.onText(/\/continue$/, async (msg) => { if (!isAuthorized(msg)) return; if (!requireSession(msg)) return; await runClaude("continue where we left off", currentSession.dir, msg.message_id, { continueSession: true }); });
|
|
1191
1260
|
bot.onText(/\/worktree$/, (msg) => { if (!isAuthorized(msg)) return; settings.worktree = !settings.worktree; send(settings.worktree ? "Worktree on." : "Worktree off."); });
|