@integrity-labs/agt-cli 0.28.164 → 0.28.166
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
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
success,
|
|
38
38
|
table,
|
|
39
39
|
warn
|
|
40
|
-
} from "../chunk-
|
|
40
|
+
} from "../chunk-HWVCQ6PC.js";
|
|
41
41
|
import {
|
|
42
42
|
CHANNEL_REGISTRY,
|
|
43
43
|
DEFAULT_FRAMEWORK,
|
|
@@ -4778,7 +4778,7 @@ import { execFileSync, execSync } from "child_process";
|
|
|
4778
4778
|
import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
|
|
4779
4779
|
import chalk18 from "chalk";
|
|
4780
4780
|
import ora16 from "ora";
|
|
4781
|
-
var cliVersion = true ? "0.28.
|
|
4781
|
+
var cliVersion = true ? "0.28.166" : "dev";
|
|
4782
4782
|
async function fetchLatestVersion() {
|
|
4783
4783
|
const host2 = getHost();
|
|
4784
4784
|
if (!host2) return null;
|
|
@@ -5792,7 +5792,7 @@ function handleError(err) {
|
|
|
5792
5792
|
}
|
|
5793
5793
|
|
|
5794
5794
|
// src/bin/agt.ts
|
|
5795
|
-
var cliVersion2 = true ? "0.28.
|
|
5795
|
+
var cliVersion2 = true ? "0.28.166" : "dev";
|
|
5796
5796
|
var program = new Command();
|
|
5797
5797
|
program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
|
|
5798
5798
|
program.hook("preAction", async (thisCommand, actionCommand) => {
|
|
@@ -7948,7 +7948,7 @@ function requireHost() {
|
|
|
7948
7948
|
}
|
|
7949
7949
|
|
|
7950
7950
|
// src/lib/api-client.ts
|
|
7951
|
-
var agtCliVersion = true ? "0.28.
|
|
7951
|
+
var agtCliVersion = true ? "0.28.166" : "dev";
|
|
7952
7952
|
var lastConfigHash = null;
|
|
7953
7953
|
function setConfigHash(hash) {
|
|
7954
7954
|
lastConfigHash = hash && hash.length > 0 ? hash : null;
|
|
@@ -9253,4 +9253,4 @@ export {
|
|
|
9253
9253
|
managerInstallSystemUnitCommand,
|
|
9254
9254
|
managerUninstallSystemUnitCommand
|
|
9255
9255
|
};
|
|
9256
|
-
//# sourceMappingURL=chunk-
|
|
9256
|
+
//# sourceMappingURL=chunk-HWVCQ6PC.js.map
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
requireHost,
|
|
29
29
|
safeWriteJsonAtomic,
|
|
30
30
|
setConfigHash
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-HWVCQ6PC.js";
|
|
32
32
|
import {
|
|
33
33
|
getProjectDir as getProjectDir2,
|
|
34
34
|
getReadyTasks,
|
|
@@ -6878,7 +6878,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
|
|
|
6878
6878
|
var lastVersionCheckAt = 0;
|
|
6879
6879
|
var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
|
|
6880
6880
|
var lastResponsivenessProbeAt = 0;
|
|
6881
|
-
var agtCliVersion = true ? "0.28.
|
|
6881
|
+
var agtCliVersion = true ? "0.28.166" : "dev";
|
|
6882
6882
|
function resolveBrewPath(execFileSync4) {
|
|
6883
6883
|
try {
|
|
6884
6884
|
const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
|
|
@@ -14182,6 +14182,204 @@ var Server = class extends Protocol {
|
|
|
14182
14182
|
}
|
|
14183
14183
|
};
|
|
14184
14184
|
|
|
14185
|
+
// src/slack-rich-text.ts
|
|
14186
|
+
var MAX_DEPTH = 12;
|
|
14187
|
+
function isRecord(v) {
|
|
14188
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14189
|
+
}
|
|
14190
|
+
function asString(v) {
|
|
14191
|
+
return typeof v === "string" ? v : "";
|
|
14192
|
+
}
|
|
14193
|
+
function asArray(v) {
|
|
14194
|
+
return Array.isArray(v) ? v : [];
|
|
14195
|
+
}
|
|
14196
|
+
function isTableElement(el) {
|
|
14197
|
+
return isRecord(el) && asString(el.type).includes("table");
|
|
14198
|
+
}
|
|
14199
|
+
function renderEmoji(el) {
|
|
14200
|
+
const unicode = asString(el.unicode);
|
|
14201
|
+
if (unicode) {
|
|
14202
|
+
try {
|
|
14203
|
+
const cps = unicode.split("-").map((h) => parseInt(h, 16));
|
|
14204
|
+
if (cps.every((n) => Number.isFinite(n) && n >= 0 && n <= 1114111)) {
|
|
14205
|
+
return String.fromCodePoint(...cps);
|
|
14206
|
+
}
|
|
14207
|
+
} catch {
|
|
14208
|
+
}
|
|
14209
|
+
}
|
|
14210
|
+
const name = asString(el.name);
|
|
14211
|
+
return name ? `:${name}:` : "";
|
|
14212
|
+
}
|
|
14213
|
+
function renderLeaf(el) {
|
|
14214
|
+
if (!isRecord(el)) return "";
|
|
14215
|
+
switch (asString(el.type)) {
|
|
14216
|
+
case "text":
|
|
14217
|
+
return asString(el.text);
|
|
14218
|
+
case "link": {
|
|
14219
|
+
const label = asString(el.text);
|
|
14220
|
+
const url = asString(el.url);
|
|
14221
|
+
if (label && url && label !== url) return `${label} (${url})`;
|
|
14222
|
+
return label || url;
|
|
14223
|
+
}
|
|
14224
|
+
case "emoji":
|
|
14225
|
+
return renderEmoji(el);
|
|
14226
|
+
case "user":
|
|
14227
|
+
return `<@${asString(el.user_id)}>`;
|
|
14228
|
+
case "usergroup":
|
|
14229
|
+
return `<!subteam^${asString(el.usergroup_id)}>`;
|
|
14230
|
+
case "channel":
|
|
14231
|
+
return `<#${asString(el.channel_id)}>`;
|
|
14232
|
+
case "broadcast":
|
|
14233
|
+
return `@${asString(el.range) || "channel"}`;
|
|
14234
|
+
case "date":
|
|
14235
|
+
return asString(el.fallback) || asString(el.timestamp);
|
|
14236
|
+
default:
|
|
14237
|
+
if (Array.isArray(el.elements)) return renderInline(el.elements);
|
|
14238
|
+
return asString(el.text);
|
|
14239
|
+
}
|
|
14240
|
+
}
|
|
14241
|
+
function renderInline(elements) {
|
|
14242
|
+
return elements.map(renderLeaf).join("");
|
|
14243
|
+
}
|
|
14244
|
+
function deepText(node, depth) {
|
|
14245
|
+
if (depth > MAX_DEPTH) return "";
|
|
14246
|
+
if (typeof node === "string") return node;
|
|
14247
|
+
if (Array.isArray(node)) return node.map((n) => deepText(n, depth + 1)).join("");
|
|
14248
|
+
if (!isRecord(node)) return "";
|
|
14249
|
+
const type = asString(node.type);
|
|
14250
|
+
if (type && type !== "rich_text" && !type.startsWith("rich_text_") && !type.includes("table")) {
|
|
14251
|
+
return renderLeaf(node);
|
|
14252
|
+
}
|
|
14253
|
+
if (Array.isArray(node.elements)) return node.elements.map((n) => deepText(n, depth + 1)).join("");
|
|
14254
|
+
if (Array.isArray(node.rows)) return node.rows.map((n) => deepText(n, depth + 1)).join(" ");
|
|
14255
|
+
return asString(node.text);
|
|
14256
|
+
}
|
|
14257
|
+
function renderCell(cell) {
|
|
14258
|
+
if (!isRecord(cell)) return deepText(cell, 0).replace(/\s*\n\s*/g, " ").trim();
|
|
14259
|
+
const inner = Array.isArray(cell.elements) ? renderSection(cell, 0) : deepText(cell, 0);
|
|
14260
|
+
return inner.replace(/\s*\n\s*/g, " ").trim();
|
|
14261
|
+
}
|
|
14262
|
+
function renderTable(el) {
|
|
14263
|
+
const rawRows = asArray(el.elements).length ? asArray(el.elements) : asArray(el.rows);
|
|
14264
|
+
const rows = [];
|
|
14265
|
+
for (const row of rawRows) {
|
|
14266
|
+
if (!isRecord(row) && !Array.isArray(row)) continue;
|
|
14267
|
+
const rawCells = Array.isArray(row) ? row : asArray(row.elements).length ? asArray(row.elements) : asArray(row.cells);
|
|
14268
|
+
if (rawCells.length === 0) continue;
|
|
14269
|
+
rows.push(rawCells.map(renderCell));
|
|
14270
|
+
}
|
|
14271
|
+
if (rows.length === 0) {
|
|
14272
|
+
const fallback = deepText(el, 0).replace(/[ \t]+\n/g, "\n").trim();
|
|
14273
|
+
return fallback;
|
|
14274
|
+
}
|
|
14275
|
+
const colCount = rows.reduce((max, r) => Math.max(max, r.length), 0);
|
|
14276
|
+
const pad = (r) => {
|
|
14277
|
+
const cells = r.slice();
|
|
14278
|
+
while (cells.length < colCount) cells.push("");
|
|
14279
|
+
return cells.map((c) => c.replace(/\|/g, "\\|"));
|
|
14280
|
+
};
|
|
14281
|
+
const lines = [];
|
|
14282
|
+
const header = rows[0] ?? [];
|
|
14283
|
+
const body = rows.slice(1);
|
|
14284
|
+
lines.push(`| ${pad(header).join(" | ")} |`);
|
|
14285
|
+
lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
|
|
14286
|
+
for (const r of body) lines.push(`| ${pad(r).join(" | ")} |`);
|
|
14287
|
+
return lines.join("\n");
|
|
14288
|
+
}
|
|
14289
|
+
function renderSection(section, depth) {
|
|
14290
|
+
if (depth > MAX_DEPTH || !isRecord(section)) return "";
|
|
14291
|
+
const type = asString(section.type);
|
|
14292
|
+
if (isTableElement(section)) return renderTable(section);
|
|
14293
|
+
switch (type) {
|
|
14294
|
+
case "rich_text_section":
|
|
14295
|
+
return renderInline(asArray(section.elements));
|
|
14296
|
+
case "rich_text_preformatted": {
|
|
14297
|
+
const code = renderInline(asArray(section.elements));
|
|
14298
|
+
return code ? `\`\`\`
|
|
14299
|
+
${code}
|
|
14300
|
+
\`\`\`` : "";
|
|
14301
|
+
}
|
|
14302
|
+
case "rich_text_quote": {
|
|
14303
|
+
const quoted = renderInline(asArray(section.elements));
|
|
14304
|
+
return quoted ? quoted.split("\n").map((l) => `> ${l}`).join("\n") : "";
|
|
14305
|
+
}
|
|
14306
|
+
case "rich_text_list": {
|
|
14307
|
+
const ordered = asString(section.style) === "ordered";
|
|
14308
|
+
const items = asArray(section.elements).map((item, i) => {
|
|
14309
|
+
const body = renderSection(item, depth + 1) || renderInline(asArray(item?.elements));
|
|
14310
|
+
const marker = ordered ? `${i + 1}.` : "-";
|
|
14311
|
+
return `${marker} ${body}`.trimEnd();
|
|
14312
|
+
});
|
|
14313
|
+
return items.join("\n");
|
|
14314
|
+
}
|
|
14315
|
+
default:
|
|
14316
|
+
if (Array.isArray(section.elements)) return renderInline(asArray(section.elements));
|
|
14317
|
+
return deepText(section, depth + 1);
|
|
14318
|
+
}
|
|
14319
|
+
}
|
|
14320
|
+
function renderSlackBlocks(blocks) {
|
|
14321
|
+
let hadTable = false;
|
|
14322
|
+
const out = [];
|
|
14323
|
+
try {
|
|
14324
|
+
for (const block of asArray(blocks)) {
|
|
14325
|
+
if (!isRecord(block) || asString(block.type) !== "rich_text") continue;
|
|
14326
|
+
for (const section of asArray(block.elements)) {
|
|
14327
|
+
if (isTableElement(section)) hadTable = true;
|
|
14328
|
+
const rendered = renderSection(section, 0);
|
|
14329
|
+
if (rendered.trim().length > 0) out.push(rendered);
|
|
14330
|
+
}
|
|
14331
|
+
}
|
|
14332
|
+
} catch {
|
|
14333
|
+
}
|
|
14334
|
+
const text = out.join("\n\n").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
14335
|
+
return { text, hadTable };
|
|
14336
|
+
}
|
|
14337
|
+
function mergeInboundText(text, blocks) {
|
|
14338
|
+
const { text: rendered, hadTable } = renderSlackBlocks(blocks);
|
|
14339
|
+
if (!hadTable) return { content: text, recoveredTable: false };
|
|
14340
|
+
const content = rendered.length > 0 ? rendered : text;
|
|
14341
|
+
return { content, recoveredTable: rendered.length > 0 && content !== text };
|
|
14342
|
+
}
|
|
14343
|
+
|
|
14344
|
+
// src/slack-forwarded.ts
|
|
14345
|
+
function asTrimmed(v) {
|
|
14346
|
+
return typeof v === "string" ? v.trim() : "";
|
|
14347
|
+
}
|
|
14348
|
+
function extractForwardedContent(attachments) {
|
|
14349
|
+
if (!Array.isArray(attachments)) return { text: "", files: [] };
|
|
14350
|
+
const parts = [];
|
|
14351
|
+
const files = [];
|
|
14352
|
+
for (const raw of attachments) {
|
|
14353
|
+
if (!raw || typeof raw !== "object") continue;
|
|
14354
|
+
const att = raw;
|
|
14355
|
+
let body = asTrimmed(att.text) || asTrimmed(att.fallback);
|
|
14356
|
+
if (!body && Array.isArray(att.message_blocks)) {
|
|
14357
|
+
for (const mb of att.message_blocks) {
|
|
14358
|
+
const rendered = renderSlackBlocks(mb?.message?.blocks).text.trim();
|
|
14359
|
+
if (rendered) {
|
|
14360
|
+
body = rendered;
|
|
14361
|
+
break;
|
|
14362
|
+
}
|
|
14363
|
+
}
|
|
14364
|
+
}
|
|
14365
|
+
const title = asTrimmed(att.title);
|
|
14366
|
+
const link = asTrimmed(att.title_link) || asTrimmed(att.from_url);
|
|
14367
|
+
const imageUrl = asTrimmed(att.image_url) || asTrimmed(att.thumb_url);
|
|
14368
|
+
const lines = [];
|
|
14369
|
+
if (body) lines.push(body);
|
|
14370
|
+
if (title && title !== body) lines.push(title);
|
|
14371
|
+
if (link) lines.push(link);
|
|
14372
|
+
if (imageUrl) lines.push(`[image] ${imageUrl}`);
|
|
14373
|
+
if (lines.length) parts.push(lines.join("\n"));
|
|
14374
|
+
if (Array.isArray(att.files)) files.push(...att.files);
|
|
14375
|
+
}
|
|
14376
|
+
return { text: parts.join("\n\n"), files };
|
|
14377
|
+
}
|
|
14378
|
+
function hasForwardedContent(attachments) {
|
|
14379
|
+
const { text, files } = extractForwardedContent(attachments);
|
|
14380
|
+
return text.length > 0 || files.length > 0;
|
|
14381
|
+
}
|
|
14382
|
+
|
|
14185
14383
|
// src/slack-inbound-filter.ts
|
|
14186
14384
|
var ALLOWED_MESSAGE_SUBTYPES = /* @__PURE__ */ new Set([
|
|
14187
14385
|
void 0,
|
|
@@ -14201,7 +14399,8 @@ function decideSlackMessageForward(evt) {
|
|
|
14201
14399
|
const hasText = typeof evt.text === "string" && evt.text.trim().length > 0;
|
|
14202
14400
|
const hasFiles = Array.isArray(evt.files) && evt.files.length > 0;
|
|
14203
14401
|
const hasBlocks = Array.isArray(evt.blocks) && evt.blocks.length > 0;
|
|
14204
|
-
|
|
14402
|
+
const hasAttachments = hasForwardedContent(evt.attachments);
|
|
14403
|
+
if (!hasText && !hasFiles && !hasBlocks && !hasAttachments) {
|
|
14205
14404
|
return { forward: false, reason: "empty" };
|
|
14206
14405
|
}
|
|
14207
14406
|
return { forward: true };
|
|
@@ -14836,6 +15035,141 @@ function buildAgentConfigReport(opts) {
|
|
|
14836
15035
|
return lines.join("\n");
|
|
14837
15036
|
}
|
|
14838
15037
|
|
|
15038
|
+
// src/agent-status-report.ts
|
|
15039
|
+
var STATUS_REPORT_SCHEMA_VERSION = 1;
|
|
15040
|
+
var FRESHNESS_VALUES = /* @__PURE__ */ new Set(["cached", "live", "unknown"]);
|
|
15041
|
+
var LEVEL_VALUES = /* @__PURE__ */ new Set(["ok", "degraded", "down", "error", "unknown"]);
|
|
15042
|
+
function coerceLevel(value) {
|
|
15043
|
+
return typeof value === "string" && LEVEL_VALUES.has(value) ? value : "unknown";
|
|
15044
|
+
}
|
|
15045
|
+
function coerceFreshness(value) {
|
|
15046
|
+
return typeof value === "string" && FRESHNESS_VALUES.has(value) ? value : "unknown";
|
|
15047
|
+
}
|
|
15048
|
+
function coerceCheckedAt(value) {
|
|
15049
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
15050
|
+
}
|
|
15051
|
+
function parseAgentStatusReport(raw) {
|
|
15052
|
+
if (!raw || typeof raw !== "object") return null;
|
|
15053
|
+
const obj = raw;
|
|
15054
|
+
if (!Array.isArray(obj.channels) || !Array.isArray(obj.integrations)) return null;
|
|
15055
|
+
const channels = obj.channels.filter((c) => !!c && typeof c === "object").map((c) => ({
|
|
15056
|
+
channel_id: typeof c.channel_id === "string" ? c.channel_id : "unknown",
|
|
15057
|
+
level: coerceLevel(c.level),
|
|
15058
|
+
freshness: coerceFreshness(c.freshness),
|
|
15059
|
+
checked_at: coerceCheckedAt(c.checked_at),
|
|
15060
|
+
...typeof c.reason === "string" && c.reason ? { reason: c.reason } : {}
|
|
15061
|
+
}));
|
|
15062
|
+
const integrations = obj.integrations.filter((i) => !!i && typeof i === "object").map((i) => ({
|
|
15063
|
+
id: typeof i.id === "string" ? i.id : "unknown",
|
|
15064
|
+
definition_id: typeof i.definition_id === "string" ? i.definition_id : "unknown",
|
|
15065
|
+
display_name: typeof i.display_name === "string" && i.display_name ? i.display_name : typeof i.definition_id === "string" ? i.definition_id : "unknown",
|
|
15066
|
+
scope: i.scope === "team" || i.scope === "organization" ? i.scope : "agent",
|
|
15067
|
+
level: coerceLevel(i.level),
|
|
15068
|
+
freshness: coerceFreshness(i.freshness),
|
|
15069
|
+
checked_at: coerceCheckedAt(i.checked_at),
|
|
15070
|
+
...typeof i.consecutive_failures === "number" ? { consecutive_failures: i.consecutive_failures } : {},
|
|
15071
|
+
...typeof i.reason === "string" && i.reason ? { reason: i.reason } : {}
|
|
15072
|
+
}));
|
|
15073
|
+
return {
|
|
15074
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 0,
|
|
15075
|
+
agent_id: typeof obj.agent_id === "string" ? obj.agent_id : "",
|
|
15076
|
+
generated_at: typeof obj.generated_at === "string" ? obj.generated_at : "",
|
|
15077
|
+
manager_last_seen: coerceCheckedAt(obj.manager_last_seen),
|
|
15078
|
+
channels,
|
|
15079
|
+
integrations
|
|
15080
|
+
};
|
|
15081
|
+
}
|
|
15082
|
+
function mergeOwnChannelLiveStatus(report, channelId, live) {
|
|
15083
|
+
const liveEntry = {
|
|
15084
|
+
channel_id: channelId,
|
|
15085
|
+
level: live.level,
|
|
15086
|
+
freshness: "live",
|
|
15087
|
+
checked_at: live.checked_at,
|
|
15088
|
+
...live.reason ? { reason: live.reason } : {}
|
|
15089
|
+
};
|
|
15090
|
+
const existingIndex = report.channels.findIndex((ch) => ch.channel_id === channelId);
|
|
15091
|
+
const channels = existingIndex === -1 ? [...report.channels, liveEntry] : report.channels.map((ch, i) => i === existingIndex ? liveEntry : ch);
|
|
15092
|
+
return { ...report, channels };
|
|
15093
|
+
}
|
|
15094
|
+
function statusLevelGlyph(level) {
|
|
15095
|
+
switch (level) {
|
|
15096
|
+
case "ok":
|
|
15097
|
+
return "\u{1F7E2}";
|
|
15098
|
+
case "degraded":
|
|
15099
|
+
return "\u{1F7E1}";
|
|
15100
|
+
case "down":
|
|
15101
|
+
case "error":
|
|
15102
|
+
return "\u{1F534}";
|
|
15103
|
+
default:
|
|
15104
|
+
return "\u26AA";
|
|
15105
|
+
}
|
|
15106
|
+
}
|
|
15107
|
+
function formatStatusAge(checkedAt, nowMs) {
|
|
15108
|
+
if (!checkedAt) return "never";
|
|
15109
|
+
const t = Date.parse(checkedAt);
|
|
15110
|
+
if (Number.isNaN(t)) return "unknown";
|
|
15111
|
+
const diffMs = nowMs - t;
|
|
15112
|
+
if (diffMs < 45e3) return "just now";
|
|
15113
|
+
const mins = Math.round(diffMs / 6e4);
|
|
15114
|
+
if (mins < 60) return `${mins}m ago`;
|
|
15115
|
+
const hours = Math.round(diffMs / 36e5);
|
|
15116
|
+
if (hours < 24) return `${hours}h ago`;
|
|
15117
|
+
const days = Math.round(diffMs / 864e5);
|
|
15118
|
+
return `${days}d ago`;
|
|
15119
|
+
}
|
|
15120
|
+
|
|
15121
|
+
// src/slack-status-render.ts
|
|
15122
|
+
var FRESHNESS_LABEL = {
|
|
15123
|
+
live: "live",
|
|
15124
|
+
cached: "cached",
|
|
15125
|
+
unknown: "unknown"
|
|
15126
|
+
};
|
|
15127
|
+
function freshnessLabel(freshness) {
|
|
15128
|
+
return FRESHNESS_LABEL[freshness] ?? freshness;
|
|
15129
|
+
}
|
|
15130
|
+
function renderChannelLine(ch, nowMs) {
|
|
15131
|
+
const glyph = statusLevelGlyph(ch.level);
|
|
15132
|
+
const fresh = freshnessLabel(ch.freshness);
|
|
15133
|
+
const age = formatStatusAge(ch.checked_at, nowMs);
|
|
15134
|
+
const detail = ch.level !== "ok" && ch.reason ? ` (${ch.reason})` : "";
|
|
15135
|
+
return `${glyph} \`${ch.channel_id}\` \xB7 ${ch.level} \xB7 ${fresh} \xB7 ${age}${detail}`;
|
|
15136
|
+
}
|
|
15137
|
+
function renderIntegrationLine(it, nowMs) {
|
|
15138
|
+
const glyph = statusLevelGlyph(it.level);
|
|
15139
|
+
const fresh = freshnessLabel(it.freshness);
|
|
15140
|
+
const age = formatStatusAge(it.checked_at, nowMs);
|
|
15141
|
+
const bits = [];
|
|
15142
|
+
if (it.level !== "ok" && it.reason) bits.push(it.reason);
|
|
15143
|
+
if (typeof it.consecutive_failures === "number" && it.consecutive_failures > 0) {
|
|
15144
|
+
bits.push(`${it.consecutive_failures} fail${it.consecutive_failures === 1 ? "" : "s"}`);
|
|
15145
|
+
}
|
|
15146
|
+
const detail = bits.length ? ` (${bits.join(", ")})` : "";
|
|
15147
|
+
return `${glyph} \`${it.display_name}\` \xB7 ${it.level} \xB7 ${fresh} \xB7 ${age}${detail}`;
|
|
15148
|
+
}
|
|
15149
|
+
function renderSlackStatusSections(report, opts) {
|
|
15150
|
+
const { probing, nowMs } = opts;
|
|
15151
|
+
const lines = [];
|
|
15152
|
+
lines.push(probing ? "*Channels* (probing...)" : "*Channels*");
|
|
15153
|
+
if (report.channels.length === 0) {
|
|
15154
|
+
lines.push("_No channels configured._");
|
|
15155
|
+
} else {
|
|
15156
|
+
for (const ch of report.channels) lines.push(renderChannelLine(ch, nowMs));
|
|
15157
|
+
}
|
|
15158
|
+
lines.push("");
|
|
15159
|
+
lines.push("*Integrations*");
|
|
15160
|
+
if (report.integrations.length === 0) {
|
|
15161
|
+
lines.push("_No integrations configured._");
|
|
15162
|
+
} else {
|
|
15163
|
+
for (const it of report.integrations) lines.push(renderIntegrationLine(it, nowMs));
|
|
15164
|
+
}
|
|
15165
|
+
lines.push("");
|
|
15166
|
+
const seen = report.manager_last_seen ? `Manager last seen ${formatStatusAge(report.manager_last_seen, nowMs)}` : "Manager has never checked in";
|
|
15167
|
+
const tail = probing ? "Integration health is cached; confirming this channel's own status..." : "Integration health is cached from the last probe.";
|
|
15168
|
+
const skew = report.schema_version !== STATUS_REPORT_SCHEMA_VERSION ? ` (report schema v${report.schema_version}; update this agent for full detail)` : "";
|
|
15169
|
+
lines.push(`_${seen}. ${tail}${skew}_`);
|
|
15170
|
+
return lines.join("\n");
|
|
15171
|
+
}
|
|
15172
|
+
|
|
14839
15173
|
// src/pane-tail.ts
|
|
14840
15174
|
import { execFile } from "child_process";
|
|
14841
15175
|
import { promisify } from "util";
|
|
@@ -16119,165 +16453,6 @@ function buildSafeInboundPath2(codeName, fileId, mimetype) {
|
|
|
16119
16453
|
return buildSafeInboundPath(resolveSlackInboundDir(codeName), fileId, mimetype);
|
|
16120
16454
|
}
|
|
16121
16455
|
|
|
16122
|
-
// src/slack-rich-text.ts
|
|
16123
|
-
var MAX_DEPTH = 12;
|
|
16124
|
-
function isRecord(v) {
|
|
16125
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
16126
|
-
}
|
|
16127
|
-
function asString(v) {
|
|
16128
|
-
return typeof v === "string" ? v : "";
|
|
16129
|
-
}
|
|
16130
|
-
function asArray(v) {
|
|
16131
|
-
return Array.isArray(v) ? v : [];
|
|
16132
|
-
}
|
|
16133
|
-
function isTableElement(el) {
|
|
16134
|
-
return isRecord(el) && asString(el.type).includes("table");
|
|
16135
|
-
}
|
|
16136
|
-
function renderEmoji(el) {
|
|
16137
|
-
const unicode = asString(el.unicode);
|
|
16138
|
-
if (unicode) {
|
|
16139
|
-
try {
|
|
16140
|
-
const cps = unicode.split("-").map((h) => parseInt(h, 16));
|
|
16141
|
-
if (cps.every((n) => Number.isFinite(n) && n >= 0 && n <= 1114111)) {
|
|
16142
|
-
return String.fromCodePoint(...cps);
|
|
16143
|
-
}
|
|
16144
|
-
} catch {
|
|
16145
|
-
}
|
|
16146
|
-
}
|
|
16147
|
-
const name = asString(el.name);
|
|
16148
|
-
return name ? `:${name}:` : "";
|
|
16149
|
-
}
|
|
16150
|
-
function renderLeaf(el) {
|
|
16151
|
-
if (!isRecord(el)) return "";
|
|
16152
|
-
switch (asString(el.type)) {
|
|
16153
|
-
case "text":
|
|
16154
|
-
return asString(el.text);
|
|
16155
|
-
case "link": {
|
|
16156
|
-
const label = asString(el.text);
|
|
16157
|
-
const url = asString(el.url);
|
|
16158
|
-
if (label && url && label !== url) return `${label} (${url})`;
|
|
16159
|
-
return label || url;
|
|
16160
|
-
}
|
|
16161
|
-
case "emoji":
|
|
16162
|
-
return renderEmoji(el);
|
|
16163
|
-
case "user":
|
|
16164
|
-
return `<@${asString(el.user_id)}>`;
|
|
16165
|
-
case "usergroup":
|
|
16166
|
-
return `<!subteam^${asString(el.usergroup_id)}>`;
|
|
16167
|
-
case "channel":
|
|
16168
|
-
return `<#${asString(el.channel_id)}>`;
|
|
16169
|
-
case "broadcast":
|
|
16170
|
-
return `@${asString(el.range) || "channel"}`;
|
|
16171
|
-
case "date":
|
|
16172
|
-
return asString(el.fallback) || asString(el.timestamp);
|
|
16173
|
-
default:
|
|
16174
|
-
if (Array.isArray(el.elements)) return renderInline(el.elements);
|
|
16175
|
-
return asString(el.text);
|
|
16176
|
-
}
|
|
16177
|
-
}
|
|
16178
|
-
function renderInline(elements) {
|
|
16179
|
-
return elements.map(renderLeaf).join("");
|
|
16180
|
-
}
|
|
16181
|
-
function deepText(node, depth) {
|
|
16182
|
-
if (depth > MAX_DEPTH) return "";
|
|
16183
|
-
if (typeof node === "string") return node;
|
|
16184
|
-
if (Array.isArray(node)) return node.map((n) => deepText(n, depth + 1)).join("");
|
|
16185
|
-
if (!isRecord(node)) return "";
|
|
16186
|
-
const type = asString(node.type);
|
|
16187
|
-
if (type && type !== "rich_text" && !type.startsWith("rich_text_") && !type.includes("table")) {
|
|
16188
|
-
return renderLeaf(node);
|
|
16189
|
-
}
|
|
16190
|
-
if (Array.isArray(node.elements)) return node.elements.map((n) => deepText(n, depth + 1)).join("");
|
|
16191
|
-
if (Array.isArray(node.rows)) return node.rows.map((n) => deepText(n, depth + 1)).join(" ");
|
|
16192
|
-
return asString(node.text);
|
|
16193
|
-
}
|
|
16194
|
-
function renderCell(cell) {
|
|
16195
|
-
if (!isRecord(cell)) return deepText(cell, 0).replace(/\s*\n\s*/g, " ").trim();
|
|
16196
|
-
const inner = Array.isArray(cell.elements) ? renderSection(cell, 0) : deepText(cell, 0);
|
|
16197
|
-
return inner.replace(/\s*\n\s*/g, " ").trim();
|
|
16198
|
-
}
|
|
16199
|
-
function renderTable(el) {
|
|
16200
|
-
const rawRows = asArray(el.elements).length ? asArray(el.elements) : asArray(el.rows);
|
|
16201
|
-
const rows = [];
|
|
16202
|
-
for (const row of rawRows) {
|
|
16203
|
-
if (!isRecord(row) && !Array.isArray(row)) continue;
|
|
16204
|
-
const rawCells = Array.isArray(row) ? row : asArray(row.elements).length ? asArray(row.elements) : asArray(row.cells);
|
|
16205
|
-
if (rawCells.length === 0) continue;
|
|
16206
|
-
rows.push(rawCells.map(renderCell));
|
|
16207
|
-
}
|
|
16208
|
-
if (rows.length === 0) {
|
|
16209
|
-
const fallback = deepText(el, 0).replace(/[ \t]+\n/g, "\n").trim();
|
|
16210
|
-
return fallback;
|
|
16211
|
-
}
|
|
16212
|
-
const colCount = rows.reduce((max, r) => Math.max(max, r.length), 0);
|
|
16213
|
-
const pad = (r) => {
|
|
16214
|
-
const cells = r.slice();
|
|
16215
|
-
while (cells.length < colCount) cells.push("");
|
|
16216
|
-
return cells.map((c) => c.replace(/\|/g, "\\|"));
|
|
16217
|
-
};
|
|
16218
|
-
const lines = [];
|
|
16219
|
-
const header = rows[0] ?? [];
|
|
16220
|
-
const body = rows.slice(1);
|
|
16221
|
-
lines.push(`| ${pad(header).join(" | ")} |`);
|
|
16222
|
-
lines.push(`| ${Array.from({ length: colCount }, () => "---").join(" | ")} |`);
|
|
16223
|
-
for (const r of body) lines.push(`| ${pad(r).join(" | ")} |`);
|
|
16224
|
-
return lines.join("\n");
|
|
16225
|
-
}
|
|
16226
|
-
function renderSection(section, depth) {
|
|
16227
|
-
if (depth > MAX_DEPTH || !isRecord(section)) return "";
|
|
16228
|
-
const type = asString(section.type);
|
|
16229
|
-
if (isTableElement(section)) return renderTable(section);
|
|
16230
|
-
switch (type) {
|
|
16231
|
-
case "rich_text_section":
|
|
16232
|
-
return renderInline(asArray(section.elements));
|
|
16233
|
-
case "rich_text_preformatted": {
|
|
16234
|
-
const code = renderInline(asArray(section.elements));
|
|
16235
|
-
return code ? `\`\`\`
|
|
16236
|
-
${code}
|
|
16237
|
-
\`\`\`` : "";
|
|
16238
|
-
}
|
|
16239
|
-
case "rich_text_quote": {
|
|
16240
|
-
const quoted = renderInline(asArray(section.elements));
|
|
16241
|
-
return quoted ? quoted.split("\n").map((l) => `> ${l}`).join("\n") : "";
|
|
16242
|
-
}
|
|
16243
|
-
case "rich_text_list": {
|
|
16244
|
-
const ordered = asString(section.style) === "ordered";
|
|
16245
|
-
const items = asArray(section.elements).map((item, i) => {
|
|
16246
|
-
const body = renderSection(item, depth + 1) || renderInline(asArray(item?.elements));
|
|
16247
|
-
const marker = ordered ? `${i + 1}.` : "-";
|
|
16248
|
-
return `${marker} ${body}`.trimEnd();
|
|
16249
|
-
});
|
|
16250
|
-
return items.join("\n");
|
|
16251
|
-
}
|
|
16252
|
-
default:
|
|
16253
|
-
if (Array.isArray(section.elements)) return renderInline(asArray(section.elements));
|
|
16254
|
-
return deepText(section, depth + 1);
|
|
16255
|
-
}
|
|
16256
|
-
}
|
|
16257
|
-
function renderSlackBlocks(blocks) {
|
|
16258
|
-
let hadTable = false;
|
|
16259
|
-
const out = [];
|
|
16260
|
-
try {
|
|
16261
|
-
for (const block of asArray(blocks)) {
|
|
16262
|
-
if (!isRecord(block) || asString(block.type) !== "rich_text") continue;
|
|
16263
|
-
for (const section of asArray(block.elements)) {
|
|
16264
|
-
if (isTableElement(section)) hadTable = true;
|
|
16265
|
-
const rendered = renderSection(section, 0);
|
|
16266
|
-
if (rendered.trim().length > 0) out.push(rendered);
|
|
16267
|
-
}
|
|
16268
|
-
}
|
|
16269
|
-
} catch {
|
|
16270
|
-
}
|
|
16271
|
-
const text = out.join("\n\n").replace(/[ \t]+$/gm, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
16272
|
-
return { text, hadTable };
|
|
16273
|
-
}
|
|
16274
|
-
function mergeInboundText(text, blocks) {
|
|
16275
|
-
const { text: rendered, hadTable } = renderSlackBlocks(blocks);
|
|
16276
|
-
if (!hadTable) return { content: text, recoveredTable: false };
|
|
16277
|
-
const content = rendered.length > 0 ? rendered : text;
|
|
16278
|
-
return { content, recoveredTable: rendered.length > 0 && content !== text };
|
|
16279
|
-
}
|
|
16280
|
-
|
|
16281
16456
|
// src/inbound-dedup.ts
|
|
16282
16457
|
var DEFAULT_TTL_MS = 5 * 6e4;
|
|
16283
16458
|
var MAX_ENTRIES = 2e3;
|
|
@@ -18312,7 +18487,7 @@ function buildSlackHelpMessage(codeName) {
|
|
|
18312
18487
|
`\u2022 \`${agentSlashCommand("/restart")}\` \u2014 restart this agent`,
|
|
18313
18488
|
`\u2022 \`${agentSlashCommand("/onboard")}\` \u2014 re-run this agent's onboarding: re-interview, existing config kept (allowlisted users)`,
|
|
18314
18489
|
`\u2022 \`${agentSlashCommand("/resume-onboarding")}\` \u2014 resume this agent's onboarding where it left off (allowlisted users)`,
|
|
18315
|
-
`\u2022 \`${agentSlashCommand("/status")}\`
|
|
18490
|
+
`\u2022 \`${agentSlashCommand("/status")}\` - full health report: model, session, uptime + per-channel and per-integration status (cached snapshot, then this channel's own live check)`,
|
|
18316
18491
|
`\u2022 \`${agentSlashCommand("/ping")}\` - confirm this agent's channel is connected: posts a visible pong (team + manager only)`,
|
|
18317
18492
|
"\u2022 `/watch <google-doc-url> [duration]` (type it in chat) \u2014 watch a Google Doc for comments that mention me (default 2h, max 7d; auto-pauses when the window ends). In a shared channel, address me as `/watch-<my-name>`.",
|
|
18318
18493
|
"\u2022 `/kill` \u2014 silence all agents in this thread for 6h (use as a thread reply)",
|
|
@@ -18403,17 +18578,101 @@ function buildAgentStatusReply(codeName) {
|
|
|
18403
18578
|
const sessionState = readAgentSessionState(SLACK_AGENT_DIR);
|
|
18404
18579
|
return buildAgentConfigReport({ codeName, connectivityLine, state: sessionState });
|
|
18405
18580
|
}
|
|
18406
|
-
|
|
18581
|
+
var SLACK_OWN_CHANNEL_ID = "slack";
|
|
18582
|
+
function statusRuntimeConfig() {
|
|
18583
|
+
if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) return null;
|
|
18584
|
+
return { apiHost: AGT_HOST, apiKey: AGT_API_KEY, agentId: AGT_AGENT_ID };
|
|
18585
|
+
}
|
|
18586
|
+
async function computeSlackOwnChannelLiveStatus() {
|
|
18587
|
+
const checked_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
18588
|
+
const connected = currentWs != null && !isShuttingDown;
|
|
18589
|
+
if (!connected) {
|
|
18590
|
+
return { level: "down", checked_at, reason: "Socket Mode disconnected" };
|
|
18591
|
+
}
|
|
18592
|
+
const { id, authFailed } = await getBotUserId();
|
|
18593
|
+
if (id) {
|
|
18594
|
+
return { level: "ok", checked_at, reason: "Socket Mode connected, auth.test ok" };
|
|
18595
|
+
}
|
|
18596
|
+
if (authFailed) {
|
|
18597
|
+
return { level: "error", checked_at, reason: "auth.test failed (token invalid)" };
|
|
18598
|
+
}
|
|
18599
|
+
return { level: "degraded", checked_at, reason: "Socket Mode connected, auth.test inconclusive" };
|
|
18600
|
+
}
|
|
18601
|
+
async function handleStatusCommand(responseUrl, codeName) {
|
|
18602
|
+
const configBlock = buildAgentStatusReply(codeName);
|
|
18603
|
+
const cfg = statusRuntimeConfig();
|
|
18604
|
+
let report = null;
|
|
18605
|
+
if (cfg) {
|
|
18606
|
+
try {
|
|
18607
|
+
const { apiCall: apiCall2 } = await Promise.resolve().then(() => (init_ask_user_runtime(), ask_user_runtime_exports));
|
|
18608
|
+
const res = await apiCall2(
|
|
18609
|
+
cfg,
|
|
18610
|
+
"GET",
|
|
18611
|
+
`/host/status?agent_id=${encodeURIComponent(cfg.agentId)}`
|
|
18612
|
+
);
|
|
18613
|
+
if (res.ok) {
|
|
18614
|
+
report = parseAgentStatusReport(await res.json());
|
|
18615
|
+
} else {
|
|
18616
|
+
process.stderr.write(
|
|
18617
|
+
`slack-channel(${codeName}): /status host fetch returned ${res.status}
|
|
18618
|
+
`
|
|
18619
|
+
);
|
|
18620
|
+
}
|
|
18621
|
+
} catch (err) {
|
|
18622
|
+
process.stderr.write(
|
|
18623
|
+
`slack-channel(${codeName}): /status host fetch failed: ${err.message}
|
|
18624
|
+
`
|
|
18625
|
+
);
|
|
18626
|
+
}
|
|
18627
|
+
}
|
|
18628
|
+
if (!report) {
|
|
18629
|
+
await postEphemeralViaResponseUrl(
|
|
18630
|
+
responseUrl,
|
|
18631
|
+
`${configBlock}
|
|
18632
|
+
|
|
18633
|
+
_Channel + integration health is unavailable right now (host unreachable). Try again shortly._`,
|
|
18634
|
+
codeName
|
|
18635
|
+
);
|
|
18636
|
+
return;
|
|
18637
|
+
}
|
|
18638
|
+
const snapshot = `${configBlock}
|
|
18639
|
+
|
|
18640
|
+
${renderSlackStatusSections(report, {
|
|
18641
|
+
probing: true,
|
|
18642
|
+
nowMs: Date.now()
|
|
18643
|
+
})}`;
|
|
18644
|
+
await postEphemeralViaResponseUrl(responseUrl, snapshot, codeName);
|
|
18645
|
+
const live = await computeSlackOwnChannelLiveStatus();
|
|
18646
|
+
const merged = mergeOwnChannelLiveStatus(report, SLACK_OWN_CHANNEL_ID, live);
|
|
18647
|
+
const finalReport = `${configBlock}
|
|
18648
|
+
|
|
18649
|
+
${renderSlackStatusSections(merged, {
|
|
18650
|
+
probing: false,
|
|
18651
|
+
nowMs: Date.now()
|
|
18652
|
+
})}`;
|
|
18653
|
+
await postEphemeralViaResponseUrl(responseUrl, finalReport, codeName, { replaceOriginal: true });
|
|
18654
|
+
}
|
|
18655
|
+
async function postEphemeralViaResponseUrl(responseUrl, text, logTag, opts = {}) {
|
|
18407
18656
|
try {
|
|
18408
|
-
await fetch(responseUrl, {
|
|
18657
|
+
const res = await fetch(responseUrl, {
|
|
18409
18658
|
method: "POST",
|
|
18410
18659
|
headers: { "Content-Type": "application/json; charset=utf-8" },
|
|
18411
|
-
body: JSON.stringify({
|
|
18660
|
+
body: JSON.stringify({
|
|
18661
|
+
response_type: "ephemeral",
|
|
18662
|
+
text,
|
|
18663
|
+
...opts.replaceOriginal ? { replace_original: true } : {}
|
|
18664
|
+
}),
|
|
18412
18665
|
// Match the rest of the Slack API call sites in this file. Without
|
|
18413
18666
|
// this, a hung response_url request can stall the live Socket Mode
|
|
18414
18667
|
// event loop indefinitely (CodeRabbit feedback on PR #578).
|
|
18415
18668
|
signal: AbortSignal.timeout(SLACK_DOWNLOAD_TIMEOUT_MS)
|
|
18416
18669
|
});
|
|
18670
|
+
if (!res.ok) {
|
|
18671
|
+
process.stderr.write(
|
|
18672
|
+
`slack-channel(${logTag}): response_url POST returned ${res.status}
|
|
18673
|
+
`
|
|
18674
|
+
);
|
|
18675
|
+
}
|
|
18417
18676
|
} catch (err) {
|
|
18418
18677
|
process.stderr.write(
|
|
18419
18678
|
`slack-channel(${logTag}): response_url POST failed: ${err.message}
|
|
@@ -18661,7 +18920,7 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
18661
18920
|
const codeName = AGENT_CODE_NAME ?? "unknown";
|
|
18662
18921
|
if (!command || !responseUrl) return;
|
|
18663
18922
|
if (matchesAgentCommand(command, "/status") || matchesAgentCommand(command, "/agent-status")) {
|
|
18664
|
-
await
|
|
18923
|
+
await handleStatusCommand(responseUrl, codeName);
|
|
18665
18924
|
return;
|
|
18666
18925
|
}
|
|
18667
18926
|
if (matchesAgentCommand(command, "/help")) {
|
|
@@ -20870,7 +21129,12 @@ async function connectSocketMode() {
|
|
|
20870
21129
|
}
|
|
20871
21130
|
}
|
|
20872
21131
|
const userName = await resolveUserName(user);
|
|
20873
|
-
const
|
|
21132
|
+
const forwarded = extractForwardedContent(evt.attachments);
|
|
21133
|
+
const fileMeta = await buildInboundFileMeta(
|
|
21134
|
+
[...evt.files ?? [], ...forwarded.files],
|
|
21135
|
+
AGENT_CODE_NAME,
|
|
21136
|
+
channel
|
|
21137
|
+
);
|
|
20874
21138
|
const downloadedImages = fileMeta.filter(
|
|
20875
21139
|
(f) => f.kind === "image" && typeof f.path === "string"
|
|
20876
21140
|
);
|
|
@@ -20898,10 +21162,20 @@ async function connectSocketMode() {
|
|
|
20898
21162
|
);
|
|
20899
21163
|
}
|
|
20900
21164
|
}
|
|
20901
|
-
const { content:
|
|
21165
|
+
const { content: mergedText, recoveredTable } = mergeInboundText(text, evt.blocks);
|
|
20902
21166
|
if (recoveredTable) {
|
|
20903
21167
|
process.stderr.write(
|
|
20904
21168
|
`slack-channel(${AGENT_CODE_NAME}): recovered rich_text table from blocks (channel=${redactSlackId(channel)} ts=${redactSlackId(ts)})
|
|
21169
|
+
`
|
|
21170
|
+
);
|
|
21171
|
+
}
|
|
21172
|
+
let inboundContent = mergedText;
|
|
21173
|
+
if (forwarded.text) {
|
|
21174
|
+
inboundContent = mergedText.trim().length > 0 ? `${mergedText}
|
|
21175
|
+
|
|
21176
|
+
${forwarded.text}` : forwarded.text;
|
|
21177
|
+
process.stderr.write(
|
|
21178
|
+
`slack-channel(${AGENT_CODE_NAME}): recovered forwarded message content (channel=${redactSlackId(channel)} ts=${redactSlackId(ts)})
|
|
20905
21179
|
`
|
|
20906
21180
|
);
|
|
20907
21181
|
}
|
package/package.json
CHANGED
|
File without changes
|