@locusai/locus-telegram 0.21.12 → 0.21.14
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/bin/locus-telegram.js +388 -316
- package/package.json +7 -2
package/bin/locus-telegram.js
CHANGED
|
@@ -49,8 +49,294 @@ var __toCommonJS = (from) => {
|
|
|
49
49
|
};
|
|
50
50
|
var __moduleCache;
|
|
51
51
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
52
|
+
var __returnValue = (v) => v;
|
|
53
|
+
function __exportSetter(name, newValue) {
|
|
54
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
55
|
+
}
|
|
56
|
+
var __export = (target, all) => {
|
|
57
|
+
for (var name in all)
|
|
58
|
+
__defProp(target, name, {
|
|
59
|
+
get: all[name],
|
|
60
|
+
enumerable: true,
|
|
61
|
+
configurable: true,
|
|
62
|
+
set: __exportSetter.bind(all, name)
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
52
66
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
53
67
|
|
|
68
|
+
// ../sdk/dist/index.js
|
|
69
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
70
|
+
import { homedir } from "node:os";
|
|
71
|
+
import { join } from "node:path";
|
|
72
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
73
|
+
function readJsonFile(filePath) {
|
|
74
|
+
if (!existsSync(filePath))
|
|
75
|
+
return null;
|
|
76
|
+
try {
|
|
77
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
78
|
+
const parsed = JSON.parse(raw);
|
|
79
|
+
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
80
|
+
return parsed;
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function deepMerge(target, source) {
|
|
88
|
+
const result = { ...target };
|
|
89
|
+
for (const [key, value] of Object.entries(source)) {
|
|
90
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
91
|
+
result[key] = deepMerge(result[key], value);
|
|
92
|
+
} else if (value !== undefined) {
|
|
93
|
+
result[key] = value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
function readLocusConfig(cwd) {
|
|
99
|
+
const workingDir = cwd ?? process.cwd();
|
|
100
|
+
const globalPath = join(homedir(), ".locus", "config.json");
|
|
101
|
+
const projectPath = join(workingDir, ".locus", "config.json");
|
|
102
|
+
const globalRaw = readJsonFile(globalPath) ?? {};
|
|
103
|
+
const projectRaw = readJsonFile(projectPath) ?? {};
|
|
104
|
+
const merged = deepMerge(deepMerge(DEFAULT_CONFIG, globalRaw), projectRaw);
|
|
105
|
+
return merged;
|
|
106
|
+
}
|
|
107
|
+
function invokeLocusStream(args, cwd) {
|
|
108
|
+
return spawn("locus", args, {
|
|
109
|
+
cwd: cwd ?? process.cwd(),
|
|
110
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
111
|
+
env: process.env,
|
|
112
|
+
shell: false
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function formatData(data) {
|
|
116
|
+
if (!data || Object.keys(data).length === 0)
|
|
117
|
+
return "";
|
|
118
|
+
return ` ${dim(JSON.stringify(data))}`;
|
|
119
|
+
}
|
|
120
|
+
function createLogger(name) {
|
|
121
|
+
const prefix = dim(`[${name}]`);
|
|
122
|
+
return {
|
|
123
|
+
info(msg, data) {
|
|
124
|
+
process.stderr.write(`${bold(cyan("●"))} ${prefix} ${msg}${formatData(data)}
|
|
125
|
+
`);
|
|
126
|
+
},
|
|
127
|
+
warn(msg, data) {
|
|
128
|
+
process.stderr.write(`${bold(yellow("⚠"))} ${prefix} ${yellow(msg)}${formatData(data)}
|
|
129
|
+
`);
|
|
130
|
+
},
|
|
131
|
+
error(msg, data) {
|
|
132
|
+
process.stderr.write(`${bold(red("✗"))} ${prefix} ${red(msg)}${formatData(data)}
|
|
133
|
+
`);
|
|
134
|
+
},
|
|
135
|
+
debug(msg, data) {
|
|
136
|
+
if (!process.env.LOCUS_DEBUG)
|
|
137
|
+
return;
|
|
138
|
+
process.stderr.write(`${gray("⋯")} ${prefix} ${gray(msg)}${formatData(data)}
|
|
139
|
+
`);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
var DEFAULT_CONFIG, colorEnabled = () => process.stderr.isTTY === true && process.env.NO_COLOR === undefined, wrap = (open, close) => (text) => colorEnabled() ? `${open}${text}${close}` : text, bold, dim, red, yellow, cyan, gray;
|
|
144
|
+
var init_dist = __esm(() => {
|
|
145
|
+
DEFAULT_CONFIG = {
|
|
146
|
+
version: "0.21.7",
|
|
147
|
+
github: {
|
|
148
|
+
owner: "",
|
|
149
|
+
repo: "",
|
|
150
|
+
defaultBranch: "main"
|
|
151
|
+
},
|
|
152
|
+
ai: {
|
|
153
|
+
provider: "claude",
|
|
154
|
+
model: "claude-sonnet-4-6"
|
|
155
|
+
},
|
|
156
|
+
agent: {
|
|
157
|
+
maxParallel: 3,
|
|
158
|
+
autoLabel: true,
|
|
159
|
+
autoPR: true,
|
|
160
|
+
baseBranch: "main",
|
|
161
|
+
rebaseBeforeTask: true
|
|
162
|
+
},
|
|
163
|
+
sprint: {
|
|
164
|
+
active: null,
|
|
165
|
+
stopOnFailure: true
|
|
166
|
+
},
|
|
167
|
+
logging: {
|
|
168
|
+
level: "normal",
|
|
169
|
+
maxFiles: 20,
|
|
170
|
+
maxTotalSizeMB: 50
|
|
171
|
+
},
|
|
172
|
+
sandbox: {
|
|
173
|
+
enabled: true,
|
|
174
|
+
providers: {},
|
|
175
|
+
extraWorkspaces: [],
|
|
176
|
+
readOnlyPaths: []
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
bold = wrap("\x1B[1m", "\x1B[22m");
|
|
180
|
+
dim = wrap("\x1B[2m", "\x1B[22m");
|
|
181
|
+
red = wrap("\x1B[31m", "\x1B[39m");
|
|
182
|
+
yellow = wrap("\x1B[33m", "\x1B[39m");
|
|
183
|
+
cyan = wrap("\x1B[36m", "\x1B[39m");
|
|
184
|
+
gray = wrap("\x1B[90m", "\x1B[39m");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// src/config.ts
|
|
188
|
+
function loadTelegramConfig() {
|
|
189
|
+
const locusConfig = readLocusConfig();
|
|
190
|
+
const pkg = locusConfig.packages?.telegram;
|
|
191
|
+
const botToken = pkg?.botToken;
|
|
192
|
+
if (!botToken || typeof botToken !== "string") {
|
|
193
|
+
throw new Error(`Telegram bot token not configured. Run:
|
|
194
|
+
locus config packages.telegram.botToken "<your-token>"
|
|
195
|
+
|
|
196
|
+
Get a token from @BotFather on Telegram.`);
|
|
197
|
+
}
|
|
198
|
+
const chatIdsRaw = pkg?.chatIds;
|
|
199
|
+
if (!chatIdsRaw) {
|
|
200
|
+
throw new Error(`Telegram chat IDs not configured. Run:
|
|
201
|
+
locus config packages.telegram.chatIds "12345678"
|
|
202
|
+
|
|
203
|
+
Send /start to your bot, then use the chat ID from the Telegram API.`);
|
|
204
|
+
}
|
|
205
|
+
const allowedChatIds = parseChatIds(chatIdsRaw);
|
|
206
|
+
if (allowedChatIds.length === 0) {
|
|
207
|
+
throw new Error("packages.telegram.chatIds must contain at least one chat ID.");
|
|
208
|
+
}
|
|
209
|
+
return { botToken, allowedChatIds };
|
|
210
|
+
}
|
|
211
|
+
function parseChatIds(raw) {
|
|
212
|
+
if (Array.isArray(raw)) {
|
|
213
|
+
return raw.map((id) => {
|
|
214
|
+
const parsed = Number(id);
|
|
215
|
+
if (Number.isNaN(parsed)) {
|
|
216
|
+
throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
|
|
217
|
+
}
|
|
218
|
+
return parsed;
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (typeof raw === "string") {
|
|
222
|
+
return raw.split(",").map((id) => id.trim()).filter((id) => id.length > 0).map((id) => {
|
|
223
|
+
const parsed = Number.parseInt(id, 10);
|
|
224
|
+
if (Number.isNaN(parsed)) {
|
|
225
|
+
throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
|
|
226
|
+
}
|
|
227
|
+
return parsed;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
if (typeof raw === "number") {
|
|
231
|
+
return [raw];
|
|
232
|
+
}
|
|
233
|
+
throw new Error("Invalid chatIds format. Expected a number, array of numbers, or comma-separated string.");
|
|
234
|
+
}
|
|
235
|
+
var init_config = __esm(() => {
|
|
236
|
+
init_dist();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// src/pm2.ts
|
|
240
|
+
import { execSync } from "node:child_process";
|
|
241
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
242
|
+
import { dirname, join as join2 } from "node:path";
|
|
243
|
+
import { fileURLToPath } from "node:url";
|
|
244
|
+
function getPm2Bin() {
|
|
245
|
+
try {
|
|
246
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
247
|
+
const packageRoot = dirname(dirname(currentFile));
|
|
248
|
+
const localPm2 = join2(packageRoot, "..", "..", ".bin", "pm2");
|
|
249
|
+
if (existsSync2(localPm2))
|
|
250
|
+
return localPm2;
|
|
251
|
+
} catch {}
|
|
252
|
+
try {
|
|
253
|
+
const result = execSync("which pm2", {
|
|
254
|
+
encoding: "utf-8",
|
|
255
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
256
|
+
}).trim();
|
|
257
|
+
if (result)
|
|
258
|
+
return result;
|
|
259
|
+
} catch {}
|
|
260
|
+
return "npx pm2";
|
|
261
|
+
}
|
|
262
|
+
function pm2Exec(args) {
|
|
263
|
+
const pm2 = getPm2Bin();
|
|
264
|
+
try {
|
|
265
|
+
return execSync(`${pm2} ${args}`, {
|
|
266
|
+
encoding: "utf-8",
|
|
267
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
268
|
+
env: process.env
|
|
269
|
+
});
|
|
270
|
+
} catch (error) {
|
|
271
|
+
const err = error;
|
|
272
|
+
throw new Error(err.stderr?.trim() || err.message || "PM2 command failed");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function getBotScriptPath() {
|
|
276
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
277
|
+
const packageRoot = dirname(dirname(currentFile));
|
|
278
|
+
return join2(packageRoot, "bin", "locus-telegram.js");
|
|
279
|
+
}
|
|
280
|
+
function pm2Start() {
|
|
281
|
+
const script = getBotScriptPath();
|
|
282
|
+
const pm2 = getPm2Bin();
|
|
283
|
+
try {
|
|
284
|
+
const list = pm2Exec("jlist");
|
|
285
|
+
const processes = JSON.parse(list);
|
|
286
|
+
const existing = processes.find((p) => p.name === PROCESS_NAME);
|
|
287
|
+
if (existing) {
|
|
288
|
+
pm2Exec(`restart ${PROCESS_NAME}`);
|
|
289
|
+
return `Restarted ${PROCESS_NAME}`;
|
|
290
|
+
}
|
|
291
|
+
} catch {}
|
|
292
|
+
execSync(`${pm2} start ${JSON.stringify(script)} --name ${PROCESS_NAME} -- bot`, {
|
|
293
|
+
encoding: "utf-8",
|
|
294
|
+
stdio: "inherit",
|
|
295
|
+
env: process.env
|
|
296
|
+
});
|
|
297
|
+
return `Started ${PROCESS_NAME}`;
|
|
298
|
+
}
|
|
299
|
+
function pm2Stop() {
|
|
300
|
+
pm2Exec(`stop ${PROCESS_NAME}`);
|
|
301
|
+
return `Stopped ${PROCESS_NAME}`;
|
|
302
|
+
}
|
|
303
|
+
function pm2Restart() {
|
|
304
|
+
pm2Exec(`restart ${PROCESS_NAME}`);
|
|
305
|
+
return `Restarted ${PROCESS_NAME}`;
|
|
306
|
+
}
|
|
307
|
+
function pm2Delete() {
|
|
308
|
+
pm2Exec(`delete ${PROCESS_NAME}`);
|
|
309
|
+
return `Deleted ${PROCESS_NAME}`;
|
|
310
|
+
}
|
|
311
|
+
function pm2Status() {
|
|
312
|
+
try {
|
|
313
|
+
const list = pm2Exec("jlist");
|
|
314
|
+
const processes = JSON.parse(list);
|
|
315
|
+
const proc = processes.find((p) => p.name === PROCESS_NAME);
|
|
316
|
+
if (!proc)
|
|
317
|
+
return null;
|
|
318
|
+
return {
|
|
319
|
+
name: PROCESS_NAME,
|
|
320
|
+
status: proc.pm2_env?.status ?? "unknown",
|
|
321
|
+
pid: proc.pid ?? null,
|
|
322
|
+
uptime: proc.pm2_env?.pm_uptime ?? null,
|
|
323
|
+
memory: proc.monit?.memory ?? null,
|
|
324
|
+
restarts: proc.pm2_env?.restart_time ?? 0
|
|
325
|
+
};
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function pm2Logs(lines = 50) {
|
|
331
|
+
try {
|
|
332
|
+
return pm2Exec(`logs ${PROCESS_NAME} --nostream --lines ${lines}`);
|
|
333
|
+
} catch {
|
|
334
|
+
return "No logs available.";
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
var PROCESS_NAME = "locus-telegram";
|
|
338
|
+
var init_pm2 = () => {};
|
|
339
|
+
|
|
54
340
|
// ../../node_modules/.bun/grammy@1.41.1/node_modules/grammy/out/filter.js
|
|
55
341
|
var require_filter = __commonJS((exports) => {
|
|
56
342
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -8642,133 +8928,7 @@ var require_mod = __commonJS((exports) => {
|
|
|
8642
8928
|
} });
|
|
8643
8929
|
});
|
|
8644
8930
|
|
|
8645
|
-
// ../sdk/dist/index.js
|
|
8646
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
8647
|
-
import { homedir } from "node:os";
|
|
8648
|
-
import { join } from "node:path";
|
|
8649
|
-
import { spawn, spawnSync } from "node:child_process";
|
|
8650
|
-
var DEFAULT_CONFIG = {
|
|
8651
|
-
version: "0.21.7",
|
|
8652
|
-
github: {
|
|
8653
|
-
owner: "",
|
|
8654
|
-
repo: "",
|
|
8655
|
-
defaultBranch: "main"
|
|
8656
|
-
},
|
|
8657
|
-
ai: {
|
|
8658
|
-
provider: "claude",
|
|
8659
|
-
model: "claude-sonnet-4-6"
|
|
8660
|
-
},
|
|
8661
|
-
agent: {
|
|
8662
|
-
maxParallel: 3,
|
|
8663
|
-
autoLabel: true,
|
|
8664
|
-
autoPR: true,
|
|
8665
|
-
baseBranch: "main",
|
|
8666
|
-
rebaseBeforeTask: true
|
|
8667
|
-
},
|
|
8668
|
-
sprint: {
|
|
8669
|
-
active: null,
|
|
8670
|
-
stopOnFailure: true
|
|
8671
|
-
},
|
|
8672
|
-
logging: {
|
|
8673
|
-
level: "normal",
|
|
8674
|
-
maxFiles: 20,
|
|
8675
|
-
maxTotalSizeMB: 50
|
|
8676
|
-
},
|
|
8677
|
-
sandbox: {
|
|
8678
|
-
enabled: true,
|
|
8679
|
-
providers: {},
|
|
8680
|
-
extraWorkspaces: [],
|
|
8681
|
-
readOnlyPaths: []
|
|
8682
|
-
}
|
|
8683
|
-
};
|
|
8684
|
-
function readJsonFile(filePath) {
|
|
8685
|
-
if (!existsSync(filePath))
|
|
8686
|
-
return null;
|
|
8687
|
-
try {
|
|
8688
|
-
const raw = readFileSync(filePath, "utf-8");
|
|
8689
|
-
const parsed = JSON.parse(raw);
|
|
8690
|
-
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
8691
|
-
return parsed;
|
|
8692
|
-
}
|
|
8693
|
-
return null;
|
|
8694
|
-
} catch {
|
|
8695
|
-
return null;
|
|
8696
|
-
}
|
|
8697
|
-
}
|
|
8698
|
-
function deepMerge(target, source) {
|
|
8699
|
-
const result = { ...target };
|
|
8700
|
-
for (const [key, value] of Object.entries(source)) {
|
|
8701
|
-
if (typeof value === "object" && value !== null && !Array.isArray(value) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
|
|
8702
|
-
result[key] = deepMerge(result[key], value);
|
|
8703
|
-
} else if (value !== undefined) {
|
|
8704
|
-
result[key] = value;
|
|
8705
|
-
}
|
|
8706
|
-
}
|
|
8707
|
-
return result;
|
|
8708
|
-
}
|
|
8709
|
-
function readLocusConfig(cwd) {
|
|
8710
|
-
const workingDir = cwd ?? process.cwd();
|
|
8711
|
-
const globalPath = join(homedir(), ".locus", "config.json");
|
|
8712
|
-
const projectPath = join(workingDir, ".locus", "config.json");
|
|
8713
|
-
const globalRaw = readJsonFile(globalPath) ?? {};
|
|
8714
|
-
const projectRaw = readJsonFile(projectPath) ?? {};
|
|
8715
|
-
const merged = deepMerge(deepMerge(DEFAULT_CONFIG, globalRaw), projectRaw);
|
|
8716
|
-
return merged;
|
|
8717
|
-
}
|
|
8718
|
-
function invokeLocusStream(args, cwd) {
|
|
8719
|
-
return spawn("locus", args, {
|
|
8720
|
-
cwd: cwd ?? process.cwd(),
|
|
8721
|
-
stdio: ["inherit", "pipe", "pipe"],
|
|
8722
|
-
env: process.env,
|
|
8723
|
-
shell: false
|
|
8724
|
-
});
|
|
8725
|
-
}
|
|
8726
|
-
var colorEnabled = () => process.stderr.isTTY === true && process.env.NO_COLOR === undefined;
|
|
8727
|
-
var wrap = (open, close) => (text) => colorEnabled() ? `${open}${text}${close}` : text;
|
|
8728
|
-
var bold = wrap("\x1B[1m", "\x1B[22m");
|
|
8729
|
-
var dim = wrap("\x1B[2m", "\x1B[22m");
|
|
8730
|
-
var red = wrap("\x1B[31m", "\x1B[39m");
|
|
8731
|
-
var yellow = wrap("\x1B[33m", "\x1B[39m");
|
|
8732
|
-
var cyan = wrap("\x1B[36m", "\x1B[39m");
|
|
8733
|
-
var gray = wrap("\x1B[90m", "\x1B[39m");
|
|
8734
|
-
function formatData(data) {
|
|
8735
|
-
if (!data || Object.keys(data).length === 0)
|
|
8736
|
-
return "";
|
|
8737
|
-
return ` ${dim(JSON.stringify(data))}`;
|
|
8738
|
-
}
|
|
8739
|
-
function createLogger(name) {
|
|
8740
|
-
const prefix = dim(`[${name}]`);
|
|
8741
|
-
return {
|
|
8742
|
-
info(msg, data) {
|
|
8743
|
-
process.stderr.write(`${bold(cyan("●"))} ${prefix} ${msg}${formatData(data)}
|
|
8744
|
-
`);
|
|
8745
|
-
},
|
|
8746
|
-
warn(msg, data) {
|
|
8747
|
-
process.stderr.write(`${bold(yellow("⚠"))} ${prefix} ${yellow(msg)}${formatData(data)}
|
|
8748
|
-
`);
|
|
8749
|
-
},
|
|
8750
|
-
error(msg, data) {
|
|
8751
|
-
process.stderr.write(`${bold(red("✗"))} ${prefix} ${red(msg)}${formatData(data)}
|
|
8752
|
-
`);
|
|
8753
|
-
},
|
|
8754
|
-
debug(msg, data) {
|
|
8755
|
-
if (!process.env.LOCUS_DEBUG)
|
|
8756
|
-
return;
|
|
8757
|
-
process.stderr.write(`${gray("⋯")} ${prefix} ${gray(msg)}${formatData(data)}
|
|
8758
|
-
`);
|
|
8759
|
-
}
|
|
8760
|
-
};
|
|
8761
|
-
}
|
|
8762
|
-
|
|
8763
|
-
// src/bot.ts
|
|
8764
|
-
var import_grammy2 = __toESM(require_mod(), 1);
|
|
8765
|
-
|
|
8766
|
-
// src/commands/git.ts
|
|
8767
|
-
import { execSync } from "node:child_process";
|
|
8768
|
-
|
|
8769
8931
|
// src/ui/format.ts
|
|
8770
|
-
var MAX_MESSAGE_LENGTH = 4096;
|
|
8771
|
-
var MAX_CODE_LENGTH = 3800;
|
|
8772
8932
|
function escapeHtml(text) {
|
|
8773
8933
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8774
8934
|
}
|
|
@@ -8836,27 +8996,9 @@ function formatSuccess(message) {
|
|
|
8836
8996
|
function formatInfo(message) {
|
|
8837
8997
|
return `ℹ️ ${escapeHtml(message)}`;
|
|
8838
8998
|
}
|
|
8999
|
+
var MAX_MESSAGE_LENGTH = 4096, MAX_CODE_LENGTH = 3800;
|
|
8839
9000
|
|
|
8840
9001
|
// src/ui/keyboards.ts
|
|
8841
|
-
var import_grammy = __toESM(require_mod(), 1);
|
|
8842
|
-
var CB = {
|
|
8843
|
-
APPROVE_PLAN: "plan:approve",
|
|
8844
|
-
REJECT_PLAN: "plan:reject",
|
|
8845
|
-
SHOW_PLAN_DETAILS: "plan:details",
|
|
8846
|
-
CONFIRM_ACTION: "confirm:yes",
|
|
8847
|
-
CANCEL_ACTION: "confirm:no",
|
|
8848
|
-
VIEW_PR: "pr:view:",
|
|
8849
|
-
VIEW_LOGS: "logs:view",
|
|
8850
|
-
RUN_AGAIN: "run:again:",
|
|
8851
|
-
APPROVE_REVIEW: "review:approve:",
|
|
8852
|
-
REQUEST_CHANGES: "review:changes:",
|
|
8853
|
-
VIEW_DIFF: "review:diff:",
|
|
8854
|
-
RUN_SPRINT: "sprint:run",
|
|
8855
|
-
VIEW_ISSUES: "issues:view",
|
|
8856
|
-
STASH_POP: "stash:pop",
|
|
8857
|
-
STASH_LIST: "stash:list",
|
|
8858
|
-
STASH_DROP: "stash:drop"
|
|
8859
|
-
};
|
|
8860
9002
|
function planKeyboard() {
|
|
8861
9003
|
return new import_grammy.InlineKeyboard().text("✅ Approve Plan", CB.APPROVE_PLAN).text("❌ Reject Plan", CB.REJECT_PLAN).row().text("\uD83D\uDCCB Show Details", CB.SHOW_PLAN_DETAILS);
|
|
8862
9004
|
}
|
|
@@ -8877,6 +9019,28 @@ function statusKeyboard() {
|
|
|
8877
9019
|
function stashKeyboard() {
|
|
8878
9020
|
return new import_grammy.InlineKeyboard().text("\uD83D\uDCE4 Pop", CB.STASH_POP).text("\uD83D\uDCCB List", CB.STASH_LIST).text("\uD83D\uDDD1 Drop", CB.STASH_DROP);
|
|
8879
9021
|
}
|
|
9022
|
+
var import_grammy, CB;
|
|
9023
|
+
var init_keyboards = __esm(() => {
|
|
9024
|
+
import_grammy = __toESM(require_mod(), 1);
|
|
9025
|
+
CB = {
|
|
9026
|
+
APPROVE_PLAN: "plan:approve",
|
|
9027
|
+
REJECT_PLAN: "plan:reject",
|
|
9028
|
+
SHOW_PLAN_DETAILS: "plan:details",
|
|
9029
|
+
CONFIRM_ACTION: "confirm:yes",
|
|
9030
|
+
CANCEL_ACTION: "confirm:no",
|
|
9031
|
+
VIEW_PR: "pr:view:",
|
|
9032
|
+
VIEW_LOGS: "logs:view",
|
|
9033
|
+
RUN_AGAIN: "run:again:",
|
|
9034
|
+
APPROVE_REVIEW: "review:approve:",
|
|
9035
|
+
REQUEST_CHANGES: "review:changes:",
|
|
9036
|
+
VIEW_DIFF: "review:diff:",
|
|
9037
|
+
RUN_SPRINT: "sprint:run",
|
|
9038
|
+
VIEW_ISSUES: "issues:view",
|
|
9039
|
+
STASH_POP: "stash:pop",
|
|
9040
|
+
STASH_LIST: "stash:list",
|
|
9041
|
+
STASH_DROP: "stash:drop"
|
|
9042
|
+
};
|
|
9043
|
+
});
|
|
8880
9044
|
|
|
8881
9045
|
// src/ui/messages.ts
|
|
8882
9046
|
function welcomeMessage() {
|
|
@@ -8990,10 +9154,12 @@ function formatMemory(bytes) {
|
|
|
8990
9154
|
const mb = bytes / (1024 * 1024);
|
|
8991
9155
|
return `${mb.toFixed(1)} MB`;
|
|
8992
9156
|
}
|
|
9157
|
+
var init_messages = () => {};
|
|
8993
9158
|
|
|
8994
9159
|
// src/commands/git.ts
|
|
9160
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
8995
9161
|
function git(args) {
|
|
8996
|
-
return
|
|
9162
|
+
return execSync2(`git ${args}`, {
|
|
8997
9163
|
encoding: "utf-8",
|
|
8998
9164
|
stdio: ["pipe", "pipe", "pipe"],
|
|
8999
9165
|
cwd: process.cwd()
|
|
@@ -9202,7 +9368,7 @@ async function handlePR(ctx, args) {
|
|
|
9202
9368
|
try {
|
|
9203
9369
|
git(`push -u origin ${branch}`);
|
|
9204
9370
|
} catch {}
|
|
9205
|
-
const result =
|
|
9371
|
+
const result = execSync2(`gh pr create --title ${JSON.stringify(title)} --body "Created via Locus Telegram Bot" --head ${branch}`, {
|
|
9206
9372
|
encoding: "utf-8",
|
|
9207
9373
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9208
9374
|
cwd: process.cwd()
|
|
@@ -9218,32 +9384,12 @@ async function handlePR(ctx, args) {
|
|
|
9218
9384
|
});
|
|
9219
9385
|
}
|
|
9220
9386
|
}
|
|
9387
|
+
var init_git = __esm(() => {
|
|
9388
|
+
init_keyboards();
|
|
9389
|
+
init_messages();
|
|
9390
|
+
});
|
|
9221
9391
|
|
|
9222
9392
|
// src/commands/locus.ts
|
|
9223
|
-
var COMMAND_MAP = {
|
|
9224
|
-
run: ["run"],
|
|
9225
|
-
status: ["status"],
|
|
9226
|
-
issues: ["issue", "list"],
|
|
9227
|
-
issue: ["issue", "show"],
|
|
9228
|
-
sprint: ["sprint"],
|
|
9229
|
-
plan: ["plan"],
|
|
9230
|
-
review: ["review"],
|
|
9231
|
-
iterate: ["iterate"],
|
|
9232
|
-
discuss: ["discuss"],
|
|
9233
|
-
exec: ["exec"],
|
|
9234
|
-
logs: ["logs"],
|
|
9235
|
-
config: ["config"],
|
|
9236
|
-
artifacts: ["artifacts"]
|
|
9237
|
-
};
|
|
9238
|
-
var STREAMING_COMMANDS = new Set([
|
|
9239
|
-
"run",
|
|
9240
|
-
"plan",
|
|
9241
|
-
"review",
|
|
9242
|
-
"iterate",
|
|
9243
|
-
"discuss",
|
|
9244
|
-
"exec"
|
|
9245
|
-
]);
|
|
9246
|
-
var EDIT_INTERVAL = 2000;
|
|
9247
9393
|
async function handleLocusCommand(ctx, command, args) {
|
|
9248
9394
|
const cliArgs = COMMAND_MAP[command];
|
|
9249
9395
|
if (!cliArgs) {
|
|
@@ -9350,98 +9496,35 @@ function getPostCommandKeyboard(command, args, exitCode) {
|
|
|
9350
9496
|
return null;
|
|
9351
9497
|
}
|
|
9352
9498
|
}
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
|
|
9361
|
-
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
}
|
|
9383
|
-
function getBotScriptPath() {
|
|
9384
|
-
const currentFile = fileURLToPath(import.meta.url);
|
|
9385
|
-
const packageRoot = dirname(dirname(currentFile));
|
|
9386
|
-
return join2(packageRoot, "bin", "locus-telegram.js");
|
|
9387
|
-
}
|
|
9388
|
-
function pm2Start() {
|
|
9389
|
-
const script = getBotScriptPath();
|
|
9390
|
-
const pm2 = getPm2Bin();
|
|
9391
|
-
try {
|
|
9392
|
-
const list = pm2Exec("jlist");
|
|
9393
|
-
const processes = JSON.parse(list);
|
|
9394
|
-
const existing = processes.find((p) => p.name === PROCESS_NAME);
|
|
9395
|
-
if (existing) {
|
|
9396
|
-
pm2Exec(`restart ${PROCESS_NAME}`);
|
|
9397
|
-
return `Restarted ${PROCESS_NAME}`;
|
|
9398
|
-
}
|
|
9399
|
-
} catch {}
|
|
9400
|
-
execSync2(`${pm2} start ${JSON.stringify(script)} --name ${PROCESS_NAME} -- bot`, {
|
|
9401
|
-
encoding: "utf-8",
|
|
9402
|
-
stdio: "inherit",
|
|
9403
|
-
env: process.env
|
|
9404
|
-
});
|
|
9405
|
-
return `Started ${PROCESS_NAME}`;
|
|
9406
|
-
}
|
|
9407
|
-
function pm2Stop() {
|
|
9408
|
-
pm2Exec(`stop ${PROCESS_NAME}`);
|
|
9409
|
-
return `Stopped ${PROCESS_NAME}`;
|
|
9410
|
-
}
|
|
9411
|
-
function pm2Restart() {
|
|
9412
|
-
pm2Exec(`restart ${PROCESS_NAME}`);
|
|
9413
|
-
return `Restarted ${PROCESS_NAME}`;
|
|
9414
|
-
}
|
|
9415
|
-
function pm2Delete() {
|
|
9416
|
-
pm2Exec(`delete ${PROCESS_NAME}`);
|
|
9417
|
-
return `Deleted ${PROCESS_NAME}`;
|
|
9418
|
-
}
|
|
9419
|
-
function pm2Status() {
|
|
9420
|
-
try {
|
|
9421
|
-
const list = pm2Exec("jlist");
|
|
9422
|
-
const processes = JSON.parse(list);
|
|
9423
|
-
const proc = processes.find((p) => p.name === PROCESS_NAME);
|
|
9424
|
-
if (!proc)
|
|
9425
|
-
return null;
|
|
9426
|
-
return {
|
|
9427
|
-
name: PROCESS_NAME,
|
|
9428
|
-
status: proc.pm2_env?.status ?? "unknown",
|
|
9429
|
-
pid: proc.pid ?? null,
|
|
9430
|
-
uptime: proc.pm2_env?.pm_uptime ?? null,
|
|
9431
|
-
memory: proc.monit?.memory ?? null,
|
|
9432
|
-
restarts: proc.pm2_env?.restart_time ?? 0
|
|
9433
|
-
};
|
|
9434
|
-
} catch {
|
|
9435
|
-
return null;
|
|
9436
|
-
}
|
|
9437
|
-
}
|
|
9438
|
-
function pm2Logs(lines = 50) {
|
|
9439
|
-
try {
|
|
9440
|
-
return pm2Exec(`logs ${PROCESS_NAME} --nostream --lines ${lines}`);
|
|
9441
|
-
} catch {
|
|
9442
|
-
return "No logs available.";
|
|
9443
|
-
}
|
|
9444
|
-
}
|
|
9499
|
+
var COMMAND_MAP, STREAMING_COMMANDS, EDIT_INTERVAL = 2000;
|
|
9500
|
+
var init_locus = __esm(() => {
|
|
9501
|
+
init_dist();
|
|
9502
|
+
init_keyboards();
|
|
9503
|
+
init_messages();
|
|
9504
|
+
COMMAND_MAP = {
|
|
9505
|
+
run: ["run"],
|
|
9506
|
+
status: ["status"],
|
|
9507
|
+
issues: ["issue", "list"],
|
|
9508
|
+
issue: ["issue", "show"],
|
|
9509
|
+
sprint: ["sprint"],
|
|
9510
|
+
plan: ["plan"],
|
|
9511
|
+
review: ["review"],
|
|
9512
|
+
iterate: ["iterate"],
|
|
9513
|
+
discuss: ["discuss"],
|
|
9514
|
+
exec: ["exec"],
|
|
9515
|
+
logs: ["logs"],
|
|
9516
|
+
config: ["config"],
|
|
9517
|
+
artifacts: ["artifacts"]
|
|
9518
|
+
};
|
|
9519
|
+
STREAMING_COMMANDS = new Set([
|
|
9520
|
+
"run",
|
|
9521
|
+
"plan",
|
|
9522
|
+
"review",
|
|
9523
|
+
"iterate",
|
|
9524
|
+
"discuss",
|
|
9525
|
+
"exec"
|
|
9526
|
+
]);
|
|
9527
|
+
});
|
|
9445
9528
|
|
|
9446
9529
|
// src/commands/service.ts
|
|
9447
9530
|
async function handleService(ctx, args) {
|
|
@@ -9495,9 +9578,16 @@ async function handleService(ctx, args) {
|
|
|
9495
9578
|
});
|
|
9496
9579
|
}
|
|
9497
9580
|
}
|
|
9581
|
+
var init_service = __esm(() => {
|
|
9582
|
+
init_pm2();
|
|
9583
|
+
init_messages();
|
|
9584
|
+
});
|
|
9498
9585
|
|
|
9499
9586
|
// src/bot.ts
|
|
9500
|
-
var
|
|
9587
|
+
var exports_bot = {};
|
|
9588
|
+
__export(exports_bot, {
|
|
9589
|
+
createBot: () => createBot
|
|
9590
|
+
});
|
|
9501
9591
|
function createBot(config) {
|
|
9502
9592
|
const bot = new import_grammy2.Bot(config.botToken);
|
|
9503
9593
|
bot.use(async (ctx, next) => {
|
|
@@ -9668,58 +9758,23 @@ function parseArgs(text, command) {
|
|
|
9668
9758
|
return [];
|
|
9669
9759
|
return rest.split(/\s+/);
|
|
9670
9760
|
}
|
|
9671
|
-
|
|
9672
|
-
|
|
9673
|
-
|
|
9674
|
-
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9681
|
-
|
|
9682
|
-
}
|
|
9683
|
-
const chatIdsRaw = pkg?.chatIds;
|
|
9684
|
-
if (!chatIdsRaw) {
|
|
9685
|
-
throw new Error(`Telegram chat IDs not configured. Run:
|
|
9686
|
-
locus config packages.telegram.chatIds "12345678"
|
|
9687
|
-
|
|
9688
|
-
Send /start to your bot, then use the chat ID from the Telegram API.`);
|
|
9689
|
-
}
|
|
9690
|
-
const allowedChatIds = parseChatIds(chatIdsRaw);
|
|
9691
|
-
if (allowedChatIds.length === 0) {
|
|
9692
|
-
throw new Error("packages.telegram.chatIds must contain at least one chat ID.");
|
|
9693
|
-
}
|
|
9694
|
-
return { botToken, allowedChatIds };
|
|
9695
|
-
}
|
|
9696
|
-
function parseChatIds(raw) {
|
|
9697
|
-
if (Array.isArray(raw)) {
|
|
9698
|
-
return raw.map((id) => {
|
|
9699
|
-
const parsed = Number(id);
|
|
9700
|
-
if (Number.isNaN(parsed)) {
|
|
9701
|
-
throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
|
|
9702
|
-
}
|
|
9703
|
-
return parsed;
|
|
9704
|
-
});
|
|
9705
|
-
}
|
|
9706
|
-
if (typeof raw === "string") {
|
|
9707
|
-
return raw.split(",").map((id) => id.trim()).filter((id) => id.length > 0).map((id) => {
|
|
9708
|
-
const parsed = Number.parseInt(id, 10);
|
|
9709
|
-
if (Number.isNaN(parsed)) {
|
|
9710
|
-
throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
|
|
9711
|
-
}
|
|
9712
|
-
return parsed;
|
|
9713
|
-
});
|
|
9714
|
-
}
|
|
9715
|
-
if (typeof raw === "number") {
|
|
9716
|
-
return [raw];
|
|
9717
|
-
}
|
|
9718
|
-
throw new Error("Invalid chatIds format. Expected a number, array of numbers, or comma-separated string.");
|
|
9719
|
-
}
|
|
9761
|
+
var import_grammy2, logger;
|
|
9762
|
+
var init_bot = __esm(() => {
|
|
9763
|
+
init_dist();
|
|
9764
|
+
init_git();
|
|
9765
|
+
init_locus();
|
|
9766
|
+
init_service();
|
|
9767
|
+
init_keyboards();
|
|
9768
|
+
init_messages();
|
|
9769
|
+
import_grammy2 = __toESM(require_mod(), 1);
|
|
9770
|
+
logger = createLogger("telegram");
|
|
9771
|
+
});
|
|
9720
9772
|
|
|
9721
9773
|
// src/index.ts
|
|
9722
|
-
var
|
|
9774
|
+
var exports_src = {};
|
|
9775
|
+
__export(exports_src, {
|
|
9776
|
+
main: () => main
|
|
9777
|
+
});
|
|
9723
9778
|
async function main(args) {
|
|
9724
9779
|
const command = args[0] ?? "help";
|
|
9725
9780
|
switch (command) {
|
|
@@ -9787,7 +9842,8 @@ function handleLogs(args) {
|
|
|
9787
9842
|
}
|
|
9788
9843
|
async function handleBot() {
|
|
9789
9844
|
const config = loadTelegramConfig();
|
|
9790
|
-
const
|
|
9845
|
+
const { createBot: createBot2 } = await Promise.resolve().then(() => (init_bot(), exports_bot));
|
|
9846
|
+
const bot = createBot2(config);
|
|
9791
9847
|
logger2.info("Starting Telegram bot...");
|
|
9792
9848
|
logger2.info(`Allowed chat IDs: ${config.allowedChatIds.join(", ")}`);
|
|
9793
9849
|
const shutdown = () => {
|
|
@@ -9833,9 +9889,25 @@ function printHelp() {
|
|
|
9833
9889
|
locus pkg telegram bot # Run in foreground (development)
|
|
9834
9890
|
`);
|
|
9835
9891
|
}
|
|
9892
|
+
var logger2;
|
|
9893
|
+
var init_src = __esm(() => {
|
|
9894
|
+
init_dist();
|
|
9895
|
+
init_config();
|
|
9896
|
+
init_pm2();
|
|
9897
|
+
logger2 = createLogger("telegram");
|
|
9898
|
+
});
|
|
9836
9899
|
|
|
9837
9900
|
// src/cli.ts
|
|
9838
|
-
|
|
9901
|
+
var origEmit = process.emit;
|
|
9902
|
+
process.emit = (event, ...args) => {
|
|
9903
|
+
const data = args[0];
|
|
9904
|
+
if (event === "warning" && typeof data === "object" && data !== null && data.name === "DeprecationWarning" && data.code === "DEP0040") {
|
|
9905
|
+
return false;
|
|
9906
|
+
}
|
|
9907
|
+
return origEmit.call(process, event, ...args);
|
|
9908
|
+
};
|
|
9909
|
+
var { main: main2 } = await Promise.resolve().then(() => (init_src(), exports_src));
|
|
9910
|
+
main2(process.argv.slice(2)).catch((error) => {
|
|
9839
9911
|
console.error(`Fatal error: ${error.message}`);
|
|
9840
9912
|
process.exit(1);
|
|
9841
9913
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@locusai/locus-telegram",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.14",
|
|
4
4
|
"description": "Remote-control Locus via Telegram with full CLI mapping, git operations, and PM2 management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,13 +26,18 @@
|
|
|
26
26
|
"format": "biome format --write ."
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@locusai/sdk": "^0.21.
|
|
29
|
+
"@locusai/sdk": "^0.21.14",
|
|
30
30
|
"grammy": "^1.35.0",
|
|
31
31
|
"pm2": "^6.0.5"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "^5.8.3"
|
|
35
35
|
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"locusai-package",
|
|
38
|
+
"locus",
|
|
39
|
+
"telegram"
|
|
40
|
+
],
|
|
36
41
|
"engines": {
|
|
37
42
|
"node": ">=18"
|
|
38
43
|
},
|