@integrity-labs/agt-cli 0.27.162 → 0.27.164
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 +4 -4
- package/dist/{chunk-LK7R6HLJ.js → chunk-3A2H4ZLD.js} +9 -2
- package/dist/{chunk-LK7R6HLJ.js.map → chunk-3A2H4ZLD.js.map} +1 -1
- package/dist/{chunk-AEECYKHW.js → chunk-5TBIEU36.js} +2 -2
- package/dist/{chunk-H5B4ESA5.js → chunk-OIX32YSR.js} +2 -2
- package/dist/{claude-pair-runtime-TZOAZFBQ.js → claude-pair-runtime-ZEFIYDUH.js} +2 -2
- package/dist/lib/manager-worker.js +10 -13
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/slack-channel.js +302 -82
- package/dist/mcp/telegram-channel.js +255 -44
- package/dist/{persistent-session-WL22MKBS.js → persistent-session-7BLPRGWR.js} +3 -3
- package/dist/{responsiveness-probe-N3Q3O6X7.js → responsiveness-probe-AL3O7SYZ.js} +3 -3
- package/package.json +1 -1
- /package/dist/{chunk-AEECYKHW.js.map → chunk-5TBIEU36.js.map} +0 -0
- /package/dist/{chunk-H5B4ESA5.js.map → chunk-OIX32YSR.js.map} +0 -0
- /package/dist/{claude-pair-runtime-TZOAZFBQ.js.map → claude-pair-runtime-ZEFIYDUH.js.map} +0 -0
- /package/dist/{persistent-session-WL22MKBS.js.map → persistent-session-7BLPRGWR.js.map} +0 -0
- /package/dist/{responsiveness-probe-N3Q3O6X7.js.map → responsiveness-probe-AL3O7SYZ.js.map} +0 -0
|
@@ -14344,9 +14344,152 @@ function decideInboundAccess(input) {
|
|
|
14344
14344
|
return { kind: "admit" };
|
|
14345
14345
|
}
|
|
14346
14346
|
|
|
14347
|
+
// src/watch-command.ts
|
|
14348
|
+
var WATCH_DEFAULT_DURATION_MS = 2 * 60 * 60 * 1e3;
|
|
14349
|
+
var WATCH_MAX_DURATION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
14350
|
+
var WATCH_MIN_DURATION_MS = 5 * 60 * 1e3;
|
|
14351
|
+
function extractDriveFileId(s) {
|
|
14352
|
+
const trimmed = s.trim().replace(/^<|>$/g, "");
|
|
14353
|
+
const pathId = trimmed.match(/\/d\/([A-Za-z0-9_-]{10,})/);
|
|
14354
|
+
if (pathId?.[1]) return pathId[1];
|
|
14355
|
+
const idParam = trimmed.match(/[?&]id=([A-Za-z0-9_-]{10,})/);
|
|
14356
|
+
if (idParam?.[1]) return idParam[1];
|
|
14357
|
+
if (!/[/:?]/.test(trimmed) && /^[A-Za-z0-9_-]{20,}$/.test(trimmed)) return trimmed;
|
|
14358
|
+
return null;
|
|
14359
|
+
}
|
|
14360
|
+
function parseDurationToken(token) {
|
|
14361
|
+
const m = token.trim().match(/^(\d+)\s*([smhd])?$/i);
|
|
14362
|
+
if (!m?.[1]) return null;
|
|
14363
|
+
const n = Number.parseInt(m[1], 10);
|
|
14364
|
+
if (!Number.isFinite(n) || n <= 0) return null;
|
|
14365
|
+
const unit = (m[2] ?? "m").toLowerCase();
|
|
14366
|
+
const mult = unit === "s" ? 1e3 : unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5;
|
|
14367
|
+
return n * mult;
|
|
14368
|
+
}
|
|
14369
|
+
function parseWatchArgs(args) {
|
|
14370
|
+
const parts = args.trim().split(/\s+/).filter(Boolean);
|
|
14371
|
+
const first = parts[0];
|
|
14372
|
+
if (!first) return { ok: false, error: "usage" };
|
|
14373
|
+
if (parts.length > 2) return { ok: false, error: "usage" };
|
|
14374
|
+
const fileId = extractDriveFileId(first);
|
|
14375
|
+
if (!fileId) return { ok: false, error: "bad-url" };
|
|
14376
|
+
let durationMs = WATCH_DEFAULT_DURATION_MS;
|
|
14377
|
+
const durationToken = parts[1];
|
|
14378
|
+
if (durationToken !== void 0) {
|
|
14379
|
+
const parsed = parseDurationToken(durationToken);
|
|
14380
|
+
if (parsed === null) return { ok: false, error: "bad-duration" };
|
|
14381
|
+
durationMs = Math.min(Math.max(parsed, WATCH_MIN_DURATION_MS), WATCH_MAX_DURATION_MS);
|
|
14382
|
+
}
|
|
14383
|
+
return { ok: true, value: { fileId, durationMs } };
|
|
14384
|
+
}
|
|
14385
|
+
function watchArgsFromText(strippedText, codeName, opts) {
|
|
14386
|
+
const forms = [];
|
|
14387
|
+
if (opts?.allowBare ?? true) forms.push("/watch");
|
|
14388
|
+
if (codeName) forms.push(`/watch-${codeName}`);
|
|
14389
|
+
for (const f of forms) {
|
|
14390
|
+
if (strippedText === f) return "";
|
|
14391
|
+
if (strippedText.startsWith(`${f} `)) return strippedText.slice(f.length + 1).trim();
|
|
14392
|
+
}
|
|
14393
|
+
return null;
|
|
14394
|
+
}
|
|
14395
|
+
async function postWatchTrigger(opts) {
|
|
14396
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
14397
|
+
try {
|
|
14398
|
+
const res = await doFetch(`${opts.host}/host/triggers`, {
|
|
14399
|
+
method: "POST",
|
|
14400
|
+
headers: {
|
|
14401
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
14402
|
+
Authorization: `Bearer ${opts.apiKey}`
|
|
14403
|
+
},
|
|
14404
|
+
body: JSON.stringify({
|
|
14405
|
+
agent_id: opts.agentId,
|
|
14406
|
+
provider: "gdrive_comments",
|
|
14407
|
+
config: { fileId: opts.fileId },
|
|
14408
|
+
expires_at: opts.expiresAtIso
|
|
14409
|
+
}),
|
|
14410
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 15e3)
|
|
14411
|
+
});
|
|
14412
|
+
if (!res.ok) {
|
|
14413
|
+
let msg = `HTTP ${res.status}`;
|
|
14414
|
+
try {
|
|
14415
|
+
const j2 = await res.json();
|
|
14416
|
+
if (j2?.error) msg = j2.error;
|
|
14417
|
+
} catch {
|
|
14418
|
+
}
|
|
14419
|
+
return { ok: false, status: res.status, error: msg };
|
|
14420
|
+
}
|
|
14421
|
+
const j = await res.json().catch(() => ({}));
|
|
14422
|
+
return { ok: true, status: res.status, reused: !!j.reused, expiresAt: j.expires_at ?? null };
|
|
14423
|
+
} catch (err) {
|
|
14424
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
14425
|
+
}
|
|
14426
|
+
}
|
|
14427
|
+
function humanDuration(ms) {
|
|
14428
|
+
const mins = Math.round(ms / 6e4);
|
|
14429
|
+
if (mins % 1440 === 0) return `${mins / 1440}d`;
|
|
14430
|
+
if (mins % 60 === 0) return `${mins / 60}h`;
|
|
14431
|
+
return `${mins}m`;
|
|
14432
|
+
}
|
|
14433
|
+
function watchUsageText() {
|
|
14434
|
+
return "Usage: `/watch <google-doc-url> [duration]` \u2014 e.g. `/watch https://docs.google.com/document/d/\u2026/edit 2h`. Duration defaults to 2h (max 7d).";
|
|
14435
|
+
}
|
|
14436
|
+
function watchBadUrlText() {
|
|
14437
|
+
return "That doesn't look like a Google Doc link. Paste the doc's share URL (the part with `/d/<id>`).";
|
|
14438
|
+
}
|
|
14439
|
+
function watchBadDurationText() {
|
|
14440
|
+
return "I couldn't read that duration. Try `30m`, `2h`, or `1d` (max 7d).";
|
|
14441
|
+
}
|
|
14442
|
+
function watchErrorText() {
|
|
14443
|
+
return "\u274C I couldn't set up that watch just now. Please try again in a moment.";
|
|
14444
|
+
}
|
|
14445
|
+
function watchSuccessTextSlack(fileId, durationMs, reused) {
|
|
14446
|
+
const url = `https://docs.google.com/document/d/${fileId}/edit`;
|
|
14447
|
+
const verb = reused ? "Extended my watch on" : "Watching";
|
|
14448
|
+
return `\u{1F440} ${verb} <${url}|that doc> for new comments that mention me, for the next ${humanDuration(durationMs)}. I'll pause automatically when the window's up. (Make sure Google Drive is connected with comment access, or I won't see them.)`;
|
|
14449
|
+
}
|
|
14450
|
+
|
|
14347
14451
|
// src/ack-reaction.ts
|
|
14348
|
-
import { readdirSync, readFileSync } from "fs";
|
|
14452
|
+
import { readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
14453
|
+
import { join as join2 } from "path";
|
|
14454
|
+
|
|
14455
|
+
// src/flags-cache-read.ts
|
|
14456
|
+
import { existsSync, readFileSync } from "fs";
|
|
14457
|
+
import { homedir } from "os";
|
|
14349
14458
|
import { join } from "path";
|
|
14459
|
+
function defaultFlagsCachePath() {
|
|
14460
|
+
return join(homedir(), ".augmented", "flags-cache.json");
|
|
14461
|
+
}
|
|
14462
|
+
function envBoolean(raw) {
|
|
14463
|
+
if (raw === void 0) return void 0;
|
|
14464
|
+
const v = raw.trim().toLowerCase();
|
|
14465
|
+
if (v === "") return void 0;
|
|
14466
|
+
if (v === "1" || v === "true" || v === "yes" || v === "on") return true;
|
|
14467
|
+
if (v === "0" || v === "false" || v === "no" || v === "off") return false;
|
|
14468
|
+
return void 0;
|
|
14469
|
+
}
|
|
14470
|
+
function cachedBoolean(key2, path) {
|
|
14471
|
+
try {
|
|
14472
|
+
if (!existsSync(path)) return void 0;
|
|
14473
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
14474
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
14475
|
+
const flags = parsed.flags;
|
|
14476
|
+
if (!flags || typeof flags !== "object") return void 0;
|
|
14477
|
+
const value = flags[key2];
|
|
14478
|
+
return typeof value === "boolean" ? value : void 0;
|
|
14479
|
+
} catch {
|
|
14480
|
+
return void 0;
|
|
14481
|
+
}
|
|
14482
|
+
}
|
|
14483
|
+
function resolveHostBooleanFlag(opts) {
|
|
14484
|
+
const env = opts.env ?? process.env;
|
|
14485
|
+
const envValue = envBoolean(env[opts.envVar]);
|
|
14486
|
+
if (envValue !== void 0) return envValue;
|
|
14487
|
+
const cached2 = cachedBoolean(opts.key, opts.cachePath ?? defaultFlagsCachePath());
|
|
14488
|
+
if (cached2 !== void 0) return cached2;
|
|
14489
|
+
return opts.defaultValue;
|
|
14490
|
+
}
|
|
14491
|
+
|
|
14492
|
+
// src/ack-reaction.ts
|
|
14350
14493
|
var REPLY_WEDGED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
14351
14494
|
var ACK_STARTUP_GRACE_MS = 6e4;
|
|
14352
14495
|
var ACK_PANE_FRESH_THRESHOLD_MS = 6e4;
|
|
@@ -14381,8 +14524,11 @@ function undeliverableNoticeText() {
|
|
|
14381
14524
|
var BUSY_ACK_THRESHOLD_MS = 9e4;
|
|
14382
14525
|
var BUSY_ACK_NOTICE_THROTTLE_MS = 10 * 60 * 1e3;
|
|
14383
14526
|
function channelBusyAckEnabled() {
|
|
14384
|
-
|
|
14385
|
-
|
|
14527
|
+
return resolveHostBooleanFlag({
|
|
14528
|
+
key: "channel-busy-ack",
|
|
14529
|
+
envVar: "AGT_CHANNEL_BUSY_ACK_ENABLED",
|
|
14530
|
+
defaultValue: false
|
|
14531
|
+
});
|
|
14386
14532
|
}
|
|
14387
14533
|
function channelBusyAckThresholdMs() {
|
|
14388
14534
|
const raw = parseInt(process.env.AGT_CHANNEL_BUSY_ACK_THRESHOLD_MS ?? "", 10);
|
|
@@ -14406,7 +14552,7 @@ var GIVE_UP_SIGNAL_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
|
14406
14552
|
function readGiveUpSignalAtMs(path, now = Date.now()) {
|
|
14407
14553
|
if (!path) return null;
|
|
14408
14554
|
try {
|
|
14409
|
-
const raw = JSON.parse(
|
|
14555
|
+
const raw = JSON.parse(readFileSync2(path, "utf8"));
|
|
14410
14556
|
if (typeof raw.gave_up_at !== "string") return null;
|
|
14411
14557
|
const t = Date.parse(raw.gave_up_at);
|
|
14412
14558
|
if (!Number.isFinite(t) || t > now) return null;
|
|
@@ -14438,7 +14584,7 @@ function oldestPendingMarkerAgeMs(dir, now = Date.now()) {
|
|
|
14438
14584
|
if (!name.endsWith(".json")) continue;
|
|
14439
14585
|
let receivedAt;
|
|
14440
14586
|
try {
|
|
14441
|
-
const raw = JSON.parse(
|
|
14587
|
+
const raw = JSON.parse(readFileSync2(join2(dir, name), "utf-8"));
|
|
14442
14588
|
receivedAt = raw.received_at;
|
|
14443
14589
|
} catch {
|
|
14444
14590
|
continue;
|
|
@@ -14521,15 +14667,15 @@ function probeAgentSessionCached(codeName, ttlMs = SESSION_PROBE_TTL_MS, now = D
|
|
|
14521
14667
|
}
|
|
14522
14668
|
|
|
14523
14669
|
// src/agent-config-state.ts
|
|
14524
|
-
import { existsSync, readFileSync as
|
|
14525
|
-
import { join as
|
|
14670
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
14671
|
+
import { join as join3 } from "path";
|
|
14526
14672
|
var SESSION_STATE_FILENAME = "session-state.json";
|
|
14527
14673
|
function readAgentSessionState(stateDir) {
|
|
14528
14674
|
if (!stateDir) return null;
|
|
14529
|
-
const path =
|
|
14530
|
-
if (!
|
|
14675
|
+
const path = join3(stateDir, SESSION_STATE_FILENAME);
|
|
14676
|
+
if (!existsSync2(path)) return null;
|
|
14531
14677
|
try {
|
|
14532
|
-
const parsed = JSON.parse(
|
|
14678
|
+
const parsed = JSON.parse(readFileSync3(path, "utf-8"));
|
|
14533
14679
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
14534
14680
|
return parsed;
|
|
14535
14681
|
} catch {
|
|
@@ -14601,10 +14747,10 @@ import { promisify } from "util";
|
|
|
14601
14747
|
import { open, stat } from "fs/promises";
|
|
14602
14748
|
|
|
14603
14749
|
// src/channel-attachments.ts
|
|
14604
|
-
import { homedir } from "os";
|
|
14605
|
-
import { join as
|
|
14750
|
+
import { homedir as homedir2 } from "os";
|
|
14751
|
+
import { join as join4, resolve, sep } from "path";
|
|
14606
14752
|
function resolveChannelInboundDir(codeName, channelSlug) {
|
|
14607
|
-
const base =
|
|
14753
|
+
const base = join4(homedir2(), ".augmented");
|
|
14608
14754
|
const allowedSegment = /^[A-Za-z0-9_-]+$/;
|
|
14609
14755
|
if (!allowedSegment.test(codeName) || !allowedSegment.test(channelSlug)) {
|
|
14610
14756
|
throw new Error(
|
|
@@ -14682,7 +14828,7 @@ function isPathInside(target, root) {
|
|
|
14682
14828
|
return normalizedTarget === resolve(root) || normalizedTarget.startsWith(normalizedRoot);
|
|
14683
14829
|
}
|
|
14684
14830
|
function redactAugmentedPaths(msg) {
|
|
14685
|
-
const homePrefix =
|
|
14831
|
+
const homePrefix = homedir2().replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14686
14832
|
return msg.replaceAll(
|
|
14687
14833
|
new RegExp(`${homePrefix}[\\\\/]\\.augmented(?:[\\\\/][^\\s'"\`]*)*`, "g"),
|
|
14688
14834
|
"<augmented-path>"
|
|
@@ -15030,14 +15176,14 @@ var SLACK_EGRESS_TOOLS = /* @__PURE__ */ new Set([
|
|
|
15030
15176
|
]);
|
|
15031
15177
|
|
|
15032
15178
|
// src/slack-pending-inbound-cleanup.ts
|
|
15033
|
-
import { existsSync as
|
|
15034
|
-
import { join as
|
|
15179
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2, statSync, unlinkSync } from "fs";
|
|
15180
|
+
import { join as join5 } from "path";
|
|
15035
15181
|
function sanitizeMarkerSegment(value) {
|
|
15036
15182
|
return value.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
15037
15183
|
}
|
|
15038
15184
|
var defaultClearMarkerFile = (fullPath) => {
|
|
15039
15185
|
try {
|
|
15040
|
-
if (
|
|
15186
|
+
if (existsSync3(fullPath)) unlinkSync(fullPath);
|
|
15041
15187
|
} catch {
|
|
15042
15188
|
}
|
|
15043
15189
|
};
|
|
@@ -15048,7 +15194,7 @@ function clearAllSlackPendingMarkersForThread(dir, channel, threadTs, clear = de
|
|
|
15048
15194
|
try {
|
|
15049
15195
|
for (const f of readdirSync2(dir)) {
|
|
15050
15196
|
if (!f.startsWith(prefix) || !f.endsWith(".json")) continue;
|
|
15051
|
-
clear(
|
|
15197
|
+
clear(join5(dir, f));
|
|
15052
15198
|
cleared += 1;
|
|
15053
15199
|
}
|
|
15054
15200
|
} catch {
|
|
@@ -15063,7 +15209,7 @@ function clearSlackPendingMarkerByMessageTs(dir, channel, messageTs, clear = def
|
|
|
15063
15209
|
try {
|
|
15064
15210
|
for (const f of readdirSync2(dir)) {
|
|
15065
15211
|
if (!f.startsWith(channelPrefix) || !f.endsWith(messageSuffix)) continue;
|
|
15066
|
-
clear(
|
|
15212
|
+
clear(join5(dir, f));
|
|
15067
15213
|
cleared += 1;
|
|
15068
15214
|
}
|
|
15069
15215
|
} catch {
|
|
@@ -15075,7 +15221,7 @@ function clearOldestSlackPendingMarkerInChannel(dir, channel, clear = defaultCle
|
|
|
15075
15221
|
const channelPrefix = `${sanitizeMarkerSegment(channel)}__`;
|
|
15076
15222
|
try {
|
|
15077
15223
|
const entries = readdirSync2(dir).filter((f) => f.startsWith(channelPrefix) && f.endsWith(".json")).map((f) => {
|
|
15078
|
-
const full =
|
|
15224
|
+
const full = join5(dir, f);
|
|
15079
15225
|
let mtime = 0;
|
|
15080
15226
|
try {
|
|
15081
15227
|
mtime = statSync(full).mtimeMs;
|
|
@@ -15103,7 +15249,7 @@ function resolveReplyThreadTs(input) {
|
|
|
15103
15249
|
}
|
|
15104
15250
|
|
|
15105
15251
|
// src/restart-confirm.ts
|
|
15106
|
-
import { existsSync as
|
|
15252
|
+
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, renameSync, unlinkSync as unlinkSync2, writeFileSync } from "fs";
|
|
15107
15253
|
import { dirname } from "path";
|
|
15108
15254
|
import { randomUUID } from "crypto";
|
|
15109
15255
|
var RESTART_CONFIRM_MAX_AGE_MS = 10 * 60 * 1e3;
|
|
@@ -15121,15 +15267,15 @@ function buildBackOnlineText(name) {
|
|
|
15121
15267
|
}
|
|
15122
15268
|
function writeRestartConfirmMarker(filePath, marker) {
|
|
15123
15269
|
const dir = dirname(filePath);
|
|
15124
|
-
if (!
|
|
15270
|
+
if (!existsSync4(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
|
|
15125
15271
|
const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
|
|
15126
15272
|
writeFileSync(tmpPath, JSON.stringify(marker) + "\n", { encoding: "utf8", mode: 384 });
|
|
15127
15273
|
renameSync(tmpPath, filePath);
|
|
15128
15274
|
}
|
|
15129
15275
|
function readRestartConfirmMarker(filePath) {
|
|
15130
15276
|
try {
|
|
15131
|
-
if (!
|
|
15132
|
-
const parsed = JSON.parse(
|
|
15277
|
+
if (!existsSync4(filePath)) return null;
|
|
15278
|
+
const parsed = JSON.parse(readFileSync4(filePath, "utf8"));
|
|
15133
15279
|
if (!parsed || typeof parsed !== "object") return null;
|
|
15134
15280
|
return parsed;
|
|
15135
15281
|
} catch {
|
|
@@ -15138,7 +15284,7 @@ function readRestartConfirmMarker(filePath) {
|
|
|
15138
15284
|
}
|
|
15139
15285
|
function clearRestartConfirmMarker(filePath) {
|
|
15140
15286
|
try {
|
|
15141
|
-
if (
|
|
15287
|
+
if (existsSync4(filePath)) unlinkSync2(filePath);
|
|
15142
15288
|
} catch {
|
|
15143
15289
|
}
|
|
15144
15290
|
}
|
|
@@ -15239,9 +15385,9 @@ var StdioServerTransport = class {
|
|
|
15239
15385
|
import {
|
|
15240
15386
|
chmodSync,
|
|
15241
15387
|
createWriteStream,
|
|
15242
|
-
existsSync as
|
|
15388
|
+
existsSync as existsSync7,
|
|
15243
15389
|
mkdirSync as mkdirSync5,
|
|
15244
|
-
readFileSync as
|
|
15390
|
+
readFileSync as readFileSync8,
|
|
15245
15391
|
readdirSync as readdirSync3,
|
|
15246
15392
|
renameSync as renameSync3,
|
|
15247
15393
|
statSync as statSync2,
|
|
@@ -15249,12 +15395,12 @@ import {
|
|
|
15249
15395
|
watch,
|
|
15250
15396
|
writeFileSync as writeFileSync5
|
|
15251
15397
|
} from "fs";
|
|
15252
|
-
import { basename, join as
|
|
15253
|
-
import { homedir as
|
|
15398
|
+
import { basename, join as join7, resolve as resolve2 } from "path";
|
|
15399
|
+
import { homedir as homedir3 } from "os";
|
|
15254
15400
|
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
15255
15401
|
|
|
15256
15402
|
// src/slack-thread-store.ts
|
|
15257
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
15403
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
15258
15404
|
import { dirname as dirname2 } from "path";
|
|
15259
15405
|
var FILE_VERSION = 1;
|
|
15260
15406
|
var DEFAULT_TTL_DAYS = 30;
|
|
@@ -15265,7 +15411,7 @@ function loadThreadStore(filePath, opts = {}) {
|
|
|
15265
15411
|
const ttlMs = ttlDays * 24 * 60 * 60 * 1e3;
|
|
15266
15412
|
let raw;
|
|
15267
15413
|
try {
|
|
15268
|
-
raw =
|
|
15414
|
+
raw = readFileSync5(filePath, "utf-8");
|
|
15269
15415
|
} catch {
|
|
15270
15416
|
return { threads: /* @__PURE__ */ new Map(), pruned: 0 };
|
|
15271
15417
|
}
|
|
@@ -15379,7 +15525,7 @@ async function runOrRetry(fn, opts) {
|
|
|
15379
15525
|
}
|
|
15380
15526
|
|
|
15381
15527
|
// src/slack-bot-photo.ts
|
|
15382
|
-
import { existsSync as
|
|
15528
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
15383
15529
|
import { dirname as dirname3 } from "path";
|
|
15384
15530
|
async function applyBotPhoto(opts) {
|
|
15385
15531
|
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
@@ -15387,9 +15533,9 @@ async function applyBotPhoto(opts) {
|
|
|
15387
15533
|
process.stderr.write(m);
|
|
15388
15534
|
});
|
|
15389
15535
|
const { token, avatarUrl, markerPath } = opts;
|
|
15390
|
-
if (markerPath &&
|
|
15536
|
+
if (markerPath && existsSync5(markerPath)) {
|
|
15391
15537
|
try {
|
|
15392
|
-
if (
|
|
15538
|
+
if (readFileSync6(markerPath, "utf-8").trim() === avatarUrl) {
|
|
15393
15539
|
return { status: "skipped-unchanged" };
|
|
15394
15540
|
}
|
|
15395
15541
|
} catch {
|
|
@@ -16182,14 +16328,14 @@ function createSlackBotUserIdClient(args) {
|
|
|
16182
16328
|
|
|
16183
16329
|
// src/mcp-spawn-lock.ts
|
|
16184
16330
|
import {
|
|
16185
|
-
existsSync as
|
|
16331
|
+
existsSync as existsSync6,
|
|
16186
16332
|
mkdirSync as mkdirSync4,
|
|
16187
|
-
readFileSync as
|
|
16333
|
+
readFileSync as readFileSync7,
|
|
16188
16334
|
renameSync as renameSync2,
|
|
16189
16335
|
unlinkSync as unlinkSync3,
|
|
16190
16336
|
writeFileSync as writeFileSync4
|
|
16191
16337
|
} from "fs";
|
|
16192
|
-
import { join as
|
|
16338
|
+
import { join as join6 } from "path";
|
|
16193
16339
|
function defaultIsPidAlive(pid) {
|
|
16194
16340
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
16195
16341
|
try {
|
|
@@ -16207,7 +16353,7 @@ function acquireMcpSpawnLock(args) {
|
|
|
16207
16353
|
const isPidAlive = options.isPidAlive ?? defaultIsPidAlive;
|
|
16208
16354
|
const selfPid = options.selfPid ?? process.pid;
|
|
16209
16355
|
const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
16210
|
-
const path =
|
|
16356
|
+
const path = join6(agentDir, basename2);
|
|
16211
16357
|
const existing = readLockHolder(path);
|
|
16212
16358
|
if (existing) {
|
|
16213
16359
|
if (existing.pid === selfPid) {
|
|
@@ -16236,9 +16382,9 @@ function releaseMcpSpawnLock(lockPath, opts = {}) {
|
|
|
16236
16382
|
}
|
|
16237
16383
|
}
|
|
16238
16384
|
function readLockHolder(path) {
|
|
16239
|
-
if (!
|
|
16385
|
+
if (!existsSync6(path)) return null;
|
|
16240
16386
|
try {
|
|
16241
|
-
const raw =
|
|
16387
|
+
const raw = readFileSync7(path, "utf8");
|
|
16242
16388
|
const parsed = JSON.parse(raw);
|
|
16243
16389
|
const pid = typeof parsed.pid === "number" ? parsed.pid : Number(parsed.pid);
|
|
16244
16390
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
@@ -16414,8 +16560,8 @@ var SLACK_PEER_CLASSIFIER_CONFIG = {
|
|
|
16414
16560
|
peers: parsePeersEnv(process.env.SLACK_PEERS, process.env.SLACK_PEERS_GATE),
|
|
16415
16561
|
peer_disabled_mode: SLACK_PEER_DISABLED_MODE
|
|
16416
16562
|
};
|
|
16417
|
-
var SLACK_AGENT_DIR = AGENT_CODE_NAME ?
|
|
16418
|
-
var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ?
|
|
16563
|
+
var SLACK_AGENT_DIR = AGENT_CODE_NAME ? join7(homedir3(), ".augmented", AGENT_CODE_NAME) : null;
|
|
16564
|
+
var SLACK_MCP_CONFIG_PATH = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "project", ".mcp.json") : null;
|
|
16419
16565
|
var liveAllowedUsersCache = null;
|
|
16420
16566
|
function readLiveAllowedUsers() {
|
|
16421
16567
|
if (!SLACK_MCP_CONFIG_PATH) return null;
|
|
@@ -16425,7 +16571,7 @@ function readLiveAllowedUsers() {
|
|
|
16425
16571
|
return liveAllowedUsersCache.value;
|
|
16426
16572
|
}
|
|
16427
16573
|
const value = extractAllowedUsersFromMcpJson(
|
|
16428
|
-
|
|
16574
|
+
readFileSync8(SLACK_MCP_CONFIG_PATH, "utf-8")
|
|
16429
16575
|
);
|
|
16430
16576
|
if (value === null) return null;
|
|
16431
16577
|
liveAllowedUsersCache = { mtimeMs, value };
|
|
@@ -16437,11 +16583,11 @@ function readLiveAllowedUsers() {
|
|
|
16437
16583
|
function getEffectiveAllowedUsers() {
|
|
16438
16584
|
return readLiveAllowedUsers() ?? ALLOWED_USERS;
|
|
16439
16585
|
}
|
|
16440
|
-
var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ?
|
|
16441
|
-
var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ?
|
|
16442
|
-
var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ?
|
|
16586
|
+
var SLACK_PENDING_INBOUND_DIR = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-pending-inbound") : null;
|
|
16587
|
+
var SLACK_RECOVERY_OUTBOX_DIR = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-recovery-outbox") : null;
|
|
16588
|
+
var SLACK_RESTART_CONFIRM_FILE = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-restart-confirm.json") : null;
|
|
16443
16589
|
var SLACK_MAX_RECOVERY_ATTEMPTS = 3;
|
|
16444
|
-
var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ?
|
|
16590
|
+
var SLACK_AVATAR_MARKER_PATH = SLACK_AGENT_DIR ? join7(SLACK_AGENT_DIR, "slack-avatar-applied") : null;
|
|
16445
16591
|
function redactSlackId(id) {
|
|
16446
16592
|
if (!id) return "<none>";
|
|
16447
16593
|
return createHash("sha256").update(id).digest("hex").slice(0, 8);
|
|
@@ -16452,7 +16598,7 @@ function safeSlackMarkerName(channel, threadTs, messageTs) {
|
|
|
16452
16598
|
}
|
|
16453
16599
|
function slackPendingInboundPath(channel, threadTs, messageTs) {
|
|
16454
16600
|
if (!SLACK_PENDING_INBOUND_DIR) return null;
|
|
16455
|
-
return
|
|
16601
|
+
return join7(SLACK_PENDING_INBOUND_DIR, safeSlackMarkerName(channel, threadTs, messageTs));
|
|
16456
16602
|
}
|
|
16457
16603
|
function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undeliverable = false) {
|
|
16458
16604
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
@@ -16477,9 +16623,9 @@ function writeSlackPendingInboundMarker(channel, threadTs, messageTs, undelivera
|
|
|
16477
16623
|
}
|
|
16478
16624
|
function readSlackPendingInboundMarker(channel, threadTs, messageTs) {
|
|
16479
16625
|
const path = slackPendingInboundPath(channel, threadTs, messageTs);
|
|
16480
|
-
if (!path || !
|
|
16626
|
+
if (!path || !existsSync7(path)) return null;
|
|
16481
16627
|
try {
|
|
16482
|
-
return JSON.parse(
|
|
16628
|
+
return JSON.parse(readFileSync8(path, "utf-8"));
|
|
16483
16629
|
} catch {
|
|
16484
16630
|
return null;
|
|
16485
16631
|
}
|
|
@@ -16573,7 +16719,7 @@ function scheduleBusyAck(channel, threadTs, messageTs, isThreadReply) {
|
|
|
16573
16719
|
let paneLogFreshAgeMs = null;
|
|
16574
16720
|
if (SLACK_AGENT_DIR) {
|
|
16575
16721
|
try {
|
|
16576
|
-
const paneMtimeMs = statSync2(
|
|
16722
|
+
const paneMtimeMs = statSync2(join7(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
|
|
16577
16723
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
16578
16724
|
} catch {
|
|
16579
16725
|
}
|
|
@@ -16598,7 +16744,7 @@ function __resetSlackBusyAckNoticeThrottle() {
|
|
|
16598
16744
|
function clearSlackMarkerFileWithHeal(fullPath) {
|
|
16599
16745
|
let marker = null;
|
|
16600
16746
|
try {
|
|
16601
|
-
marker = JSON.parse(
|
|
16747
|
+
marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
16602
16748
|
} catch {
|
|
16603
16749
|
}
|
|
16604
16750
|
if (marker && decideRecoveryHeal({
|
|
@@ -16608,7 +16754,7 @@ function clearSlackMarkerFileWithHeal(fullPath) {
|
|
|
16608
16754
|
healSlackUndeliverable(marker.channel, marker.message_ts);
|
|
16609
16755
|
}
|
|
16610
16756
|
try {
|
|
16611
|
-
if (
|
|
16757
|
+
if (existsSync7(fullPath)) unlinkSync4(fullPath);
|
|
16612
16758
|
} catch {
|
|
16613
16759
|
}
|
|
16614
16760
|
}
|
|
@@ -16649,10 +16795,10 @@ function slackNextRetryName(filename) {
|
|
|
16649
16795
|
async function processSlackRecoveryOutboxFile(filename) {
|
|
16650
16796
|
if (!SLACK_RECOVERY_OUTBOX_DIR) return;
|
|
16651
16797
|
if (filename.endsWith(".poison.json") || filename.endsWith(".tmp")) return;
|
|
16652
|
-
const fullPath =
|
|
16798
|
+
const fullPath = join7(SLACK_RECOVERY_OUTBOX_DIR, filename);
|
|
16653
16799
|
let payload;
|
|
16654
16800
|
try {
|
|
16655
|
-
payload = JSON.parse(
|
|
16801
|
+
payload = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
16656
16802
|
} catch (err) {
|
|
16657
16803
|
process.stderr.write(
|
|
16658
16804
|
`slack-channel(${AGENT_CODE_NAME}): recovery outbox parse failed (${filename}): ${err.message}
|
|
@@ -16726,7 +16872,7 @@ async function processSlackRecoveryOutboxFile(filename) {
|
|
|
16726
16872
|
const next = slackNextRetryName(filename);
|
|
16727
16873
|
if (next) {
|
|
16728
16874
|
try {
|
|
16729
|
-
renameSync3(fullPath,
|
|
16875
|
+
renameSync3(fullPath, join7(SLACK_RECOVERY_OUTBOX_DIR, next.next));
|
|
16730
16876
|
if (next.attempt >= SLACK_MAX_RECOVERY_ATTEMPTS) {
|
|
16731
16877
|
process.stderr.write(
|
|
16732
16878
|
`slack-channel(${AGENT_CODE_NAME}): ghost-reply recovery exhausted retries \u2014 moved to ${next.next}
|
|
@@ -16765,7 +16911,7 @@ function scanSlackRecoveryRetries() {
|
|
|
16765
16911
|
if (!f.includes(".retry-") || f.endsWith(".poison.json")) continue;
|
|
16766
16912
|
let mtimeMs;
|
|
16767
16913
|
try {
|
|
16768
|
-
mtimeMs = statSync2(
|
|
16914
|
+
mtimeMs = statSync2(join7(SLACK_RECOVERY_OUTBOX_DIR, f)).mtimeMs;
|
|
16769
16915
|
} catch {
|
|
16770
16916
|
continue;
|
|
16771
16917
|
}
|
|
@@ -16795,7 +16941,7 @@ function startSlackRecoveryOutboxWatcher() {
|
|
|
16795
16941
|
const watcher = watch(SLACK_RECOVERY_OUTBOX_DIR, (event, filename) => {
|
|
16796
16942
|
if (event !== "rename" || !filename) return;
|
|
16797
16943
|
if (!isFirstAttemptSlackOutboxFile(filename)) return;
|
|
16798
|
-
if (
|
|
16944
|
+
if (existsSync7(join7(SLACK_RECOVERY_OUTBOX_DIR, filename))) {
|
|
16799
16945
|
void processSlackRecoveryOutboxFile(filename);
|
|
16800
16946
|
}
|
|
16801
16947
|
});
|
|
@@ -16816,7 +16962,7 @@ function trackPendingMessage(channel, threadTs, messageTs, undeliverable = false
|
|
|
16816
16962
|
}
|
|
16817
16963
|
function sweepSlackStaleMarkers(thresholdMs) {
|
|
16818
16964
|
if (!SLACK_PENDING_INBOUND_DIR) return;
|
|
16819
|
-
if (!
|
|
16965
|
+
if (!existsSync7(SLACK_PENDING_INBOUND_DIR)) return;
|
|
16820
16966
|
let filenames;
|
|
16821
16967
|
try {
|
|
16822
16968
|
filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
|
|
@@ -16832,10 +16978,10 @@ function sweepSlackStaleMarkers(thresholdMs) {
|
|
|
16832
16978
|
for (const filename of filenames) {
|
|
16833
16979
|
if (!filename.endsWith(".json")) continue;
|
|
16834
16980
|
if (filename.endsWith(".tmp")) continue;
|
|
16835
|
-
const fullPath =
|
|
16981
|
+
const fullPath = join7(SLACK_PENDING_INBOUND_DIR, filename);
|
|
16836
16982
|
let marker;
|
|
16837
16983
|
try {
|
|
16838
|
-
marker = JSON.parse(
|
|
16984
|
+
marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
16839
16985
|
} catch (err) {
|
|
16840
16986
|
process.stderr.write(
|
|
16841
16987
|
`slack-channel(${AGENT_CODE_NAME}): stale-marker parse failed for ${redactSlackId(filename)}: ${err.message}
|
|
@@ -16874,14 +17020,14 @@ var slackOrphanSweepTimer = setInterval(() => {
|
|
|
16874
17020
|
slackOrphanSweepTimer.unref?.();
|
|
16875
17021
|
var lastSlackGiveUpHandledAtMs = null;
|
|
16876
17022
|
function listPendingSlackConversations() {
|
|
16877
|
-
if (!SLACK_PENDING_INBOUND_DIR || !
|
|
17023
|
+
if (!SLACK_PENDING_INBOUND_DIR || !existsSync7(SLACK_PENDING_INBOUND_DIR)) return [];
|
|
16878
17024
|
const byKey = /* @__PURE__ */ new Map();
|
|
16879
17025
|
try {
|
|
16880
17026
|
for (const name of readdirSync3(SLACK_PENDING_INBOUND_DIR)) {
|
|
16881
17027
|
if (!name.endsWith(".json")) continue;
|
|
16882
17028
|
try {
|
|
16883
17029
|
const marker = JSON.parse(
|
|
16884
|
-
|
|
17030
|
+
readFileSync8(join7(SLACK_PENDING_INBOUND_DIR, name), "utf8")
|
|
16885
17031
|
);
|
|
16886
17032
|
if (typeof marker.channel !== "string" || !marker.channel) continue;
|
|
16887
17033
|
if (typeof marker.thread_ts !== "string" || !marker.thread_ts) continue;
|
|
@@ -16931,7 +17077,7 @@ function postSlackWatchdogGiveUpNotice(channel, threadTs, isThreadReply) {
|
|
|
16931
17077
|
}
|
|
16932
17078
|
function checkSlackWatchdogGiveUpNotice() {
|
|
16933
17079
|
if (!SLACK_AGENT_DIR) return;
|
|
16934
|
-
const signalAtMs = readGiveUpSignalAtMs(
|
|
17080
|
+
const signalAtMs = readGiveUpSignalAtMs(join7(SLACK_AGENT_DIR, GIVE_UP_SIGNAL_FILENAME));
|
|
16935
17081
|
const act = decideGiveUpNotice({
|
|
16936
17082
|
signalAtMs,
|
|
16937
17083
|
lastHandledAtMs: lastSlackGiveUpHandledAtMs,
|
|
@@ -16958,7 +17104,7 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
16958
17104
|
strandedInboundNoticeInFlight = true;
|
|
16959
17105
|
let hadFailure = false;
|
|
16960
17106
|
try {
|
|
16961
|
-
if (!SLACK_PENDING_INBOUND_DIR || !
|
|
17107
|
+
if (!SLACK_PENDING_INBOUND_DIR || !existsSync7(SLACK_PENDING_INBOUND_DIR)) return;
|
|
16962
17108
|
let filenames;
|
|
16963
17109
|
try {
|
|
16964
17110
|
filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
|
|
@@ -16971,10 +17117,10 @@ async function notifyStrandedInboundsOnFirstConnect() {
|
|
|
16971
17117
|
let notified = 0;
|
|
16972
17118
|
for (const filename of filenames) {
|
|
16973
17119
|
if (!filename.endsWith(".json")) continue;
|
|
16974
|
-
const fullPath =
|
|
17120
|
+
const fullPath = join7(SLACK_PENDING_INBOUND_DIR, filename);
|
|
16975
17121
|
let marker;
|
|
16976
17122
|
try {
|
|
16977
|
-
marker = JSON.parse(
|
|
17123
|
+
marker = JSON.parse(readFileSync8(fullPath, "utf-8"));
|
|
16978
17124
|
} catch {
|
|
16979
17125
|
continue;
|
|
16980
17126
|
}
|
|
@@ -17101,7 +17247,7 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
|
|
|
17101
17247
|
if (!channel || !messageTs) return;
|
|
17102
17248
|
clearPendingMessage(channel, messageTs);
|
|
17103
17249
|
if (!SLACK_PENDING_INBOUND_DIR) return;
|
|
17104
|
-
if (!
|
|
17250
|
+
if (!existsSync7(SLACK_PENDING_INBOUND_DIR)) return;
|
|
17105
17251
|
let filenames;
|
|
17106
17252
|
try {
|
|
17107
17253
|
filenames = readdirSync3(SLACK_PENDING_INBOUND_DIR);
|
|
@@ -17115,10 +17261,10 @@ function noteThreadActivityByMessageTs(channel, messageTs) {
|
|
|
17115
17261
|
for (const filename of filenames) {
|
|
17116
17262
|
if (!filename.startsWith(channelPrefix)) continue;
|
|
17117
17263
|
if (!filename.endsWith(messageSuffix)) continue;
|
|
17118
|
-
clearSlackMarkerFileWithHeal(
|
|
17264
|
+
clearSlackMarkerFileWithHeal(join7(SLACK_PENDING_INBOUND_DIR, filename));
|
|
17119
17265
|
}
|
|
17120
17266
|
}
|
|
17121
|
-
var RESTART_FLAGS_DIR =
|
|
17267
|
+
var RESTART_FLAGS_DIR = join7(homedir3(), ".augmented", "restart-flags");
|
|
17122
17268
|
function buildAugmentedSlackMetadata() {
|
|
17123
17269
|
if (!AGT_TEAM_ID) return void 0;
|
|
17124
17270
|
return {
|
|
@@ -17172,6 +17318,7 @@ function buildSlackHelpMessage(codeName) {
|
|
|
17172
17318
|
`\u2022 \`${agentSlashCommand("/help")}\` (or type \`/help\`) \u2014 show this help`,
|
|
17173
17319
|
`\u2022 \`${agentSlashCommand("/restart")}\` \u2014 restart this agent`,
|
|
17174
17320
|
`\u2022 \`${agentSlashCommand("/status")}\` \u2014 this agent's model, session origin, uptime + connectivity`,
|
|
17321
|
+
"\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>`.",
|
|
17175
17322
|
"\u2022 `/kill` \u2014 silence all agents in this thread for 6h (use as a thread reply)",
|
|
17176
17323
|
"\u2022 `/unkill` \u2014 clear a kill (use as a thread reply)",
|
|
17177
17324
|
`\u2022 \`${agentSlashCommand("/investigate")}\` \u2014 live tail of this agent's terminal pane (DM only, allowlisted users; works while the channel process is alive \u2014 a wedged host still needs SSM diagnostics)`
|
|
@@ -17504,10 +17651,10 @@ async function handleSlashCommandEnvelope(payload) {
|
|
|
17504
17651
|
return;
|
|
17505
17652
|
}
|
|
17506
17653
|
try {
|
|
17507
|
-
if (!
|
|
17654
|
+
if (!existsSync7(RESTART_FLAGS_DIR)) {
|
|
17508
17655
|
mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
|
|
17509
17656
|
}
|
|
17510
|
-
const flagPath =
|
|
17657
|
+
const flagPath = join7(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
17511
17658
|
writeSlackRestartConfirm(
|
|
17512
17659
|
{
|
|
17513
17660
|
channel: payload.channel_id,
|
|
@@ -17622,10 +17769,10 @@ async function handleHelpCommand(opts) {
|
|
|
17622
17769
|
async function handleRestartCommand(opts) {
|
|
17623
17770
|
const codeName = AGENT_CODE_NAME ?? "unknown";
|
|
17624
17771
|
try {
|
|
17625
|
-
if (!
|
|
17772
|
+
if (!existsSync7(RESTART_FLAGS_DIR)) {
|
|
17626
17773
|
mkdirSync5(RESTART_FLAGS_DIR, { recursive: true });
|
|
17627
17774
|
}
|
|
17628
|
-
const flagPath =
|
|
17775
|
+
const flagPath = join7(RESTART_FLAGS_DIR, `${codeName}.flag`);
|
|
17629
17776
|
writeSlackRestartConfirm(
|
|
17630
17777
|
{
|
|
17631
17778
|
channel: opts.channel,
|
|
@@ -17685,13 +17832,68 @@ async function denyUnauthorizedRestart(opts) {
|
|
|
17685
17832
|
...opts.threadTs ? { thread_ts: opts.threadTs } : {}
|
|
17686
17833
|
});
|
|
17687
17834
|
}
|
|
17835
|
+
async function handleWatchCommand(opts) {
|
|
17836
|
+
const codeName = AGENT_CODE_NAME ?? "unknown";
|
|
17837
|
+
const replyThread = opts.threadTs ?? opts.ts;
|
|
17838
|
+
const post = (text) => postSlackMessage({
|
|
17839
|
+
channel: opts.channel,
|
|
17840
|
+
text,
|
|
17841
|
+
...replyThread ? { thread_ts: replyThread } : {}
|
|
17842
|
+
});
|
|
17843
|
+
const parsed = parseWatchArgs(watchArgsFromText(opts.rawText, AGENT_CODE_NAME) ?? "");
|
|
17844
|
+
if (!parsed.ok) {
|
|
17845
|
+
await post(
|
|
17846
|
+
parsed.error === "bad-url" ? watchBadUrlText() : parsed.error === "bad-duration" ? watchBadDurationText() : watchUsageText()
|
|
17847
|
+
);
|
|
17848
|
+
return;
|
|
17849
|
+
}
|
|
17850
|
+
if (!AGT_HOST || !AGT_API_KEY || !AGT_AGENT_ID) {
|
|
17851
|
+
process.stderr.write(`slack-channel(${codeName}): /watch missing AGT_* env \u2014 cannot create watch
|
|
17852
|
+
`);
|
|
17853
|
+
await post(watchErrorText());
|
|
17854
|
+
return;
|
|
17855
|
+
}
|
|
17856
|
+
const expiresAtIso = new Date(Date.now() + parsed.value.durationMs).toISOString();
|
|
17857
|
+
const res = await postWatchTrigger({
|
|
17858
|
+
host: AGT_HOST,
|
|
17859
|
+
apiKey: AGT_API_KEY,
|
|
17860
|
+
agentId: AGT_AGENT_ID,
|
|
17861
|
+
fileId: parsed.value.fileId,
|
|
17862
|
+
expiresAtIso
|
|
17863
|
+
});
|
|
17864
|
+
if (!res.ok) {
|
|
17865
|
+
process.stderr.write(
|
|
17866
|
+
`slack-channel(${codeName}): /watch create failed (status=${res.status ?? "?"}): ${res.error ?? "unknown"}
|
|
17867
|
+
`
|
|
17868
|
+
);
|
|
17869
|
+
await post(watchErrorText());
|
|
17870
|
+
return;
|
|
17871
|
+
}
|
|
17872
|
+
process.stderr.write(
|
|
17873
|
+
`slack-channel(${codeName}): /watch ${res.reused ? "extended" : "created"} for doc ${parsed.value.fileId.slice(0, 8)}\u2026 channel ${hashChannelId(opts.channel)}
|
|
17874
|
+
`
|
|
17875
|
+
);
|
|
17876
|
+
await post(watchSuccessTextSlack(parsed.value.fileId, parsed.value.durationMs, !!res.reused));
|
|
17877
|
+
}
|
|
17878
|
+
async function denyUnauthorizedWatch(opts) {
|
|
17879
|
+
const codeName = AGENT_CODE_NAME ?? "unknown";
|
|
17880
|
+
process.stderr.write(
|
|
17881
|
+
`slack-channel(${codeName}): /watch denied \u2014 sender not in SLACK_ALLOWED_USERS, channel ${hashChannelId(opts.channel)}
|
|
17882
|
+
`
|
|
17883
|
+
);
|
|
17884
|
+
await postSlackMessage({
|
|
17885
|
+
channel: opts.channel,
|
|
17886
|
+
text: `\u{1F6AB} \`/watch\` denied \u2014 your Slack user is not in the allowlist for \`${codeName}\`.`,
|
|
17887
|
+
...opts.threadTs ? { thread_ts: opts.threadTs } : {}
|
|
17888
|
+
});
|
|
17889
|
+
}
|
|
17688
17890
|
var trackedThreads = /* @__PURE__ */ new Map();
|
|
17689
17891
|
var THREAD_STORE_PATH = resolveThreadStorePath();
|
|
17690
17892
|
var THREAD_STORE_TTL_DAYS = parseTtlDays(process.env.SLACK_THREAD_FOLLOW_TTL_DAYS);
|
|
17691
17893
|
var threadPersister = null;
|
|
17692
17894
|
function resolveThreadStorePath() {
|
|
17693
17895
|
if (!AGENT_CODE_NAME) return null;
|
|
17694
|
-
return
|
|
17896
|
+
return join7(homedir3(), ".augmented", AGENT_CODE_NAME, "slack-tracked-threads.json");
|
|
17695
17897
|
}
|
|
17696
17898
|
function parseTtlDays(raw) {
|
|
17697
17899
|
if (!raw) return void 0;
|
|
@@ -17726,9 +17928,9 @@ if (!BOT_TOKEN || !APP_TOKEN) {
|
|
|
17726
17928
|
var slackStderrLogStream = null;
|
|
17727
17929
|
if (AGENT_CODE_NAME) {
|
|
17728
17930
|
try {
|
|
17729
|
-
const logDir =
|
|
17931
|
+
const logDir = join7(homedir3(), ".augmented", AGENT_CODE_NAME);
|
|
17730
17932
|
mkdirSync5(logDir, { recursive: true });
|
|
17731
|
-
slackStderrLogStream = createWriteStream(
|
|
17933
|
+
slackStderrLogStream = createWriteStream(join7(logDir, "slack-channel-stderr.log"), {
|
|
17732
17934
|
flags: "a",
|
|
17733
17935
|
mode: 384
|
|
17734
17936
|
});
|
|
@@ -18285,7 +18487,7 @@ ${result.formatted}` : "Thread is empty or not found."
|
|
|
18285
18487
|
isError: true
|
|
18286
18488
|
};
|
|
18287
18489
|
}
|
|
18288
|
-
const allowedRoot = resolve2(
|
|
18490
|
+
const allowedRoot = resolve2(homedir3(), ".augmented", AGENT_CODE_NAME, "project") + "/";
|
|
18289
18491
|
const resolvedPath = resolve2(path);
|
|
18290
18492
|
if (!resolvedPath.startsWith(allowedRoot)) {
|
|
18291
18493
|
return {
|
|
@@ -18307,7 +18509,7 @@ ${result.formatted}` : "Thread is empty or not found."
|
|
|
18307
18509
|
};
|
|
18308
18510
|
}
|
|
18309
18511
|
size = stat2.size;
|
|
18310
|
-
bytes =
|
|
18512
|
+
bytes = readFileSync8(resolvedPath);
|
|
18311
18513
|
} catch (err) {
|
|
18312
18514
|
return {
|
|
18313
18515
|
content: [{ type: "text", text: `Failed to read file: ${err.message}` }],
|
|
@@ -18894,7 +19096,7 @@ function isDownloadableFileId(fileId, channel) {
|
|
|
18894
19096
|
}
|
|
18895
19097
|
function redactAugmentedPaths2(msg) {
|
|
18896
19098
|
return msg.replaceAll(
|
|
18897
|
-
new RegExp(`${
|
|
19099
|
+
new RegExp(`${homedir3().replace(/[.*+?^${}()|[\\]\\\\]/g, "\\\\$&")}/\\.augmented/[^\\s'"\`]*`, "g"),
|
|
18898
19100
|
"<augmented-path>"
|
|
18899
19101
|
);
|
|
18900
19102
|
}
|
|
@@ -19146,7 +19348,9 @@ async function connectSocketMode() {
|
|
|
19146
19348
|
const helpSuffixed = agentSlashCommand("/help");
|
|
19147
19349
|
const isRestartCommand = strippedText === "/restart" || strippedText.startsWith("/restart ") || strippedText === restartSuffixed || strippedText.startsWith(`${restartSuffixed} `);
|
|
19148
19350
|
const isHelpCommand = strippedText === "/help" || strippedText.startsWith("/help ") || strippedText === helpSuffixed || strippedText.startsWith(`${helpSuffixed} `);
|
|
19149
|
-
const
|
|
19351
|
+
const isWatchDm = evt.channel?.startsWith("D") ?? false;
|
|
19352
|
+
const isWatchCommand = !isBot && watchArgsFromText(strippedText, AGENT_CODE_NAME, { allowBare: isWatchDm }) !== null;
|
|
19353
|
+
const command = isBot ? void 0 : isHelpCommand ? { command: "help", authorized: true } : isWatchCommand ? { command: "watch", authorized: isRestartSenderAllowed(getEffectiveAllowedUsers(), evt.user) } : isRestartCommand ? { command: "restart", authorized: isRestartSenderAllowed(getEffectiveAllowedUsers(), evt.user) } : void 0;
|
|
19150
19354
|
const slackHomeTeamId = process.env.SLACK_HOME_TEAM_ID;
|
|
19151
19355
|
const sameOrg = !!slackHomeTeamId && evt.team === slackHomeTeamId;
|
|
19152
19356
|
const access = decideInboundAccess({
|
|
@@ -19205,6 +19409,22 @@ async function connectSocketMode() {
|
|
|
19205
19409
|
});
|
|
19206
19410
|
return;
|
|
19207
19411
|
}
|
|
19412
|
+
if (access.command === "watch") {
|
|
19413
|
+
if (!access.authorized) {
|
|
19414
|
+
await denyUnauthorizedWatch({
|
|
19415
|
+
channel: evt.channel ?? "",
|
|
19416
|
+
threadTs: evt.thread_ts
|
|
19417
|
+
});
|
|
19418
|
+
return;
|
|
19419
|
+
}
|
|
19420
|
+
await handleWatchCommand({
|
|
19421
|
+
channel: evt.channel ?? "",
|
|
19422
|
+
threadTs: evt.thread_ts,
|
|
19423
|
+
ts: evt.ts ?? "",
|
|
19424
|
+
rawText: strippedText
|
|
19425
|
+
});
|
|
19426
|
+
return;
|
|
19427
|
+
}
|
|
19208
19428
|
if (access.command === "restart") {
|
|
19209
19429
|
if (!access.authorized) {
|
|
19210
19430
|
await denyUnauthorizedRestart({
|
|
@@ -19286,7 +19506,7 @@ async function connectSocketMode() {
|
|
|
19286
19506
|
let paneLogFreshAgeMs = null;
|
|
19287
19507
|
if (SLACK_AGENT_DIR) {
|
|
19288
19508
|
try {
|
|
19289
|
-
const paneMtimeMs = statSync2(
|
|
19509
|
+
const paneMtimeMs = statSync2(join7(SLACK_AGENT_DIR, "pane.log")).mtimeMs;
|
|
19290
19510
|
paneLogFreshAgeMs = Math.max(0, Date.now() - paneMtimeMs);
|
|
19291
19511
|
} catch {
|
|
19292
19512
|
}
|