@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.
Files changed (2) hide show
  1. package/bin/locus-telegram.js +388 -316
  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 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,98 +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 { dirname, join as join2 } from "node:path";
9357
- import { fileURLToPath } from "node:url";
9358
- var PROCESS_NAME = "locus-telegram";
9359
- function getPm2Bin() {
9360
- try {
9361
- const result = execSync2("which pm2", {
9362
- encoding: "utf-8",
9363
- stdio: ["pipe", "pipe", "pipe"]
9364
- }).trim();
9365
- if (result)
9366
- return result;
9367
- } catch {}
9368
- return "npx pm2";
9369
- }
9370
- function pm2Exec(args) {
9371
- const pm2 = getPm2Bin();
9372
- try {
9373
- return execSync2(`${pm2} ${args}`, {
9374
- encoding: "utf-8",
9375
- stdio: ["pipe", "pipe", "pipe"],
9376
- env: process.env
9377
- });
9378
- } catch (error) {
9379
- const err = error;
9380
- throw new Error(err.stderr?.trim() || err.message || "PM2 command failed");
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 logger = createLogger("telegram");
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
- // src/config.ts
9673
- function loadTelegramConfig() {
9674
- const locusConfig = readLocusConfig();
9675
- const pkg = locusConfig.packages?.telegram;
9676
- const botToken = pkg?.botToken;
9677
- if (!botToken || typeof botToken !== "string") {
9678
- throw new Error(`Telegram bot token not configured. Run:
9679
- locus config packages.telegram.botToken "<your-token>"
9680
-
9681
- Get a token from @BotFather on Telegram.`);
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 logger2 = createLogger("telegram");
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 bot = createBot(config);
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
- 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) => {
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.12",
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.12",
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
  },