@locusai/locus-telegram 0.21.13 → 0.21.15

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.
Files changed (2) hide show
  1. package/bin/locus-telegram.js +390 -326
  2. package/package.json +7 -2
@@ -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 set 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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
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 execSync(`git ${args}`, {
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 = execSync(`gh pr create --title ${JSON.stringify(title)} --body "Created via Locus Telegram Bot" --head ${branch}`, {
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,106 +9496,35 @@ function getPostCommandKeyboard(command, args, exitCode) {
9350
9496
  return null;
9351
9497
  }
9352
9498
  }
9353
-
9354
- // src/pm2.ts
9355
- import { execSync as execSync2 } from "node:child_process";
9356
- import { existsSync as existsSync2 } from "node:fs";
9357
- import { dirname, join as join2 } from "node:path";
9358
- import { fileURLToPath } from "node:url";
9359
- var PROCESS_NAME = "locus-telegram";
9360
- function getPm2Bin() {
9361
- try {
9362
- const currentFile = fileURLToPath(import.meta.url);
9363
- const packageRoot = dirname(dirname(currentFile));
9364
- const localPm2 = join2(packageRoot, "..", "..", ".bin", "pm2");
9365
- if (existsSync2(localPm2))
9366
- return localPm2;
9367
- } catch {}
9368
- try {
9369
- const result = execSync2("which pm2", {
9370
- encoding: "utf-8",
9371
- stdio: ["pipe", "pipe", "pipe"]
9372
- }).trim();
9373
- if (result)
9374
- return result;
9375
- } catch {}
9376
- return "npx pm2";
9377
- }
9378
- function pm2Exec(args) {
9379
- const pm2 = getPm2Bin();
9380
- try {
9381
- return execSync2(`${pm2} ${args}`, {
9382
- encoding: "utf-8",
9383
- stdio: ["pipe", "pipe", "pipe"],
9384
- env: process.env
9385
- });
9386
- } catch (error) {
9387
- const err = error;
9388
- throw new Error(err.stderr?.trim() || err.message || "PM2 command failed");
9389
- }
9390
- }
9391
- function getBotScriptPath() {
9392
- const currentFile = fileURLToPath(import.meta.url);
9393
- const packageRoot = dirname(dirname(currentFile));
9394
- return join2(packageRoot, "bin", "locus-telegram.js");
9395
- }
9396
- function pm2Start() {
9397
- const script = getBotScriptPath();
9398
- const pm2 = getPm2Bin();
9399
- try {
9400
- const list = pm2Exec("jlist");
9401
- const processes = JSON.parse(list);
9402
- const existing = processes.find((p) => p.name === PROCESS_NAME);
9403
- if (existing) {
9404
- pm2Exec(`restart ${PROCESS_NAME}`);
9405
- return `Restarted ${PROCESS_NAME}`;
9406
- }
9407
- } catch {}
9408
- execSync2(`${pm2} start ${JSON.stringify(script)} --name ${PROCESS_NAME} -- bot`, {
9409
- encoding: "utf-8",
9410
- stdio: "inherit",
9411
- env: process.env
9412
- });
9413
- return `Started ${PROCESS_NAME}`;
9414
- }
9415
- function pm2Stop() {
9416
- pm2Exec(`stop ${PROCESS_NAME}`);
9417
- return `Stopped ${PROCESS_NAME}`;
9418
- }
9419
- function pm2Restart() {
9420
- pm2Exec(`restart ${PROCESS_NAME}`);
9421
- return `Restarted ${PROCESS_NAME}`;
9422
- }
9423
- function pm2Delete() {
9424
- pm2Exec(`delete ${PROCESS_NAME}`);
9425
- return `Deleted ${PROCESS_NAME}`;
9426
- }
9427
- function pm2Status() {
9428
- try {
9429
- const list = pm2Exec("jlist");
9430
- const processes = JSON.parse(list);
9431
- const proc = processes.find((p) => p.name === PROCESS_NAME);
9432
- if (!proc)
9433
- return null;
9434
- return {
9435
- name: PROCESS_NAME,
9436
- status: proc.pm2_env?.status ?? "unknown",
9437
- pid: proc.pid ?? null,
9438
- uptime: proc.pm2_env?.pm_uptime ?? null,
9439
- memory: proc.monit?.memory ?? null,
9440
- restarts: proc.pm2_env?.restart_time ?? 0
9441
- };
9442
- } catch {
9443
- return null;
9444
- }
9445
- }
9446
- function pm2Logs(lines = 50) {
9447
- try {
9448
- return pm2Exec(`logs ${PROCESS_NAME} --nostream --lines ${lines}`);
9449
- } catch {
9450
- return "No logs available.";
9451
- }
9452
- }
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
+ });
9453
9528
 
9454
9529
  // src/commands/service.ts
9455
9530
  async function handleService(ctx, args) {
@@ -9503,9 +9578,16 @@ async function handleService(ctx, args) {
9503
9578
  });
9504
9579
  }
9505
9580
  }
9581
+ var init_service = __esm(() => {
9582
+ init_pm2();
9583
+ init_messages();
9584
+ });
9506
9585
 
