@locusai/locus-telegram 0.23.0 → 0.23.2

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.
@@ -10250,8 +10250,14 @@ var init_cancel = __esm(() => {
10250
10250
  });
10251
10251
 
10252
10252
  // src/ui/keyboards.ts
10253
- function planKeyboard() {
10254
- return new import_grammy2.InlineKeyboard().text("✅ Approve Plan", CB.APPROVE_PLAN).text("❌ Reject Plan", CB.REJECT_PLAN).row().text("\uD83D\uDCCB Show Details", CB.SHOW_PLAN_DETAILS);
10253
+ function planKeyboard(planId) {
10254
+ return new import_grammy2.InlineKeyboard().text("✅ Approve Plan", `${CB.APPROVE_PLAN}${planId}`).text("❌ Reject Plan", CB.REJECT_PLAN);
10255
+ }
10256
+ function sprintActiveKeyboard(sprintName) {
10257
+ return new import_grammy2.InlineKeyboard().text("\uD83D\uDE80 Activate Sprint", `${CB.SPRINT_ACTIVE}${sprintName}`);
10258
+ }
10259
+ function runKeyboard() {
10260
+ return new import_grammy2.InlineKeyboard().text("\uD83D\uDE80 Run", CB.RUN_START);
10255
10261
  }
10256
10262
  function runCompleteKeyboard(issueNumber) {
10257
10263
  const kb = new import_grammy2.InlineKeyboard;
@@ -10274,9 +10280,10 @@ var import_grammy2, CB;
10274
10280
  var init_keyboards = __esm(() => {
10275
10281
  import_grammy2 = __toESM(require_mod(), 1);
10276
10282
  CB = {
10277
- APPROVE_PLAN: "plan:approve",
10283
+ APPROVE_PLAN: "plan:approve:",
10278
10284
  REJECT_PLAN: "plan:reject",
10279
- SHOW_PLAN_DETAILS: "plan:details",
10285
+ SPRINT_ACTIVE: "sprint:active:",
10286
+ RUN_START: "run:start",
10280
10287
  CONFIRM_ACTION: "confirm:yes",
10281
10288
  CANCEL_ACTION: "confirm:no",
10282
10289
  VIEW_PR: "pr:view:",
@@ -10706,7 +10713,7 @@ async function handleLocusCommand(ctx, command, args) {
10706
10713
  if (isStreaming) {
10707
10714
  await handleStreamingCommand(ctx, displayCmd, fullArgs, command, args);
10708
10715
  } else {
10709
- await handleBufferedCommand(ctx, displayCmd, fullArgs, command);
10716
+ await handleBufferedCommand(ctx, displayCmd, fullArgs, command, args);
10710
10717
  }
10711
10718
  }
10712
10719
  async function handleStreamingCommand(ctx, displayCmd, fullArgs, command, args) {
@@ -10748,7 +10755,7 @@ async function handleStreamingCommand(ctx, displayCmd, fullArgs, command, args)
10748
10755
  try {
10749
10756
  await ctx.api.editMessageText(msg.chat.id, msg.message_id, formatStreamingMessage(displayCmd, output, true), { parse_mode: "HTML" });
10750
10757
  } catch {}
10751
- const keyboard = getPostCommandKeyboard(command, args, exitCode ?? 0);
10758
+ const keyboard = getPostCommandKeyboard(command, args, exitCode ?? 0, output);
10752
10759
  if (keyboard) {
10753
10760
  await ctx.reply(exitCode === 0 ? "What would you like to do next?" : "Command failed.", { reply_markup: keyboard });
10754
10761
  }
@@ -10756,13 +10763,13 @@ async function handleStreamingCommand(ctx, displayCmd, fullArgs, command, args)
10756
10763
  });
10757
10764
  });
10758
10765
  }
10759
- async function handleBufferedCommand(ctx, displayCmd, fullArgs, command) {
10766
+ async function handleBufferedCommand(ctx, displayCmd, fullArgs, command, args) {
10760
10767
  const chatId = ctx.chat?.id;
10761
10768
  if (!chatId)
10762
10769
  return;
10763
10770
  const sessionId = String(chatId);
10764
10771
  const child = invokeLocusStream(fullArgs);
10765
- const trackingId = commandTracker.track(sessionId, command, [], child);
10772
+ const trackingId = commandTracker.track(sessionId, command, args, child);
10766
10773
  let output = "";
10767
10774
  child.stdout?.on("data", (chunk) => {
10768
10775
  output += chunk.toString();
@@ -10774,7 +10781,7 @@ async function handleBufferedCommand(ctx, displayCmd, fullArgs, command) {
10774
10781
  child.on("close", async (exitCode) => {
10775
10782
  commandTracker.untrack(sessionId, trackingId);
10776
10783
  const result = formatCommandResult(displayCmd, output, exitCode ?? 0);
10777
- const keyboard = getPostCommandKeyboard(command, [], exitCode ?? 0);
10784
+ const keyboard = getPostCommandKeyboard(command, args, exitCode ?? 0, output);
10778
10785
  await ctx.reply(result, {
10779
10786
  parse_mode: "HTML",
10780
10787
  reply_markup: keyboard ?? undefined
@@ -10783,12 +10790,43 @@ async function handleBufferedCommand(ctx, displayCmd, fullArgs, command) {
10783
10790
  });
10784
10791
  });
10785
10792
  }
10786
- function getPostCommandKeyboard(command, args, exitCode) {
10793
+ function stripAnsi(text) {
10794
+ return text.replace(/\x1B\[[0-9;]*m/g, "");
10795
+ }
10796
+ function extractPlanId(output) {
10797
+ const clean = stripAnsi(output);
10798
+ const match = clean.match(/Plan saved:\s*(\S+)/);
10799
+ return match?.[1] ?? null;
10800
+ }
10801
+ function extractSprintName(output) {
10802
+ const clean = stripAnsi(output);
10803
+ const match = clean.match(/Sprint:\s*(.+?)$/m);
10804
+ return match?.[1]?.trim() ?? null;
10805
+ }
10806
+ function getPostCommandKeyboard(command, args, exitCode, output = "") {
10787
10807
  if (exitCode !== 0)
10788
10808
  return null;
10789
10809
  switch (command) {
10790
- case "plan":
10791
- return planKeyboard();
10810
+ case "plan": {
10811
+ if (args[0] === "approve") {
10812
+ const sprint = extractSprintName(output);
10813
+ if (sprint)
10814
+ return sprintActiveKeyboard(sprint);
10815
+ return runKeyboard();
10816
+ }
10817
+ if (args[0] !== "list" && args[0] !== "show") {
10818
+ const planId = extractPlanId(output);
10819
+ if (planId)
10820
+ return planKeyboard(planId);
10821
+ }
10822
+ return null;
10823
+ }
10824
+ case "sprint": {
10825
+ if (args[0] === "active" && args.length > 1) {
10826
+ return runKeyboard();
10827
+ }
10828
+ return null;
10829
+ }
10792
10830
  case "review":
10793
10831
  if (args.length > 0) {
10794
10832
  return reviewKeyboard(Number(args[0]));
@@ -10877,6 +10915,8 @@ var exports_bot = {};
10877
10915
  __export(exports_bot, {
10878
10916
  createBot: () => createBot
10879
10917
  });
10918
+ import { exec as execCb3 } from "node:child_process";
10919
+ import { promisify as promisify3 } from "node:util";
10880
10920
  function createBot(config) {
10881
10921
  const bot = new import_grammy3.Bot(config.botToken);
10882
10922
  bot.use(async (ctx, next) => {
@@ -10964,13 +11004,11 @@ function createBot(config) {
10964
11004
  return bot;
10965
11005
  }
10966
11006
  function registerCallbackHandlers(bot) {
10967
- bot.callbackQuery(CB.APPROVE_PLAN, async (ctx) => {
10968
- await ctx.answerCallbackQuery({ text: "Plan approved!" });
11007
+ bot.callbackQuery(/^plan:approve:(.+)$/, async (ctx) => {
11008
+ const planId = ctx.match[1];
11009
+ await ctx.answerCallbackQuery({ text: "Approving plan..." });
10969
11010
  await ctx.editMessageReplyMarkup({ reply_markup: undefined });
10970
- await ctx.reply(formatSuccess("Plan approved. Starting execution..."), {
10971
- parse_mode: "HTML"
10972
- });
10973
- await handleLocusCommand(ctx, "run", []);
11011
+ await handleLocusCommand(ctx, "plan", ["approve", planId]);
10974
11012
  });
10975
11013
  bot.callbackQuery(CB.REJECT_PLAN, async (ctx) => {
10976
11014
  await ctx.answerCallbackQuery({ text: "Plan rejected." });
@@ -10979,9 +11017,16 @@ function registerCallbackHandlers(bot) {
10979
11017
  parse_mode: "HTML"
10980
11018
  });
10981
11019
  });
10982
- bot.callbackQuery(CB.SHOW_PLAN_DETAILS, async (ctx) => {
10983
- await ctx.answerCallbackQuery();
10984
- await handleLocusCommand(ctx, "plan", ["--show"]);
11020
+ bot.callbackQuery(/^sprint:active:(.+)$/, async (ctx) => {
11021
+ const sprintName = ctx.match[1];
11022
+ await ctx.answerCallbackQuery({ text: "Activating sprint..." });
11023
+ await ctx.editMessageReplyMarkup({ reply_markup: undefined });
11024
+ await handleLocusCommand(ctx, "sprint", ["active", sprintName]);
11025
+ });
11026
+ bot.callbackQuery(CB.RUN_START, async (ctx) => {
11027
+ await ctx.answerCallbackQuery({ text: "Starting run..." });
11028
+ await ctx.editMessageReplyMarkup({ reply_markup: undefined });
11029
+ await handleLocusCommand(ctx, "run", []);
10985
11030
  });
10986
11031
  bot.callbackQuery(CB.VIEW_LOGS, async (ctx) => {
10987
11032
  await ctx.answerCallbackQuery();
@@ -10997,9 +11042,16 @@ function registerCallbackHandlers(bot) {
10997
11042
  const pr = ctx.match[1];
10998
11043
  await ctx.answerCallbackQuery({ text: "Approving PR..." });
10999
11044
  await ctx.editMessageReplyMarkup({ reply_markup: undefined });
11000
- await ctx.reply(formatSuccess(`Approved PR #${pr}`), {
11001
- parse_mode: "HTML"
11002
- });
11045
+ try {
11046
+ await exec3(`gh pr review ${pr} --approve`, { cwd: process.cwd() });
11047
+ await ctx.reply(formatSuccess(`Approved PR #${pr}`), {
11048
+ parse_mode: "HTML"
11049
+ });
11050
+ } catch (error) {
11051
+ await ctx.reply(formatError(`Failed to approve PR #${pr}`, String(error)), {
11052
+ parse_mode: "HTML"
11053
+ });
11054
+ }
11003
11055
  });
11004
11056
  bot.callbackQuery(/^review:changes:(\d+)$/, async (ctx) => {
11005
11057
  const pr = ctx.match[1];
@@ -11010,7 +11062,7 @@ function registerCallbackHandlers(bot) {
11010
11062
  bot.callbackQuery(/^review:diff:(\d+)$/, async (ctx) => {
11011
11063
  const pr = ctx.match[1];
11012
11064
  await ctx.answerCallbackQuery();
11013
- await handleLocusCommand(ctx, "review", [pr, "--diff"]);
11065
+ await handleLocusCommand(ctx, "review", [pr]);
11014
11066
  });
11015
11067
  bot.callbackQuery(CB.RUN_SPRINT, async (ctx) => {
11016
11068
  await ctx.answerCallbackQuery({ text: "Starting sprint run..." });
@@ -11056,7 +11108,7 @@ function parseArgs(text, command) {
11056
11108
  return [];
11057
11109
  return rest.split(/\s+/);
11058
11110
  }
11059
- var import_grammy3, logger2;
11111
+ var import_grammy3, exec3, logger2;
11060
11112
  var init_bot = __esm(() => {
11061
11113
  init_dist2();
11062
11114
  init_cancel();
@@ -11066,6 +11118,7 @@ var init_bot = __esm(() => {
11066
11118
  init_keyboards();
11067
11119
  init_messages();
11068
11120
  import_grammy3 = __toESM(require_mod(), 1);
11121
+ exec3 = promisify3(execCb3);
11069
11122
  logger2 = createLogger("telegram");
11070
11123
  });
11071
11124
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/locus-telegram",
3
- "version": "0.23.0",
3
+ "version": "0.23.2",
4
4
  "description": "Remote-control Locus via Telegram with full CLI mapping, git operations, and PM2 management",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,9 +27,9 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@grammyjs/runner": "^2.0.3",
30
- "@locusai/locus-gateway": "^0.23.0",
31
- "@locusai/locus-pm2": "^0.23.0",
32
- "@locusai/sdk": "^0.23.0",
30
+ "@locusai/locus-gateway": "^0.23.2",
31
+ "@locusai/locus-pm2": "^0.23.2",
32
+ "@locusai/sdk": "^0.23.2",
33
33
  "grammy": "^1.35.0"
34
34
  },
35
35
  "devDependencies": {