@integrity-labs/agt-cli 0.28.25 → 0.28.26
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.
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
provisionStopHook,
|
|
23
23
|
requireHost,
|
|
24
24
|
safeWriteJsonAtomic
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-NDGLXWV7.js";
|
|
26
26
|
import {
|
|
27
27
|
getProjectDir as getProjectDir2,
|
|
28
28
|
getReadyTasks,
|
|
@@ -105,10 +105,10 @@ import {
|
|
|
105
105
|
|
|
106
106
|
// src/lib/manager-worker.ts
|
|
107
107
|
import { createHash as createHash4 } from "crypto";
|
|
108
|
-
import { readFileSync as
|
|
108
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync8, rmSync as rmSync3, readdirSync as readdirSync5, statSync as statSync4, unlinkSync, copyFileSync } from "fs";
|
|
109
109
|
import https from "https";
|
|
110
110
|
import { execFileSync as syncExecFile } from "child_process";
|
|
111
|
-
import { join as
|
|
111
|
+
import { join as join14, dirname as dirname3 } from "path";
|
|
112
112
|
import { homedir as homedir7 } from "os";
|
|
113
113
|
import { fileURLToPath } from "url";
|
|
114
114
|
|
|
@@ -3831,6 +3831,273 @@ async function applyClaudeAuthToEnv(childEnv, label) {
|
|
|
3831
3831
|
}
|
|
3832
3832
|
}
|
|
3833
3833
|
|
|
3834
|
+
// src/lib/manager/kanban/parsers.ts
|
|
3835
|
+
import { existsSync as existsSync6, readFileSync as readFileSync10 } from "fs";
|
|
3836
|
+
import { join as join12 } from "path";
|
|
3837
|
+
var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
|
|
3838
|
+
var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
|
|
3839
|
+
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
3840
|
+
var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
3841
|
+
function isPlainScheduledTemplate(templateId) {
|
|
3842
|
+
return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
|
|
3843
|
+
}
|
|
3844
|
+
function isKanbanHybridEnabled() {
|
|
3845
|
+
return true;
|
|
3846
|
+
}
|
|
3847
|
+
function isKanbanHybridDryRun() {
|
|
3848
|
+
const v = process.env["AGT_KANBAN_HYBRID_DRY_RUN"];
|
|
3849
|
+
return v === "1" || v?.toLowerCase() === "true";
|
|
3850
|
+
}
|
|
3851
|
+
var HYBRID_ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
3852
|
+
function isHybridActionable(item) {
|
|
3853
|
+
return HYBRID_ACTIONABLE_STATUSES.has(item.status) && item.source_type !== "scheduled_task";
|
|
3854
|
+
}
|
|
3855
|
+
function isSlashCommand(command) {
|
|
3856
|
+
return command.trimStart().startsWith("/");
|
|
3857
|
+
}
|
|
3858
|
+
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary"]);
|
|
3859
|
+
function parseStandupSummary(summary) {
|
|
3860
|
+
const lines = summary.split("\n");
|
|
3861
|
+
let yesterday = "";
|
|
3862
|
+
let today = "";
|
|
3863
|
+
let blockers = "";
|
|
3864
|
+
let currentSection = null;
|
|
3865
|
+
for (const line of lines) {
|
|
3866
|
+
const lower = line.toLowerCase();
|
|
3867
|
+
if (lower.includes("yesterday") || lower.includes("accomplished")) {
|
|
3868
|
+
currentSection = "yesterday";
|
|
3869
|
+
continue;
|
|
3870
|
+
} else if (lower.includes("today") || lower.includes("todo") || lower.includes("working on")) {
|
|
3871
|
+
currentSection = "todo";
|
|
3872
|
+
continue;
|
|
3873
|
+
} else if (lower.includes("blocker")) {
|
|
3874
|
+
currentSection = "blockers";
|
|
3875
|
+
continue;
|
|
3876
|
+
}
|
|
3877
|
+
const trimmed = line.replace(/^[-*•]\s*/, "").trim();
|
|
3878
|
+
if (!trimmed) continue;
|
|
3879
|
+
switch (currentSection) {
|
|
3880
|
+
case "yesterday":
|
|
3881
|
+
yesterday += (yesterday ? "\n" : "") + trimmed;
|
|
3882
|
+
break;
|
|
3883
|
+
case "todo":
|
|
3884
|
+
today += (today ? "\n" : "") + trimmed;
|
|
3885
|
+
break;
|
|
3886
|
+
case "blockers":
|
|
3887
|
+
blockers += (blockers ? "\n" : "") + trimmed;
|
|
3888
|
+
break;
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
if (!yesterday && !today && !blockers) {
|
|
3892
|
+
today = summary;
|
|
3893
|
+
}
|
|
3894
|
+
return { yesterday, today, blockers };
|
|
3895
|
+
}
|
|
3896
|
+
function parsePlanItems(summary) {
|
|
3897
|
+
const items = [];
|
|
3898
|
+
const lines = summary.split("\n");
|
|
3899
|
+
let currentItem = null;
|
|
3900
|
+
for (const line of lines) {
|
|
3901
|
+
const trimmed = line.trim();
|
|
3902
|
+
const itemMatch = trimmed.match(/^(?:\d+[\.\)]\s*|[-*•]\s*)\[?(HIGH|MEDIUM|LOW|MED)\]?\s*(.+)/i);
|
|
3903
|
+
if (itemMatch) {
|
|
3904
|
+
if (currentItem) items.push(currentItem);
|
|
3905
|
+
const priorityStr = itemMatch[1].toUpperCase();
|
|
3906
|
+
const rest = itemMatch[2];
|
|
3907
|
+
let estimatedMinutes;
|
|
3908
|
+
const timeMatch = rest.match(/\(~?(\d+)\s*(min(?:utes?)?|hr?(?:ours?)?|h)\)/i);
|
|
3909
|
+
if (timeMatch) {
|
|
3910
|
+
const val = parseInt(timeMatch[1], 10);
|
|
3911
|
+
const unit = timeMatch[2].toLowerCase();
|
|
3912
|
+
estimatedMinutes = unit.startsWith("h") ? val * 60 : val;
|
|
3913
|
+
}
|
|
3914
|
+
const title = sanitizeKanbanString(
|
|
3915
|
+
rest.replace(/\(~?\d+\s*(?:min(?:utes?)?|hr?(?:ours?)?|h)\)/i, ""),
|
|
3916
|
+
MAX_KANBAN_TITLE_LENGTH
|
|
3917
|
+
);
|
|
3918
|
+
if (!title) continue;
|
|
3919
|
+
const priorityMap = { HIGH: 1, MEDIUM: 2, MED: 2, LOW: 3 };
|
|
3920
|
+
const priority = priorityMap[priorityStr] ?? 2;
|
|
3921
|
+
if (![1, 2, 3].includes(priority)) continue;
|
|
3922
|
+
currentItem = {
|
|
3923
|
+
title,
|
|
3924
|
+
priority,
|
|
3925
|
+
estimated_minutes: estimatedMinutes,
|
|
3926
|
+
status: "todo"
|
|
3927
|
+
};
|
|
3928
|
+
} else if (currentItem && trimmed && !trimmed.match(/^(?:PLAN|---)/i)) {
|
|
3929
|
+
const descLine = sanitizeKanbanString(trimmed, MAX_KANBAN_NOTES_LENGTH);
|
|
3930
|
+
currentItem.description = currentItem.description ? sanitizeKanbanString(currentItem.description + "\n" + descLine, MAX_KANBAN_NOTES_LENGTH) : descLine;
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
if (currentItem) items.push(currentItem);
|
|
3934
|
+
return items;
|
|
3935
|
+
}
|
|
3936
|
+
var VALID_KANBAN_STATUSES = /* @__PURE__ */ new Set(["backlog", "todo", "in_progress", "done"]);
|
|
3937
|
+
var MAX_KANBAN_TITLE_LENGTH = 500;
|
|
3938
|
+
var MAX_KANBAN_NOTES_LENGTH = 2e3;
|
|
3939
|
+
function sanitizeKanbanString(value, maxLen) {
|
|
3940
|
+
if (!value) return "";
|
|
3941
|
+
return value.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "").replace(/\{\{.*?\}\}/g, "").replace(/^(System|Assistant|Human):\s*/gmi, "").replace(/#{2,}/g, "").replace(/\s+/g, " ").trim().slice(0, maxLen);
|
|
3942
|
+
}
|
|
3943
|
+
function sanitizeBoardItem(item) {
|
|
3944
|
+
return {
|
|
3945
|
+
...item,
|
|
3946
|
+
title: sanitizeKanbanString(item.title, 200),
|
|
3947
|
+
status: sanitizeKanbanString(item.status, 50),
|
|
3948
|
+
...item.deliverable ? { deliverable: sanitizeKanbanString(item.deliverable, 500) } : {}
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
var builtInSkillCache = /* @__PURE__ */ new Map();
|
|
3952
|
+
function getBuiltInSkillContent(skillId) {
|
|
3953
|
+
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
3954
|
+
try {
|
|
3955
|
+
const candidates = [
|
|
3956
|
+
join12(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
3957
|
+
join12(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
3958
|
+
];
|
|
3959
|
+
for (const candidate of candidates) {
|
|
3960
|
+
if (existsSync6(candidate)) {
|
|
3961
|
+
const content = readFileSync10(candidate, "utf-8");
|
|
3962
|
+
const files = [{ relativePath: "SKILL.md", content }];
|
|
3963
|
+
builtInSkillCache.set(skillId, files);
|
|
3964
|
+
return files;
|
|
3965
|
+
}
|
|
3966
|
+
}
|
|
3967
|
+
builtInSkillCache.set(skillId, null);
|
|
3968
|
+
return null;
|
|
3969
|
+
} catch {
|
|
3970
|
+
builtInSkillCache.set(skillId, null);
|
|
3971
|
+
return null;
|
|
3972
|
+
}
|
|
3973
|
+
}
|
|
3974
|
+
function parseKanbanUpdates(summary) {
|
|
3975
|
+
const updates = [];
|
|
3976
|
+
const markerMatch = /kanban update:/i.exec(summary);
|
|
3977
|
+
if (!markerMatch) return updates;
|
|
3978
|
+
const kanbanSection = summary.slice(markerMatch.index + markerMatch[0].length);
|
|
3979
|
+
const lines = kanbanSection.split("\n");
|
|
3980
|
+
for (const line of lines) {
|
|
3981
|
+
const trimmed = line.trim();
|
|
3982
|
+
const match = trimmed.match(/^[-*•]\s*"([^"]+)":\s*(backlog|todo|today|in_progress|done)(?:\s*\((.+)\))?/i);
|
|
3983
|
+
if (match) {
|
|
3984
|
+
const rawStatus = match[2].toLowerCase();
|
|
3985
|
+
const status = rawStatus === "today" ? "todo" : rawStatus;
|
|
3986
|
+
if (!VALID_KANBAN_STATUSES.has(status)) continue;
|
|
3987
|
+
const title = sanitizeKanbanString(match[1], MAX_KANBAN_TITLE_LENGTH);
|
|
3988
|
+
if (!title) continue;
|
|
3989
|
+
const parenthetical = match[3] ?? void 0;
|
|
3990
|
+
let notes;
|
|
3991
|
+
let result;
|
|
3992
|
+
if (parenthetical && status === "done") {
|
|
3993
|
+
const resultMatch = parenthetical.match(/^result:\s*(.+)/i);
|
|
3994
|
+
if (resultMatch) {
|
|
3995
|
+
result = sanitizeKanbanString(resultMatch[1], MAX_KANBAN_NOTES_LENGTH);
|
|
3996
|
+
} else {
|
|
3997
|
+
notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);
|
|
3998
|
+
}
|
|
3999
|
+
} else if (parenthetical) {
|
|
4000
|
+
notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);
|
|
4001
|
+
}
|
|
4002
|
+
updates.push({
|
|
4003
|
+
title,
|
|
4004
|
+
status,
|
|
4005
|
+
notes,
|
|
4006
|
+
result
|
|
4007
|
+
});
|
|
4008
|
+
}
|
|
4009
|
+
}
|
|
4010
|
+
return updates;
|
|
4011
|
+
}
|
|
4012
|
+
function formatBoardForPrompt(items, template) {
|
|
4013
|
+
if (items.length === 0) return "";
|
|
4014
|
+
const priorityLabel = (p) => p === 1 ? "HIGH" : p === 3 ? "LOW" : "MED";
|
|
4015
|
+
const timeLabel = (m) => m ? ` (~${m >= 60 ? `${Math.round(m / 60)}hr` : `${m}min`})` : "";
|
|
4016
|
+
const deliverableLine = (d) => d ? `
|
|
4017
|
+
Deliverable: ${d}` : "";
|
|
4018
|
+
const sourceLine = (channel, thread, url) => {
|
|
4019
|
+
const parts = [];
|
|
4020
|
+
if (channel && thread) parts.push(`${channel} thread ${thread}`);
|
|
4021
|
+
if (url) parts.push(url);
|
|
4022
|
+
return parts.length > 0 ? `
|
|
4023
|
+
source: ${parts.join(" \u2022 ")}` : "";
|
|
4024
|
+
};
|
|
4025
|
+
const grouped = {};
|
|
4026
|
+
for (const item of items) {
|
|
4027
|
+
const key = item.status;
|
|
4028
|
+
if (!grouped[key]) grouped[key] = [];
|
|
4029
|
+
grouped[key].push(item);
|
|
4030
|
+
}
|
|
4031
|
+
const hasSourceThread = items.some(
|
|
4032
|
+
(i) => (i.status === "todo" || i.status === "in_progress") && !!i.source_integration && !!i.source_external_id
|
|
4033
|
+
);
|
|
4034
|
+
const lines = [];
|
|
4035
|
+
if (template === "morning-plan") {
|
|
4036
|
+
lines.push("=== CURRENT BOARD ===");
|
|
4037
|
+
for (const [status, label] of [["backlog", "BACKLOG (carry-over)"], ["todo", "TO DO"], ["in_progress", "IN PROGRESS"]]) {
|
|
4038
|
+
const statusItems = grouped[status];
|
|
4039
|
+
if (statusItems && statusItems.length > 0) {
|
|
4040
|
+
lines.push(`${label}:`);
|
|
4041
|
+
statusItems.forEach((item, i) => {
|
|
4042
|
+
lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}${sourceLine(item.source_integration, item.source_external_id, item.source_url)}`);
|
|
4043
|
+
});
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
lines.push("=====================");
|
|
4047
|
+
lines.push("");
|
|
4048
|
+
lines.push("Create today's plan. You may:");
|
|
4049
|
+
lines.push('- Move backlog items to "todo"');
|
|
4050
|
+
lines.push("- Add new items you've identified");
|
|
4051
|
+
lines.push("- Reprioritise existing items");
|
|
4052
|
+
lines.push("");
|
|
4053
|
+
} else {
|
|
4054
|
+
lines.push("=== YOUR KANBAN BOARD ===");
|
|
4055
|
+
for (const [status, label] of [["todo", "TO DO"], ["in_progress", "IN PROGRESS"], ["backlog", "BACKLOG"]]) {
|
|
4056
|
+
const statusItems = grouped[status];
|
|
4057
|
+
if (statusItems && statusItems.length > 0) {
|
|
4058
|
+
lines.push(`${label}:`);
|
|
4059
|
+
statusItems.forEach((item, i) => {
|
|
4060
|
+
lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}${sourceLine(item.source_integration, item.source_external_id, item.source_url)}`);
|
|
4061
|
+
});
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
const doneItems = grouped["done"];
|
|
4065
|
+
if (doneItems && doneItems.length > 0) {
|
|
4066
|
+
lines.push("DONE TODAY:");
|
|
4067
|
+
doneItems.forEach((item, i) => {
|
|
4068
|
+
lines.push(` ${i + 1}. ${item.title}`);
|
|
4069
|
+
});
|
|
4070
|
+
}
|
|
4071
|
+
lines.push("=========================");
|
|
4072
|
+
lines.push("");
|
|
4073
|
+
lines.push("IMPORTANT: Use kanban MCP tools to update the board IN REAL TIME:");
|
|
4074
|
+
lines.push("1. FIRST call kanban_move to move your chosen item to in_progress BEFORE starting work");
|
|
4075
|
+
lines.push("2. Do the work");
|
|
4076
|
+
lines.push("3. Call kanban_done with a result summary when finished");
|
|
4077
|
+
lines.push("4. If blocked, call kanban_update with notes, then pick the next item");
|
|
4078
|
+
lines.push("");
|
|
4079
|
+
if (hasSourceThread) {
|
|
4080
|
+
lines.push("THREAD CONTINUITY: If a card shows a `source:` line, the request originated");
|
|
4081
|
+
lines.push("in that Slack/Telegram thread. When you deliver the result, reply in that");
|
|
4082
|
+
lines.push("thread (not the default channel) so the user sees the answer where they");
|
|
4083
|
+
lines.push("asked. The card's `source_channel` + `source_thread_id` are the thread");
|
|
4084
|
+
lines.push("coordinates to use.");
|
|
4085
|
+
lines.push("");
|
|
4086
|
+
}
|
|
4087
|
+
lines.push("SELF-MANAGEMENT: When you receive a request from a channel (Slack, Telegram)");
|
|
4088
|
+
lines.push("that takes more than a quick response, create a task first with kanban_add,");
|
|
4089
|
+
lines.push("move to in_progress, do the work, then kanban_done with a result summary.");
|
|
4090
|
+
lines.push("");
|
|
4091
|
+
lines.push("If MCP tools are unavailable, include a KANBAN UPDATE section in your output:");
|
|
4092
|
+
lines.push("KANBAN UPDATE:");
|
|
4093
|
+
lines.push('- "item title": new_status (optional notes)');
|
|
4094
|
+
lines.push('- "item title": done (result: <what you produced>)');
|
|
4095
|
+
lines.push("Statuses: backlog, today, in_progress, done");
|
|
4096
|
+
lines.push("");
|
|
4097
|
+
}
|
|
4098
|
+
return lines.join("\n");
|
|
4099
|
+
}
|
|
4100
|
+
|
|
3834
4101
|
// src/lib/wedge-detection.ts
|
|
3835
4102
|
var DEFAULTS = {
|
|
3836
4103
|
inboundWaitSeconds: 120,
|
|
@@ -3970,24 +4237,24 @@ function partitionActionableByPoison(actionable, states, config2) {
|
|
|
3970
4237
|
}
|
|
3971
4238
|
|
|
3972
4239
|
// src/lib/restart-flags.ts
|
|
3973
|
-
import { existsSync as
|
|
4240
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readFileSync as readFileSync11, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
3974
4241
|
import { homedir as homedir6 } from "os";
|
|
3975
|
-
import { join as
|
|
4242
|
+
import { join as join13 } from "path";
|
|
3976
4243
|
import { randomUUID } from "crypto";
|
|
3977
4244
|
function restartFlagsDir() {
|
|
3978
|
-
return
|
|
4245
|
+
return join13(homedir6(), ".augmented", "restart-flags");
|
|
3979
4246
|
}
|
|
3980
4247
|
function flagPath(codeName) {
|
|
3981
|
-
return
|
|
4248
|
+
return join13(restartFlagsDir(), `${codeName}.flag`);
|
|
3982
4249
|
}
|
|
3983
4250
|
function readRestartFlags() {
|
|
3984
4251
|
const dir = restartFlagsDir();
|
|
3985
|
-
if (!
|
|
4252
|
+
if (!existsSync7(dir)) return [];
|
|
3986
4253
|
const out = [];
|
|
3987
4254
|
for (const entry of readdirSync4(dir)) {
|
|
3988
4255
|
if (!entry.endsWith(".flag")) continue;
|
|
3989
4256
|
try {
|
|
3990
|
-
const raw =
|
|
4257
|
+
const raw = readFileSync11(join13(dir, entry), "utf8");
|
|
3991
4258
|
const parsed = JSON.parse(raw);
|
|
3992
4259
|
if (typeof parsed.codeName !== "string" || parsed.codeName.length === 0) {
|
|
3993
4260
|
parsed.codeName = entry.replace(/\.flag$/, "");
|
|
@@ -4005,7 +4272,7 @@ function readRestartFlags() {
|
|
|
4005
4272
|
}
|
|
4006
4273
|
function deleteRestartFlag(codeName) {
|
|
4007
4274
|
const path = flagPath(codeName);
|
|
4008
|
-
if (
|
|
4275
|
+
if (existsSync7(path)) {
|
|
4009
4276
|
rmSync2(path, { force: true });
|
|
4010
4277
|
}
|
|
4011
4278
|
}
|
|
@@ -4540,8 +4807,8 @@ function applyRestartAcks(args) {
|
|
|
4540
4807
|
var GATEWAY_PORT_BASE = 18800;
|
|
4541
4808
|
var GATEWAY_PORT_STEP = 10;
|
|
4542
4809
|
var GATEWAY_PORT_MAX = 18899;
|
|
4543
|
-
var AUGMENTED_DIR =
|
|
4544
|
-
var GATEWAY_PORTS_FILE =
|
|
4810
|
+
var AUGMENTED_DIR = join14(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
4811
|
+
var GATEWAY_PORTS_FILE = join14(AUGMENTED_DIR, "gateway-ports.json");
|
|
4545
4812
|
var CHANNEL_SWEEP_INTERVAL_MS = (() => {
|
|
4546
4813
|
const raw = parseInt(process.env["AGT_CHANNEL_SWEEP_INTERVAL_MS"] ?? "", 10);
|
|
4547
4814
|
if (!Number.isFinite(raw)) return 5 * 60 * 1e3;
|
|
@@ -5006,7 +5273,7 @@ var runningMcpServerKeys = /* @__PURE__ */ new Map();
|
|
|
5006
5273
|
var runningChannelSecretHashes = /* @__PURE__ */ new Map();
|
|
5007
5274
|
function projectMcpHash(_codeName, projectDir) {
|
|
5008
5275
|
try {
|
|
5009
|
-
const raw =
|
|
5276
|
+
const raw = readFileSync12(join14(projectDir, ".mcp.json"), "utf-8");
|
|
5010
5277
|
return createHash4("sha256").update(canonicalJson(JSON.parse(raw))).digest("hex");
|
|
5011
5278
|
} catch {
|
|
5012
5279
|
return null;
|
|
@@ -5014,7 +5281,7 @@ function projectMcpHash(_codeName, projectDir) {
|
|
|
5014
5281
|
}
|
|
5015
5282
|
function projectMcpKeys(_codeName, projectDir) {
|
|
5016
5283
|
try {
|
|
5017
|
-
const raw =
|
|
5284
|
+
const raw = readFileSync12(join14(projectDir, ".mcp.json"), "utf-8");
|
|
5018
5285
|
const parsed = JSON.parse(raw);
|
|
5019
5286
|
const servers = parsed.mcpServers;
|
|
5020
5287
|
if (!servers || typeof servers !== "object") return /* @__PURE__ */ new Set();
|
|
@@ -5025,7 +5292,7 @@ function projectMcpKeys(_codeName, projectDir) {
|
|
|
5025
5292
|
}
|
|
5026
5293
|
function readMcpHttpServerConfig(projectDir, serverKey, env) {
|
|
5027
5294
|
try {
|
|
5028
|
-
const raw =
|
|
5295
|
+
const raw = readFileSync12(join14(projectDir, ".mcp.json"), "utf-8");
|
|
5029
5296
|
const servers = JSON.parse(raw).mcpServers ?? {};
|
|
5030
5297
|
const entry = servers[serverKey];
|
|
5031
5298
|
if (entry && typeof entry.url === "string" && (entry.type === "http" || entry.type === void 0)) {
|
|
@@ -5063,9 +5330,9 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
|
|
|
5063
5330
|
if (integrations.length === 0) return;
|
|
5064
5331
|
const probeEnv = { ...process.env };
|
|
5065
5332
|
try {
|
|
5066
|
-
const envIntPath =
|
|
5067
|
-
if (
|
|
5068
|
-
Object.assign(probeEnv, parseEnvIntegrations(
|
|
5333
|
+
const envIntPath = join14(projectDir, ".env.integrations");
|
|
5334
|
+
if (existsSync8(envIntPath)) {
|
|
5335
|
+
Object.assign(probeEnv, parseEnvIntegrations(readFileSync12(envIntPath, "utf-8")));
|
|
5069
5336
|
}
|
|
5070
5337
|
} catch {
|
|
5071
5338
|
}
|
|
@@ -5270,7 +5537,7 @@ function checkMcpConfigDriftAndScheduleRestart(codeName, projectDir) {
|
|
|
5270
5537
|
function projectChannelSecretHash(projectDir) {
|
|
5271
5538
|
try {
|
|
5272
5539
|
const entries = parseEnvIntegrations(
|
|
5273
|
-
|
|
5540
|
+
readFileSync12(join14(projectDir, ".env.integrations"), "utf-8")
|
|
5274
5541
|
);
|
|
5275
5542
|
return channelSecretValueHash(entries, CHANNEL_SECRET_ENV_KEYS);
|
|
5276
5543
|
} catch {
|
|
@@ -5362,7 +5629,7 @@ var cachedMaintenanceWindow = null;
|
|
|
5362
5629
|
var lastVersionCheckAt = 0;
|
|
5363
5630
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
5364
5631
|
var lastResponsivenessProbeAt = 0;
|
|
5365
|
-
var agtCliVersion = true ? "0.28.
|
|
5632
|
+
var agtCliVersion = true ? "0.28.26" : "dev";
|
|
5366
5633
|
function resolveBrewPath(execFileSync4) {
|
|
5367
5634
|
try {
|
|
5368
5635
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -5375,7 +5642,7 @@ function resolveBrewPath(execFileSync4) {
|
|
|
5375
5642
|
"/usr/local/bin/brew"
|
|
5376
5643
|
];
|
|
5377
5644
|
for (const path of fallbacks) {
|
|
5378
|
-
if (
|
|
5645
|
+
if (existsSync8(path)) return path;
|
|
5379
5646
|
}
|
|
5380
5647
|
return null;
|
|
5381
5648
|
}
|
|
@@ -5385,7 +5652,7 @@ function claudeBinaryInstalled(execFileSync4) {
|
|
|
5385
5652
|
"/opt/homebrew/bin/claude",
|
|
5386
5653
|
"/usr/local/bin/claude"
|
|
5387
5654
|
];
|
|
5388
|
-
if (canonical.some((path) =>
|
|
5655
|
+
if (canonical.some((path) => existsSync8(path))) return true;
|
|
5389
5656
|
try {
|
|
5390
5657
|
execFileSync4("which", ["claude"], { timeout: 5e3 });
|
|
5391
5658
|
return true;
|
|
@@ -5538,8 +5805,8 @@ function claudeManagedSettingsPath() {
|
|
|
5538
5805
|
function ensureClaudeManagedSettings(path = claudeManagedSettingsPath()) {
|
|
5539
5806
|
try {
|
|
5540
5807
|
let settings = {};
|
|
5541
|
-
if (
|
|
5542
|
-
const raw =
|
|
5808
|
+
if (existsSync8(path)) {
|
|
5809
|
+
const raw = readFileSync12(path, "utf-8").trim();
|
|
5543
5810
|
if (raw) {
|
|
5544
5811
|
let parsed;
|
|
5545
5812
|
try {
|
|
@@ -5601,7 +5868,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
5601
5868
|
if (!process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
5602
5869
|
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
5603
5870
|
}
|
|
5604
|
-
if (
|
|
5871
|
+
if (existsSync8("/home/linuxbrew/.linuxbrew/bin/claude")) {
|
|
5605
5872
|
log("Claude Code installed successfully");
|
|
5606
5873
|
} else {
|
|
5607
5874
|
log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
|
|
@@ -5613,7 +5880,7 @@ async function ensureFrameworkBinary(frameworkId) {
|
|
|
5613
5880
|
var CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
5614
5881
|
var claudeCodeUpgradeInFlight = false;
|
|
5615
5882
|
function claudeCodeUpgradeMarkerPath() {
|
|
5616
|
-
return
|
|
5883
|
+
return join14(homedir7(), ".augmented", ".last-claude-code-upgrade-check");
|
|
5617
5884
|
}
|
|
5618
5885
|
function stampClaudeCodeUpgradeMarker() {
|
|
5619
5886
|
try {
|
|
@@ -5623,7 +5890,7 @@ function stampClaudeCodeUpgradeMarker() {
|
|
|
5623
5890
|
}
|
|
5624
5891
|
function claudeCodeUpgradeThrottled() {
|
|
5625
5892
|
try {
|
|
5626
|
-
const lastCheck = parseInt(
|
|
5893
|
+
const lastCheck = parseInt(readFileSync12(claudeCodeUpgradeMarkerPath(), "utf-8").trim(), 10);
|
|
5627
5894
|
if (!Number.isFinite(lastCheck)) return false;
|
|
5628
5895
|
return Date.now() - lastCheck < CLAUDE_CODE_UPGRADE_CHECK_INTERVAL_MS;
|
|
5629
5896
|
} catch {
|
|
@@ -5676,7 +5943,7 @@ ${r.stderr}`;
|
|
|
5676
5943
|
}
|
|
5677
5944
|
var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
5678
5945
|
function selfUpdateAppliedMarkerPath() {
|
|
5679
|
-
return
|
|
5946
|
+
return join14(homedir7(), ".augmented", ".last-self-update-applied");
|
|
5680
5947
|
}
|
|
5681
5948
|
var selfUpdateUpToDateLogged = false;
|
|
5682
5949
|
var restartAfterUpgrade = false;
|
|
@@ -5699,7 +5966,7 @@ async function checkAndUpdateCli() {
|
|
|
5699
5966
|
const isNpmGlobal = !isBrewFormula && resolvedPath.includes("node_modules");
|
|
5700
5967
|
if (!isBrewFormula && !isNpmGlobal) return;
|
|
5701
5968
|
const { readFileSync: readF, writeFileSync: writeF } = await import("fs");
|
|
5702
|
-
const markerPath =
|
|
5969
|
+
const markerPath = join14(homedir7(), ".augmented", ".last-update-check");
|
|
5703
5970
|
try {
|
|
5704
5971
|
const lastCheck = parseInt(readF(markerPath, "utf-8").trim(), 10);
|
|
5705
5972
|
if (Date.now() - lastCheck < UPDATE_CHECK_INTERVAL_MS) return;
|
|
@@ -5956,13 +6223,13 @@ async function checkClaudeAuth() {
|
|
|
5956
6223
|
}
|
|
5957
6224
|
var evalEmptyMcpConfigPath = null;
|
|
5958
6225
|
function ensureEvalEmptyMcpConfig() {
|
|
5959
|
-
if (evalEmptyMcpConfigPath &&
|
|
5960
|
-
const dir =
|
|
6226
|
+
if (evalEmptyMcpConfigPath && existsSync8(evalEmptyMcpConfigPath)) return evalEmptyMcpConfigPath;
|
|
6227
|
+
const dir = join14(homedir7(), ".augmented");
|
|
5961
6228
|
try {
|
|
5962
6229
|
mkdirSync4(dir, { recursive: true });
|
|
5963
6230
|
} catch {
|
|
5964
6231
|
}
|
|
5965
|
-
const p =
|
|
6232
|
+
const p = join14(dir, ".eval-empty-mcp.json");
|
|
5966
6233
|
writeFileSync4(p, JSON.stringify({ mcpServers: {} }));
|
|
5967
6234
|
evalEmptyMcpConfigPath = p;
|
|
5968
6235
|
return p;
|
|
@@ -6037,7 +6304,7 @@ function resolveConversationEvalBackend() {
|
|
|
6037
6304
|
}
|
|
6038
6305
|
function loadGatewayPorts() {
|
|
6039
6306
|
try {
|
|
6040
|
-
return JSON.parse(
|
|
6307
|
+
return JSON.parse(readFileSync12(GATEWAY_PORTS_FILE, "utf-8"));
|
|
6041
6308
|
} catch {
|
|
6042
6309
|
return {};
|
|
6043
6310
|
}
|
|
@@ -6067,10 +6334,10 @@ function freePort(codeName) {
|
|
|
6067
6334
|
}
|
|
6068
6335
|
}
|
|
6069
6336
|
function getStateFile() {
|
|
6070
|
-
return
|
|
6337
|
+
return join14(config?.configDir ?? join14(process.env["HOME"] ?? "/tmp", ".augmented"), "manager-state.json");
|
|
6071
6338
|
}
|
|
6072
6339
|
function channelHashCacheDir() {
|
|
6073
|
-
return config?.configDir ??
|
|
6340
|
+
return config?.configDir ?? join14(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
6074
6341
|
}
|
|
6075
6342
|
function loadChannelHashCache2() {
|
|
6076
6343
|
loadChannelHashCache(agentState.knownChannelConfigHashes, channelHashCacheDir());
|
|
@@ -6081,7 +6348,7 @@ function saveChannelHashCache2() {
|
|
|
6081
6348
|
var _channelQuarantineStore = null;
|
|
6082
6349
|
function channelQuarantineStore() {
|
|
6083
6350
|
if (!_channelQuarantineStore) {
|
|
6084
|
-
const dir = config?.configDir ??
|
|
6351
|
+
const dir = config?.configDir ?? join14(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
6085
6352
|
_channelQuarantineStore = new ChannelQuarantineStore(defaultQuarantinePath(dir));
|
|
6086
6353
|
}
|
|
6087
6354
|
return _channelQuarantineStore;
|
|
@@ -6089,7 +6356,7 @@ function channelQuarantineStore() {
|
|
|
6089
6356
|
var _hostFlagStore = null;
|
|
6090
6357
|
function hostFlagStore() {
|
|
6091
6358
|
if (!_hostFlagStore) {
|
|
6092
|
-
const dir = config?.configDir ??
|
|
6359
|
+
const dir = config?.configDir ?? join14(process.env["HOME"] ?? "/tmp", ".augmented");
|
|
6093
6360
|
_hostFlagStore = new HostFlagStore({ cachePath: defaultFlagsCachePath(dir), log });
|
|
6094
6361
|
}
|
|
6095
6362
|
return _hostFlagStore;
|
|
@@ -6141,12 +6408,12 @@ function parseSkillFrontmatter(content) {
|
|
|
6141
6408
|
}
|
|
6142
6409
|
async function refreshSkillsIndexInClaudeMd(configDir, codeName, log2) {
|
|
6143
6410
|
const { readdirSync: readdirSync6, readFileSync: rfs, existsSync: ex, writeFileSync: writeFileSync5 } = await import("fs");
|
|
6144
|
-
const skillsDir =
|
|
6145
|
-
const claudeMdPath =
|
|
6411
|
+
const skillsDir = join14(configDir, codeName, "project", ".claude", "skills");
|
|
6412
|
+
const claudeMdPath = join14(configDir, codeName, "project", "CLAUDE.md");
|
|
6146
6413
|
if (!ex(skillsDir) || !ex(claudeMdPath)) return;
|
|
6147
6414
|
const entries = [];
|
|
6148
6415
|
for (const dir of readdirSync6(skillsDir).sort()) {
|
|
6149
|
-
const skillFile =
|
|
6416
|
+
const skillFile = join14(skillsDir, dir, "SKILL.md");
|
|
6150
6417
|
if (!ex(skillFile)) continue;
|
|
6151
6418
|
try {
|
|
6152
6419
|
const { name, description } = parseSkillFrontmatter(rfs(skillFile, "utf-8"));
|
|
@@ -6194,10 +6461,10 @@ ${SKILLS_INDEX_END}`;
|
|
|
6194
6461
|
}
|
|
6195
6462
|
async function migrateToProfiles() {
|
|
6196
6463
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6197
|
-
const sharedConfigPath =
|
|
6464
|
+
const sharedConfigPath = join14(homeDir, ".openclaw", "openclaw.json");
|
|
6198
6465
|
let sharedConfig;
|
|
6199
6466
|
try {
|
|
6200
|
-
sharedConfig = JSON.parse(
|
|
6467
|
+
sharedConfig = JSON.parse(readFileSync12(sharedConfigPath, "utf-8"));
|
|
6201
6468
|
} catch {
|
|
6202
6469
|
return;
|
|
6203
6470
|
}
|
|
@@ -6210,19 +6477,19 @@ async function migrateToProfiles() {
|
|
|
6210
6477
|
const codeName = agentEntry["id"];
|
|
6211
6478
|
if (!codeName) continue;
|
|
6212
6479
|
if (codeName === "main") continue;
|
|
6213
|
-
const profileDir =
|
|
6214
|
-
if (
|
|
6480
|
+
const profileDir = join14(homeDir, `.openclaw-${codeName}`);
|
|
6481
|
+
if (existsSync8(join14(profileDir, "openclaw.json"))) continue;
|
|
6215
6482
|
log(`Migrating agent '${codeName}' to per-agent profile`);
|
|
6216
6483
|
if (adapter.seedProfileConfig) {
|
|
6217
6484
|
adapter.seedProfileConfig(codeName);
|
|
6218
6485
|
}
|
|
6219
|
-
const sharedAuthDir =
|
|
6220
|
-
const profileAuthDir =
|
|
6221
|
-
const authFile =
|
|
6222
|
-
if (
|
|
6486
|
+
const sharedAuthDir = join14(homeDir, ".openclaw", "agents", codeName, "agent");
|
|
6487
|
+
const profileAuthDir = join14(profileDir, "agents", codeName, "agent");
|
|
6488
|
+
const authFile = join14(sharedAuthDir, "auth-profiles.json");
|
|
6489
|
+
if (existsSync8(authFile)) {
|
|
6223
6490
|
mkdirSync4(profileAuthDir, { recursive: true });
|
|
6224
|
-
const authContent =
|
|
6225
|
-
writeFileSync4(
|
|
6491
|
+
const authContent = readFileSync12(authFile, "utf-8");
|
|
6492
|
+
writeFileSync4(join14(profileAuthDir, "auth-profiles.json"), authContent);
|
|
6226
6493
|
}
|
|
6227
6494
|
allocatePort(codeName);
|
|
6228
6495
|
migrated++;
|
|
@@ -6238,7 +6505,7 @@ function readGatewayToken(codeName) {
|
|
|
6238
6505
|
}
|
|
6239
6506
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6240
6507
|
try {
|
|
6241
|
-
const cfg = JSON.parse(
|
|
6508
|
+
const cfg = JSON.parse(readFileSync12(join14(homeDir, `.openclaw-${codeName}`, "openclaw.json"), "utf-8"));
|
|
6242
6509
|
return cfg?.gateway?.auth?.token;
|
|
6243
6510
|
} catch {
|
|
6244
6511
|
return void 0;
|
|
@@ -6247,10 +6514,10 @@ function readGatewayToken(codeName) {
|
|
|
6247
6514
|
var GATEWAY_HUNG_TIMEOUT_MS = 5 * 6e4;
|
|
6248
6515
|
function isGatewayHung(codeName) {
|
|
6249
6516
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6250
|
-
const jobsPath =
|
|
6251
|
-
if (!
|
|
6517
|
+
const jobsPath = join14(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
6518
|
+
if (!existsSync8(jobsPath)) return false;
|
|
6252
6519
|
try {
|
|
6253
|
-
const data = JSON.parse(
|
|
6520
|
+
const data = JSON.parse(readFileSync12(jobsPath, "utf-8"));
|
|
6254
6521
|
const jobs = data.jobs ?? data;
|
|
6255
6522
|
if (!Array.isArray(jobs)) return false;
|
|
6256
6523
|
const now = Date.now();
|
|
@@ -6283,15 +6550,15 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
6283
6550
|
}
|
|
6284
6551
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
6285
6552
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6286
|
-
const cronJobsPath =
|
|
6553
|
+
const cronJobsPath = join14(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
6287
6554
|
clearStaleCronRunState(cronJobsPath);
|
|
6288
6555
|
} else {
|
|
6289
6556
|
if (status.port) {
|
|
6290
6557
|
try {
|
|
6291
6558
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6292
|
-
const configPath =
|
|
6293
|
-
if (
|
|
6294
|
-
const cfg = JSON.parse(
|
|
6559
|
+
const configPath = join14(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
6560
|
+
if (existsSync8(configPath)) {
|
|
6561
|
+
const cfg = JSON.parse(readFileSync12(configPath, "utf-8"));
|
|
6295
6562
|
if (cfg.gateway?.port !== status.port) {
|
|
6296
6563
|
if (!cfg.gateway) cfg.gateway = {};
|
|
6297
6564
|
cfg.gateway.port = status.port;
|
|
@@ -6315,9 +6582,9 @@ async function ensureGatewayRunning(codeName, adapter) {
|
|
|
6315
6582
|
gatewaysStartedThisCycle.add(codeName);
|
|
6316
6583
|
try {
|
|
6317
6584
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
6318
|
-
const configPath =
|
|
6319
|
-
if (
|
|
6320
|
-
const cfg = JSON.parse(
|
|
6585
|
+
const configPath = join14(homeDir, `.openclaw-${codeName}`, "openclaw.json");
|
|
6586
|
+
if (existsSync8(configPath)) {
|
|
6587
|
+
const cfg = JSON.parse(readFileSync12(configPath, "utf-8"));
|
|
6321
6588
|
if (!cfg.gateway) cfg.gateway = {};
|
|
6322
6589
|
cfg.gateway.port = port;
|
|
6323
6590
|
writeFileSync4(configPath, JSON.stringify(cfg, null, 2));
|
|
@@ -6873,7 +7140,7 @@ async function pollCycle() {
|
|
|
6873
7140
|
}
|
|
6874
7141
|
killAgentChannelProcesses(prev.codeName, { log });
|
|
6875
7142
|
freePort(prev.codeName);
|
|
6876
|
-
const agentDir =
|
|
7143
|
+
const agentDir = join14(adapter.getAgentDir(prev.codeName), "provision");
|
|
6877
7144
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
6878
7145
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
6879
7146
|
}
|
|
@@ -6959,10 +7226,10 @@ async function pollCycle() {
|
|
|
6959
7226
|
// pending-inbound marker. Best-effort: a write failure is logged by
|
|
6960
7227
|
// the watchdog, never fails the poll cycle.
|
|
6961
7228
|
signalGiveUp: (codeName) => {
|
|
6962
|
-
const dir =
|
|
6963
|
-
if (!
|
|
7229
|
+
const dir = join14(homedir7(), ".augmented", codeName);
|
|
7230
|
+
if (!existsSync8(dir)) return;
|
|
6964
7231
|
atomicWriteFileSync(
|
|
6965
|
-
|
|
7232
|
+
join14(dir, "watchdog-give-up.json"),
|
|
6966
7233
|
JSON.stringify({ gave_up_at: (/* @__PURE__ */ new Date()).toISOString() })
|
|
6967
7234
|
);
|
|
6968
7235
|
}
|
|
@@ -7089,7 +7356,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7089
7356
|
}
|
|
7090
7357
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7091
7358
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
7092
|
-
let agentDir =
|
|
7359
|
+
let agentDir = join14(adapter.getAgentDir(agent.code_name), "provision");
|
|
7093
7360
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
7094
7361
|
if (previousKnownStatus !== agent.status) {
|
|
7095
7362
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
@@ -7141,7 +7408,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7141
7408
|
const residuals = {
|
|
7142
7409
|
gatewayRunning: gatewayLiveness.running,
|
|
7143
7410
|
portAllocated: Object.prototype.hasOwnProperty.call(ports, agent.code_name),
|
|
7144
|
-
provisionDirExists:
|
|
7411
|
+
provisionDirExists: existsSync8(agentDir)
|
|
7145
7412
|
};
|
|
7146
7413
|
if (!hasRevokedResiduals(residuals)) {
|
|
7147
7414
|
agentStates.push({
|
|
@@ -7293,7 +7560,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7293
7560
|
const frameworkId = refreshData.agent.framework ?? "openclaw";
|
|
7294
7561
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
7295
7562
|
const frameworkAdapter = getFramework(frameworkId);
|
|
7296
|
-
agentDir =
|
|
7563
|
+
agentDir = join14(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
7297
7564
|
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
7298
7565
|
if (frameworkAdapter.migrateSecretStorage && !migratedSecretStorage.has(agent.code_name)) {
|
|
7299
7566
|
try {
|
|
@@ -7336,7 +7603,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7336
7603
|
const changedFiles = [];
|
|
7337
7604
|
mkdirSync4(agentDir, { recursive: true });
|
|
7338
7605
|
for (const artifact of artifacts) {
|
|
7339
|
-
const filePath =
|
|
7606
|
+
const filePath = join14(agentDir, artifact.relativePath);
|
|
7340
7607
|
let existingHash;
|
|
7341
7608
|
let newHash;
|
|
7342
7609
|
let writeContent = artifact.content;
|
|
@@ -7355,8 +7622,8 @@ async function processAgent(agent, agentStates) {
|
|
|
7355
7622
|
};
|
|
7356
7623
|
newHash = sha256(stripDynamicSections(artifact.content));
|
|
7357
7624
|
try {
|
|
7358
|
-
const projectClaudeMd =
|
|
7359
|
-
const existing =
|
|
7625
|
+
const projectClaudeMd = join14(config.configDir, agent.code_name, "project", "CLAUDE.md");
|
|
7626
|
+
const existing = readFileSync12(projectClaudeMd, "utf-8");
|
|
7360
7627
|
existingHash = sha256(stripDynamicSections(existing));
|
|
7361
7628
|
} catch {
|
|
7362
7629
|
existingHash = null;
|
|
@@ -7374,7 +7641,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7374
7641
|
const generatorKeys = Object.keys(generatorServers);
|
|
7375
7642
|
let existingRaw = "";
|
|
7376
7643
|
try {
|
|
7377
|
-
existingRaw =
|
|
7644
|
+
existingRaw = readFileSync12(filePath, "utf-8");
|
|
7378
7645
|
} catch {
|
|
7379
7646
|
}
|
|
7380
7647
|
const existingServers = parseMcp(existingRaw);
|
|
@@ -7396,12 +7663,12 @@ async function processAgent(agent, agentStates) {
|
|
|
7396
7663
|
}
|
|
7397
7664
|
}
|
|
7398
7665
|
if (changedFiles.length > 0) {
|
|
7399
|
-
const isFirst = !
|
|
7666
|
+
const isFirst = !existsSync8(join14(agentDir, "CHARTER.md"));
|
|
7400
7667
|
const verb = isFirst ? "Provisioning" : "Updating";
|
|
7401
7668
|
const fileNames = changedFiles.map((f) => f.relativePath).join(", ");
|
|
7402
7669
|
log(`${verb} '${agent.code_name}': ${fileNames}`);
|
|
7403
7670
|
for (const file of changedFiles) {
|
|
7404
|
-
const filePath =
|
|
7671
|
+
const filePath = join14(agentDir, file.relativePath);
|
|
7405
7672
|
mkdirSync4(dirname3(filePath), { recursive: true });
|
|
7406
7673
|
if (file.relativePath === ".mcp.json") {
|
|
7407
7674
|
safeWriteJsonAtomic(filePath, file.content, { mode: 384 });
|
|
@@ -7410,12 +7677,12 @@ async function processAgent(agent, agentStates) {
|
|
|
7410
7677
|
}
|
|
7411
7678
|
}
|
|
7412
7679
|
try {
|
|
7413
|
-
const provSkillsDir =
|
|
7414
|
-
if (
|
|
7680
|
+
const provSkillsDir = join14(agentDir, ".claude", "skills");
|
|
7681
|
+
if (existsSync8(provSkillsDir)) {
|
|
7415
7682
|
for (const folder of readdirSync5(provSkillsDir)) {
|
|
7416
7683
|
if (folder.startsWith("knowledge-")) {
|
|
7417
7684
|
try {
|
|
7418
|
-
rmSync3(
|
|
7685
|
+
rmSync3(join14(provSkillsDir, folder), { recursive: true });
|
|
7419
7686
|
} catch {
|
|
7420
7687
|
}
|
|
7421
7688
|
}
|
|
@@ -7428,7 +7695,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7428
7695
|
const trackedFiles2 = frameworkAdapter.driftTrackedFiles();
|
|
7429
7696
|
const hashes = /* @__PURE__ */ new Map();
|
|
7430
7697
|
for (const file of trackedFiles2) {
|
|
7431
|
-
const h = hashFile(
|
|
7698
|
+
const h = hashFile(join14(agentDir, file));
|
|
7432
7699
|
if (h) hashes.set(file, h);
|
|
7433
7700
|
}
|
|
7434
7701
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -7446,14 +7713,14 @@ async function processAgent(agent, agentStates) {
|
|
|
7446
7713
|
}
|
|
7447
7714
|
if (Array.isArray(refreshData.workflows)) {
|
|
7448
7715
|
try {
|
|
7449
|
-
const provWorkflowsDir =
|
|
7450
|
-
if (
|
|
7716
|
+
const provWorkflowsDir = join14(agentDir, ".claude", "workflows");
|
|
7717
|
+
if (existsSync8(provWorkflowsDir)) {
|
|
7451
7718
|
const expected = new Set(refreshData.workflows.map((w) => `${w.name}.js`));
|
|
7452
7719
|
for (const file of readdirSync5(provWorkflowsDir)) {
|
|
7453
7720
|
if (!file.endsWith(".js")) continue;
|
|
7454
7721
|
if (expected.has(file)) continue;
|
|
7455
7722
|
try {
|
|
7456
|
-
rmSync3(
|
|
7723
|
+
rmSync3(join14(provWorkflowsDir, file));
|
|
7457
7724
|
} catch {
|
|
7458
7725
|
}
|
|
7459
7726
|
}
|
|
@@ -7510,10 +7777,10 @@ async function processAgent(agent, agentStates) {
|
|
|
7510
7777
|
}
|
|
7511
7778
|
let lastDriftCheckAt = now;
|
|
7512
7779
|
const written = agentState.writtenHashes.get(agent.agent_id);
|
|
7513
|
-
if (written &&
|
|
7780
|
+
if (written && existsSync8(agentDir)) {
|
|
7514
7781
|
const driftedFiles = [];
|
|
7515
7782
|
for (const [file, expectedHash] of written) {
|
|
7516
|
-
const localHash = hashFile(
|
|
7783
|
+
const localHash = hashFile(join14(agentDir, file));
|
|
7517
7784
|
if (localHash && localHash !== expectedHash) {
|
|
7518
7785
|
driftedFiles.push(file);
|
|
7519
7786
|
}
|
|
@@ -7524,7 +7791,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7524
7791
|
try {
|
|
7525
7792
|
const localHashes = {};
|
|
7526
7793
|
for (const file of driftedFiles) {
|
|
7527
|
-
localHashes[file] = hashFile(
|
|
7794
|
+
localHashes[file] = hashFile(join14(agentDir, file));
|
|
7528
7795
|
}
|
|
7529
7796
|
await api.post("/host/drift", {
|
|
7530
7797
|
agent_id: agent.agent_id,
|
|
@@ -7848,24 +8115,24 @@ async function processAgent(agent, agentStates) {
|
|
|
7848
8115
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
7849
8116
|
try {
|
|
7850
8117
|
const agentProvisionDir = agentDir;
|
|
7851
|
-
const projectDir =
|
|
8118
|
+
const projectDir = join14(homedir7(), ".augmented", agent.code_name, "project");
|
|
7852
8119
|
mkdirSync4(agentProvisionDir, { recursive: true });
|
|
7853
8120
|
mkdirSync4(projectDir, { recursive: true });
|
|
7854
|
-
const provisionMcpPath =
|
|
7855
|
-
const projectMcpPath =
|
|
8121
|
+
const provisionMcpPath = join14(agentProvisionDir, ".mcp.json");
|
|
8122
|
+
const projectMcpPath = join14(projectDir, ".mcp.json");
|
|
7856
8123
|
let mcpConfig = { mcpServers: {} };
|
|
7857
8124
|
try {
|
|
7858
|
-
mcpConfig = JSON.parse(
|
|
8125
|
+
mcpConfig = JSON.parse(readFileSync12(provisionMcpPath, "utf-8"));
|
|
7859
8126
|
if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
|
|
7860
8127
|
} catch {
|
|
7861
8128
|
}
|
|
7862
|
-
const localDirectChatChannel =
|
|
8129
|
+
const localDirectChatChannel = join14(homedir7(), ".augmented", "_mcp", "direct-chat-channel.js");
|
|
7863
8130
|
const directChatTeamSettings = refreshData.team?.settings;
|
|
7864
8131
|
const directChatTz = (() => {
|
|
7865
8132
|
const tz = directChatTeamSettings?.["timezone"];
|
|
7866
8133
|
return typeof tz === "string" && tz.trim() !== "" ? tz.trim() : void 0;
|
|
7867
8134
|
})();
|
|
7868
|
-
if (
|
|
8135
|
+
if (existsSync8(localDirectChatChannel)) {
|
|
7869
8136
|
const directChatEnv = {
|
|
7870
8137
|
AGT_HOST: requireHost(),
|
|
7871
8138
|
// ENG-5901 Track D: templated — the manager exports the real
|
|
@@ -7889,8 +8156,8 @@ async function processAgent(agent, agentStates) {
|
|
|
7889
8156
|
log(`Channel credentials written for '${agent.code_name}/direct-chat'`);
|
|
7890
8157
|
}
|
|
7891
8158
|
}
|
|
7892
|
-
const staleChannelsPath =
|
|
7893
|
-
if (
|
|
8159
|
+
const staleChannelsPath = join14(projectDir, ".mcp-channels.json");
|
|
8160
|
+
if (existsSync8(staleChannelsPath)) {
|
|
7894
8161
|
try {
|
|
7895
8162
|
rmSync3(staleChannelsPath, { force: true });
|
|
7896
8163
|
} catch {
|
|
@@ -7954,7 +8221,7 @@ async function processAgent(agent, agentStates) {
|
|
|
7954
8221
|
}
|
|
7955
8222
|
if (process.env.AGT_CONNECTIVITY_PROBE_ENABLED === "true") {
|
|
7956
8223
|
try {
|
|
7957
|
-
const probeProjectDir =
|
|
8224
|
+
const probeProjectDir = join14(homedir7(), ".augmented", agent.code_name, "project");
|
|
7958
8225
|
await runAgentConnectivityProbes(agent, integrations, probeProjectDir);
|
|
7959
8226
|
} catch (err) {
|
|
7960
8227
|
log(`Connectivity probe failed for '${agent.code_name}': ${err.message}`);
|
|
@@ -7972,11 +8239,11 @@ async function processAgent(agent, agentStates) {
|
|
|
7972
8239
|
recordConfigChurnEvent(agent.agent_id, agent.code_name, FLAP_CHANNEL_INTEGRATIONS, intMembership);
|
|
7973
8240
|
}
|
|
7974
8241
|
if (intHash !== prevIntHash) {
|
|
7975
|
-
const projectDir =
|
|
7976
|
-
const envIntPath =
|
|
8242
|
+
const projectDir = join14(homedir7(), ".augmented", agent.code_name, "project");
|
|
8243
|
+
const envIntPath = join14(projectDir, ".env.integrations");
|
|
7977
8244
|
let preWriteEnv;
|
|
7978
8245
|
try {
|
|
7979
|
-
preWriteEnv =
|
|
8246
|
+
preWriteEnv = readFileSync12(envIntPath, "utf-8");
|
|
7980
8247
|
} catch {
|
|
7981
8248
|
preWriteEnv = void 0;
|
|
7982
8249
|
}
|
|
@@ -7988,9 +8255,9 @@ async function processAgent(agent, agentStates) {
|
|
|
7988
8255
|
let rotationHandled = true;
|
|
7989
8256
|
if (fw === "claude-code" && isSessionHealthy(agent.code_name)) {
|
|
7990
8257
|
try {
|
|
7991
|
-
const projectMcpPath =
|
|
7992
|
-
const postWriteEnv =
|
|
7993
|
-
const mcpContent =
|
|
8258
|
+
const projectMcpPath = join14(projectDir, ".mcp.json");
|
|
8259
|
+
const postWriteEnv = readFileSync12(envIntPath, "utf-8");
|
|
8260
|
+
const mcpContent = readFileSync12(projectMcpPath, "utf-8");
|
|
7994
8261
|
const changedVars = diffEnvIntegrations(preWriteEnv, postWriteEnv);
|
|
7995
8262
|
const mcpJsonForReap = JSON.parse(mcpContent);
|
|
7996
8263
|
const affectedServerKeys = findMcpServersUsingVars(mcpJsonForReap, changedVars);
|
|
@@ -8070,8 +8337,8 @@ async function processAgent(agent, agentStates) {
|
|
|
8070
8337
|
const mcpPath = frameworkAdapter.getMcpPath(agent.code_name);
|
|
8071
8338
|
if (mcpPath) {
|
|
8072
8339
|
try {
|
|
8073
|
-
const { readFileSync:
|
|
8074
|
-
const mcpConfig = JSON.parse(
|
|
8340
|
+
const { readFileSync: readFileSync13 } = await import("fs");
|
|
8341
|
+
const mcpConfig = JSON.parse(readFileSync13(mcpPath, "utf-8"));
|
|
8075
8342
|
if (mcpConfig.mcpServers) {
|
|
8076
8343
|
const managedPrefixes = [
|
|
8077
8344
|
"composio_",
|
|
@@ -8172,8 +8439,8 @@ async function processAgent(agent, agentStates) {
|
|
|
8172
8439
|
if (agent.status === "active") {
|
|
8173
8440
|
if (frameworkAdapter.installPlugin) {
|
|
8174
8441
|
try {
|
|
8175
|
-
const pluginPath =
|
|
8176
|
-
if (
|
|
8442
|
+
const pluginPath = join14(process.cwd(), "packages", "openclaw-plugin-augmented", "src", "index.ts");
|
|
8443
|
+
if (existsSync8(pluginPath)) {
|
|
8177
8444
|
frameworkAdapter.installPlugin(agent.code_name, "augmented", pluginPath, {
|
|
8178
8445
|
agtHost: requireHost(),
|
|
8179
8446
|
agtApiKey: getApiKey() ?? void 0,
|
|
@@ -8243,16 +8510,16 @@ async function processAgent(agent, agentStates) {
|
|
|
8243
8510
|
const frameworkId2 = frameworkAdapter.id;
|
|
8244
8511
|
const candidateSkillDirs = [
|
|
8245
8512
|
// Claude Code — framework runtime tree
|
|
8246
|
-
|
|
8513
|
+
join14(homedir8(), ".augmented", agent.code_name, "skills"),
|
|
8247
8514
|
// Claude Code — project tree
|
|
8248
|
-
|
|
8515
|
+
join14(homedir8(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
8249
8516
|
// OpenClaw — framework runtime tree
|
|
8250
|
-
|
|
8517
|
+
join14(homedir8(), `.openclaw-${agent.code_name}`, "skills"),
|
|
8251
8518
|
// Defensive: legacy provision-side path, not currently an
|
|
8252
8519
|
// install target but cheap to sweep.
|
|
8253
|
-
|
|
8520
|
+
join14(agentDir, ".claude", "skills")
|
|
8254
8521
|
];
|
|
8255
|
-
const existingDirs = candidateSkillDirs.filter((d) =>
|
|
8522
|
+
const existingDirs = candidateSkillDirs.filter((d) => existsSync8(d));
|
|
8256
8523
|
const discoveredEntries = /* @__PURE__ */ new Set();
|
|
8257
8524
|
for (const dir of existingDirs) {
|
|
8258
8525
|
try {
|
|
@@ -8266,8 +8533,8 @@ async function processAgent(agent, agentStates) {
|
|
|
8266
8533
|
}
|
|
8267
8534
|
const removeSkillFolder = (entry, reason) => {
|
|
8268
8535
|
for (const dir of existingDirs) {
|
|
8269
|
-
const p =
|
|
8270
|
-
if (
|
|
8536
|
+
const p = join14(dir, entry);
|
|
8537
|
+
if (existsSync8(p)) {
|
|
8271
8538
|
rmSync4(p, { recursive: true, force: true });
|
|
8272
8539
|
}
|
|
8273
8540
|
}
|
|
@@ -8297,15 +8564,15 @@ async function processAgent(agent, agentStates) {
|
|
|
8297
8564
|
const { rmSync: rmSync4 } = await import("fs");
|
|
8298
8565
|
const { homedir: homedir8 } = await import("os");
|
|
8299
8566
|
const globalSkillDirs = [
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8567
|
+
join14(homedir8(), ".augmented", agent.code_name, "skills"),
|
|
8568
|
+
join14(homedir8(), ".augmented", agent.code_name, "project", ".claude", "skills"),
|
|
8569
|
+
join14(homedir8(), `.openclaw-${agent.code_name}`, "skills"),
|
|
8570
|
+
join14(agentDir, ".claude", "skills")
|
|
8304
8571
|
];
|
|
8305
8572
|
for (const id of plan.removes) {
|
|
8306
8573
|
for (const dir of globalSkillDirs) {
|
|
8307
|
-
const p =
|
|
8308
|
-
if (
|
|
8574
|
+
const p = join14(dir, id);
|
|
8575
|
+
if (existsSync8(p)) rmSync4(p, { recursive: true, force: true });
|
|
8309
8576
|
}
|
|
8310
8577
|
agentState.knownSkillHashes.delete(`global-skill:${agent.agent_id}:${id}`);
|
|
8311
8578
|
log(`Removed unpublished global skill '${id}' for '${agent.code_name}'`);
|
|
@@ -8480,8 +8747,8 @@ async function processAgent(agent, agentStates) {
|
|
|
8480
8747
|
const sess = getSessionState(agent.code_name);
|
|
8481
8748
|
let mcpJsonParsed = null;
|
|
8482
8749
|
try {
|
|
8483
|
-
const mcpPath =
|
|
8484
|
-
mcpJsonParsed = JSON.parse(
|
|
8750
|
+
const mcpPath = join14(getProjectDir(agent.code_name), ".mcp.json");
|
|
8751
|
+
mcpJsonParsed = JSON.parse(readFileSync12(mcpPath, "utf-8"));
|
|
8485
8752
|
} catch {
|
|
8486
8753
|
}
|
|
8487
8754
|
reapMissingMcpSessions({
|
|
@@ -8690,10 +8957,10 @@ async function processAgent(agent, agentStates) {
|
|
|
8690
8957
|
lastWorkTriggerAt.set(agent.code_name, triggerTs);
|
|
8691
8958
|
if (agentFw === "openclaw" && gatewayRunning && gatewayPort) {
|
|
8692
8959
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
8693
|
-
const jobsPath =
|
|
8694
|
-
if (
|
|
8960
|
+
const jobsPath = join14(homeDir, `.openclaw-${agent.code_name}`, "cron", "jobs.json");
|
|
8961
|
+
if (existsSync8(jobsPath)) {
|
|
8695
8962
|
try {
|
|
8696
|
-
const jobsData = JSON.parse(
|
|
8963
|
+
const jobsData = JSON.parse(readFileSync12(jobsPath, "utf-8"));
|
|
8697
8964
|
const kanbanJob = (jobsData.jobs ?? []).find(
|
|
8698
8965
|
(j) => typeof j.name === "string" && j.name.includes("kanban-work")
|
|
8699
8966
|
);
|
|
@@ -8827,10 +9094,10 @@ In progress for ${age} minutes \u2014 auto-failed`).catch(() => {
|
|
|
8827
9094
|
}
|
|
8828
9095
|
}
|
|
8829
9096
|
const trackedFiles = frameworkAdapter.driftTrackedFiles();
|
|
8830
|
-
if (trackedFiles.length > 0 &&
|
|
9097
|
+
if (trackedFiles.length > 0 && existsSync8(agentDir)) {
|
|
8831
9098
|
const hashes = /* @__PURE__ */ new Map();
|
|
8832
9099
|
for (const file of trackedFiles) {
|
|
8833
|
-
const h = hashFile(
|
|
9100
|
+
const h = hashFile(join14(agentDir, file));
|
|
8834
9101
|
if (h) hashes.set(file, h);
|
|
8835
9102
|
}
|
|
8836
9103
|
agentState.writtenHashes.set(agent.agent_id, hashes);
|
|
@@ -8864,19 +9131,19 @@ function cleanupStaleSessions(codeName) {
|
|
|
8864
9131
|
lastCleanupAt.set(codeName, Date.now());
|
|
8865
9132
|
const homeDir = process.env["HOME"] ?? "/tmp";
|
|
8866
9133
|
for (const agentDir of ["main", codeName]) {
|
|
8867
|
-
const sessionsDir =
|
|
9134
|
+
const sessionsDir = join14(homeDir, `.openclaw-${codeName}`, "agents", agentDir, "sessions");
|
|
8868
9135
|
cleanupCronSessions(sessionsDir, CRON_SESSION_KEEP_COUNT);
|
|
8869
9136
|
}
|
|
8870
|
-
const cronRunsDir =
|
|
9137
|
+
const cronRunsDir = join14(homeDir, `.openclaw-${codeName}`, "cron", "runs");
|
|
8871
9138
|
cleanupOldFiles(cronRunsDir, CRON_RUN_RETENTION_DAYS, ".jsonl");
|
|
8872
|
-
const cronJobsPath =
|
|
9139
|
+
const cronJobsPath = join14(homeDir, `.openclaw-${codeName}`, "cron", "jobs.json");
|
|
8873
9140
|
clearStaleCronRunState(cronJobsPath);
|
|
8874
9141
|
}
|
|
8875
9142
|
function cleanupCronSessions(sessionsDir, keepCount) {
|
|
8876
|
-
const indexPath =
|
|
8877
|
-
if (!
|
|
9143
|
+
const indexPath = join14(sessionsDir, "sessions.json");
|
|
9144
|
+
if (!existsSync8(indexPath)) return;
|
|
8878
9145
|
try {
|
|
8879
|
-
const raw =
|
|
9146
|
+
const raw = readFileSync12(indexPath, "utf-8");
|
|
8880
9147
|
const index = JSON.parse(raw);
|
|
8881
9148
|
const cronRunKeys = Object.keys(index).filter((k) => k.includes(":cron:") && k.includes(":run:")).map((k) => ({
|
|
8882
9149
|
key: k,
|
|
@@ -8889,9 +9156,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
8889
9156
|
for (const entry of toDelete) {
|
|
8890
9157
|
delete index[entry.key];
|
|
8891
9158
|
if (entry.sessionId) {
|
|
8892
|
-
const sessionFile =
|
|
9159
|
+
const sessionFile = join14(sessionsDir, `${entry.sessionId}.jsonl`);
|
|
8893
9160
|
try {
|
|
8894
|
-
if (
|
|
9161
|
+
if (existsSync8(sessionFile)) {
|
|
8895
9162
|
unlinkSync(sessionFile);
|
|
8896
9163
|
deletedFiles++;
|
|
8897
9164
|
}
|
|
@@ -8911,8 +9178,8 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
8911
9178
|
delete index[parentKey];
|
|
8912
9179
|
if (parentSessionId) {
|
|
8913
9180
|
try {
|
|
8914
|
-
const f =
|
|
8915
|
-
if (
|
|
9181
|
+
const f = join14(sessionsDir, `${parentSessionId}.jsonl`);
|
|
9182
|
+
if (existsSync8(f)) {
|
|
8916
9183
|
unlinkSync(f);
|
|
8917
9184
|
deletedFiles++;
|
|
8918
9185
|
}
|
|
@@ -8930,9 +9197,9 @@ function cleanupCronSessions(sessionsDir, keepCount) {
|
|
|
8930
9197
|
}
|
|
8931
9198
|
var STALE_RUN_TIMEOUT_MS = 5 * 6e4;
|
|
8932
9199
|
function clearStaleCronRunState(jobsPath) {
|
|
8933
|
-
if (!
|
|
9200
|
+
if (!existsSync8(jobsPath)) return;
|
|
8934
9201
|
try {
|
|
8935
|
-
const raw =
|
|
9202
|
+
const raw = readFileSync12(jobsPath, "utf-8");
|
|
8936
9203
|
const data = JSON.parse(raw);
|
|
8937
9204
|
const jobs = data.jobs ?? data;
|
|
8938
9205
|
if (!Array.isArray(jobs)) return;
|
|
@@ -8963,13 +9230,13 @@ function clearStaleCronRunState(jobsPath) {
|
|
|
8963
9230
|
}
|
|
8964
9231
|
}
|
|
8965
9232
|
function cleanupOldFiles(dir, maxAgeDays, ext) {
|
|
8966
|
-
if (!
|
|
9233
|
+
if (!existsSync8(dir)) return;
|
|
8967
9234
|
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
8968
9235
|
let removed = 0;
|
|
8969
9236
|
try {
|
|
8970
9237
|
for (const f of readdirSync5(dir)) {
|
|
8971
9238
|
if (!f.endsWith(ext)) continue;
|
|
8972
|
-
const fullPath =
|
|
9239
|
+
const fullPath = join14(dir, f);
|
|
8973
9240
|
try {
|
|
8974
9241
|
const st = statSync4(fullPath);
|
|
8975
9242
|
if (st.mtimeMs < cutoff) {
|
|
@@ -9009,7 +9276,7 @@ var inFlightClaudeTasks = /* @__PURE__ */ new Set();
|
|
|
9009
9276
|
var claudeTaskConcurrency = /* @__PURE__ */ new Map();
|
|
9010
9277
|
var MAX_CLAUDE_CONCURRENCY = 2;
|
|
9011
9278
|
function claudePidFilePath() {
|
|
9012
|
-
return
|
|
9279
|
+
return join14(homedir7(), ".augmented", "manager-claude-pids.json");
|
|
9013
9280
|
}
|
|
9014
9281
|
var inFlightClaudePids = /* @__PURE__ */ new Map();
|
|
9015
9282
|
function registerClaudeSpawn(record) {
|
|
@@ -9349,7 +9616,7 @@ async function fireScheduledTaskViaKanban(codeName, agentId, task, prompt) {
|
|
|
9349
9616
|
}
|
|
9350
9617
|
async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
9351
9618
|
const projectDir = getProjectDir2(codeName);
|
|
9352
|
-
const mcpConfigPath =
|
|
9619
|
+
const mcpConfigPath = join14(projectDir, ".mcp.json");
|
|
9353
9620
|
let runId = null;
|
|
9354
9621
|
let kanbanItemId = null;
|
|
9355
9622
|
let taskResult;
|
|
@@ -9357,11 +9624,11 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
9357
9624
|
const priorRuns = await fetchPriorScheduledRuns(agentId, task.taskId);
|
|
9358
9625
|
prompt = wrapScheduledTaskPrompt(prompt, { priorRuns });
|
|
9359
9626
|
try {
|
|
9360
|
-
const claudeMdPath =
|
|
9627
|
+
const claudeMdPath = join14(projectDir, "CLAUDE.md");
|
|
9361
9628
|
const serverNames = [];
|
|
9362
|
-
if (
|
|
9629
|
+
if (existsSync8(mcpConfigPath)) {
|
|
9363
9630
|
try {
|
|
9364
|
-
const d = JSON.parse(
|
|
9631
|
+
const d = JSON.parse(readFileSync12(mcpConfigPath, "utf-8"));
|
|
9365
9632
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
9366
9633
|
} catch {
|
|
9367
9634
|
}
|
|
@@ -9380,14 +9647,14 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
9380
9647
|
"--allowedTools",
|
|
9381
9648
|
allowedTools
|
|
9382
9649
|
];
|
|
9383
|
-
if (
|
|
9650
|
+
if (existsSync8(claudeMdPath)) {
|
|
9384
9651
|
claudeArgs.push("--system-prompt-file", claudeMdPath);
|
|
9385
9652
|
}
|
|
9386
9653
|
const childEnv = { ...process.env };
|
|
9387
|
-
const envIntPath =
|
|
9388
|
-
if (
|
|
9654
|
+
const envIntPath = join14(projectDir, ".env.integrations");
|
|
9655
|
+
if (existsSync8(envIntPath)) {
|
|
9389
9656
|
try {
|
|
9390
|
-
Object.assign(childEnv, parseEnvIntegrations(
|
|
9657
|
+
Object.assign(childEnv, parseEnvIntegrations(readFileSync12(envIntPath, "utf-8")));
|
|
9391
9658
|
} catch {
|
|
9392
9659
|
}
|
|
9393
9660
|
}
|
|
@@ -9559,8 +9826,8 @@ var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
|
|
|
9559
9826
|
async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
|
|
9560
9827
|
const codeName = agent.code_name;
|
|
9561
9828
|
const projectDir = getProjectDir(codeName);
|
|
9562
|
-
const mcpConfigPath =
|
|
9563
|
-
const claudeMdPath =
|
|
9829
|
+
const mcpConfigPath = join14(projectDir, ".mcp.json");
|
|
9830
|
+
const claudeMdPath = join14(projectDir, "CLAUDE.md");
|
|
9564
9831
|
if (restartBreaker.isTripped(codeName)) {
|
|
9565
9832
|
const trip = restartBreaker.getTrip(codeName);
|
|
9566
9833
|
return {
|
|
@@ -10205,11 +10472,11 @@ ${escapeXml(msg.content)}
|
|
|
10205
10472
|
log(`[direct-chat] One-shot spawn for '${agent.codeName}' (msg=${msg.id}; host in-flight=${directChatSpawnGate.hostInFlight}, queued=${directChatSpawnGate.queuedCount})`);
|
|
10206
10473
|
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
|
|
10207
10474
|
const projDir = ccProjectDir(agent.codeName);
|
|
10208
|
-
const mcpConfigPath =
|
|
10475
|
+
const mcpConfigPath = join14(projDir, ".mcp.json");
|
|
10209
10476
|
const serverNames = [];
|
|
10210
|
-
if (
|
|
10477
|
+
if (existsSync8(mcpConfigPath)) {
|
|
10211
10478
|
try {
|
|
10212
|
-
const d = JSON.parse(
|
|
10479
|
+
const d = JSON.parse(readFileSync12(mcpConfigPath, "utf-8"));
|
|
10213
10480
|
if (d.mcpServers) serverNames.push(...Object.keys(d.mcpServers));
|
|
10214
10481
|
} catch {
|
|
10215
10482
|
}
|
|
@@ -10228,15 +10495,15 @@ ${escapeXml(msg.content)}
|
|
|
10228
10495
|
"--allowedTools",
|
|
10229
10496
|
allowedTools
|
|
10230
10497
|
];
|
|
10231
|
-
const chatClaudeMd =
|
|
10232
|
-
if (
|
|
10498
|
+
const chatClaudeMd = join14(projDir, "CLAUDE.md");
|
|
10499
|
+
if (existsSync8(chatClaudeMd)) {
|
|
10233
10500
|
chatArgs.push("--system-prompt-file", chatClaudeMd);
|
|
10234
10501
|
}
|
|
10235
|
-
const envIntPath =
|
|
10502
|
+
const envIntPath = join14(projDir, ".env.integrations");
|
|
10236
10503
|
const childEnv = { ...process.env };
|
|
10237
|
-
if (
|
|
10504
|
+
if (existsSync8(envIntPath)) {
|
|
10238
10505
|
try {
|
|
10239
|
-
Object.assign(childEnv, parseEnvIntegrations(
|
|
10506
|
+
Object.assign(childEnv, parseEnvIntegrations(readFileSync12(envIntPath, "utf-8")));
|
|
10240
10507
|
} catch {
|
|
10241
10508
|
}
|
|
10242
10509
|
}
|
|
@@ -10291,51 +10558,27 @@ ${escapeXml(msg.content)}
|
|
|
10291
10558
|
await api.post("/host/direct-chat/reply", {
|
|
10292
10559
|
agent_id: agent.agentId,
|
|
10293
10560
|
session_id: msg.session_id,
|
|
10294
|
-
content: reply
|
|
10295
|
-
});
|
|
10296
|
-
log(`[direct-chat] Reply sent for '${agent.codeName}'`);
|
|
10297
|
-
} catch (err) {
|
|
10298
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
10299
|
-
const errorId = createHash4("sha256").update(errMsg).digest("hex").slice(0, 12);
|
|
10300
|
-
log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId} error=${errMsg.slice(0, 500)}`);
|
|
10301
|
-
try {
|
|
10302
|
-
await api.post("/host/direct-chat/reply", {
|
|
10303
|
-
agent_id: agent.agentId,
|
|
10304
|
-
session_id: msg.session_id,
|
|
10305
|
-
content: `[Error] Failed to process message (ref: ${errorId}). Please retry.`
|
|
10306
|
-
});
|
|
10307
|
-
} catch {
|
|
10308
|
-
}
|
|
10309
|
-
} finally {
|
|
10310
|
-
releaseSpawnSlot?.();
|
|
10311
|
-
}
|
|
10312
|
-
}
|
|
10313
|
-
var STANDUP_TEMPLATES = /* @__PURE__ */ new Set(["daily-standup", "end-of-day-summary"]);
|
|
10314
|
-
var TASK_UPDATE_TEMPLATES = /* @__PURE__ */ new Set(["hourly-status", "task-update"]);
|
|
10315
|
-
var PLAN_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan"]);
|
|
10316
|
-
var KANBAN_WORK_TEMPLATES = /* @__PURE__ */ new Set(["kanban-work"]);
|
|
10317
|
-
function isPlainScheduledTemplate(templateId) {
|
|
10318
|
-
return !STANDUP_TEMPLATES.has(templateId) && !TASK_UPDATE_TEMPLATES.has(templateId) && !PLAN_TEMPLATES.has(templateId) && !KANBAN_WORK_TEMPLATES.has(templateId);
|
|
10319
|
-
}
|
|
10320
|
-
function isKanbanHybridEnabled() {
|
|
10321
|
-
return true;
|
|
10322
|
-
}
|
|
10323
|
-
function isKanbanHybridDryRun() {
|
|
10324
|
-
const v = process.env["AGT_KANBAN_HYBRID_DRY_RUN"];
|
|
10325
|
-
return v === "1" || v?.toLowerCase() === "true";
|
|
10326
|
-
}
|
|
10327
|
-
var HYBRID_ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
10328
|
-
function isHybridActionable(item) {
|
|
10329
|
-
return HYBRID_ACTIONABLE_STATUSES.has(item.status) && item.source_type !== "scheduled_task";
|
|
10330
|
-
}
|
|
10331
|
-
function hasHybridActionableItems(items) {
|
|
10332
|
-
return items.some(isHybridActionable);
|
|
10561
|
+
content: reply
|
|
10562
|
+
});
|
|
10563
|
+
log(`[direct-chat] Reply sent for '${agent.codeName}'`);
|
|
10564
|
+
} catch (err) {
|
|
10565
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
10566
|
+
const errorId = createHash4("sha256").update(errMsg).digest("hex").slice(0, 12);
|
|
10567
|
+
log(`[direct-chat] Failed to process message for '${agent.codeName}': error_id=${errorId} error=${errMsg.slice(0, 500)}`);
|
|
10568
|
+
try {
|
|
10569
|
+
await api.post("/host/direct-chat/reply", {
|
|
10570
|
+
agent_id: agent.agentId,
|
|
10571
|
+
session_id: msg.session_id,
|
|
10572
|
+
content: `[Error] Failed to process message (ref: ${errorId}). Please retry.`
|
|
10573
|
+
});
|
|
10574
|
+
} catch {
|
|
10575
|
+
}
|
|
10576
|
+
} finally {
|
|
10577
|
+
releaseSpawnSlot?.();
|
|
10578
|
+
}
|
|
10333
10579
|
}
|
|
10334
10580
|
var lastKanbanInjectAt = /* @__PURE__ */ new Map();
|
|
10335
10581
|
var openInjectedRunByCode = /* @__PURE__ */ new Map();
|
|
10336
|
-
function isSlashCommand(command) {
|
|
10337
|
-
return command.trimStart().startsWith("/");
|
|
10338
|
-
}
|
|
10339
10582
|
function closeInjectedRunIfOpen(codeName, outcome, outcomeMessage) {
|
|
10340
10583
|
const runId = openInjectedRunByCode.get(codeName);
|
|
10341
10584
|
if (!runId) return;
|
|
@@ -10393,11 +10636,6 @@ ${formatRunMarker(run_id)}` : KANBAN_CHECK_COMMAND;
|
|
|
10393
10636
|
log(`[manager-worker] kanban inject failed for '${codeName}'`);
|
|
10394
10637
|
}
|
|
10395
10638
|
}
|
|
10396
|
-
var BOARD_INJECT_TEMPLATES = /* @__PURE__ */ new Set(["morning-plan", "task-update", "hourly-status", "end-of-day-summary"]);
|
|
10397
|
-
var ACTIONABLE_STATUSES = /* @__PURE__ */ new Set(["todo", "in_progress"]);
|
|
10398
|
-
function hasActionableItems(items) {
|
|
10399
|
-
return items.some((item) => ACTIONABLE_STATUSES.has(item.status));
|
|
10400
|
-
}
|
|
10401
10639
|
var lastHarvestAt = /* @__PURE__ */ new Map();
|
|
10402
10640
|
var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
|
|
10403
10641
|
var kanbanBoardCache = /* @__PURE__ */ new Map();
|
|
@@ -10517,247 +10755,6 @@ async function harvestCronResults(codeName, tasks, gatewayPort) {
|
|
|
10517
10755
|
}
|
|
10518
10756
|
}
|
|
10519
10757
|
}
|
|
10520
|
-
function parseStandupSummary(summary) {
|
|
10521
|
-
const lines = summary.split("\n");
|
|
10522
|
-
let yesterday = "";
|
|
10523
|
-
let today = "";
|
|
10524
|
-
let blockers = "";
|
|
10525
|
-
let currentSection = null;
|
|
10526
|
-
for (const line of lines) {
|
|
10527
|
-
const lower = line.toLowerCase();
|
|
10528
|
-
if (lower.includes("yesterday") || lower.includes("accomplished")) {
|
|
10529
|
-
currentSection = "yesterday";
|
|
10530
|
-
continue;
|
|
10531
|
-
} else if (lower.includes("todo") || lower.includes("working on")) {
|
|
10532
|
-
currentSection = "todo";
|
|
10533
|
-
continue;
|
|
10534
|
-
} else if (lower.includes("blocker")) {
|
|
10535
|
-
currentSection = "blockers";
|
|
10536
|
-
continue;
|
|
10537
|
-
}
|
|
10538
|
-
const trimmed = line.replace(/^[-*•]\s*/, "").trim();
|
|
10539
|
-
if (!trimmed) continue;
|
|
10540
|
-
switch (currentSection) {
|
|
10541
|
-
case "yesterday":
|
|
10542
|
-
yesterday += (yesterday ? "\n" : "") + trimmed;
|
|
10543
|
-
break;
|
|
10544
|
-
case "todo":
|
|
10545
|
-
today += (today ? "\n" : "") + trimmed;
|
|
10546
|
-
break;
|
|
10547
|
-
case "blockers":
|
|
10548
|
-
blockers += (blockers ? "\n" : "") + trimmed;
|
|
10549
|
-
break;
|
|
10550
|
-
}
|
|
10551
|
-
}
|
|
10552
|
-
if (!yesterday && !today && !blockers) {
|
|
10553
|
-
today = summary;
|
|
10554
|
-
}
|
|
10555
|
-
return { yesterday, today, blockers };
|
|
10556
|
-
}
|
|
10557
|
-
function parsePlanItems(summary) {
|
|
10558
|
-
const items = [];
|
|
10559
|
-
const lines = summary.split("\n");
|
|
10560
|
-
let currentItem = null;
|
|
10561
|
-
for (const line of lines) {
|
|
10562
|
-
const trimmed = line.trim();
|
|
10563
|
-
const itemMatch = trimmed.match(/^(?:\d+[\.\)]\s*|[-*•]\s*)\[?(HIGH|MEDIUM|LOW|MED)\]?\s*(.+)/i);
|
|
10564
|
-
if (itemMatch) {
|
|
10565
|
-
if (currentItem) items.push(currentItem);
|
|
10566
|
-
const priorityStr = itemMatch[1].toUpperCase();
|
|
10567
|
-
const rest = itemMatch[2];
|
|
10568
|
-
let estimatedMinutes;
|
|
10569
|
-
const timeMatch = rest.match(/\(~?(\d+)\s*(min(?:utes?)?|hr?(?:ours?)?|h)\)/i);
|
|
10570
|
-
if (timeMatch) {
|
|
10571
|
-
const val = parseInt(timeMatch[1], 10);
|
|
10572
|
-
const unit = timeMatch[2].toLowerCase();
|
|
10573
|
-
estimatedMinutes = unit.startsWith("h") ? val * 60 : val;
|
|
10574
|
-
}
|
|
10575
|
-
const title = sanitizeKanbanString(
|
|
10576
|
-
rest.replace(/\(~?\d+\s*(?:min(?:utes?)?|hr?(?:ours?)?|h)\)/i, ""),
|
|
10577
|
-
MAX_KANBAN_TITLE_LENGTH
|
|
10578
|
-
);
|
|
10579
|
-
if (!title) continue;
|
|
10580
|
-
const priorityMap = { HIGH: 1, MEDIUM: 2, MED: 2, LOW: 3 };
|
|
10581
|
-
const priority = priorityMap[priorityStr] ?? 2;
|
|
10582
|
-
if (![1, 2, 3].includes(priority)) continue;
|
|
10583
|
-
currentItem = {
|
|
10584
|
-
title,
|
|
10585
|
-
priority,
|
|
10586
|
-
estimated_minutes: estimatedMinutes,
|
|
10587
|
-
status: "todo"
|
|
10588
|
-
};
|
|
10589
|
-
} else if (currentItem && trimmed && !trimmed.match(/^(?:PLAN|---)/i)) {
|
|
10590
|
-
const descLine = sanitizeKanbanString(trimmed, MAX_KANBAN_NOTES_LENGTH);
|
|
10591
|
-
currentItem.description = currentItem.description ? sanitizeKanbanString(currentItem.description + "\n" + descLine, MAX_KANBAN_NOTES_LENGTH) : descLine;
|
|
10592
|
-
}
|
|
10593
|
-
}
|
|
10594
|
-
if (currentItem) items.push(currentItem);
|
|
10595
|
-
return items;
|
|
10596
|
-
}
|
|
10597
|
-
var VALID_KANBAN_STATUSES = /* @__PURE__ */ new Set(["backlog", "todo", "in_progress", "done"]);
|
|
10598
|
-
var MAX_KANBAN_TITLE_LENGTH = 500;
|
|
10599
|
-
var MAX_KANBAN_NOTES_LENGTH = 2e3;
|
|
10600
|
-
function sanitizeKanbanString(value, maxLen) {
|
|
10601
|
-
if (!value) return "";
|
|
10602
|
-
return value.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "").replace(/\{\{.*?\}\}/g, "").replace(/^(System|Assistant|Human):\s*/gmi, "").replace(/#{2,}/g, "").replace(/\s+/g, " ").trim().slice(0, maxLen);
|
|
10603
|
-
}
|
|
10604
|
-
function sanitizeBoardItem(item) {
|
|
10605
|
-
return {
|
|
10606
|
-
...item,
|
|
10607
|
-
title: sanitizeKanbanString(item.title, 200),
|
|
10608
|
-
status: sanitizeKanbanString(item.status, 50),
|
|
10609
|
-
...item.deliverable ? { deliverable: sanitizeKanbanString(item.deliverable, 500) } : {}
|
|
10610
|
-
};
|
|
10611
|
-
}
|
|
10612
|
-
var builtInSkillCache = /* @__PURE__ */ new Map();
|
|
10613
|
-
function getBuiltInSkillContent(skillId) {
|
|
10614
|
-
if (builtInSkillCache.has(skillId)) return builtInSkillCache.get(skillId);
|
|
10615
|
-
try {
|
|
10616
|
-
const candidates = [
|
|
10617
|
-
join13(process.cwd(), "skills", skillId, "SKILL.md"),
|
|
10618
|
-
join13(new URL(".", import.meta.url).pathname, "..", "..", "..", "..", "skills", skillId, "SKILL.md")
|
|
10619
|
-
];
|
|
10620
|
-
for (const candidate of candidates) {
|
|
10621
|
-
if (existsSync7(candidate)) {
|
|
10622
|
-
const content = readFileSync11(candidate, "utf-8");
|
|
10623
|
-
const files = [{ relativePath: "SKILL.md", content }];
|
|
10624
|
-
builtInSkillCache.set(skillId, files);
|
|
10625
|
-
return files;
|
|
10626
|
-
}
|
|
10627
|
-
}
|
|
10628
|
-
builtInSkillCache.set(skillId, null);
|
|
10629
|
-
return null;
|
|
10630
|
-
} catch {
|
|
10631
|
-
builtInSkillCache.set(skillId, null);
|
|
10632
|
-
return null;
|
|
10633
|
-
}
|
|
10634
|
-
}
|
|
10635
|
-
function parseKanbanUpdates(summary) {
|
|
10636
|
-
const updates = [];
|
|
10637
|
-
const kanbanIdx = summary.indexOf("KANBAN UPDATE:");
|
|
10638
|
-
if (kanbanIdx === -1) return updates;
|
|
10639
|
-
const kanbanSection = summary.slice(kanbanIdx + "KANBAN UPDATE:".length);
|
|
10640
|
-
const lines = kanbanSection.split("\n");
|
|
10641
|
-
for (const line of lines) {
|
|
10642
|
-
const trimmed = line.trim();
|
|
10643
|
-
const match = trimmed.match(/^[-*•]\s*"([^"]+)":\s*(backlog|todo|today|in_progress|done)(?:\s*\((.+)\))?/i);
|
|
10644
|
-
if (match) {
|
|
10645
|
-
const rawStatus = match[2].toLowerCase();
|
|
10646
|
-
const status = rawStatus === "today" ? "todo" : rawStatus;
|
|
10647
|
-
if (!VALID_KANBAN_STATUSES.has(status)) continue;
|
|
10648
|
-
const title = sanitizeKanbanString(match[1], MAX_KANBAN_TITLE_LENGTH);
|
|
10649
|
-
if (!title) continue;
|
|
10650
|
-
const parenthetical = match[3] ?? void 0;
|
|
10651
|
-
let notes;
|
|
10652
|
-
let result;
|
|
10653
|
-
if (parenthetical && status === "done") {
|
|
10654
|
-
const resultMatch = parenthetical.match(/^result:\s*(.+)/i);
|
|
10655
|
-
if (resultMatch) {
|
|
10656
|
-
result = sanitizeKanbanString(resultMatch[1], MAX_KANBAN_NOTES_LENGTH);
|
|
10657
|
-
} else {
|
|
10658
|
-
notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);
|
|
10659
|
-
}
|
|
10660
|
-
} else if (parenthetical) {
|
|
10661
|
-
notes = sanitizeKanbanString(parenthetical, MAX_KANBAN_NOTES_LENGTH);
|
|
10662
|
-
}
|
|
10663
|
-
updates.push({
|
|
10664
|
-
title,
|
|
10665
|
-
status,
|
|
10666
|
-
notes,
|
|
10667
|
-
result
|
|
10668
|
-
});
|
|
10669
|
-
}
|
|
10670
|
-
}
|
|
10671
|
-
return updates;
|
|
10672
|
-
}
|
|
10673
|
-
function formatBoardForPrompt(items, template) {
|
|
10674
|
-
if (items.length === 0) return "";
|
|
10675
|
-
const priorityLabel = (p) => p === 1 ? "HIGH" : p === 3 ? "LOW" : "MED";
|
|
10676
|
-
const timeLabel = (m) => m ? ` (~${m >= 60 ? `${Math.round(m / 60)}hr` : `${m}min`})` : "";
|
|
10677
|
-
const deliverableLine = (d) => d ? `
|
|
10678
|
-
Deliverable: ${d}` : "";
|
|
10679
|
-
const sourceLine = (channel, thread, url) => {
|
|
10680
|
-
const parts = [];
|
|
10681
|
-
if (channel && thread) parts.push(`${channel} thread ${thread}`);
|
|
10682
|
-
if (url) parts.push(url);
|
|
10683
|
-
return parts.length > 0 ? `
|
|
10684
|
-
source: ${parts.join(" \u2022 ")}` : "";
|
|
10685
|
-
};
|
|
10686
|
-
const grouped = {};
|
|
10687
|
-
for (const item of items) {
|
|
10688
|
-
const key = item.status;
|
|
10689
|
-
if (!grouped[key]) grouped[key] = [];
|
|
10690
|
-
grouped[key].push(item);
|
|
10691
|
-
}
|
|
10692
|
-
const hasSourceThread = items.some(
|
|
10693
|
-
(i) => (i.status === "todo" || i.status === "in_progress") && !!i.source_integration && !!i.source_external_id
|
|
10694
|
-
);
|
|
10695
|
-
const lines = [];
|
|
10696
|
-
if (template === "morning-plan") {
|
|
10697
|
-
lines.push("=== CURRENT BOARD ===");
|
|
10698
|
-
for (const [status, label] of [["backlog", "BACKLOG (carry-over)"], ["todo", "TO DO"], ["in_progress", "IN PROGRESS"]]) {
|
|
10699
|
-
const statusItems = grouped[status];
|
|
10700
|
-
if (statusItems && statusItems.length > 0) {
|
|
10701
|
-
lines.push(`${label}:`);
|
|
10702
|
-
statusItems.forEach((item, i) => {
|
|
10703
|
-
lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}${sourceLine(item.source_integration, item.source_external_id, item.source_url)}`);
|
|
10704
|
-
});
|
|
10705
|
-
}
|
|
10706
|
-
}
|
|
10707
|
-
lines.push("=====================");
|
|
10708
|
-
lines.push("");
|
|
10709
|
-
lines.push("Create today's plan. You may:");
|
|
10710
|
-
lines.push('- Move backlog items to "todo"');
|
|
10711
|
-
lines.push("- Add new items you've identified");
|
|
10712
|
-
lines.push("- Reprioritise existing items");
|
|
10713
|
-
lines.push("");
|
|
10714
|
-
} else {
|
|
10715
|
-
lines.push("=== YOUR KANBAN BOARD ===");
|
|
10716
|
-
for (const [status, label] of [["todo", "TO DO"], ["in_progress", "IN PROGRESS"], ["backlog", "BACKLOG"]]) {
|
|
10717
|
-
const statusItems = grouped[status];
|
|
10718
|
-
if (statusItems && statusItems.length > 0) {
|
|
10719
|
-
lines.push(`${label}:`);
|
|
10720
|
-
statusItems.forEach((item, i) => {
|
|
10721
|
-
lines.push(` ${i + 1}. [${priorityLabel(item.priority)}] ${item.title}${timeLabel(item.estimated_minutes)}${deliverableLine(item.deliverable)}${sourceLine(item.source_integration, item.source_external_id, item.source_url)}`);
|
|
10722
|
-
});
|
|
10723
|
-
}
|
|
10724
|
-
}
|
|
10725
|
-
const doneItems = grouped["done"];
|
|
10726
|
-
if (doneItems && doneItems.length > 0) {
|
|
10727
|
-
lines.push("DONE TODAY:");
|
|
10728
|
-
doneItems.forEach((item, i) => {
|
|
10729
|
-
lines.push(` ${i + 1}. ${item.title}`);
|
|
10730
|
-
});
|
|
10731
|
-
}
|
|
10732
|
-
lines.push("=========================");
|
|
10733
|
-
lines.push("");
|
|
10734
|
-
lines.push("IMPORTANT: Use kanban MCP tools to update the board IN REAL TIME:");
|
|
10735
|
-
lines.push("1. FIRST call kanban_move to move your chosen item to in_progress BEFORE starting work");
|
|
10736
|
-
lines.push("2. Do the work");
|
|
10737
|
-
lines.push("3. Call kanban_done with a result summary when finished");
|
|
10738
|
-
lines.push("4. If blocked, call kanban_update with notes, then pick the next item");
|
|
10739
|
-
lines.push("");
|
|
10740
|
-
if (hasSourceThread) {
|
|
10741
|
-
lines.push("THREAD CONTINUITY: If a card shows a `source:` line, the request originated");
|
|
10742
|
-
lines.push("in that Slack/Telegram thread. When you deliver the result, reply in that");
|
|
10743
|
-
lines.push("thread (not the default channel) so the user sees the answer where they");
|
|
10744
|
-
lines.push("asked. The card's `source_channel` + `source_thread_id` are the thread");
|
|
10745
|
-
lines.push("coordinates to use.");
|
|
10746
|
-
lines.push("");
|
|
10747
|
-
}
|
|
10748
|
-
lines.push("SELF-MANAGEMENT: When you receive a request from a channel (Slack, Telegram)");
|
|
10749
|
-
lines.push("that takes more than a quick response, create a task first with kanban_add,");
|
|
10750
|
-
lines.push("move to in_progress, do the work, then kanban_done with a result summary.");
|
|
10751
|
-
lines.push("");
|
|
10752
|
-
lines.push("If MCP tools are unavailable, include a KANBAN UPDATE section in your output:");
|
|
10753
|
-
lines.push("KANBAN UPDATE:");
|
|
10754
|
-
lines.push('- "item title": new_status (optional notes)');
|
|
10755
|
-
lines.push('- "item title": done (result: <what you produced>)');
|
|
10756
|
-
lines.push("Statuses: backlog, today, in_progress, done");
|
|
10757
|
-
lines.push("");
|
|
10758
|
-
}
|
|
10759
|
-
return lines.join("\n");
|
|
10760
|
-
}
|
|
10761
10758
|
var LATE_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
10762
10759
|
async function monitorCronHealth(agentStates) {
|
|
10763
10760
|
const alerts = [];
|
|
@@ -11521,8 +11518,8 @@ function parseMemoryFile(raw, fallbackName) {
|
|
|
11521
11518
|
};
|
|
11522
11519
|
}
|
|
11523
11520
|
async function syncMemories(agent, configDir, log2) {
|
|
11524
|
-
const projectDir =
|
|
11525
|
-
const memoryDir =
|
|
11521
|
+
const projectDir = join14(configDir, agent.code_name, "project");
|
|
11522
|
+
const memoryDir = join14(projectDir, "memory");
|
|
11526
11523
|
const isFreshSync = pendingFreshMemorySync.has(agent.agent_id);
|
|
11527
11524
|
if (isFreshSync) {
|
|
11528
11525
|
log2(`[memory-sync] Fresh-sync requested for '${agent.code_name}' \u2014 pulling DB first`);
|
|
@@ -11533,14 +11530,14 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
11533
11530
|
}
|
|
11534
11531
|
pendingFreshMemorySync.delete(agent.agent_id);
|
|
11535
11532
|
}
|
|
11536
|
-
if (
|
|
11533
|
+
if (existsSync8(memoryDir)) {
|
|
11537
11534
|
const prevHashes = memoryFileHashes.get(agent.agent_id) ?? /* @__PURE__ */ new Map();
|
|
11538
11535
|
const currentHashes = /* @__PURE__ */ new Map();
|
|
11539
11536
|
const changedMemories = [];
|
|
11540
11537
|
for (const file of readdirSync5(memoryDir)) {
|
|
11541
11538
|
if (!file.endsWith(".md")) continue;
|
|
11542
11539
|
try {
|
|
11543
|
-
const raw =
|
|
11540
|
+
const raw = readFileSync12(join14(memoryDir, file), "utf-8");
|
|
11544
11541
|
const fileHash = createHash4("sha256").update(raw).digest("hex").slice(0, 16);
|
|
11545
11542
|
currentHashes.set(file, fileHash);
|
|
11546
11543
|
if (prevHashes.get(file) === fileHash) continue;
|
|
@@ -11565,7 +11562,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
11565
11562
|
} catch (err) {
|
|
11566
11563
|
for (const mem of changedMemories) {
|
|
11567
11564
|
for (const [file] of currentHashes) {
|
|
11568
|
-
const parsed = parseMemoryFile(
|
|
11565
|
+
const parsed = parseMemoryFile(readFileSync12(join14(memoryDir, file), "utf-8"), file.replace(/\.md$/, ""));
|
|
11569
11566
|
if (parsed?.name === mem.name) currentHashes.delete(file);
|
|
11570
11567
|
}
|
|
11571
11568
|
}
|
|
@@ -11578,7 +11575,7 @@ async function syncMemories(agent, configDir, log2) {
|
|
|
11578
11575
|
}
|
|
11579
11576
|
}
|
|
11580
11577
|
async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
11581
|
-
const localFiles =
|
|
11578
|
+
const localFiles = existsSync8(memoryDir) ? readdirSync5(memoryDir).filter((f) => f.endsWith(".md")).sort() : [];
|
|
11582
11579
|
const localListHash = createHash4("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
|
|
11583
11580
|
const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
|
|
11584
11581
|
const prevDownload = lastDownloadHash.get(agent.agent_id);
|
|
@@ -11600,7 +11597,7 @@ async function downloadMemories(agent, memoryDir, log2, { force }) {
|
|
|
11600
11597
|
const mem = dbMemories.memories[i];
|
|
11601
11598
|
const rawSlug = mem.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "").slice(0, 60);
|
|
11602
11599
|
const slug = rawSlug || `memory-${i}`;
|
|
11603
|
-
const filePath =
|
|
11600
|
+
const filePath = join14(memoryDir, `${slug}.md`);
|
|
11604
11601
|
const desired = `---
|
|
11605
11602
|
name: ${JSON.stringify(mem.name)}
|
|
11606
11603
|
type: ${mem.type}
|
|
@@ -11609,10 +11606,10 @@ description: ${JSON.stringify(mem.content.slice(0, 200))}
|
|
|
11609
11606
|
|
|
11610
11607
|
${mem.content}
|
|
11611
11608
|
`;
|
|
11612
|
-
if (
|
|
11609
|
+
if (existsSync8(filePath)) {
|
|
11613
11610
|
let existing = "";
|
|
11614
11611
|
try {
|
|
11615
|
-
existing =
|
|
11612
|
+
existing = readFileSync12(filePath, "utf-8");
|
|
11616
11613
|
} catch {
|
|
11617
11614
|
}
|
|
11618
11615
|
if (existing === desired) continue;
|
|
@@ -11636,7 +11633,7 @@ ${mem.content}
|
|
|
11636
11633
|
}
|
|
11637
11634
|
}
|
|
11638
11635
|
async function cleanupAgentFiles(codeName, agentDir) {
|
|
11639
|
-
if (
|
|
11636
|
+
if (existsSync8(agentDir)) {
|
|
11640
11637
|
try {
|
|
11641
11638
|
rmSync3(agentDir, { recursive: true, force: true });
|
|
11642
11639
|
log(`Removed provision directory for '${codeName}'`);
|
|
@@ -11886,8 +11883,8 @@ function startManager(opts) {
|
|
|
11886
11883
|
config = opts;
|
|
11887
11884
|
try {
|
|
11888
11885
|
const stateFile = getStateFile();
|
|
11889
|
-
if (
|
|
11890
|
-
const raw =
|
|
11886
|
+
if (existsSync8(stateFile)) {
|
|
11887
|
+
const raw = readFileSync12(stateFile, "utf-8");
|
|
11891
11888
|
const parsed = JSON.parse(raw);
|
|
11892
11889
|
if (Array.isArray(parsed.agents)) {
|
|
11893
11890
|
state6.agents = parsed.agents;
|
|
@@ -11908,7 +11905,7 @@ function startManager(opts) {
|
|
|
11908
11905
|
log(`[startup] state rehydration failed (continuing with empty state): ${err.message}`);
|
|
11909
11906
|
}
|
|
11910
11907
|
log(
|
|
11911
|
-
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${
|
|
11908
|
+
`[startup] worker pid=${process.pid} ppid=${process.ppid} node=${process.version} log=${join14(homedir7(), ".augmented", "manager.log")}`
|
|
11912
11909
|
);
|
|
11913
11910
|
deployMcpAssets();
|
|
11914
11911
|
reapOrphanChannelMcps({ log });
|
|
@@ -11929,7 +11926,7 @@ async function reapOrphanedClaudePids() {
|
|
|
11929
11926
|
const looksLikeClaude = (pid) => {
|
|
11930
11927
|
if (process.platform !== "linux") return true;
|
|
11931
11928
|
try {
|
|
11932
|
-
const comm =
|
|
11929
|
+
const comm = readFileSync12(`/proc/${pid}/comm`, "utf-8").trim().toLowerCase();
|
|
11933
11930
|
return comm.includes("claude");
|
|
11934
11931
|
} catch {
|
|
11935
11932
|
return false;
|
|
@@ -12039,14 +12036,14 @@ function restartRunningChannelMcps(basenames) {
|
|
|
12039
12036
|
}
|
|
12040
12037
|
}
|
|
12041
12038
|
function deployMcpAssets() {
|
|
12042
|
-
const targetDir =
|
|
12039
|
+
const targetDir = join14(homedir7(), ".augmented", "_mcp");
|
|
12043
12040
|
mkdirSync4(targetDir, { recursive: true });
|
|
12044
12041
|
const moduleDir = dirname3(fileURLToPath(import.meta.url));
|
|
12045
12042
|
let mcpSourceDir = "";
|
|
12046
12043
|
let dir = moduleDir;
|
|
12047
12044
|
for (let i = 0; i < 6; i++) {
|
|
12048
|
-
const candidate =
|
|
12049
|
-
if (
|
|
12045
|
+
const candidate = join14(dir, "dist", "mcp");
|
|
12046
|
+
if (existsSync8(join14(candidate, "index.js"))) {
|
|
12050
12047
|
mcpSourceDir = candidate;
|
|
12051
12048
|
break;
|
|
12052
12049
|
}
|
|
@@ -12061,8 +12058,8 @@ function deployMcpAssets() {
|
|
|
12061
12058
|
const changedBasenames = [];
|
|
12062
12059
|
const fileHash = (p) => {
|
|
12063
12060
|
try {
|
|
12064
|
-
if (!
|
|
12065
|
-
return createHash4("sha256").update(
|
|
12061
|
+
if (!existsSync8(p)) return null;
|
|
12062
|
+
return createHash4("sha256").update(readFileSync12(p)).digest("hex");
|
|
12066
12063
|
} catch {
|
|
12067
12064
|
return null;
|
|
12068
12065
|
}
|
|
@@ -12089,9 +12086,9 @@ function deployMcpAssets() {
|
|
|
12089
12086
|
// natural session restart.
|
|
12090
12087
|
"augmented-admin.js"
|
|
12091
12088
|
]) {
|
|
12092
|
-
const src =
|
|
12093
|
-
const dst =
|
|
12094
|
-
if (!
|
|
12089
|
+
const src = join14(mcpSourceDir, file);
|
|
12090
|
+
const dst = join14(targetDir, file);
|
|
12091
|
+
if (!existsSync8(src)) continue;
|
|
12095
12092
|
const before = fileHash(dst);
|
|
12096
12093
|
try {
|
|
12097
12094
|
copyFileSync(src, dst);
|
|
@@ -12108,16 +12105,16 @@ function deployMcpAssets() {
|
|
|
12108
12105
|
log(`[manager] Bundle(s) updated: ${changedBasenames.join(", ")} \u2014 signalling running instances to restart`);
|
|
12109
12106
|
restartRunningChannelMcps(changedBasenames);
|
|
12110
12107
|
}
|
|
12111
|
-
const localMcpPath =
|
|
12108
|
+
const localMcpPath = join14(targetDir, "index.js");
|
|
12112
12109
|
try {
|
|
12113
|
-
const agentsDir =
|
|
12114
|
-
if (
|
|
12110
|
+
const agentsDir = join14(homedir7(), ".augmented", "agents");
|
|
12111
|
+
if (existsSync8(agentsDir)) {
|
|
12115
12112
|
for (const entry of readdirSync5(agentsDir, { withFileTypes: true })) {
|
|
12116
12113
|
if (!entry.isDirectory()) continue;
|
|
12117
12114
|
for (const subdir of ["provision", "project"]) {
|
|
12118
|
-
const mcpJsonPath =
|
|
12115
|
+
const mcpJsonPath = join14(agentsDir, entry.name, subdir, ".mcp.json");
|
|
12119
12116
|
try {
|
|
12120
|
-
const raw =
|
|
12117
|
+
const raw = readFileSync12(mcpJsonPath, "utf-8");
|
|
12121
12118
|
if (!raw.includes("@integrity-labs/augmented-mcp")) continue;
|
|
12122
12119
|
const mcpConfig = JSON.parse(raw);
|
|
12123
12120
|
const augServer = mcpConfig.mcpServers?.["augmented"];
|
|
@@ -12177,15 +12174,8 @@ export {
|
|
|
12177
12174
|
extractCharterSlackPeers,
|
|
12178
12175
|
extractCharterTelegramPeers,
|
|
12179
12176
|
fireScheduledTaskViaKanban,
|
|
12180
|
-
formatBoardForPrompt,
|
|
12181
|
-
hasActionableItems,
|
|
12182
|
-
hasHybridActionableItems,
|
|
12183
12177
|
hasRevokedResiduals,
|
|
12184
|
-
isHybridActionable,
|
|
12185
|
-
isKanbanHybridDryRun,
|
|
12186
|
-
isKanbanHybridEnabled,
|
|
12187
12178
|
isOlderSemverTuple,
|
|
12188
|
-
isPlainScheduledTemplate,
|
|
12189
12179
|
isPrereleaseVersion,
|
|
12190
12180
|
isScheduledCardTracked,
|
|
12191
12181
|
isScheduledViaKanbanEnabled,
|