@locusai/telegram 0.9.14 → 0.9.16

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/telegram.js +145 -35
  2. package/package.json +2 -2
package/bin/telegram.js CHANGED
@@ -20094,6 +20094,10 @@ var HELP_TEXT = `<b>Locus Bot — Command Center</b>
20094
20094
  /tasks — List active tasks
20095
20095
  /rejecttask &lt;id&gt; &lt;feedback&gt; — Reject an IN_REVIEW task
20096
20096
 
20097
+ <b>Sprints:</b>
20098
+ /sprints — List all sprints
20099
+ /completesprint &lt;id&gt; — Complete a sprint
20100
+
20097
20101
  <b>Execution:</b>
20098
20102
  /run — Start agents on sprint tasks
20099
20103
  /stop — Stop all running processes
@@ -20223,9 +20227,9 @@ async function cancelCommand(ctx, executor) {
20223
20227
  var activeRunKill = null;
20224
20228
  async function runCommand(ctx, executor, config) {
20225
20229
  const text = (ctx.message && "text" in ctx.message ? ctx.message.text : "") || "";
20226
- const input = text.replace(/^\/run\s*/, "").trim();
20230
+ const input = normalizeInput(text.replace(/^\/run\s*/, "").trim());
20227
20231
  let parsedAgentCount;
20228
- const agentsMatch = input.match(/(?:--agents|-a)\s+(\d+)/);
20232
+ const agentsMatch = input.match(/(?:--agents|-agents|-a)\s+(\d+)/);
20229
20233
  if (agentsMatch) {
20230
20234
  parsedAgentCount = Number.parseInt(agentsMatch[1], 10);
20231
20235
  if (parsedAgentCount < 1 || parsedAgentCount > 5) {
@@ -20321,34 +20325,6 @@ async function stopCommand(ctx, executor) {
20321
20325
  });
20322
20326
  }
20323
20327
  }
20324
- // src/commands/status.ts
20325
- async function statusCommand(ctx, executor) {
20326
- console.log("[status] Checking status");
20327
- const running = executor.getRunning();
20328
- let msg = `<b>Locus Bot Status</b>
20329
-
20330
- `;
20331
- if (running.length === 0) {
20332
- msg += `No running processes.
20333
- `;
20334
- } else {
20335
- msg += `<b>Running processes (${running.length}):</b>
20336
- `;
20337
- for (const proc of running) {
20338
- const elapsed = Math.round((Date.now() - proc.startedAt.getTime()) / 1000);
20339
- msg += ` • <code>${escapeHtml(proc.command)}</code> (${elapsed}s)
20340
- `;
20341
- }
20342
- }
20343
- await ctx.reply(msg, { parse_mode: "HTML" });
20344
- }
20345
- async function agentsCommand(ctx, executor) {
20346
- console.log("[agents] Listing agents");
20347
- const args = executor.buildArgs(["agents", "list"]);
20348
- const result = await executor.execute(args);
20349
- const output = (result.stdout + result.stderr).trim();
20350
- await ctx.reply(formatCommandOutput("locus agents list", output, result.exitCode), { parse_mode: "HTML" });
20351
- }
20352
20328
  // ../../node_modules/axios/lib/helpers/bind.js
20353
20329
  function bind(fn, thisArg) {
20354
20330
  return function wrap() {
@@ -38423,7 +38399,7 @@ class LocusClient {
38423
38399
  }
38424
38400
  }
38425
38401
 
38426
- // src/commands/tasks.ts
38402
+ // src/commands/sprints.ts
38427
38403
  function createClient(config2) {
38428
38404
  return new LocusClient({
38429
38405
  baseUrl: config2.apiBase || "https://api.locusai.dev/api",
@@ -38442,6 +38418,138 @@ async function resolveWorkspaceId(client, config2) {
38442
38418
  }
38443
38419
  throw new Error("Could not resolve workspace from API key. Please set workspaceId in settings.");
38444
38420
  }
38421
+ async function sprintsCommand(ctx, config2) {
38422
+ console.log("[sprints] Listing sprints");
38423
+ if (!config2.apiKey) {
38424
+ await ctx.reply(formatError("API key is required for /sprints. Run: locus config setup --api-key <KEY>"), { parse_mode: "HTML" });
38425
+ return;
38426
+ }
38427
+ try {
38428
+ const client = createClient(config2);
38429
+ const workspaceId = await resolveWorkspaceId(client, config2);
38430
+ const sprints2 = await client.sprints.list(workspaceId);
38431
+ if (sprints2.length === 0) {
38432
+ await ctx.reply(formatInfo("No sprints found."), {
38433
+ parse_mode: "HTML"
38434
+ });
38435
+ return;
38436
+ }
38437
+ const statusIcon = {
38438
+ ["ACTIVE" /* ACTIVE */]: "\uD83D\uDFE2",
38439
+ ["PLANNED" /* PLANNED */]: "\uD83D\uDCCB",
38440
+ ["COMPLETED" /* COMPLETED */]: "✅"
38441
+ };
38442
+ const active = sprints2.filter((s) => s.status === "ACTIVE" /* ACTIVE */);
38443
+ const planned = sprints2.filter((s) => s.status === "PLANNED" /* PLANNED */);
38444
+ const completed = sprints2.filter((s) => s.status === "COMPLETED" /* COMPLETED */);
38445
+ let msg = `<b>Sprints</b>
38446
+
38447
+ `;
38448
+ const formatGroup = (label, items, icon) => {
38449
+ if (items.length === 0)
38450
+ return;
38451
+ msg += `<b>${label}</b>
38452
+ `;
38453
+ for (const sprint2 of items) {
38454
+ msg += `${icon} <b>${escapeHtml(sprint2.name)}</b>
38455
+ `;
38456
+ msg += ` Status: <code>${sprint2.status}</code>
38457
+ `;
38458
+ msg += ` ID: <code>${sprint2.id}</code>
38459
+
38460
+ `;
38461
+ }
38462
+ };
38463
+ formatGroup("Active", active, statusIcon["ACTIVE" /* ACTIVE */]);
38464
+ formatGroup("Planned", planned, statusIcon["PLANNED" /* PLANNED */]);
38465
+ formatGroup("Completed", completed, statusIcon["COMPLETED" /* COMPLETED */]);
38466
+ await ctx.reply(msg.trim(), {
38467
+ parse_mode: "HTML"
38468
+ });
38469
+ } catch (err) {
38470
+ console.error("[sprints] Failed:", err);
38471
+ await ctx.reply(formatError(`Failed to fetch sprints: ${err instanceof Error ? err.message : String(err)}`), { parse_mode: "HTML" });
38472
+ }
38473
+ }
38474
+ async function completeSprintCommand(ctx, config2) {
38475
+ const text = (ctx.message && "text" in ctx.message ? ctx.message.text : "") || "";
38476
+ const sprintId = text.replace(/^\/completesprint\s*/, "").trim();
38477
+ console.log(`[completesprint] Received: ${sprintId || "(empty)"}`);
38478
+ if (!sprintId) {
38479
+ await ctx.reply(formatError("Usage: /completesprint &lt;sprint-id&gt;"), {
38480
+ parse_mode: "HTML"
38481
+ });
38482
+ return;
38483
+ }
38484
+ if (!config2.apiKey) {
38485
+ await ctx.reply(formatError("API key is required for /completesprint. Run: locus config setup --api-key <KEY>"), { parse_mode: "HTML" });
38486
+ return;
38487
+ }
38488
+ try {
38489
+ const client = createClient(config2);
38490
+ const workspaceId = await resolveWorkspaceId(client, config2);
38491
+ const sprint2 = await client.sprints.getById(sprintId, workspaceId);
38492
+ if (sprint2.status === "COMPLETED" /* COMPLETED */) {
38493
+ await ctx.reply(formatInfo(`Sprint "${escapeHtml(sprint2.name)}" is already completed.`), { parse_mode: "HTML" });
38494
+ return;
38495
+ }
38496
+ await client.sprints.complete(sprintId, workspaceId);
38497
+ console.log(`[completesprint] Sprint ${sprintId} completed`);
38498
+ await ctx.reply(`✅ Sprint "<b>${escapeHtml(sprint2.name)}</b>" has been completed.
38499
+
38500
+ IN_REVIEW tasks moved to DONE. IN_PROGRESS tasks moved to BACKLOG.`, { parse_mode: "HTML" });
38501
+ } catch (err) {
38502
+ console.error("[completesprint] Failed:", err);
38503
+ await ctx.reply(formatError(`Failed to complete sprint: ${err instanceof Error ? err.message : String(err)}`), { parse_mode: "HTML" });
38504
+ }
38505
+ }
38506
+ // src/commands/status.ts
38507
+ async function statusCommand(ctx, executor) {
38508
+ console.log("[status] Checking status");
38509
+ const running = executor.getRunning();
38510
+ let msg = `<b>Locus Bot Status</b>
38511
+
38512
+ `;
38513
+ if (running.length === 0) {
38514
+ msg += `No running processes.
38515
+ `;
38516
+ } else {
38517
+ msg += `<b>Running processes (${running.length}):</b>
38518
+ `;
38519
+ for (const proc of running) {
38520
+ const elapsed = Math.round((Date.now() - proc.startedAt.getTime()) / 1000);
38521
+ msg += ` • <code>${escapeHtml(proc.command)}</code> (${elapsed}s)
38522
+ `;
38523
+ }
38524
+ }
38525
+ await ctx.reply(msg, { parse_mode: "HTML" });
38526
+ }
38527
+ async function agentsCommand(ctx, executor) {
38528
+ console.log("[agents] Listing agents");
38529
+ const args = executor.buildArgs(["agents", "list"]);
38530
+ const result = await executor.execute(args);
38531
+ const output = (result.stdout + result.stderr).trim();
38532
+ await ctx.reply(formatCommandOutput("locus agents list", output, result.exitCode), { parse_mode: "HTML" });
38533
+ }
38534
+ // src/commands/tasks.ts
38535
+ function createClient2(config2) {
38536
+ return new LocusClient({
38537
+ baseUrl: config2.apiBase || "https://api.locusai.dev/api",
38538
+ token: config2.apiKey
38539
+ });
38540
+ }
38541
+ async function resolveWorkspaceId2(client, config2) {
38542
+ if (config2.workspaceId) {
38543
+ return config2.workspaceId;
38544
+ }
38545
+ console.log("[workspace] Resolving workspace from API key...");
38546
+ const info = await client.auth.getApiKeyInfo();
38547
+ if (info.workspaceId) {
38548
+ console.log(`[workspace] Resolved workspace: ${info.workspaceId}`);
38549
+ return info.workspaceId;
38550
+ }
38551
+ throw new Error("Could not resolve workspace from API key. Please set workspaceId in settings.");
38552
+ }
38445
38553
  async function tasksCommand(ctx, config2) {
38446
38554
  console.log("[tasks] Listing active tasks");
38447
38555
  if (!config2.apiKey) {
@@ -38449,8 +38557,8 @@ async function tasksCommand(ctx, config2) {
38449
38557
  return;
38450
38558
  }
38451
38559
  try {
38452
- const client = createClient(config2);
38453
- const workspaceId = await resolveWorkspaceId(client, config2);
38560
+ const client = createClient2(config2);
38561
+ const workspaceId = await resolveWorkspaceId2(client, config2);
38454
38562
  const tasks2 = await client.tasks.list(workspaceId, {
38455
38563
  status: [
38456
38564
  "IN_PROGRESS" /* IN_PROGRESS */,
@@ -38512,8 +38620,8 @@ async function rejectTaskCommand(ctx, config2) {
38512
38620
  return;
38513
38621
  }
38514
38622
  try {
38515
- const client = createClient(config2);
38516
- const workspaceId = await resolveWorkspaceId(client, config2);
38623
+ const client = createClient2(config2);
38624
+ const workspaceId = await resolveWorkspaceId2(client, config2);
38517
38625
  const task2 = await client.tasks.getById(taskId, workspaceId);
38518
38626
  if (task2.status !== "IN_REVIEW" /* IN_REVIEW */) {
38519
38627
  await ctx.reply(formatError(`Task "${task2.title}" is in ${task2.status} status. Only IN_REVIEW tasks can be rejected.`), { parse_mode: "HTML" });
@@ -42637,6 +42745,8 @@ function createBot(config2) {
42637
42745
  bot.command("exec", (ctx) => execCommand(ctx, executor));
42638
42746
  bot.command("tasks", (ctx) => tasksCommand(ctx, config2));
42639
42747
  bot.command("rejecttask", (ctx) => rejectTaskCommand(ctx, config2));
42748
+ bot.command("sprints", (ctx) => sprintsCommand(ctx, config2));
42749
+ bot.command("completesprint", (ctx) => completeSprintCommand(ctx, config2));
42640
42750
  bot.command("git", (ctx) => gitCommand(ctx, config2));
42641
42751
  bot.command("dev", (ctx) => devCommand(ctx, config2));
42642
42752
  bot.command("status", (ctx) => statusCommand(ctx, executor));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@locusai/telegram",
3
- "version": "0.9.14",
3
+ "version": "0.9.16",
4
4
  "description": "Telegram bot for Locus - remote control your AI agents from Telegram",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,7 +32,7 @@
32
32
  "author": "",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@locusai/sdk": "^0.9.14",
35
+ "@locusai/sdk": "^0.9.16",
36
36
  "dotenv": "^16.4.7",
37
37
  "telegraf": "^4.16.3"
38
38
  },