@locusai/locus-telegram 0.23.1 → 0.23.3

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, sprintName) {
10254
+ return new import_grammy2.InlineKeyboard().text("✅ Approve Plan", `${CB.APPROVE_PLAN}${planId}:${sprintName}`).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,44 @@ 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
+ const sprint = extractSprintName(output);
10820
+ if (planId && sprint)
10821
+ return planKeyboard(planId, sprint);
10822
+ }
10823
+ return null;
10824
+ }
10825
+ case "sprint": {
10826
+ if (args[0] === "active" && args.length > 1) {
10827
+ return runKeyboard();
10828
+ }
10829
+ return null;
10830
+ }
10792
10831
  case "review":
10793
10832
  if (args.length > 0) {
10794
10833
  return reviewKeyboard(Number(args[0]));
@@ -10966,13 +11005,12 @@ function createBot(config) {
10966
11005
  return bot;
10967
11006
  }
10968
11007
  function registerCallbackHandlers(bot) {
10969
- bot.callbackQuery(CB.APPROVE_PLAN, async (ctx) => {
10970
- await ctx.answerCallbackQuery({ text: "Plan approved!" });
11008
+ bot.callbackQuery(/^plan:approve:([^:]+):(.+)$/, async (ctx) => {
11009
+ const planId = ctx.match[1];
11010
+ const sprintName = ctx.match[2];
11011
+ await ctx.answerCallbackQuery({ text: "Approving plan..." });
10971
11012
  await ctx.editMessageReplyMarkup({ reply_markup: undefined });
10972
- await ctx.reply(formatSuccess("Plan approved. Starting execution..."), {
10973
- parse_mode: "HTML"
10974
- });
10975
- await handleLocusCommand(ctx, "run", []);
11013
+ await handleLocusCommand(ctx, "plan", ["approve", planId, sprintName]);
10976
11014
  });
10977
11015
  bot.callbackQuery(CB.REJECT_PLAN, async (ctx) => {
10978
11016
  await ctx.answerCallbackQuery({ text: "Plan rejected." });
@@ -10981,9 +11019,16 @@ function registerCallbackHandlers(bot) {
10981
11019
  parse_mode: "HTML"
10982
11020
  });
10983
11021
  });
10984
- bot.callbackQuery(CB.SHOW_PLAN_DETAILS, async (ctx) => {
10985
- await ctx.answerCallbackQuery();
10986
- await handleLocusCommand(ctx, "plan", ["list"]);
11022
+ bot.callbackQuery(/^sprint:active:(.+)$/, async (ctx) => {
11023
+ const sprintName = ctx.match[1];
11024
+ await ctx.answerCallbackQuery({ text: "Activating sprint..." });
11025
+ await ctx.editMessageReplyMarkup({ reply_markup: undefined });
11026
+ await handleLocusCommand(ctx, "sprint", ["active", sprintName]);
11027
+ });
11028
+ bot.callbackQuery(CB.RUN_START, async (ctx) => {
11029
+ await ctx.answerCallbackQuery({ text: "Starting run..." });
11030
+ await ctx.editMessageReplyMarkup({ reply_markup: undefined });
11031
+ await handleLocusCommand(ctx, "run", []);
10987
11032
  });
10988
11033
  bot.callbackQuery(CB.VIEW_LOGS, async (ctx) => {
10989
11034
  await ctx.answerCallbackQuery();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/locus-telegram",
3
- "version": "0.23.1",
3
+ "version": "0.23.3",
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.1",
31
- "@locusai/locus-pm2": "^0.23.1",
32
- "@locusai/sdk": "^0.23.1",
30
+ "@locusai/locus-gateway": "^0.23.3",
31
+ "@locusai/locus-pm2": "^0.23.3",
32
+ "@locusai/sdk": "^0.23.3",
33
33
  "grammy": "^1.35.0"
34
34
  },
35
35
  "devDependencies": {