@integrity-labs/agt-cli 0.15.6 → 0.15.8
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/dist/bin/agt.js +19 -8
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-IGKAMH32.js → chunk-32D5TUSD.js} +8 -1
- package/dist/chunk-32D5TUSD.js.map +1 -0
- package/dist/lib/manager-worker.js +85 -21
- package/dist/lib/manager-worker.js.map +1 -1
- package/mcp/index.js +9 -0
- package/mcp/slack-channel.js +11 -7
- package/mcp/telegram-channel.js +36 -5
- package/package.json +1 -1
- package/dist/chunk-IGKAMH32.js.map +0 -1
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveChannels,
|
|
23
23
|
resolveDmTarget,
|
|
24
24
|
wrapScheduledTaskPrompt
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-32D5TUSD.js";
|
|
26
26
|
import {
|
|
27
27
|
findTaskByTemplate,
|
|
28
28
|
getProjectDir,
|
|
@@ -1069,8 +1069,8 @@ function startRealtimeKanban(config2) {
|
|
|
1069
1069
|
filter: filterStr
|
|
1070
1070
|
}, (payload) => {
|
|
1071
1071
|
const item = payload.new;
|
|
1072
|
-
if (item.status === "
|
|
1073
|
-
log2(`[realtime] New kanban item in '
|
|
1072
|
+
if (item.status === "todo") {
|
|
1073
|
+
log2(`[realtime] New kanban item in 'todo': item_id=${item.id} agent=${item.agent_id}`);
|
|
1074
1074
|
onTodayItem(item);
|
|
1075
1075
|
}
|
|
1076
1076
|
}).on("postgres_changes", {
|
|
@@ -1081,8 +1081,8 @@ function startRealtimeKanban(config2) {
|
|
|
1081
1081
|
}, (payload) => {
|
|
1082
1082
|
const item = payload.new;
|
|
1083
1083
|
const old = payload.old;
|
|
1084
|
-
if (item.status === "
|
|
1085
|
-
log2(`[realtime] Kanban item moved to '
|
|
1084
|
+
if (item.status === "todo" && old.status !== "todo") {
|
|
1085
|
+
log2(`[realtime] Kanban item moved to 'todo': item_id=${item.id} agent=${item.agent_id}`);
|
|
1086
1086
|
onTodayItem(item);
|
|
1087
1087
|
}
|
|
1088
1088
|
if (onCompletion && (item.status === "done" || item.status === "failed") && old.status !== item.status) {
|
|
@@ -3141,7 +3141,7 @@ async function processAgent(agent, agentStates) {
|
|
|
3141
3141
|
} else if (agentFw === "claude-code") {
|
|
3142
3142
|
if (sessionMode === "persistent") {
|
|
3143
3143
|
if (isSessionHealthy(agent.code_name)) {
|
|
3144
|
-
const todayItem = boardItems.find((b) => b.status === "
|
|
3144
|
+
const todayItem = boardItems.find((b) => b.status === "todo");
|
|
3145
3145
|
const taskHint = todayItem ? ` Top item: "${todayItem.title}" (priority ${todayItem.priority}).` : "";
|
|
3146
3146
|
injectMessage(agent.code_name, "task", `New work triggered. Check your kanban board with kanban_list and pick up the next item.${taskHint}`, {
|
|
3147
3147
|
task_name: "kanban-work-trigger"
|
|
@@ -3467,7 +3467,7 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
3467
3467
|
prompt = boardPrefix + prompt;
|
|
3468
3468
|
}
|
|
3469
3469
|
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
3470
|
-
const todayItem = boardItems.find((b) => b.status === "
|
|
3470
|
+
const todayItem = boardItems.find((b) => b.status === "todo");
|
|
3471
3471
|
if (todayItem) {
|
|
3472
3472
|
try {
|
|
3473
3473
|
await api.post("/host/kanban", {
|
|
@@ -3489,9 +3489,42 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
|
|
|
3489
3489
|
});
|
|
3490
3490
|
}
|
|
3491
3491
|
}
|
|
3492
|
+
async function startRun(opts) {
|
|
3493
|
+
try {
|
|
3494
|
+
const res = await api.post(
|
|
3495
|
+
"/host/runs/start",
|
|
3496
|
+
opts
|
|
3497
|
+
);
|
|
3498
|
+
return { run_id: res.run_id ?? null, kanban_item_id: res.kanban_item_id ?? null };
|
|
3499
|
+
} catch (err) {
|
|
3500
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
3501
|
+
const errId = createHash("sha256").update(errText).digest("hex").slice(0, 12);
|
|
3502
|
+
log(`[runs] start failed for agent_id=${opts.agent_id} source_type=${opts.source_type} error_id=${errId}`);
|
|
3503
|
+
return { run_id: null, kanban_item_id: null };
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
async function finishRun(runId, outcome, options = {}) {
|
|
3507
|
+
try {
|
|
3508
|
+
await api.post("/host/runs/finish", {
|
|
3509
|
+
run_id: runId,
|
|
3510
|
+
outcome,
|
|
3511
|
+
outcome_message: options.outcomeMessage,
|
|
3512
|
+
metadata: options.metadata,
|
|
3513
|
+
complete_kanban_item_id: options.completeKanbanItemId ?? void 0,
|
|
3514
|
+
result: options.result
|
|
3515
|
+
});
|
|
3516
|
+
} catch (err) {
|
|
3517
|
+
const errText = err instanceof Error ? err.message : String(err);
|
|
3518
|
+
const errId = createHash("sha256").update(errText).digest("hex").slice(0, 12);
|
|
3519
|
+
log(`[runs] finish failed for run_id=${runId} outcome=${outcome} error_id=${errId}`);
|
|
3520
|
+
}
|
|
3521
|
+
}
|
|
3492
3522
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
3493
3523
|
const projectDir = getProjectDir(codeName);
|
|
3494
3524
|
const mcpConfigPath = join2(projectDir, ".mcp.json");
|
|
3525
|
+
let runId = null;
|
|
3526
|
+
let kanbanItemId = null;
|
|
3527
|
+
let taskResult;
|
|
3495
3528
|
sanitizeMcpJson(mcpConfigPath, requireHost());
|
|
3496
3529
|
prompt = wrapScheduledTaskPrompt(prompt);
|
|
3497
3530
|
try {
|
|
@@ -3538,6 +3571,16 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3538
3571
|
log(`[claude-scheduler] Skipping task '${task.name}' for '${codeName}' \u2014 auth resolve failed: ${err.message}`);
|
|
3539
3572
|
return;
|
|
3540
3573
|
}
|
|
3574
|
+
const startResult = await startRun({
|
|
3575
|
+
agent_id: agentId,
|
|
3576
|
+
source_type: "scheduled_task",
|
|
3577
|
+
source_ref: task.taskId,
|
|
3578
|
+
metadata: { template_id: task.templateId, name: task.name },
|
|
3579
|
+
materialize_kanban: { title: task.name, priority: 2 }
|
|
3580
|
+
});
|
|
3581
|
+
runId = startResult.run_id;
|
|
3582
|
+
kanbanItemId = startResult.kanban_item_id;
|
|
3583
|
+
if (runId) childEnv["AGT_RUN_ID"] = runId;
|
|
3541
3584
|
const { stdout, stderr } = await execFilePromiseLong(resolveClaudeBinary(), claudeArgs, {
|
|
3542
3585
|
cwd: projectDir,
|
|
3543
3586
|
timeout: 3e5,
|
|
@@ -3548,6 +3591,7 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3548
3591
|
log(`[claude-scheduler] Task '${task.name}' stderr for '${codeName}': ${stderr.slice(0, 500)}`);
|
|
3549
3592
|
}
|
|
3550
3593
|
const output = stdout.trim();
|
|
3594
|
+
taskResult = output.slice(0, 4e3) || void 0;
|
|
3551
3595
|
log(`[claude-scheduler] Task '${task.name}' completed for '${codeName}' (${output.length} chars): ${output.slice(0, 300)}`);
|
|
3552
3596
|
await processClaudeTaskResult(codeName, agentId, task.templateId, output, {
|
|
3553
3597
|
mode: task.deliveryMode,
|
|
@@ -3555,6 +3599,13 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3555
3599
|
to: task.deliveryTo,
|
|
3556
3600
|
taskId: task.taskId
|
|
3557
3601
|
});
|
|
3602
|
+
if (runId) {
|
|
3603
|
+
await finishRun(runId, "completed", {
|
|
3604
|
+
metadata: { output_length: output.length },
|
|
3605
|
+
completeKanbanItemId: kanbanItemId,
|
|
3606
|
+
result: taskResult
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3558
3609
|
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
3559
3610
|
claudeSchedulerStates.set(codeName, updated);
|
|
3560
3611
|
if (task.scheduleKind === "at") {
|
|
@@ -3567,13 +3618,25 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
3567
3618
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3568
3619
|
log(`[claude-scheduler] Task '${task.name}' failed for '${codeName}': ${errMsg}`);
|
|
3569
3620
|
if (err instanceof ChildProcessError) {
|
|
3570
|
-
|
|
3571
|
-
|
|
3621
|
+
const errStdout = err.stdout.trim();
|
|
3622
|
+
if (errStdout) {
|
|
3623
|
+
taskResult = errStdout.slice(0, 4e3) || taskResult;
|
|
3624
|
+
log(`[claude-scheduler] Task '${task.name}' stdout for '${codeName}': ${errStdout.slice(0, 1e3)}`);
|
|
3572
3625
|
}
|
|
3573
3626
|
if (err.stderr.trim()) {
|
|
3574
3627
|
log(`[claude-scheduler] Task '${task.name}' stderr for '${codeName}': ${err.stderr.trim().slice(0, 1e3)}`);
|
|
3575
3628
|
}
|
|
3576
3629
|
}
|
|
3630
|
+
if (runId) {
|
|
3631
|
+
try {
|
|
3632
|
+
await finishRun(runId, "failed", {
|
|
3633
|
+
outcomeMessage: errMsg,
|
|
3634
|
+
completeKanbanItemId: kanbanItemId,
|
|
3635
|
+
result: taskResult
|
|
3636
|
+
});
|
|
3637
|
+
} catch {
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3577
3640
|
const updated = markTaskFired(codeName, task.taskId, "error");
|
|
3578
3641
|
claudeSchedulerStates.set(codeName, updated);
|
|
3579
3642
|
}
|
|
@@ -3821,7 +3884,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
|
3821
3884
|
prompt = boardPrefix + prompt;
|
|
3822
3885
|
}
|
|
3823
3886
|
if (KANBAN_WORK_TEMPLATES.has(task.templateId)) {
|
|
3824
|
-
const todayItem = boardItems.find((b) => b.status === "
|
|
3887
|
+
const todayItem = boardItems.find((b) => b.status === "todo");
|
|
3825
3888
|
if (todayItem) {
|
|
3826
3889
|
try {
|
|
3827
3890
|
await api.post("/host/kanban", {
|
|
@@ -4216,7 +4279,7 @@ var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-upda
|
|
|
4216
4279
|
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
4217
4280
|
var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
4218
4281
|
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary", "kanban-work"]);
|
|
4219
|
-
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["backlog", "
|
|
4282
|
+
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["backlog", "todo", "in_progress"]);
|
|
4220
4283
|
function hasActionableItems(items) {
|
|
4221
4284
|
return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
|
|
4222
4285
|
}
|
|
@@ -4349,8 +4412,8 @@ function parseStandupSummary(summary) {
|
|
|
4349
4412
|
if (lower.includes("yesterday") || lower.includes("accomplished")) {
|
|
4350
4413
|
currentSection = "yesterday";
|
|
4351
4414
|
continue;
|
|
4352
|
-
} else if (lower.includes("
|
|
4353
|
-
currentSection = "
|
|
4415
|
+
} else if (lower.includes("todo") || lower.includes("working on")) {
|
|
4416
|
+
currentSection = "todo";
|
|
4354
4417
|
continue;
|
|
4355
4418
|
} else if (lower.includes("blocker")) {
|
|
4356
4419
|
currentSection = "blockers";
|
|
@@ -4362,7 +4425,7 @@ function parseStandupSummary(summary) {
|
|
|
4362
4425
|
case "yesterday":
|
|
4363
4426
|
yesterday += (yesterday ? "\n" : "") + trimmed;
|
|
4364
4427
|
break;
|
|
4365
|
-
case "
|
|
4428
|
+
case "todo":
|
|
4366
4429
|
today += (today ? "\n" : "") + trimmed;
|
|
4367
4430
|
break;
|
|
4368
4431
|
case "blockers":
|
|
@@ -4405,7 +4468,7 @@ function parsePlanItems(summary) {
|
|
|
4405
4468
|
title,
|
|
4406
4469
|
priority,
|
|
4407
4470
|
estimated_minutes: estimatedMinutes,
|
|
4408
|
-
status: "
|
|
4471
|
+
status: "todo"
|
|
4409
4472
|
};
|
|
4410
4473
|
} else if (currentItem && trimmed && !trimmed.match(/^(?:PLAN|---)/i)) {
|
|
4411
4474
|
const descLine = sanitizeKanbanString(trimmed, MAX_KANBAN_NOTES_LENGTH);
|
|
@@ -4415,7 +4478,7 @@ function parsePlanItems(summary) {
|
|
|
4415
4478
|
if (currentItem) items.push(currentItem);
|
|
4416
4479
|
return items;
|
|
4417
4480
|
}
|
|
4418
|
-
var VALID_KANBAN_STATUSES = /* @__PURE__ */ new Set(["backlog", "
|
|
4481
|
+
var VALID_KANBAN_STATUSES = /* @__PURE__ */ new Set(["backlog", "todo", "in_progress", "done"]);
|
|
4419
4482
|
var MAX_KANBAN_TITLE_LENGTH = 500;
|
|
4420
4483
|
var MAX_KANBAN_NOTES_LENGTH = 2e3;
|
|
4421
4484
|
function sanitizeKanbanString(value, maxLen) {
|
|
@@ -4461,9 +4524,10 @@ function parseKanbanUpdates(summary) {
|
|
|
4461
4524
|
const lines = kanbanSection.split("\n");
|
|
4462
4525
|
for (const line of lines) {
|
|
4463
4526
|
const trimmed = line.trim();
|
|
4464
|
-
const match = trimmed.match(/^[-*•]\s*"([^"]+)":\s*(backlog|today|in_progress|done)(?:\s*\((.+)\))?/i);
|
|
4527
|
+
const match = trimmed.match(/^[-*•]\s*"([^"]+)":\s*(backlog|todo|today|in_progress|done)(?:\s*\((.+)\))?/i);
|
|
4465
4528
|
if (match) {
|
|
4466
|
-
const
|
|
4529
|
+
const rawStatus = match[2].toLowerCase();
|
|
4530
|
+
const status = rawStatus === "today" ? "todo" : rawStatus;
|
|
4467
4531
|
if (!VALID_KANBAN_STATUSES.has(status)) continue;
|
|
4468
4532
|
const title = sanitizeKanbanString(match[1], MAX_KANBAN_TITLE_LENGTH);
|
|
4469
4533
|
if (!title) continue;
|
|
@@ -4505,7 +4569,7 @@ function formatBoardForPrompt(items, template) {
|
|
|
4505
4569
|
const lines = [];
|
|
4506
4570
|
if (template === "morning-plan") {
|
|
4507
4571
|
lines.push("=== CURRENT BOARD ===");
|
|
4508
|
-
for (const [status, label] of [["backlog", "BACKLOG (carry-over)"], ["
|
|
4572
|
+
for (const [status, label] of [["backlog", "BACKLOG (carry-over)"], ["todo", "TO DO"], ["in_progress", "IN PROGRESS"]]) {
|
|
4509
4573
|
const statusItems = grouped[status];
|
|
4510
4574
|
if (statusItems && statusItems.length > 0) {
|
|
4511
4575
|
lines.push(`${label}:`);
|
|
@@ -4517,13 +4581,13 @@ function formatBoardForPrompt(items, template) {
|
|
|
4517
4581
|
lines.push("=====================");
|
|
4518
4582
|
lines.push("");
|
|
4519
4583
|
lines.push("Create today's plan. You may:");
|
|
4520
|
-
lines.push('- Move backlog items to "
|
|
4584
|
+
lines.push('- Move backlog items to "todo"');
|
|
4521
4585
|
lines.push("- Add new items you've identified");
|
|
4522
4586
|
lines.push("- Reprioritise existing items");
|
|
4523
4587
|
lines.push("");
|
|
4524
4588
|
} else {
|
|
4525
4589
|
lines.push("=== YOUR KANBAN BOARD ===");
|
|
4526
|
-
for (const [status, label] of [["
|
|
4590
|
+
for (const [status, label] of [["todo", "TO DO"], ["in_progress", "IN PROGRESS"], ["backlog", "BACKLOG"]]) {
|
|
4527
4591
|
const statusItems = grouped[status];
|
|
4528
4592
|
if (statusItems && statusItems.length > 0) {
|
|
4529
4593
|
lines.push(`${label}:`);
|