@integrity-labs/agt-cli 0.11.0 → 0.12.2
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 +6 -4
- package/dist/bin/agt.js.map +1 -1
- package/dist/{chunk-QU7FBXH3.js → chunk-M6FSTVGG.js} +2 -2
- package/dist/chunk-M6FSTVGG.js.map +1 -0
- package/dist/{chunk-WTMVQND4.js → chunk-S5VHDDAJ.js} +576 -232
- package/dist/chunk-S5VHDDAJ.js.map +1 -0
- package/dist/{claude-scheduler-7PVWQHWU.js → claude-scheduler-CLSMSF5W.js} +2 -2
- package/dist/lib/manager-worker.js +340 -23
- package/dist/lib/manager-worker.js.map +1 -1
- package/mcp/index.js +23 -3
- package/mcp/slack-channel.js +59 -4
- package/package.json +1 -1
- package/dist/chunk-QU7FBXH3.js.map +0 -1
- package/dist/chunk-WTMVQND4.js.map +0 -1
- /package/dist/{claude-scheduler-7PVWQHWU.js.map → claude-scheduler-CLSMSF5W.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
markTaskFired,
|
|
8
8
|
saveSchedulerState,
|
|
9
9
|
syncTasksToScheduler
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-M6FSTVGG.js";
|
|
11
11
|
export {
|
|
12
12
|
computeNextFire,
|
|
13
13
|
findTaskByTemplate,
|
|
@@ -18,4 +18,4 @@ export {
|
|
|
18
18
|
saveSchedulerState,
|
|
19
19
|
syncTasksToScheduler
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=claude-scheduler-
|
|
21
|
+
//# sourceMappingURL=claude-scheduler-CLSMSF5W.js.map
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
api,
|
|
3
|
+
appendDmFooter,
|
|
3
4
|
exchangeApiKey,
|
|
4
5
|
extractFrontmatter,
|
|
5
6
|
getApiKey,
|
|
6
7
|
getFramework,
|
|
7
8
|
getHostId,
|
|
9
|
+
getIntegration,
|
|
10
|
+
isParseError,
|
|
11
|
+
isResolveError,
|
|
12
|
+
parseDeliveryTarget,
|
|
8
13
|
provision,
|
|
9
14
|
provisionIsolationHook,
|
|
10
15
|
provisionStopHook,
|
|
11
16
|
requireHost,
|
|
12
|
-
resolveChannels
|
|
13
|
-
|
|
17
|
+
resolveChannels,
|
|
18
|
+
resolveDmTarget
|
|
19
|
+
} from "../chunk-S5VHDDAJ.js";
|
|
14
20
|
import {
|
|
15
21
|
findTaskByTemplate,
|
|
16
22
|
getProjectDir,
|
|
@@ -18,7 +24,7 @@ import {
|
|
|
18
24
|
loadSchedulerState,
|
|
19
25
|
markTaskFired,
|
|
20
26
|
syncTasksToScheduler
|
|
21
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-M6FSTVGG.js";
|
|
22
28
|
import {
|
|
23
29
|
getProjectDir as getProjectDir2,
|
|
24
30
|
injectMessage,
|
|
@@ -814,6 +820,91 @@ function resolveBrewPath(execFileSync) {
|
|
|
814
820
|
if (existsSync(fallback)) return fallback;
|
|
815
821
|
return null;
|
|
816
822
|
}
|
|
823
|
+
var toolkitCliEnsured = /* @__PURE__ */ new Set();
|
|
824
|
+
var toolkitCliRetryAfter = /* @__PURE__ */ new Map();
|
|
825
|
+
var TOOLKIT_INSTALL_RETRY_MS = 5 * 6e4;
|
|
826
|
+
async function ensureToolkitCli(toolkitSlug) {
|
|
827
|
+
if (toolkitCliEnsured.has(toolkitSlug)) return;
|
|
828
|
+
const retryAfter = toolkitCliRetryAfter.get(toolkitSlug) ?? 0;
|
|
829
|
+
if (retryAfter > Date.now()) return;
|
|
830
|
+
const integration = getIntegration(toolkitSlug);
|
|
831
|
+
if (!integration?.cli_tool) {
|
|
832
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
833
|
+
return;
|
|
834
|
+
}
|
|
835
|
+
const { binary, installer, package: pkg, script } = integration.cli_tool;
|
|
836
|
+
const resolvedInstaller = installer ?? "manual";
|
|
837
|
+
const { execFileSync, execSync } = await import("child_process");
|
|
838
|
+
try {
|
|
839
|
+
execFileSync("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
840
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
841
|
+
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
842
|
+
return;
|
|
843
|
+
} catch {
|
|
844
|
+
}
|
|
845
|
+
if (resolvedInstaller === "manual") {
|
|
846
|
+
log(`[toolkit-install] ${toolkitSlug}: binary '${binary}' missing, installer=manual \u2014 operator must install`);
|
|
847
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
let brewBinDir = null;
|
|
851
|
+
try {
|
|
852
|
+
if (resolvedInstaller === "npm") {
|
|
853
|
+
if (!pkg) {
|
|
854
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=npm but no package declared`);
|
|
855
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
log(`[toolkit-install] ${toolkitSlug}: installing via npm (${pkg})\u2026`);
|
|
859
|
+
execFileSync("npm", ["install", "-g", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
860
|
+
} else if (resolvedInstaller === "brew") {
|
|
861
|
+
if (!pkg) {
|
|
862
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=brew but no package declared`);
|
|
863
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
const brewPath = resolveBrewPath(execFileSync);
|
|
867
|
+
if (!brewPath) {
|
|
868
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=brew but Homebrew not available \u2014 install manually: brew install ${pkg}`);
|
|
869
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
brewBinDir = dirname(brewPath);
|
|
873
|
+
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
874
|
+
log(`[toolkit-install] ${toolkitSlug}: installing via brew (${pkg})\u2026`);
|
|
875
|
+
if (isRoot) {
|
|
876
|
+
execFileSync("sudo", ["-u", "ec2-user", "-H", brewPath, "install", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
877
|
+
} else {
|
|
878
|
+
execFileSync(brewPath, ["install", pkg], { timeout: 18e4, stdio: "pipe" });
|
|
879
|
+
}
|
|
880
|
+
} else if (resolvedInstaller === "script") {
|
|
881
|
+
if (!script) {
|
|
882
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=script but no script declared`);
|
|
883
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
log(`[toolkit-install] ${toolkitSlug}: running declared install script\u2026`);
|
|
887
|
+
execSync(script, { timeout: 18e4, stdio: "pipe" });
|
|
888
|
+
}
|
|
889
|
+
} catch (err) {
|
|
890
|
+
const msg = err.message.slice(0, 200);
|
|
891
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=${resolvedInstaller} failed \u2014 ${msg} (retrying in ${TOOLKIT_INSTALL_RETRY_MS / 6e4}m)`);
|
|
892
|
+
toolkitCliRetryAfter.set(toolkitSlug, Date.now() + TOOLKIT_INSTALL_RETRY_MS);
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (brewBinDir && !process.env.PATH?.split(":").includes(brewBinDir)) {
|
|
896
|
+
process.env.PATH = `${brewBinDir}:${process.env.PATH ?? ""}`;
|
|
897
|
+
}
|
|
898
|
+
try {
|
|
899
|
+
execFileSync("which", [binary], { timeout: 5e3, stdio: "pipe" });
|
|
900
|
+
log(`[toolkit-install] ${toolkitSlug}: installed \u2014 ${binary} now on PATH`);
|
|
901
|
+
toolkitCliEnsured.add(toolkitSlug);
|
|
902
|
+
toolkitCliRetryAfter.delete(toolkitSlug);
|
|
903
|
+
} catch {
|
|
904
|
+
log(`[toolkit-install] ${toolkitSlug}: installer=${resolvedInstaller} completed but ${binary} still not on PATH (retrying in ${TOOLKIT_INSTALL_RETRY_MS / 6e4}m)`);
|
|
905
|
+
toolkitCliRetryAfter.set(toolkitSlug, Date.now() + TOOLKIT_INSTALL_RETRY_MS);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
817
908
|
async function ensureFrameworkBinary(frameworkId) {
|
|
818
909
|
if (frameworkId !== "claude-code") return;
|
|
819
910
|
if (frameworkBinaryChecked.has(frameworkId)) return;
|
|
@@ -1459,7 +1550,7 @@ async function pollCycle() {
|
|
|
1459
1550
|
const adapter = resolveAgentFramework(prev.codeName);
|
|
1460
1551
|
await stopGatewayIfRunning(prev.codeName, adapter);
|
|
1461
1552
|
freePort(prev.codeName);
|
|
1462
|
-
const agentDir = join2(
|
|
1553
|
+
const agentDir = join2(adapter.getAgentDir(prev.codeName), "provision");
|
|
1463
1554
|
await cleanupAgentFiles(prev.codeName, agentDir);
|
|
1464
1555
|
clearAgentCaches(prev.agentId, prev.codeName);
|
|
1465
1556
|
}
|
|
@@ -1527,8 +1618,8 @@ async function processAgent(agent, agentStates) {
|
|
|
1527
1618
|
agentFrameworkCache.set(agent.code_name, agent.framework);
|
|
1528
1619
|
}
|
|
1529
1620
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1530
|
-
const agentDir = join2(config.configDir, agent.code_name, "provision");
|
|
1531
1621
|
const adapter = resolveAgentFramework(agent.code_name);
|
|
1622
|
+
let agentDir = join2(adapter.getAgentDir(agent.code_name), "provision");
|
|
1532
1623
|
if (agent.status === "draft" || agent.status === "paused") {
|
|
1533
1624
|
log(`Agent '${agent.code_name}' is ${agent.status}, skipping provisioning`);
|
|
1534
1625
|
await stopGatewayIfRunning(agent.code_name, adapter);
|
|
@@ -1652,6 +1743,8 @@ async function processAgent(agent, agentStates) {
|
|
|
1652
1743
|
const frameworkId = refreshData.agent.framework ?? "openclaw";
|
|
1653
1744
|
agentFrameworkCache.set(agent.code_name, frameworkId);
|
|
1654
1745
|
const frameworkAdapter = getFramework(frameworkId);
|
|
1746
|
+
agentDir = join2(frameworkAdapter.getAgentDir(agent.code_name), "provision");
|
|
1747
|
+
cacheAgentDeliveryMetadata(agent.code_name, refreshData);
|
|
1655
1748
|
if (frameworkAdapter.seedProfileConfig) {
|
|
1656
1749
|
frameworkAdapter.seedProfileConfig(agent.code_name);
|
|
1657
1750
|
}
|
|
@@ -1896,7 +1989,7 @@ async function processAgent(agent, agentStates) {
|
|
|
1896
1989
|
const agentSessionMode = refreshData.agent.session_mode;
|
|
1897
1990
|
if (agentSessionMode === "persistent" && (agentFrameworkCache.get(agent.code_name) ?? "openclaw") === "claude-code") {
|
|
1898
1991
|
try {
|
|
1899
|
-
const agentProvisionDir =
|
|
1992
|
+
const agentProvisionDir = agentDir;
|
|
1900
1993
|
const projectDir = join2(homedir2(), ".augmented", agent.code_name, "project");
|
|
1901
1994
|
mkdirSync(agentProvisionDir, { recursive: true });
|
|
1902
1995
|
mkdirSync(projectDir, { recursive: true });
|
|
@@ -2025,8 +2118,7 @@ async function processAgent(agent, agentStates) {
|
|
|
2025
2118
|
try {
|
|
2026
2119
|
const { readFileSync: readFileSync2 } = await import("fs");
|
|
2027
2120
|
const { join: join3 } = await import("path");
|
|
2028
|
-
const
|
|
2029
|
-
const mcpPath = join3(homedir3(), ".augmented", "agents", agent.code_name, "provision", ".mcp.json");
|
|
2121
|
+
const mcpPath = join3(frameworkAdapter.getAgentDir(agent.code_name), "provision", ".mcp.json");
|
|
2030
2122
|
const mcpConfig = JSON.parse(readFileSync2(mcpPath, "utf-8"));
|
|
2031
2123
|
if (mcpConfig.mcpServers) {
|
|
2032
2124
|
const managedPrefixes = [
|
|
@@ -2228,6 +2320,16 @@ async function processAgent(agent, agentStates) {
|
|
|
2228
2320
|
}
|
|
2229
2321
|
}
|
|
2230
2322
|
}
|
|
2323
|
+
const agentFwForToolkits = agentFrameworkCache.get(agent.code_name) ?? "openclaw";
|
|
2324
|
+
if (agentFwForToolkits === "claude-code" && refreshData.plugin_toolkits?.length) {
|
|
2325
|
+
const toolkitUnion = /* @__PURE__ */ new Set();
|
|
2326
|
+
for (const { toolkits } of refreshData.plugin_toolkits) {
|
|
2327
|
+
for (const t of toolkits) toolkitUnion.add(t);
|
|
2328
|
+
}
|
|
2329
|
+
for (const toolkitSlug of toolkitUnion) {
|
|
2330
|
+
await ensureToolkitCli(toolkitSlug);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2231
2333
|
const agentFw2 = agentFrameworkCache.get(agent.code_name) ?? "openclaw";
|
|
2232
2334
|
if (agentFw2 === "claude-code" && installedPluginSkills.length > 0 && isSessionHealthy(agent.code_name)) {
|
|
2233
2335
|
const names = installedPluginSkills.join(", ");
|
|
@@ -2754,7 +2856,8 @@ async function executeAndProcessClaudeTask(codeName, agentId, task, prompt) {
|
|
|
2754
2856
|
await processClaudeTaskResult(codeName, agentId, task.templateId, output, {
|
|
2755
2857
|
mode: task.deliveryMode,
|
|
2756
2858
|
channel: task.deliveryChannel,
|
|
2757
|
-
to: task.deliveryTo
|
|
2859
|
+
to: task.deliveryTo,
|
|
2860
|
+
taskId: task.taskId
|
|
2758
2861
|
});
|
|
2759
2862
|
const updated = markTaskFired(codeName, task.taskId, "ok");
|
|
2760
2863
|
claudeSchedulerStates.set(codeName, updated);
|
|
@@ -2814,8 +2917,14 @@ async function processClaudeTaskResult(codeName, agentId, templateId, output, de
|
|
|
2814
2917
|
log(`[claude-scheduler] Kanban updates posted for '${codeName}' (${kanbanUpdates.length} updates)`);
|
|
2815
2918
|
}
|
|
2816
2919
|
}
|
|
2817
|
-
if (delivery?.mode === "announce" && delivery.
|
|
2818
|
-
await
|
|
2920
|
+
if (delivery?.mode === "announce" && delivery.to && output) {
|
|
2921
|
+
await deliverScheduledTaskOutput(
|
|
2922
|
+
codeName,
|
|
2923
|
+
agentId,
|
|
2924
|
+
delivery.to,
|
|
2925
|
+
output.slice(0, 4e3),
|
|
2926
|
+
delivery.taskId
|
|
2927
|
+
);
|
|
2819
2928
|
}
|
|
2820
2929
|
} catch (err) {
|
|
2821
2930
|
log(`[claude-scheduler] Failed to post result for '${codeName}': ${err.message}`);
|
|
@@ -3281,7 +3390,7 @@ async function processDirectChatMessage(agent, msg) {
|
|
|
3281
3390
|
try {
|
|
3282
3391
|
let reply;
|
|
3283
3392
|
if (fw === "claude-code") {
|
|
3284
|
-
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-
|
|
3393
|
+
const { getProjectDir: ccProjectDir } = await import("../claude-scheduler-CLSMSF5W.js");
|
|
3285
3394
|
const projDir = ccProjectDir(agent.codeName);
|
|
3286
3395
|
const mcpConfigPath = join2(projDir, ".mcp.json");
|
|
3287
3396
|
const serverNames = [];
|
|
@@ -3944,41 +4053,249 @@ ${a.detail}`;
|
|
|
3944
4053
|
|
|
3945
4054
|
${blocks.join("\n\n")}`);
|
|
3946
4055
|
}
|
|
4056
|
+
async function deliverScheduledTaskOutput(agentCodeName, agentId, rawTarget, body, taskId) {
|
|
4057
|
+
if (typeof rawTarget === "string") {
|
|
4058
|
+
if (rawTarget.startsWith("channel:")) {
|
|
4059
|
+
const result = await sendTaskNotification(agentCodeName, "slack", rawTarget, body);
|
|
4060
|
+
await reportDeliveryStatus(agentId, taskId, {
|
|
4061
|
+
status: result.ok ? "ok" : "failed",
|
|
4062
|
+
medium: "slack",
|
|
4063
|
+
error_code: result.ok ? null : result.error_code ?? "SLACK_SEND_FAILED"
|
|
4064
|
+
});
|
|
4065
|
+
return;
|
|
4066
|
+
}
|
|
4067
|
+
if (rawTarget.startsWith("chat:")) {
|
|
4068
|
+
const result = await sendTaskNotification(agentCodeName, "telegram", rawTarget, body);
|
|
4069
|
+
await reportDeliveryStatus(agentId, taskId, {
|
|
4070
|
+
status: result.ok ? "ok" : "failed",
|
|
4071
|
+
medium: "telegram",
|
|
4072
|
+
error_code: result.ok ? null : result.error_code ?? "TELEGRAM_SEND_FAILED"
|
|
4073
|
+
});
|
|
4074
|
+
return;
|
|
4075
|
+
}
|
|
4076
|
+
log(`[delivery] Unrecognised legacy delivery_to string for '${agentCodeName}': ${rawTarget.slice(0, 60)}`);
|
|
4077
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: "LEGACY_DELIVERY_TO_UNRECOGNISED" });
|
|
4078
|
+
return;
|
|
4079
|
+
}
|
|
4080
|
+
const parsed = parseDeliveryTarget(rawTarget);
|
|
4081
|
+
if (isParseError(parsed)) {
|
|
4082
|
+
log(`[delivery] Malformed delivery_to for '${agentCodeName}': ${parsed.code} \u2014 ${parsed.detail}`);
|
|
4083
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: parsed.code });
|
|
4084
|
+
return;
|
|
4085
|
+
}
|
|
4086
|
+
if (parsed.kind === "channel") {
|
|
4087
|
+
if (parsed.provider === "slack") {
|
|
4088
|
+
const sent = await sendSlackChannelMessage(agentCodeName, parsed.channel_id ?? "", body);
|
|
4089
|
+
await reportDeliveryStatus(agentId, taskId, {
|
|
4090
|
+
status: sent ? "ok" : "failed",
|
|
4091
|
+
medium: "slack",
|
|
4092
|
+
error_code: sent ? null : "SLACK_SEND_FAILED"
|
|
4093
|
+
});
|
|
4094
|
+
return;
|
|
4095
|
+
}
|
|
4096
|
+
const toStr = `chat:${parsed.chat_id ?? ""}`;
|
|
4097
|
+
const result = await sendTaskNotification(agentCodeName, "telegram", toStr, body);
|
|
4098
|
+
await reportDeliveryStatus(agentId, taskId, {
|
|
4099
|
+
status: result.ok ? "ok" : "failed",
|
|
4100
|
+
medium: "telegram",
|
|
4101
|
+
error_code: result.ok ? null : result.error_code ?? "TELEGRAM_SEND_FAILED"
|
|
4102
|
+
});
|
|
4103
|
+
return;
|
|
4104
|
+
}
|
|
4105
|
+
const agentRow = agentInfoForDelivery.get(agentCodeName);
|
|
4106
|
+
if (!agentRow) {
|
|
4107
|
+
log(`[delivery] No agent metadata cached for '${agentCodeName}' \u2014 dropping DM`);
|
|
4108
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: "AGENT_METADATA_UNAVAILABLE" });
|
|
4109
|
+
return;
|
|
4110
|
+
}
|
|
4111
|
+
const resolved = resolveDmTarget(parsed, agentRow.resolverAgent, agentRow.peopleByPersonId);
|
|
4112
|
+
if (isResolveError(resolved)) {
|
|
4113
|
+
log(`[delivery] Cannot resolve DM target for '${agentCodeName}': ${resolved.code} \u2014 ${resolved.detail}`);
|
|
4114
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: resolved.code });
|
|
4115
|
+
return;
|
|
4116
|
+
}
|
|
4117
|
+
const footeredBody = appendDmFooter(
|
|
4118
|
+
body,
|
|
4119
|
+
agentRow.ownerTeamName,
|
|
4120
|
+
agentRow.agentDisplayName
|
|
4121
|
+
);
|
|
4122
|
+
if (resolved.kind === "dm" && resolved.medium === "slack") {
|
|
4123
|
+
const tokens = agentChannelTokens.get(agentCodeName);
|
|
4124
|
+
const botToken = tokens?.slack;
|
|
4125
|
+
if (!botToken) {
|
|
4126
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: "SLACK_MISSING_SCOPE", medium: "slack" });
|
|
4127
|
+
log(`[delivery] No Slack bot token for '${agentCodeName}' \u2014 DM dropped`);
|
|
4128
|
+
return;
|
|
4129
|
+
}
|
|
4130
|
+
try {
|
|
4131
|
+
const controller = new AbortController();
|
|
4132
|
+
const timeoutHandle = setTimeout(() => controller.abort(), 5e3);
|
|
4133
|
+
let openJson;
|
|
4134
|
+
try {
|
|
4135
|
+
const openResp = await fetch("https://slack.com/api/conversations.open", {
|
|
4136
|
+
method: "POST",
|
|
4137
|
+
headers: {
|
|
4138
|
+
Authorization: `Bearer ${botToken}`,
|
|
4139
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
4140
|
+
},
|
|
4141
|
+
body: JSON.stringify({ users: resolved.slack_user_id }),
|
|
4142
|
+
signal: controller.signal
|
|
4143
|
+
});
|
|
4144
|
+
openJson = await openResp.json();
|
|
4145
|
+
} finally {
|
|
4146
|
+
clearTimeout(timeoutHandle);
|
|
4147
|
+
}
|
|
4148
|
+
if (!openJson.ok || !openJson.channel?.id) {
|
|
4149
|
+
const errCode = openJson.error === "missing_scope" ? "SLACK_MISSING_SCOPE" : `SLACK_OPEN_FAILED:${openJson.error ?? "unknown"}`;
|
|
4150
|
+
log(`[delivery] conversations.open failed for '${agentCodeName}': ${openJson.error}`);
|
|
4151
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: errCode, medium: "slack" });
|
|
4152
|
+
return;
|
|
4153
|
+
}
|
|
4154
|
+
const sent = await sendSlackChannelMessage(agentCodeName, openJson.channel.id, footeredBody);
|
|
4155
|
+
await reportDeliveryStatus(agentId, taskId, {
|
|
4156
|
+
status: sent ? "ok" : "failed",
|
|
4157
|
+
medium: "slack",
|
|
4158
|
+
error_code: sent ? null : "SLACK_SEND_FAILED"
|
|
4159
|
+
});
|
|
4160
|
+
} catch (err) {
|
|
4161
|
+
const isAbort = err.name === "AbortError";
|
|
4162
|
+
const errCode = isAbort ? "SLACK_OPEN_TIMEOUT" : "SLACK_EXCEPTION";
|
|
4163
|
+
log(`[delivery] Slack DM ${isAbort ? "timeout" : "failure"} for '${agentCodeName}': ${err.message}`);
|
|
4164
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: errCode, medium: "slack" });
|
|
4165
|
+
}
|
|
4166
|
+
return;
|
|
4167
|
+
}
|
|
4168
|
+
if (resolved.kind === "dm" && resolved.medium === "telegram") {
|
|
4169
|
+
const tokens = agentChannelTokens.get(agentCodeName);
|
|
4170
|
+
const botToken = tokens?.telegram;
|
|
4171
|
+
if (!botToken) {
|
|
4172
|
+
log(`[delivery] No Telegram bot token for '${agentCodeName}' \u2014 DM dropped`);
|
|
4173
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: "TELEGRAM_NO_TOKEN", medium: "telegram" });
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
try {
|
|
4177
|
+
const result = await telegramApiCall(botToken, "sendMessage", {
|
|
4178
|
+
chat_id: resolved.telegram_chat_id,
|
|
4179
|
+
text: footeredBody
|
|
4180
|
+
});
|
|
4181
|
+
if (!result.ok) {
|
|
4182
|
+
log(`[delivery] Telegram DM failed for '${agentCodeName}': ${result.description}`);
|
|
4183
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: `TELEGRAM_SEND_FAILED:${result.description ?? "unknown"}`, medium: "telegram" });
|
|
4184
|
+
return;
|
|
4185
|
+
}
|
|
4186
|
+
await reportDeliveryStatus(agentId, taskId, { status: "ok", medium: "telegram" });
|
|
4187
|
+
} catch (err) {
|
|
4188
|
+
log(`[delivery] Telegram DM exception for '${agentCodeName}': ${err.message}`);
|
|
4189
|
+
await reportDeliveryStatus(agentId, taskId, { status: "failed", error_code: "TELEGRAM_EXCEPTION", medium: "telegram" });
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
var agentInfoForDelivery = /* @__PURE__ */ new Map();
|
|
4194
|
+
function cacheAgentDeliveryMetadata(codeName, refreshData) {
|
|
4195
|
+
const agentRow = refreshData["agent"] ?? {};
|
|
4196
|
+
const displayName = agentRow["display_name"] ?? codeName;
|
|
4197
|
+
const ownerTeamName = agentRow["owner_team_name"] ?? null;
|
|
4198
|
+
const framework = agentRow["framework"] ?? "openclaw";
|
|
4199
|
+
const reportsToPersonId = agentRow["reports_to"] ?? null;
|
|
4200
|
+
const reportsToType = agentRow["reports_to_type"] ?? null;
|
|
4201
|
+
const channelConfigs = refreshData["channel_configs"] ?? {};
|
|
4202
|
+
const dmCapable = [];
|
|
4203
|
+
const slackBotToken = channelConfigs["slack"]?.config?.["bot_token"];
|
|
4204
|
+
if (typeof slackBotToken === "string" && slackBotToken.length > 0) {
|
|
4205
|
+
dmCapable.push("slack");
|
|
4206
|
+
}
|
|
4207
|
+
const telegramBotToken = channelConfigs["telegram"]?.config?.["bot_token"];
|
|
4208
|
+
if (typeof telegramBotToken === "string" && telegramBotToken.length > 0) {
|
|
4209
|
+
dmCapable.push("telegram");
|
|
4210
|
+
}
|
|
4211
|
+
const resolverAgent = {
|
|
4212
|
+
agent_id: agentRow["agent_id"] ?? "",
|
|
4213
|
+
framework,
|
|
4214
|
+
dm_capable_mediums: dmCapable,
|
|
4215
|
+
reports_to_person_id: reportsToType === "person" ? reportsToPersonId : null,
|
|
4216
|
+
reports_to_type: reportsToType
|
|
4217
|
+
};
|
|
4218
|
+
const peopleByPersonId = /* @__PURE__ */ new Map();
|
|
4219
|
+
if (reportsToPersonId && reportsToType === "person") {
|
|
4220
|
+
peopleByPersonId.set(reportsToPersonId, {
|
|
4221
|
+
person_id: reportsToPersonId,
|
|
4222
|
+
display_name: agentRow["reports_to_name"] ?? "Reports-To",
|
|
4223
|
+
slack_user_id: agentRow["reports_to_slack_user_id"] ?? null,
|
|
4224
|
+
telegram_chat_id: agentRow["reports_to_telegram_chat_id"] ?? null
|
|
4225
|
+
});
|
|
4226
|
+
}
|
|
4227
|
+
const people = refreshData["people"] ?? [];
|
|
4228
|
+
for (const p of people) {
|
|
4229
|
+
const personId = p["person_id"];
|
|
4230
|
+
if (!personId) continue;
|
|
4231
|
+
const contactPrefs = p["contact_preferences"] ?? {};
|
|
4232
|
+
peopleByPersonId.set(personId, {
|
|
4233
|
+
person_id: personId,
|
|
4234
|
+
display_name: p["display_name"] ?? "person",
|
|
4235
|
+
slack_user_id: contactPrefs["slack_user_id"] ?? null,
|
|
4236
|
+
telegram_chat_id: contactPrefs["telegram_chat_id"] ?? null
|
|
4237
|
+
});
|
|
4238
|
+
}
|
|
4239
|
+
agentInfoForDelivery.set(codeName, {
|
|
4240
|
+
agentDisplayName: displayName,
|
|
4241
|
+
ownerTeamName,
|
|
4242
|
+
resolverAgent,
|
|
4243
|
+
peopleByPersonId
|
|
4244
|
+
});
|
|
4245
|
+
}
|
|
4246
|
+
async function reportDeliveryStatus(agentId, taskId, payload) {
|
|
4247
|
+
if (!taskId) return;
|
|
4248
|
+
try {
|
|
4249
|
+
await api.post("/host/schedules/delivery-status", {
|
|
4250
|
+
agent_id: agentId,
|
|
4251
|
+
task_id: taskId,
|
|
4252
|
+
status: payload.status,
|
|
4253
|
+
medium: payload.medium ?? null,
|
|
4254
|
+
error_code: payload.error_code ?? null
|
|
4255
|
+
});
|
|
4256
|
+
} catch (err) {
|
|
4257
|
+
log(`[delivery] Failed to report delivery status for ${agentId}/${taskId}: ${err.message}`);
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
3947
4260
|
async function sendTaskNotification(agentCodeName, channel, to, text) {
|
|
3948
4261
|
const tokens = agentChannelTokens.get(agentCodeName);
|
|
3949
4262
|
if (channel === "slack") {
|
|
3950
4263
|
const botToken = tokens?.slack;
|
|
3951
4264
|
const channelId = to.replace(/^channel:/, "");
|
|
3952
|
-
if (botToken) {
|
|
3953
|
-
|
|
3954
|
-
|
|
4265
|
+
if (!botToken) {
|
|
4266
|
+
log(`No Slack bot token for '${agentCodeName}' \u2014 targeted notification dropped`);
|
|
4267
|
+
return { ok: false, error_code: "SLACK_NO_TOKEN" };
|
|
3955
4268
|
}
|
|
3956
|
-
|
|
3957
|
-
|
|
4269
|
+
const sent = await sendSlackChannelMessage(agentCodeName, channelId, text);
|
|
4270
|
+
return sent ? { ok: true } : { ok: false, error_code: "SLACK_SEND_FAILED" };
|
|
4271
|
+
}
|
|
4272
|
+
if (channel === "telegram") {
|
|
3958
4273
|
const botToken = tokens?.telegram;
|
|
3959
4274
|
const chatId = to.replace(/^chat:/, "");
|
|
3960
4275
|
if (!botToken) {
|
|
3961
4276
|
log(`No Telegram bot token for '${agentCodeName}' \u2014 notification dropped`);
|
|
3962
|
-
return;
|
|
4277
|
+
return { ok: false, error_code: "TELEGRAM_NO_TOKEN" };
|
|
3963
4278
|
}
|
|
3964
4279
|
const allowedChats = tokens?.telegramAllowedChats;
|
|
3965
4280
|
if (allowedChats && allowedChats.length > 0 && !allowedChats.includes(chatId)) {
|
|
3966
4281
|
log(`Telegram chat ${chatId} not in allowed_chat_ids for '${agentCodeName}'`);
|
|
3967
|
-
return;
|
|
4282
|
+
return { ok: false, error_code: "TELEGRAM_CHAT_NOT_ALLOWED" };
|
|
3968
4283
|
}
|
|
3969
4284
|
try {
|
|
3970
4285
|
const result = await telegramApiCall(botToken, "sendMessage", { chat_id: chatId, text });
|
|
3971
4286
|
if (!result.ok) {
|
|
3972
4287
|
log(`Telegram sendMessage failed for '${agentCodeName}': ${result.description}`);
|
|
3973
|
-
|
|
3974
|
-
log(`Telegram notification sent for '${agentCodeName}' to chat ${chatId}`);
|
|
4288
|
+
return { ok: false, error_code: `TELEGRAM_SEND_FAILED:${result.description ?? "unknown"}` };
|
|
3975
4289
|
}
|
|
4290
|
+
log(`Telegram notification sent for '${agentCodeName}' to chat ${chatId}`);
|
|
4291
|
+
return { ok: true };
|
|
3976
4292
|
} catch (err) {
|
|
3977
4293
|
log(`Telegram API error for '${agentCodeName}': ${err.message}`);
|
|
4294
|
+
return { ok: false, error_code: "TELEGRAM_EXCEPTION" };
|
|
3978
4295
|
}
|
|
3979
|
-
} else {
|
|
3980
|
-
log(`Unknown notify_channel '${channel}' for '${agentCodeName}'`);
|
|
3981
4296
|
}
|
|
4297
|
+
log(`Unknown notify_channel '${channel}' for '${agentCodeName}'`);
|
|
4298
|
+
return { ok: false, error_code: `UNKNOWN_CHANNEL:${channel}` };
|
|
3982
4299
|
}
|
|
3983
4300
|
function generateArtifacts(agent, refreshData, adapter) {
|
|
3984
4301
|
if (!refreshData.charter || !refreshData.tools) {
|