9507
9586
  // src/bot.ts
9508
- var logger = createLogger("telegram");
9587
+ var exports_bot = {};
9588
+ __export(exports_bot, {
9589
+ createBot: () => createBot
9590
+ });
9509
9591
  function createBot(config) {
9510
9592
  const bot = new import_grammy2.Bot(config.botToken);
9511
9593
  bot.use(async (ctx, next) => {
@@ -9676,58 +9758,23 @@ function parseArgs(text, command) {
9676
9758
  return [];
9677
9759
  return rest.split(/\s+/);
9678
9760
  }
9679
-
9680
- // src/config.ts
9681
- function loadTelegramConfig() {
9682
- const locusConfig = readLocusConfig();
9683
- const pkg = locusConfig.packages?.telegram;
9684
- const botToken = pkg?.botToken;
9685
- if (!botToken || typeof botToken !== "string") {
9686
- throw new Error(`Telegram bot token not configured. Run:
9687
- locus config packages.telegram.botToken "<your-token>"
9688
-
9689
- Get a token from @BotFather on Telegram.`);
9690
- }
9691
- const chatIdsRaw = pkg?.chatIds;
9692
- if (!chatIdsRaw) {
9693
- throw new Error(`Telegram chat IDs not configured. Run:
9694
- locus config packages.telegram.chatIds "12345678"
9695
-
9696
- Send /start to your bot, then use the chat ID from the Telegram API.`);
9697
- }
9698
- const allowedChatIds = parseChatIds(chatIdsRaw);
9699
- if (allowedChatIds.length === 0) {
9700
- throw new Error("packages.telegram.chatIds must contain at least one chat ID.");
9701
- }
9702
- return { botToken, allowedChatIds };
9703
- }
9704
- function parseChatIds(raw) {
9705
- if (Array.isArray(raw)) {
9706
- return raw.map((id) => {
9707
- const parsed = Number(id);
9708
- if (Number.isNaN(parsed)) {
9709
- throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
9710
- }
9711
- return parsed;
9712
- });
9713
- }
9714
- if (typeof raw === "string") {
9715
- return raw.split(",").map((id) => id.trim()).filter((id) => id.length > 0).map((id) => {
9716
- const parsed = Number.parseInt(id, 10);
9717
- if (Number.isNaN(parsed)) {
9718
- throw new Error(`Invalid chat ID: "${id}". Must be a number.`);
9719
- }
9720
- return parsed;
9721
- });
9722
- }
9723
- if (typeof raw === "number") {
9724
- return [raw];
9725
- }
9726
- throw new Error("Invalid chatIds format. Expected a number, array of numbers, or comma-separated string.");
9727
- }
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
+ });
9728
9772
 
9729
9773
  // src/index.ts
9730
- var logger2 = createLogger("telegram");
9774
+ var exports_src = {};
9775
+ __export(exports_src, {
9776
+ main: () => main
9777
+ });
9731
9778
  async function main(args) {
9732
9779
  const command = args[0] ?? "help";
9733
9780
  switch (command) {
@@ -9795,7 +9842,8 @@ function handleLogs(args) {
9795
9842
  }
9796
9843
  async function handleBot() {
9797
9844
  const config = loadTelegramConfig();
9798
- const bot = createBot(config);
9845
+ const { createBot: createBot2 } = await Promise.resolve().then(() => (init_bot(), exports_bot));
9846
+ const bot = createBot2(config);
9799
9847
  logger2.info("Starting Telegram bot...");
9800
9848
  logger2.info(`Allowed chat IDs: ${config.allowedChatIds.join(", ")}`);
9801
9849
  const shutdown = () => {
@@ -9833,17 +9881,33 @@ function printHelp() {
9833
9881
  packages.telegram.chatIds Comma-separated chat IDs or JSON array
9834
9882
 
9835
9883
  Setup:
9836
- locus config packages.telegram.botToken "123456:ABC-DEF..."
9837
- locus config packages.telegram.chatIds "12345678"
9884
+ locus config set packages.telegram.botToken "123456:ABC-DEF..."
9885
+ locus config set packages.telegram.chatIds "12345678"
9838
9886
 
9839
9887
  Examples:
9840
9888
  locus pkg telegram start # Start in background
9841
9889
  locus pkg telegram bot # Run in foreground (development)
9842
9890
  `);
9843
9891
  }
9892
+ var logger2;
9893
+ var init_src = __esm(() => {
9894
+ init_dist();
9895
+ init_config();
9896
+ init_pm2();
9897
+ logger2 = createLogger("telegram");
9898
+ });
9844
9899
 
9845
9900
  // src/cli.ts
9846
- main(process.argv.slice(2)).catch((error) => {
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) => {
9847
9911
  console.error(`Fatal error: ${error.message}`);
9848
9912
  process.exit(1);
9849
9913
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/locus-telegram",
3
- "version": "0.21.13",
3
+ "version": "0.21.15",
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.13",
29
+ "@locusai/sdk": "^0.21.15",
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
  },