@locusai/telegram 0.9.13 → 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.
- package/bin/telegram.js +145 -37
- 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 <id> <feedback> — Reject an IN_REVIEW task
|
|
20096
20096
|
|
|
20097
|
+
<b>Sprints:</b>
|
|
20098
|
+
/sprints — List all sprints
|
|
20099
|
+
/completesprint <id> — 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/
|
|
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 <sprint-id>"), {
|
|
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 =
|
|
38453
|
-
const workspaceId = await
|
|
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 =
|
|
38516
|
-
const workspaceId = await
|
|
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" });
|
|
@@ -40518,8 +40626,6 @@ class WorktreeManager {
|
|
|
40518
40626
|
this.log("No changes to commit", "info");
|
|
40519
40627
|
return null;
|
|
40520
40628
|
}
|
|
40521
|
-
this.gitExec(["config", "user.name", "LocusAgent"], worktreePath);
|
|
40522
|
-
this.gitExec(["config", "user.email", "agent@locusai.team"], worktreePath);
|
|
40523
40629
|
this.git("add -A", worktreePath);
|
|
40524
40630
|
const staged = this.git("diff --cached --name-only", worktreePath).trim();
|
|
40525
40631
|
if (!staged) {
|
|
@@ -42639,6 +42745,8 @@ function createBot(config2) {
|
|
|
42639
42745
|
bot.command("exec", (ctx) => execCommand(ctx, executor));
|
|
42640
42746
|
bot.command("tasks", (ctx) => tasksCommand(ctx, config2));
|
|
42641
42747
|
bot.command("rejecttask", (ctx) => rejectTaskCommand(ctx, config2));
|
|
42748
|
+
bot.command("sprints", (ctx) => sprintsCommand(ctx, config2));
|
|
42749
|
+
bot.command("completesprint", (ctx) => completeSprintCommand(ctx, config2));
|
|
42642
42750
|
bot.command("git", (ctx) => gitCommand(ctx, config2));
|
|
42643
42751
|
bot.command("dev", (ctx) => devCommand(ctx, config2));
|
|
42644
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.
|
|
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.
|
|
35
|
+
"@locusai/sdk": "^0.9.16",
|
|
36
36
|
"dotenv": "^16.4.7",
|
|
37
37
|
"telegraf": "^4.16.3"
|
|
38
38
|
},
|