switchroom 0.19.13 → 0.19.15
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/cli/switchroom.js +1 -1
- package/dist/host-control/main.js +4 -2
- package/package.json +1 -1
- package/telegram-plugin/bridge/bridge.ts +1 -1
- package/telegram-plugin/dist/bridge/bridge.js +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +1027 -509
- package/telegram-plugin/dist/server.js +1 -1
- package/telegram-plugin/gateway/forward-origin.ts +6 -1
- package/telegram-plugin/gateway/gateway.ts +4 -0
- package/telegram-plugin/gateway/narrative-lane.ts +11 -0
- package/telegram-plugin/gateway/outbound-send-path.ts +9 -3
- package/telegram-plugin/gateway/outbox-sweep.ts +73 -5
- package/telegram-plugin/gateway/rich-message-handler.ts +235 -0
- package/telegram-plugin/gateway/stream-render.ts +107 -15
- package/telegram-plugin/gateway/unhandled-message.ts +14 -0
- package/telegram-plugin/hooks/narration-classify.d.mts +23 -0
- package/telegram-plugin/hooks/narration-classify.mjs +210 -0
- package/telegram-plugin/hooks/silent-end-interrupt-stop.mjs +33 -7
- package/telegram-plugin/hooks/silent-end-scan.mjs +171 -85
- package/telegram-plugin/narrative-flush.ts +35 -0
- package/telegram-plugin/outbox.ts +87 -0
- package/telegram-plugin/shown-ledger.ts +145 -0
- package/telegram-plugin/silent-end.ts +42 -0
- package/telegram-plugin/tests/backstop-exactly-once.test.ts +335 -0
- package/telegram-plugin/tests/catch-all-unhandled-message.test.ts +14 -0
- package/telegram-plugin/tests/forward-origin.test.ts +20 -0
- package/telegram-plugin/tests/forwarded-rich-message.test.ts +305 -0
- package/telegram-plugin/tests/gateway-handler-registration-wiring.test.ts +1 -0
- package/telegram-plugin/tests/narration-leak-3513.test.ts +352 -0
- package/telegram-plugin/tests/outbox-reply-then-recap-e2e.test.ts +600 -0
- package/telegram-plugin/tests/silent-end-interrupt-stop-integration.test.ts +19 -11
- package/telegram-plugin/tests/silent-end-interrupt-stop-scan.test.ts +42 -13
- package/telegram-plugin/tests/silent-end.test.ts +7 -1
- package/telegram-plugin/tests/turn-flush-safety.test.ts +35 -3
- package/telegram-plugin/turn-flush-safety.ts +66 -53
|
@@ -29091,8 +29091,8 @@ __export(exports_history, {
|
|
|
29091
29091
|
_resetForTests: () => _resetForTests,
|
|
29092
29092
|
MIN_PREFIX_MATCH_CHARS: () => MIN_PREFIX_MATCH_CHARS2
|
|
29093
29093
|
});
|
|
29094
|
-
import { chmodSync as chmodSync9, existsSync as
|
|
29095
|
-
import { join as
|
|
29094
|
+
import { chmodSync as chmodSync9, existsSync as existsSync27, mkdirSync as mkdirSync28 } from "fs";
|
|
29095
|
+
import { join as join31 } from "path";
|
|
29096
29096
|
function loadDatabaseClass2() {
|
|
29097
29097
|
if (DatabaseClass2 != null)
|
|
29098
29098
|
return DatabaseClass2;
|
|
@@ -29123,8 +29123,8 @@ function initHistory2(stateDir, retentionDays = 30) {
|
|
|
29123
29123
|
if (db2 != null)
|
|
29124
29124
|
return;
|
|
29125
29125
|
const Database = loadDatabaseClass2();
|
|
29126
|
-
|
|
29127
|
-
const path2 =
|
|
29126
|
+
mkdirSync28(stateDir, { recursive: true, mode: 448 });
|
|
29127
|
+
const path2 = join31(stateDir, "history.db");
|
|
29128
29128
|
dbPath2 = path2;
|
|
29129
29129
|
db2 = new Database(path2, { create: true });
|
|
29130
29130
|
db2.exec("PRAGMA journal_mode = WAL");
|
|
@@ -29190,7 +29190,7 @@ function initHistory2(stateDir, retentionDays = 30) {
|
|
|
29190
29190
|
}
|
|
29191
29191
|
for (const suffix of ["", "-shm", "-wal"]) {
|
|
29192
29192
|
const f = path2 + suffix;
|
|
29193
|
-
if (
|
|
29193
|
+
if (existsSync27(f)) {
|
|
29194
29194
|
try {
|
|
29195
29195
|
chmodSync9(f, 420);
|
|
29196
29196
|
} catch {}
|
|
@@ -29242,7 +29242,7 @@ function checkpointWal2() {
|
|
|
29242
29242
|
if (dbPath2) {
|
|
29243
29243
|
for (const suffix of ["-shm", "-wal"]) {
|
|
29244
29244
|
const f = dbPath2 + suffix;
|
|
29245
|
-
if (
|
|
29245
|
+
if (existsSync27(f)) {
|
|
29246
29246
|
try {
|
|
29247
29247
|
chmodSync9(f, 420);
|
|
29248
29248
|
} catch {}
|
|
@@ -29489,7 +29489,7 @@ var FLUSH_SUPPRESSION_WINDOW_MS = 2000;
|
|
|
29489
29489
|
var init_turn_flush_suppression = () => {};
|
|
29490
29490
|
|
|
29491
29491
|
// ../src/util/atomic.ts
|
|
29492
|
-
import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as
|
|
29492
|
+
import { closeSync as closeSync6, constants as constants2, fchmodSync, fchownSync, fsyncSync as fsyncSync2, openSync as openSync6, renameSync as renameSync13, rmSync as rmSync5, writeSync as writeSync4 } from "node:fs";
|
|
29493
29493
|
var TMP_OPEN_FLAGS;
|
|
29494
29494
|
var init_atomic = __esm(() => {
|
|
29495
29495
|
TMP_OPEN_FLAGS = constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL | (constants2.O_NOFOLLOW ?? 0);
|
|
@@ -32451,7 +32451,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
32451
32451
|
return path2;
|
|
32452
32452
|
}
|
|
32453
32453
|
exports2.normalize = normalize;
|
|
32454
|
-
function
|
|
32454
|
+
function join39(aRoot, aPath) {
|
|
32455
32455
|
if (aRoot === "") {
|
|
32456
32456
|
aRoot = ".";
|
|
32457
32457
|
}
|
|
@@ -32483,7 +32483,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
32483
32483
|
}
|
|
32484
32484
|
return joined;
|
|
32485
32485
|
}
|
|
32486
|
-
exports2.join =
|
|
32486
|
+
exports2.join = join39;
|
|
32487
32487
|
exports2.isAbsolute = function(aPath) {
|
|
32488
32488
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
32489
32489
|
};
|
|
@@ -32656,7 +32656,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
32656
32656
|
parsed.path = parsed.path.substring(0, index2 + 1);
|
|
32657
32657
|
}
|
|
32658
32658
|
}
|
|
32659
|
-
sourceURL =
|
|
32659
|
+
sourceURL = join39(urlGenerate(parsed), sourceURL);
|
|
32660
32660
|
}
|
|
32661
32661
|
return normalize(sourceURL);
|
|
32662
32662
|
}
|
|
@@ -35261,19 +35261,19 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
|
|
|
35261
35261
|
}
|
|
35262
35262
|
|
|
35263
35263
|
// gateway/quota-cache.ts
|
|
35264
|
-
import { existsSync as
|
|
35265
|
-
import { join as
|
|
35264
|
+
import { existsSync as existsSync43, readFileSync as readFileSync44, writeFileSync as writeFileSync37, mkdirSync as mkdirSync38 } from "fs";
|
|
35265
|
+
import { join as join48, dirname as dirname15 } from "path";
|
|
35266
35266
|
function defaultCachePath() {
|
|
35267
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
35267
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join48(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
35268
35268
|
}
|
|
35269
35269
|
function readQuotaCache(opts = {}) {
|
|
35270
35270
|
const path2 = opts.path ?? defaultCachePath();
|
|
35271
35271
|
const now = opts.now ?? Date.now();
|
|
35272
|
-
if (!
|
|
35272
|
+
if (!existsSync43(path2))
|
|
35273
35273
|
return null;
|
|
35274
35274
|
let entry;
|
|
35275
35275
|
try {
|
|
35276
|
-
entry = JSON.parse(
|
|
35276
|
+
entry = JSON.parse(readFileSync44(path2, "utf8"));
|
|
35277
35277
|
} catch {
|
|
35278
35278
|
return null;
|
|
35279
35279
|
}
|
|
@@ -35299,8 +35299,8 @@ function writeQuotaCache(result, opts = {}) {
|
|
|
35299
35299
|
result
|
|
35300
35300
|
};
|
|
35301
35301
|
try {
|
|
35302
|
-
|
|
35303
|
-
|
|
35302
|
+
mkdirSync38(dirname15(path2), { recursive: true });
|
|
35303
|
+
writeFileSync37(path2, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
35304
35304
|
} catch {}
|
|
35305
35305
|
}
|
|
35306
35306
|
var DEFAULT_TTL_MS4, RATE_LIMIT_TTL_MS;
|
|
@@ -35310,8 +35310,8 @@ var init_quota_cache = __esm(() => {
|
|
|
35310
35310
|
});
|
|
35311
35311
|
|
|
35312
35312
|
// gateway/boot-probes.ts
|
|
35313
|
-
import { readFileSync as
|
|
35314
|
-
import { join as
|
|
35313
|
+
import { readFileSync as readFileSync45, readdirSync as readdirSync10, existsSync as existsSync44 } from "fs";
|
|
35314
|
+
import { join as join49 } from "path";
|
|
35315
35315
|
import { execFile as execFileCb } from "child_process";
|
|
35316
35316
|
import { promisify } from "util";
|
|
35317
35317
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -35353,11 +35353,11 @@ function mapPlan(billingType, hasExtra) {
|
|
|
35353
35353
|
}
|
|
35354
35354
|
async function probeAccount(agentDir) {
|
|
35355
35355
|
return withTimeout("Account", (async () => {
|
|
35356
|
-
const claudeDir =
|
|
35357
|
-
const claudeJsonPath =
|
|
35356
|
+
const claudeDir = join49(agentDir, ".claude");
|
|
35357
|
+
const claudeJsonPath = join49(claudeDir, ".claude.json");
|
|
35358
35358
|
let cfg = {};
|
|
35359
35359
|
try {
|
|
35360
|
-
const raw =
|
|
35360
|
+
const raw = readFileSync45(claudeJsonPath, "utf8");
|
|
35361
35361
|
cfg = JSON.parse(raw);
|
|
35362
35362
|
} catch {
|
|
35363
35363
|
return { status: "fail", label: "Account", detail: "no .claude.json" };
|
|
@@ -35375,12 +35375,12 @@ async function probeAccount(agentDir) {
|
|
|
35375
35375
|
let tokenStr = "";
|
|
35376
35376
|
let status = "ok";
|
|
35377
35377
|
for (const candidate of [
|
|
35378
|
-
|
|
35379
|
-
|
|
35378
|
+
join49(claudeDir, ".oauth-token.meta.json"),
|
|
35379
|
+
join49(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
35380
35380
|
]) {
|
|
35381
|
-
if (
|
|
35381
|
+
if (existsSync44(candidate)) {
|
|
35382
35382
|
try {
|
|
35383
|
-
const meta = JSON.parse(
|
|
35383
|
+
const meta = JSON.parse(readFileSync45(candidate, "utf8"));
|
|
35384
35384
|
if (meta.expiresAt) {
|
|
35385
35385
|
tokenStr = " \u00b7 " + formatDaysFromNow(meta.expiresAt);
|
|
35386
35386
|
const daysLeft = Math.round((meta.expiresAt - Date.now()) / 86400000);
|
|
@@ -35555,9 +35555,9 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
35555
35555
|
if (!cgroup)
|
|
35556
35556
|
return null;
|
|
35557
35557
|
const procsPath = `/sys/fs/cgroup${cgroup}/cgroup.procs`;
|
|
35558
|
-
if (!
|
|
35558
|
+
if (!existsSync44(procsPath))
|
|
35559
35559
|
return null;
|
|
35560
|
-
const pidsRaw =
|
|
35560
|
+
const pidsRaw = readFileSync45(procsPath, "utf-8");
|
|
35561
35561
|
const pids = pidsRaw.split(`
|
|
35562
35562
|
`).map((s) => s.trim()).filter(Boolean);
|
|
35563
35563
|
if (pids.length === 0)
|
|
@@ -35570,7 +35570,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
35570
35570
|
let rss = 0;
|
|
35571
35571
|
let comm = "";
|
|
35572
35572
|
try {
|
|
35573
|
-
const status =
|
|
35573
|
+
const status = readFileSync45(`/proc/${pid}/status`, "utf-8");
|
|
35574
35574
|
const rssLine = status.split(`
|
|
35575
35575
|
`).find((l) => l.startsWith("VmRSS:"));
|
|
35576
35576
|
if (rssLine) {
|
|
@@ -35582,7 +35582,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
35582
35582
|
continue;
|
|
35583
35583
|
}
|
|
35584
35584
|
try {
|
|
35585
|
-
comm =
|
|
35585
|
+
comm = readFileSync45(`/proc/${pid}/comm`, "utf-8").trim();
|
|
35586
35586
|
} catch {}
|
|
35587
35587
|
candidates.push({ pid, rss, comm });
|
|
35588
35588
|
}
|
|
@@ -35762,9 +35762,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
35762
35762
|
let claudeDirForProbe = null;
|
|
35763
35763
|
for (const candidate of [
|
|
35764
35764
|
claudeConfigDir,
|
|
35765
|
-
|
|
35765
|
+
join49(claudeConfigDir, "accounts", "default")
|
|
35766
35766
|
]) {
|
|
35767
|
-
if (
|
|
35767
|
+
if (existsSync44(join49(candidate, ".oauth-token"))) {
|
|
35768
35768
|
claudeDirForProbe = candidate;
|
|
35769
35769
|
break;
|
|
35770
35770
|
}
|
|
@@ -35829,7 +35829,7 @@ async function probeHindsight(bankName, fetchImpl = fetch) {
|
|
|
35829
35829
|
}
|
|
35830
35830
|
function readContainerBootTimeMsForProbe() {
|
|
35831
35831
|
try {
|
|
35832
|
-
const stat1 =
|
|
35832
|
+
const stat1 = readFileSync45("/proc/1/stat", "utf8");
|
|
35833
35833
|
const lastParen = stat1.lastIndexOf(")");
|
|
35834
35834
|
if (lastParen < 0)
|
|
35835
35835
|
return null;
|
|
@@ -35837,7 +35837,7 @@ function readContainerBootTimeMsForProbe() {
|
|
|
35837
35837
|
const starttimeTicks = Number(after[19]);
|
|
35838
35838
|
if (!Number.isFinite(starttimeTicks))
|
|
35839
35839
|
return null;
|
|
35840
|
-
const procStat =
|
|
35840
|
+
const procStat = readFileSync45("/proc/stat", "utf8");
|
|
35841
35841
|
const btimeLine = procStat.split(`
|
|
35842
35842
|
`).find((l) => l.startsWith("btime "));
|
|
35843
35843
|
if (!btimeLine)
|
|
@@ -35935,7 +35935,7 @@ async function probeUds(label, socketPath, opts = {}) {
|
|
|
35935
35935
|
}
|
|
35936
35936
|
return withTimeout(label, (async () => {
|
|
35937
35937
|
if (!opts.connectImpl) {
|
|
35938
|
-
if (!
|
|
35938
|
+
if (!existsSync44(socketPath)) {
|
|
35939
35939
|
return {
|
|
35940
35940
|
status: "fail",
|
|
35941
35941
|
label,
|
|
@@ -35999,7 +35999,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
35999
35999
|
return withTimeout("Skills", (async () => {
|
|
36000
36000
|
const fs2 = opts.fs ?? realSkillsFs;
|
|
36001
36001
|
const max = opts.maxNamesShown ?? 3;
|
|
36002
|
-
const skillsDir =
|
|
36002
|
+
const skillsDir = join49(agentDir, ".claude", "skills");
|
|
36003
36003
|
if (!fs2.exists(skillsDir)) {
|
|
36004
36004
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
36005
36005
|
}
|
|
@@ -36014,17 +36014,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
36014
36014
|
}
|
|
36015
36015
|
const dangling = [];
|
|
36016
36016
|
for (const name of entries) {
|
|
36017
|
-
const skillPath =
|
|
36017
|
+
const skillPath = join49(skillsDir, name);
|
|
36018
36018
|
if (!fs2.exists(skillPath)) {
|
|
36019
36019
|
dangling.push(name);
|
|
36020
36020
|
continue;
|
|
36021
36021
|
}
|
|
36022
|
-
const skillMd =
|
|
36022
|
+
const skillMd = join49(skillPath, "SKILL.md");
|
|
36023
36023
|
if (!fs2.exists(skillMd) && !fs2.exists(skillPath + ".md")) {
|
|
36024
36024
|
continue;
|
|
36025
36025
|
}
|
|
36026
36026
|
}
|
|
36027
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
36027
|
+
const overlayDir = opts.overlaySkillsDir ?? join49(agentDir, "skills.d");
|
|
36028
36028
|
const overlaySlugs = new Set;
|
|
36029
36029
|
if (fs2.exists(overlayDir)) {
|
|
36030
36030
|
let overlayEntries = [];
|
|
@@ -36066,8 +36066,8 @@ function renderBucketedSkills(switchroom, agent) {
|
|
|
36066
36066
|
}
|
|
36067
36067
|
async function probeConnections(agentDir, opts = {}) {
|
|
36068
36068
|
return withTimeout("Connections", (async () => {
|
|
36069
|
-
const path2 =
|
|
36070
|
-
const read = opts.readFileImpl ?? ((p) =>
|
|
36069
|
+
const path2 = join49(agentDir, ".claude", "connection-health.json");
|
|
36070
|
+
const read = opts.readFileImpl ?? ((p) => readFileSync45(p, "utf8"));
|
|
36071
36071
|
let issues = [];
|
|
36072
36072
|
try {
|
|
36073
36073
|
const parsed = JSON.parse(read(path2));
|
|
@@ -36098,24 +36098,24 @@ var init_boot_probes = __esm(() => {
|
|
|
36098
36098
|
execFile = promisify(execFileCb);
|
|
36099
36099
|
realProcFs = {
|
|
36100
36100
|
readdir: (p) => readdirSync10(p),
|
|
36101
|
-
readFile: (p) =>
|
|
36101
|
+
readFile: (p) => readFileSync45(p, "utf-8")
|
|
36102
36102
|
};
|
|
36103
36103
|
realSchedulerFs = {
|
|
36104
|
-
readFile: (p) =>
|
|
36104
|
+
readFile: (p) => readFileSync45(p, "utf-8"),
|
|
36105
36105
|
mtimeMs: (p) => {
|
|
36106
36106
|
const { statSync: statSync14 } = __require("fs");
|
|
36107
36107
|
return statSync14(p).mtimeMs;
|
|
36108
36108
|
},
|
|
36109
|
-
exists: (p) =>
|
|
36109
|
+
exists: (p) => existsSync44(p)
|
|
36110
36110
|
};
|
|
36111
36111
|
realSkillsFs = {
|
|
36112
36112
|
readdir: (p) => readdirSync10(p),
|
|
36113
|
-
exists: (p) =>
|
|
36113
|
+
exists: (p) => existsSync44(p)
|
|
36114
36114
|
};
|
|
36115
36115
|
});
|
|
36116
36116
|
|
|
36117
36117
|
// gateway/boot-issue-cache.ts
|
|
36118
|
-
import { existsSync as
|
|
36118
|
+
import { existsSync as existsSync45, readFileSync as readFileSync46, writeFileSync as writeFileSync38, mkdirSync as mkdirSync39, renameSync as renameSync19 } from "fs";
|
|
36119
36119
|
import { dirname as dirname16 } from "path";
|
|
36120
36120
|
function fingerprintProbe(key, r) {
|
|
36121
36121
|
if (r.status === "ok")
|
|
@@ -36195,11 +36195,11 @@ function diffProbes(probes, cache, opts = {}) {
|
|
|
36195
36195
|
return out;
|
|
36196
36196
|
}
|
|
36197
36197
|
function loadCache(path2, now = Date.now) {
|
|
36198
|
-
if (!
|
|
36198
|
+
if (!existsSync45(path2))
|
|
36199
36199
|
return { ...EMPTY_CACHE, probes: {} };
|
|
36200
36200
|
let raw;
|
|
36201
36201
|
try {
|
|
36202
|
-
raw =
|
|
36202
|
+
raw = readFileSync46(path2, "utf-8");
|
|
36203
36203
|
} catch {
|
|
36204
36204
|
return { ...EMPTY_CACHE, probes: {} };
|
|
36205
36205
|
}
|
|
@@ -36208,7 +36208,7 @@ function loadCache(path2, now = Date.now) {
|
|
|
36208
36208
|
parsed = JSON.parse(raw);
|
|
36209
36209
|
} catch {
|
|
36210
36210
|
try {
|
|
36211
|
-
|
|
36211
|
+
renameSync19(path2, `${path2}.corrupt-${now()}`);
|
|
36212
36212
|
} catch {}
|
|
36213
36213
|
return { ...EMPTY_CACHE, probes: {} };
|
|
36214
36214
|
}
|
|
@@ -36242,10 +36242,10 @@ function applyAndSave(path2, cache, diff) {
|
|
|
36242
36242
|
}
|
|
36243
36243
|
}
|
|
36244
36244
|
try {
|
|
36245
|
-
|
|
36245
|
+
mkdirSync39(dirname16(path2), { recursive: true });
|
|
36246
36246
|
const tmp = `${path2}.tmp`;
|
|
36247
|
-
|
|
36248
|
-
|
|
36247
|
+
writeFileSync38(tmp, JSON.stringify(next), { mode: 384 });
|
|
36248
|
+
renameSync19(tmp, path2);
|
|
36249
36249
|
} catch {}
|
|
36250
36250
|
return next;
|
|
36251
36251
|
}
|
|
@@ -36257,14 +36257,14 @@ var init_boot_issue_cache = __esm(() => {
|
|
|
36257
36257
|
});
|
|
36258
36258
|
|
|
36259
36259
|
// gateway/config-snapshot.ts
|
|
36260
|
-
import { createHash as
|
|
36261
|
-
import { existsSync as
|
|
36260
|
+
import { createHash as createHash5 } from "crypto";
|
|
36261
|
+
import { existsSync as existsSync46, readFileSync as readFileSync47, writeFileSync as writeFileSync39, mkdirSync as mkdirSync40, renameSync as renameSync20 } from "fs";
|
|
36262
36262
|
import { dirname as dirname17 } from "path";
|
|
36263
36263
|
function hashStringArray(items) {
|
|
36264
36264
|
if (!items || items.length === 0)
|
|
36265
36265
|
return null;
|
|
36266
36266
|
const sorted = [...items].sort();
|
|
36267
|
-
const raw =
|
|
36267
|
+
const raw = createHash5("sha256").update(sorted.join("\x00")).digest("hex");
|
|
36268
36268
|
return raw.slice(0, 12);
|
|
36269
36269
|
}
|
|
36270
36270
|
function normalizeModel(model) {
|
|
@@ -36323,11 +36323,11 @@ function renderConfigChangeDim(dim) {
|
|
|
36323
36323
|
}
|
|
36324
36324
|
}
|
|
36325
36325
|
function loadSnapshot(path2, now = Date.now) {
|
|
36326
|
-
if (!
|
|
36326
|
+
if (!existsSync46(path2))
|
|
36327
36327
|
return null;
|
|
36328
36328
|
let raw;
|
|
36329
36329
|
try {
|
|
36330
|
-
raw =
|
|
36330
|
+
raw = readFileSync47(path2, "utf-8");
|
|
36331
36331
|
} catch {
|
|
36332
36332
|
return null;
|
|
36333
36333
|
}
|
|
@@ -36336,7 +36336,7 @@ function loadSnapshot(path2, now = Date.now) {
|
|
|
36336
36336
|
parsed = JSON.parse(raw);
|
|
36337
36337
|
} catch {
|
|
36338
36338
|
try {
|
|
36339
|
-
|
|
36339
|
+
renameSync20(path2, `${path2}.corrupt-${now()}`);
|
|
36340
36340
|
} catch {}
|
|
36341
36341
|
return null;
|
|
36342
36342
|
}
|
|
@@ -36357,10 +36357,10 @@ function loadSnapshot(path2, now = Date.now) {
|
|
|
36357
36357
|
}
|
|
36358
36358
|
function persistSnapshot(path2, snapshot) {
|
|
36359
36359
|
try {
|
|
36360
|
-
|
|
36360
|
+
mkdirSync40(dirname17(path2), { recursive: true });
|
|
36361
36361
|
const tmp = `${path2}.tmp`;
|
|
36362
|
-
|
|
36363
|
-
|
|
36362
|
+
writeFileSync39(tmp, JSON.stringify(snapshot), { mode: 384 });
|
|
36363
|
+
renameSync20(tmp, path2);
|
|
36364
36364
|
} catch {}
|
|
36365
36365
|
}
|
|
36366
36366
|
var init_config_snapshot = __esm(() => {
|
|
@@ -36368,13 +36368,13 @@ var init_config_snapshot = __esm(() => {
|
|
|
36368
36368
|
});
|
|
36369
36369
|
|
|
36370
36370
|
// gateway/boot-card-msgid.ts
|
|
36371
|
-
import { readFileSync as
|
|
36371
|
+
import { readFileSync as readFileSync48, writeFileSync as writeFileSync40 } from "node:fs";
|
|
36372
36372
|
function bootCardChatKey(chatId, threadId) {
|
|
36373
36373
|
return `${chatId}:${threadId ?? ""}`;
|
|
36374
36374
|
}
|
|
36375
36375
|
function readStore(path2) {
|
|
36376
36376
|
try {
|
|
36377
|
-
const parsed = JSON.parse(
|
|
36377
|
+
const parsed = JSON.parse(readFileSync48(path2, "utf8"));
|
|
36378
36378
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
36379
36379
|
return parsed;
|
|
36380
36380
|
}
|
|
@@ -36393,7 +36393,7 @@ function saveBootCardMsgId(path2, chatKey3, messageId) {
|
|
|
36393
36393
|
if (store2[chatKey3] === messageId)
|
|
36394
36394
|
return;
|
|
36395
36395
|
store2[chatKey3] = messageId;
|
|
36396
|
-
|
|
36396
|
+
writeFileSync40(path2, JSON.stringify(store2), "utf8");
|
|
36397
36397
|
} catch {}
|
|
36398
36398
|
}
|
|
36399
36399
|
var init_boot_card_msgid = () => {};
|
|
@@ -36411,8 +36411,8 @@ __export(exports_boot_card, {
|
|
|
36411
36411
|
readRoutingMode: () => readRoutingMode,
|
|
36412
36412
|
containerBootStartMs: () => containerBootStartMs
|
|
36413
36413
|
});
|
|
36414
|
-
import { join as
|
|
36415
|
-
import { readFileSync as
|
|
36414
|
+
import { join as join50 } from "path";
|
|
36415
|
+
import { readFileSync as readFileSync49, statSync as statSync14 } from "fs";
|
|
36416
36416
|
function resolvePersonaName(slug, loadConfig3) {
|
|
36417
36417
|
try {
|
|
36418
36418
|
const config = loadConfig3 ? loadConfig3() : loadConfig();
|
|
@@ -36434,7 +36434,7 @@ function shouldSkipDuplicateBootCard(gate, site) {
|
|
|
36434
36434
|
}
|
|
36435
36435
|
return { skip: false };
|
|
36436
36436
|
}
|
|
36437
|
-
function containerBootStartMs(fsImpl = { readFileSync:
|
|
36437
|
+
function containerBootStartMs(fsImpl = { readFileSync: readFileSync49 }) {
|
|
36438
36438
|
try {
|
|
36439
36439
|
const btimeLine = fsImpl.readFileSync("/proc/stat", "utf-8").split(`
|
|
36440
36440
|
`).find((l) => l.startsWith("btime "));
|
|
@@ -36455,8 +36455,8 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync48 }) {
|
|
|
36455
36455
|
return null;
|
|
36456
36456
|
}
|
|
36457
36457
|
}
|
|
36458
|
-
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync:
|
|
36459
|
-
const path2 =
|
|
36458
|
+
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync: statSync14 }) {
|
|
36459
|
+
const path2 = join50(agentDir, ".routing-mode");
|
|
36460
36460
|
try {
|
|
36461
36461
|
const raw = fsImpl.readFileSync(path2, "utf-8");
|
|
36462
36462
|
const line = raw.split(`
|
|
@@ -36563,7 +36563,7 @@ function renderBootCard(opts) {
|
|
|
36563
36563
|
return stackCardLines(flatLines);
|
|
36564
36564
|
}
|
|
36565
36565
|
async function runAllProbes(opts) {
|
|
36566
|
-
const claudeDir =
|
|
36566
|
+
const claudeDir = join50(opts.agentDir, ".claude");
|
|
36567
36567
|
const probes = {};
|
|
36568
36568
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
36569
36569
|
await Promise.allSettled([
|
|
@@ -37417,7 +37417,7 @@ __export(exports_tmux2, {
|
|
|
37417
37417
|
captureAgentPane: () => captureAgentPane2
|
|
37418
37418
|
});
|
|
37419
37419
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
37420
|
-
import { chmodSync as chmodSync13, mkdirSync as
|
|
37420
|
+
import { chmodSync as chmodSync13, mkdirSync as mkdirSync48, readdirSync as readdirSync13, statSync as statSync19, unlinkSync as unlinkSync26, writeFileSync as writeFileSync49 } from "node:fs";
|
|
37421
37421
|
import { resolve as resolve12 } from "node:path";
|
|
37422
37422
|
function captureAgentPane2(opts) {
|
|
37423
37423
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -37429,7 +37429,7 @@ function captureAgentPane2(opts) {
|
|
|
37429
37429
|
const reasonSlug = sanitizeReason2(reason);
|
|
37430
37430
|
const outPath = resolve12(outDir, `${ts}-${reasonSlug}.txt`);
|
|
37431
37431
|
try {
|
|
37432
|
-
|
|
37432
|
+
mkdirSync48(outDir, { recursive: true, mode: 448 });
|
|
37433
37433
|
} catch (err) {
|
|
37434
37434
|
const msg = `mkdir crash-reports failed: ${err.message}`;
|
|
37435
37435
|
console.error(`[tmux-capture] ${agentName3}: ${msg}`);
|
|
@@ -37468,7 +37468,7 @@ function captureAgentPane2(opts) {
|
|
|
37468
37468
|
` + `
|
|
37469
37469
|
`;
|
|
37470
37470
|
try {
|
|
37471
|
-
|
|
37471
|
+
writeFileSync49(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
|
|
37472
37472
|
mode: 384
|
|
37473
37473
|
});
|
|
37474
37474
|
} catch (err) {
|
|
@@ -38348,7 +38348,7 @@ __export(exports_materialize_bot_token, {
|
|
|
38348
38348
|
materializeBotToken: () => materializeBotToken,
|
|
38349
38349
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
38350
38350
|
});
|
|
38351
|
-
import { existsSync as
|
|
38351
|
+
import { existsSync as existsSync55 } from "node:fs";
|
|
38352
38352
|
function pickConfiguredToken(config, agentName3) {
|
|
38353
38353
|
if (agentName3) {
|
|
38354
38354
|
const agent = config.agents?.[agentName3];
|
|
@@ -38362,7 +38362,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
|
|
|
38362
38362
|
if (!passphrase)
|
|
38363
38363
|
return null;
|
|
38364
38364
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
38365
|
-
if (!
|
|
38365
|
+
if (!existsSync55(vaultPath))
|
|
38366
38366
|
return null;
|
|
38367
38367
|
try {
|
|
38368
38368
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -38514,26 +38514,26 @@ var init_approvals_commands = __esm(() => {
|
|
|
38514
38514
|
// gateway/gateway.ts
|
|
38515
38515
|
var import_grammy16 = __toESM(require_mod(), 1);
|
|
38516
38516
|
var import_runner3 = __toESM(require_mod3(), 1);
|
|
38517
|
-
import { randomBytes as randomBytes10, createHash as
|
|
38517
|
+
import { randomBytes as randomBytes10, createHash as createHash6 } from "crypto";
|
|
38518
38518
|
import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
38519
38519
|
import {
|
|
38520
|
-
readFileSync as
|
|
38521
|
-
writeFileSync as
|
|
38522
|
-
mkdirSync as
|
|
38520
|
+
readFileSync as readFileSync60,
|
|
38521
|
+
writeFileSync as writeFileSync50,
|
|
38522
|
+
mkdirSync as mkdirSync49,
|
|
38523
38523
|
readdirSync as readdirSync14,
|
|
38524
38524
|
rmSync as rmSync6,
|
|
38525
38525
|
statSync as statSync20,
|
|
38526
|
-
renameSync as
|
|
38526
|
+
renameSync as renameSync23,
|
|
38527
38527
|
realpathSync as realpathSync4,
|
|
38528
38528
|
chmodSync as chmodSync14,
|
|
38529
38529
|
openSync as openSync12,
|
|
38530
38530
|
closeSync as closeSync12,
|
|
38531
|
-
existsSync as
|
|
38531
|
+
existsSync as existsSync56,
|
|
38532
38532
|
unlinkSync as unlinkSync27,
|
|
38533
|
-
appendFileSync as
|
|
38533
|
+
appendFileSync as appendFileSync9
|
|
38534
38534
|
} from "fs";
|
|
38535
38535
|
import { homedir as homedir20 } from "os";
|
|
38536
|
-
import { join as
|
|
38536
|
+
import { join as join62, sep as sep4, basename as basename15 } from "path";
|
|
38537
38537
|
|
|
38538
38538
|
// plugin-logger.ts
|
|
38539
38539
|
import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
|
|
@@ -40819,6 +40819,141 @@ function forwardOriginDateIso(o) {
|
|
|
40819
40819
|
return new Date(o.date * 1000).toISOString();
|
|
40820
40820
|
}
|
|
40821
40821
|
|
|
40822
|
+
// gateway/rich-message-handler.ts
|
|
40823
|
+
var MAX_DEPTH = 32;
|
|
40824
|
+
function renderRichText(rt, depth = 0) {
|
|
40825
|
+
if (depth > MAX_DEPTH || rt == null)
|
|
40826
|
+
return "";
|
|
40827
|
+
if (typeof rt === "string")
|
|
40828
|
+
return rt;
|
|
40829
|
+
if (Array.isArray(rt))
|
|
40830
|
+
return rt.map((t) => renderRichText(t, depth + 1)).join("");
|
|
40831
|
+
if (typeof rt !== "object")
|
|
40832
|
+
return "";
|
|
40833
|
+
const node = rt;
|
|
40834
|
+
if (node.type === "custom_emoji")
|
|
40835
|
+
return node.alternative_text ?? "";
|
|
40836
|
+
if (node.type === "mathematical_expression") {
|
|
40837
|
+
return typeof node.expression === "string" ? node.expression : "";
|
|
40838
|
+
}
|
|
40839
|
+
if (node.type === "anchor")
|
|
40840
|
+
return "";
|
|
40841
|
+
if ("text" in node)
|
|
40842
|
+
return renderRichText(node.text, depth + 1);
|
|
40843
|
+
return "";
|
|
40844
|
+
}
|
|
40845
|
+
function renderCaption(caption, depth) {
|
|
40846
|
+
if (caption == null || typeof caption !== "object")
|
|
40847
|
+
return renderRichText(caption, depth);
|
|
40848
|
+
const c = caption;
|
|
40849
|
+
const text = renderRichText(c.text, depth);
|
|
40850
|
+
const credit = renderRichText(c.credit, depth);
|
|
40851
|
+
return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
40852
|
+
}
|
|
40853
|
+
function renderBlocks(blocks, depth) {
|
|
40854
|
+
if (depth > MAX_DEPTH || !Array.isArray(blocks))
|
|
40855
|
+
return "";
|
|
40856
|
+
return blocks.map((b) => renderRichBlock(b, depth + 1)).filter((s) => s.length > 0).join(`
|
|
40857
|
+
`);
|
|
40858
|
+
}
|
|
40859
|
+
function renderRichBlock(block, depth = 0) {
|
|
40860
|
+
if (depth > MAX_DEPTH || block == null || typeof block !== "object")
|
|
40861
|
+
return "";
|
|
40862
|
+
const b = block;
|
|
40863
|
+
switch (b.type) {
|
|
40864
|
+
case "paragraph":
|
|
40865
|
+
case "heading":
|
|
40866
|
+
case "footer":
|
|
40867
|
+
return renderRichText(b.text, depth);
|
|
40868
|
+
case "pre": {
|
|
40869
|
+
const body = renderRichText(b.text, depth);
|
|
40870
|
+
return body.length > 0 ? `\`\`\`${b.language ?? ""}
|
|
40871
|
+
${body}
|
|
40872
|
+
\`\`\`` : "";
|
|
40873
|
+
}
|
|
40874
|
+
case "divider":
|
|
40875
|
+
return "---";
|
|
40876
|
+
case "mathematical_expression":
|
|
40877
|
+
return typeof b.expression === "string" ? b.expression : "";
|
|
40878
|
+
case "anchor":
|
|
40879
|
+
return "";
|
|
40880
|
+
case "list": {
|
|
40881
|
+
if (!Array.isArray(b.items))
|
|
40882
|
+
return "";
|
|
40883
|
+
return b.items.map((item) => {
|
|
40884
|
+
const body = renderBlocks(item?.blocks, depth);
|
|
40885
|
+
const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
|
|
40886
|
+
const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
|
|
40887
|
+
return body.length > 0 ? `${label} ${check}${body}` : "";
|
|
40888
|
+
}).filter((s) => s.length > 0).join(`
|
|
40889
|
+
`);
|
|
40890
|
+
}
|
|
40891
|
+
case "blockquote": {
|
|
40892
|
+
const body = renderBlocks(b.blocks, depth);
|
|
40893
|
+
const credit = renderRichText(b.credit, depth);
|
|
40894
|
+
const quoted = body.split(`
|
|
40895
|
+
`).map((line) => `> ${line}`).join(`
|
|
40896
|
+
`);
|
|
40897
|
+
return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
|
|
40898
|
+
`);
|
|
40899
|
+
}
|
|
40900
|
+
case "pullquote": {
|
|
40901
|
+
const body = renderRichText(b.text, depth);
|
|
40902
|
+
const credit = renderRichText(b.credit, depth);
|
|
40903
|
+
return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
40904
|
+
}
|
|
40905
|
+
case "details": {
|
|
40906
|
+
const summary = renderRichText(b.summary, depth);
|
|
40907
|
+
const body = renderBlocks(b.blocks, depth);
|
|
40908
|
+
return [summary, body].filter((s) => s.length > 0).join(`
|
|
40909
|
+
`);
|
|
40910
|
+
}
|
|
40911
|
+
case "collage":
|
|
40912
|
+
case "slideshow": {
|
|
40913
|
+
const body = renderBlocks(b.blocks, depth);
|
|
40914
|
+
const caption = renderCaption(b.caption, depth);
|
|
40915
|
+
return [body, caption].filter((s) => s.length > 0).join(`
|
|
40916
|
+
`);
|
|
40917
|
+
}
|
|
40918
|
+
case "table": {
|
|
40919
|
+
if (!Array.isArray(b.cells))
|
|
40920
|
+
return "";
|
|
40921
|
+
const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
|
|
40922
|
+
`);
|
|
40923
|
+
const caption = renderRichText(b.caption, depth);
|
|
40924
|
+
return [caption, rows].filter((s) => s.length > 0).join(`
|
|
40925
|
+
`);
|
|
40926
|
+
}
|
|
40927
|
+
case "map":
|
|
40928
|
+
case "animation":
|
|
40929
|
+
case "audio":
|
|
40930
|
+
case "photo":
|
|
40931
|
+
case "video":
|
|
40932
|
+
case "voice_note": {
|
|
40933
|
+
const caption = renderCaption(b.caption, depth);
|
|
40934
|
+
const tag = `[${b.type}]`;
|
|
40935
|
+
return caption.length > 0 ? `${tag} ${caption}` : tag;
|
|
40936
|
+
}
|
|
40937
|
+
case "thinking":
|
|
40938
|
+
return "";
|
|
40939
|
+
default: {
|
|
40940
|
+
const text = renderRichText(b.text, depth);
|
|
40941
|
+
if (text.length > 0)
|
|
40942
|
+
return text;
|
|
40943
|
+
return renderBlocks(b.blocks, depth);
|
|
40944
|
+
}
|
|
40945
|
+
}
|
|
40946
|
+
}
|
|
40947
|
+
function extractRichMessageText(rich) {
|
|
40948
|
+
if (rich == null || typeof rich !== "object")
|
|
40949
|
+
return;
|
|
40950
|
+
const blocks = rich.blocks;
|
|
40951
|
+
const rendered = renderBlocks(blocks, 0).replace(/\n{3,}/g, `
|
|
40952
|
+
|
|
40953
|
+
`).trim();
|
|
40954
|
+
return rendered.length > 0 ? rendered : undefined;
|
|
40955
|
+
}
|
|
40956
|
+
|
|
40822
40957
|
// gateway/unhandled-message.ts
|
|
40823
40958
|
var MESSAGE_ENVELOPE_KEYS = new Set([
|
|
40824
40959
|
"message_id",
|
|
@@ -40847,7 +40982,13 @@ var MESSAGE_ENVELOPE_KEYS = new Set([
|
|
|
40847
40982
|
"show_caption_above_media",
|
|
40848
40983
|
"entities",
|
|
40849
40984
|
"caption_entities",
|
|
40850
|
-
"paid_star_count"
|
|
40985
|
+
"paid_star_count",
|
|
40986
|
+
"forward_from",
|
|
40987
|
+
"forward_from_chat",
|
|
40988
|
+
"forward_from_message_id",
|
|
40989
|
+
"forward_signature",
|
|
40990
|
+
"forward_sender_name",
|
|
40991
|
+
"forward_date"
|
|
40851
40992
|
]);
|
|
40852
40993
|
var SERVICE_NOISE_KEYS = new Set([
|
|
40853
40994
|
"new_chat_members",
|
|
@@ -40892,7 +41033,7 @@ function planUnhandledMessage(msg) {
|
|
|
40892
41033
|
return { action: "log-only", contentKeys };
|
|
40893
41034
|
}
|
|
40894
41035
|
const contentType = contentKeys[0] ?? "unknown";
|
|
40895
|
-
const text = (typeof msg.text === "string" ? msg.text : undefined) ?? (typeof msg.caption === "string" ? msg.caption : undefined) ?? `(unhandled message content: ${contentType})`;
|
|
41036
|
+
const text = (typeof msg.text === "string" ? msg.text : undefined) ?? (typeof msg.caption === "string" ? msg.caption : undefined) ?? extractRichMessageText(msg.rich_message) ?? `(unhandled message content: ${contentType})`;
|
|
40896
41037
|
return { action: "turn", text, contentKeys };
|
|
40897
41038
|
}
|
|
40898
41039
|
var TAP_MAX_LINES_PER_MINUTE = 300;
|
|
@@ -41091,6 +41232,153 @@ async function handlePassportDataMessage(ctx, deps) {
|
|
|
41091
41232
|
await deps.handleRefusal(ctx, "passport_data", PASSPORT_REFUSAL_TEXT);
|
|
41092
41233
|
}
|
|
41093
41234
|
|
|
41235
|
+
// gateway/rich-message-handler.ts
|
|
41236
|
+
var RICH_MESSAGE_EMPTY_TEXT = "(rich message with no extractable text)";
|
|
41237
|
+
var MAX_DEPTH2 = 32;
|
|
41238
|
+
function renderRichText2(rt, depth = 0) {
|
|
41239
|
+
if (depth > MAX_DEPTH2 || rt == null)
|
|
41240
|
+
return "";
|
|
41241
|
+
if (typeof rt === "string")
|
|
41242
|
+
return rt;
|
|
41243
|
+
if (Array.isArray(rt))
|
|
41244
|
+
return rt.map((t) => renderRichText2(t, depth + 1)).join("");
|
|
41245
|
+
if (typeof rt !== "object")
|
|
41246
|
+
return "";
|
|
41247
|
+
const node = rt;
|
|
41248
|
+
if (node.type === "custom_emoji")
|
|
41249
|
+
return node.alternative_text ?? "";
|
|
41250
|
+
if (node.type === "mathematical_expression") {
|
|
41251
|
+
return typeof node.expression === "string" ? node.expression : "";
|
|
41252
|
+
}
|
|
41253
|
+
if (node.type === "anchor")
|
|
41254
|
+
return "";
|
|
41255
|
+
if ("text" in node)
|
|
41256
|
+
return renderRichText2(node.text, depth + 1);
|
|
41257
|
+
return "";
|
|
41258
|
+
}
|
|
41259
|
+
function renderCaption2(caption, depth) {
|
|
41260
|
+
if (caption == null || typeof caption !== "object")
|
|
41261
|
+
return renderRichText2(caption, depth);
|
|
41262
|
+
const c = caption;
|
|
41263
|
+
const text = renderRichText2(c.text, depth);
|
|
41264
|
+
const credit = renderRichText2(c.credit, depth);
|
|
41265
|
+
return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41266
|
+
}
|
|
41267
|
+
function renderBlocks2(blocks, depth) {
|
|
41268
|
+
if (depth > MAX_DEPTH2 || !Array.isArray(blocks))
|
|
41269
|
+
return "";
|
|
41270
|
+
return blocks.map((b) => renderRichBlock2(b, depth + 1)).filter((s) => s.length > 0).join(`
|
|
41271
|
+
`);
|
|
41272
|
+
}
|
|
41273
|
+
function renderRichBlock2(block, depth = 0) {
|
|
41274
|
+
if (depth > MAX_DEPTH2 || block == null || typeof block !== "object")
|
|
41275
|
+
return "";
|
|
41276
|
+
const b = block;
|
|
41277
|
+
switch (b.type) {
|
|
41278
|
+
case "paragraph":
|
|
41279
|
+
case "heading":
|
|
41280
|
+
case "footer":
|
|
41281
|
+
return renderRichText2(b.text, depth);
|
|
41282
|
+
case "pre": {
|
|
41283
|
+
const body = renderRichText2(b.text, depth);
|
|
41284
|
+
return body.length > 0 ? `\`\`\`${b.language ?? ""}
|
|
41285
|
+
${body}
|
|
41286
|
+
\`\`\`` : "";
|
|
41287
|
+
}
|
|
41288
|
+
case "divider":
|
|
41289
|
+
return "---";
|
|
41290
|
+
case "mathematical_expression":
|
|
41291
|
+
return typeof b.expression === "string" ? b.expression : "";
|
|
41292
|
+
case "anchor":
|
|
41293
|
+
return "";
|
|
41294
|
+
case "list": {
|
|
41295
|
+
if (!Array.isArray(b.items))
|
|
41296
|
+
return "";
|
|
41297
|
+
return b.items.map((item) => {
|
|
41298
|
+
const body = renderBlocks2(item?.blocks, depth);
|
|
41299
|
+
const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
|
|
41300
|
+
const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
|
|
41301
|
+
return body.length > 0 ? `${label} ${check}${body}` : "";
|
|
41302
|
+
}).filter((s) => s.length > 0).join(`
|
|
41303
|
+
`);
|
|
41304
|
+
}
|
|
41305
|
+
case "blockquote": {
|
|
41306
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41307
|
+
const credit = renderRichText2(b.credit, depth);
|
|
41308
|
+
const quoted = body.split(`
|
|
41309
|
+
`).map((line) => `> ${line}`).join(`
|
|
41310
|
+
`);
|
|
41311
|
+
return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
|
|
41312
|
+
`);
|
|
41313
|
+
}
|
|
41314
|
+
case "pullquote": {
|
|
41315
|
+
const body = renderRichText2(b.text, depth);
|
|
41316
|
+
const credit = renderRichText2(b.credit, depth);
|
|
41317
|
+
return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41318
|
+
}
|
|
41319
|
+
case "details": {
|
|
41320
|
+
const summary = renderRichText2(b.summary, depth);
|
|
41321
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41322
|
+
return [summary, body].filter((s) => s.length > 0).join(`
|
|
41323
|
+
`);
|
|
41324
|
+
}
|
|
41325
|
+
case "collage":
|
|
41326
|
+
case "slideshow": {
|
|
41327
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41328
|
+
const caption = renderCaption2(b.caption, depth);
|
|
41329
|
+
return [body, caption].filter((s) => s.length > 0).join(`
|
|
41330
|
+
`);
|
|
41331
|
+
}
|
|
41332
|
+
case "table": {
|
|
41333
|
+
if (!Array.isArray(b.cells))
|
|
41334
|
+
return "";
|
|
41335
|
+
const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText2(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
|
|
41336
|
+
`);
|
|
41337
|
+
const caption = renderRichText2(b.caption, depth);
|
|
41338
|
+
return [caption, rows].filter((s) => s.length > 0).join(`
|
|
41339
|
+
`);
|
|
41340
|
+
}
|
|
41341
|
+
case "map":
|
|
41342
|
+
case "animation":
|
|
41343
|
+
case "audio":
|
|
41344
|
+
case "photo":
|
|
41345
|
+
case "video":
|
|
41346
|
+
case "voice_note": {
|
|
41347
|
+
const caption = renderCaption2(b.caption, depth);
|
|
41348
|
+
const tag = `[${b.type}]`;
|
|
41349
|
+
return caption.length > 0 ? `${tag} ${caption}` : tag;
|
|
41350
|
+
}
|
|
41351
|
+
case "thinking":
|
|
41352
|
+
return "";
|
|
41353
|
+
default: {
|
|
41354
|
+
const text = renderRichText2(b.text, depth);
|
|
41355
|
+
if (text.length > 0)
|
|
41356
|
+
return text;
|
|
41357
|
+
return renderBlocks2(b.blocks, depth);
|
|
41358
|
+
}
|
|
41359
|
+
}
|
|
41360
|
+
}
|
|
41361
|
+
function extractRichMessageText2(rich) {
|
|
41362
|
+
if (rich == null || typeof rich !== "object")
|
|
41363
|
+
return;
|
|
41364
|
+
const blocks = rich.blocks;
|
|
41365
|
+
const rendered = renderBlocks2(blocks, 0).replace(/\n{3,}/g, `
|
|
41366
|
+
|
|
41367
|
+
`).trim();
|
|
41368
|
+
return rendered.length > 0 ? rendered : undefined;
|
|
41369
|
+
}
|
|
41370
|
+
async function handleRichMessageMessage(ctx, deps) {
|
|
41371
|
+
try {
|
|
41372
|
+
const text = extractRichMessageText2(ctx.message.rich_message) ?? RICH_MESSAGE_EMPTY_TEXT;
|
|
41373
|
+
deps.log(`telegram gateway: inbound rich_message from chat=${ctx.chat?.id ?? "?"} chars=${text.length}
|
|
41374
|
+
`);
|
|
41375
|
+
await deps.handleInbound(ctx, text, undefined);
|
|
41376
|
+
} catch (err) {
|
|
41377
|
+
deps.log(`telegram gateway: rich_message handler error: ${err.message}
|
|
41378
|
+
`);
|
|
41379
|
+
}
|
|
41380
|
+
}
|
|
41381
|
+
|
|
41094
41382
|
// gateway/stop-command.ts
|
|
41095
41383
|
function parseStopKeyword2(text) {
|
|
41096
41384
|
return /^stop[.!]?$/i.test(text.trim());
|
|
@@ -42712,6 +43000,8 @@ function buildForwardOriginMeta(origins) {
|
|
|
42712
43000
|
if (o.date != null) {
|
|
42713
43001
|
out[`forwarded_date${suffix}`] = fmtLocalStamp(o.date * 1000, resolveEnvTimezone());
|
|
42714
43002
|
}
|
|
43003
|
+
if (o.messageId != null)
|
|
43004
|
+
out[`forwarded_message_id${suffix}`] = String(o.messageId);
|
|
42715
43005
|
});
|
|
42716
43006
|
return out;
|
|
42717
43007
|
}
|
|
@@ -61243,7 +61533,7 @@ function prefixLines(text4, prefix) {
|
|
|
61243
61533
|
`);
|
|
61244
61534
|
}
|
|
61245
61535
|
function renderBlockquote(node2) {
|
|
61246
|
-
const inner =
|
|
61536
|
+
const inner = renderBlocks3(node2.children);
|
|
61247
61537
|
if (node2.expandable) {
|
|
61248
61538
|
const lines = inner.split(`
|
|
61249
61539
|
`);
|
|
@@ -61339,7 +61629,7 @@ function renderBlock(node2) {
|
|
|
61339
61629
|
function renderBlocksJoined(blocks, sep2) {
|
|
61340
61630
|
return blocks.map(renderBlock).join(sep2);
|
|
61341
61631
|
}
|
|
61342
|
-
function
|
|
61632
|
+
function renderBlocks3(blocks) {
|
|
61343
61633
|
return renderBlocksJoined(blocks, `
|
|
61344
61634
|
|
|
61345
61635
|
`);
|
|
@@ -74010,6 +74300,33 @@ function readDeliveredNonces(stateDir) {
|
|
|
74010
74300
|
} catch {}
|
|
74011
74301
|
return set;
|
|
74012
74302
|
}
|
|
74303
|
+
function isBackstopDeliveredEntry(e) {
|
|
74304
|
+
if (e.deliverySource === "sweep" || e.deliverySource === "flush")
|
|
74305
|
+
return true;
|
|
74306
|
+
if (e.deliverySource === "reply-tool" && e.replyAlreadyDeliveredThisTurn === false)
|
|
74307
|
+
return true;
|
|
74308
|
+
return false;
|
|
74309
|
+
}
|
|
74310
|
+
function backstopAlreadyDelivered(nonce, stateDir) {
|
|
74311
|
+
if (nonce == null || nonce === "")
|
|
74312
|
+
return false;
|
|
74313
|
+
const path2 = join28(resolveOutboxDir(stateDir), JOURNAL_FILE);
|
|
74314
|
+
if (!existsSync24(path2))
|
|
74315
|
+
return false;
|
|
74316
|
+
try {
|
|
74317
|
+
for (const line of readFileSync24(path2, "utf8").split(`
|
|
74318
|
+
`)) {
|
|
74319
|
+
if (!line)
|
|
74320
|
+
continue;
|
|
74321
|
+
try {
|
|
74322
|
+
const e = JSON.parse(line);
|
|
74323
|
+
if (e.turnNonce === nonce && isBackstopDeliveredEntry(e))
|
|
74324
|
+
return true;
|
|
74325
|
+
} catch {}
|
|
74326
|
+
}
|
|
74327
|
+
} catch {}
|
|
74328
|
+
return false;
|
|
74329
|
+
}
|
|
74013
74330
|
var JOURNAL_KEEP = 2000;
|
|
74014
74331
|
var JOURNAL_ROTATE_AT = 4000;
|
|
74015
74332
|
function appendDelivered(entry, stateDir) {
|
|
@@ -74053,10 +74370,13 @@ function decideOutboxSweep(input) {
|
|
|
74053
74370
|
routable,
|
|
74054
74371
|
routePrefix = "",
|
|
74055
74372
|
quietMs = OUTBOX_QUIET_MS,
|
|
74056
|
-
maxAgeMs = OUTBOX_MAX_AGE_MS
|
|
74373
|
+
maxAgeMs = OUTBOX_MAX_AGE_MS,
|
|
74374
|
+
shownLedgerHit = false
|
|
74057
74375
|
} = input;
|
|
74058
74376
|
if (deliveredNonces.has(record.turnNonce))
|
|
74059
74377
|
return { action: "skip-journaled" };
|
|
74378
|
+
if (shownLedgerHit)
|
|
74379
|
+
return { action: "skip-ephemeral-shown" };
|
|
74060
74380
|
const age = now - record.createdAt;
|
|
74061
74381
|
if (age < quietMs)
|
|
74062
74382
|
return { action: "skip-quiet" };
|
|
@@ -74089,6 +74409,149 @@ function extractTaskId(anchorContent) {
|
|
|
74089
74409
|
return m ? m[1] : null;
|
|
74090
74410
|
}
|
|
74091
74411
|
|
|
74412
|
+
// shown-ledger.ts
|
|
74413
|
+
import {
|
|
74414
|
+
existsSync as existsSync25,
|
|
74415
|
+
mkdirSync as mkdirSync26,
|
|
74416
|
+
readFileSync as readFileSync25,
|
|
74417
|
+
renameSync as renameSync9,
|
|
74418
|
+
writeFileSync as writeFileSync23,
|
|
74419
|
+
appendFileSync as appendFileSync5
|
|
74420
|
+
} from "node:fs";
|
|
74421
|
+
import { join as join29 } from "node:path";
|
|
74422
|
+
|
|
74423
|
+
// hooks/narration-classify.mjs
|
|
74424
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
74425
|
+
var SUBSTANTIVE_MIN_CHARS = 200;
|
|
74426
|
+
var NARRATION_OPENER = /^(let me\b|lemme\b|i'?ll\b|i will\b|i am going to\b|i'?m going to\b|i'?m about to\b|going to\b|first,?\s+(?:let me|i'?ll|i will)\b|now,?\s+(?:let me|i'?ll|i will)\b|next,?\s+(?:let me|i'?ll|i will)\b|let'?s\b)/i;
|
|
74427
|
+
var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
|
|
74428
|
+
function isTrailingNarrationLine(block) {
|
|
74429
|
+
const t = typeof block === "string" ? block.trim() : "";
|
|
74430
|
+
if (t.length === 0 || t.length >= SUBSTANTIVE_MIN_CHARS)
|
|
74431
|
+
return false;
|
|
74432
|
+
if (t.includes(`
|
|
74433
|
+
`))
|
|
74434
|
+
return false;
|
|
74435
|
+
return NARRATION_TRAILER.test(t);
|
|
74436
|
+
}
|
|
74437
|
+
function isNarrationBlock(block) {
|
|
74438
|
+
const s = typeof block === "string" ? block : "";
|
|
74439
|
+
return NARRATION_OPENER.test(s.trimStart()) || isTrailingNarrationLine(s);
|
|
74440
|
+
}
|
|
74441
|
+
function isStructuralNarration(text4, followedByToolUse) {
|
|
74442
|
+
if (followedByToolUse !== true)
|
|
74443
|
+
return false;
|
|
74444
|
+
const t = typeof text4 === "string" ? text4.trim() : "";
|
|
74445
|
+
if (t.length === 0)
|
|
74446
|
+
return true;
|
|
74447
|
+
return isNarrationBlock(t) || t.length < SUBSTANTIVE_MIN_CHARS;
|
|
74448
|
+
}
|
|
74449
|
+
var EPHEMERAL_TOOLS = new Set([
|
|
74450
|
+
"react",
|
|
74451
|
+
"send_typing",
|
|
74452
|
+
"pin_message",
|
|
74453
|
+
"delete_message",
|
|
74454
|
+
"edit_message"
|
|
74455
|
+
]);
|
|
74456
|
+
function isEphemeralTool(name) {
|
|
74457
|
+
if (typeof name !== "string")
|
|
74458
|
+
return false;
|
|
74459
|
+
const suffix = name.replace(/^mcp__[^_].*?telegram__/, "");
|
|
74460
|
+
return EPHEMERAL_TOOLS.has(suffix);
|
|
74461
|
+
}
|
|
74462
|
+
function selectBackstopDelivery(blocks) {
|
|
74463
|
+
const nonEmpty = (Array.isArray(blocks) ? blocks : []).map((b) => ({
|
|
74464
|
+
text: typeof b?.text === "string" ? b.text.trim() : "",
|
|
74465
|
+
followedByToolUse: b?.followedByToolUse
|
|
74466
|
+
})).filter((b) => b.text.length > 0);
|
|
74467
|
+
if (nonEmpty.length === 0)
|
|
74468
|
+
return null;
|
|
74469
|
+
const run3 = [];
|
|
74470
|
+
for (let i = nonEmpty.length - 1;i >= 0; i--) {
|
|
74471
|
+
if (nonEmpty[i].followedByToolUse === true)
|
|
74472
|
+
break;
|
|
74473
|
+
run3.unshift(nonEmpty[i].text);
|
|
74474
|
+
}
|
|
74475
|
+
if (run3.length > 0)
|
|
74476
|
+
return { text: run3.join(`
|
|
74477
|
+
|
|
74478
|
+
`) };
|
|
74479
|
+
const last = nonEmpty[nonEmpty.length - 1];
|
|
74480
|
+
if (last.text.length >= SUBSTANTIVE_MIN_CHARS)
|
|
74481
|
+
return { text: last.text };
|
|
74482
|
+
return null;
|
|
74483
|
+
}
|
|
74484
|
+
function ledgerHashHex(text4) {
|
|
74485
|
+
return createHash4("sha256").update(String(text4 ?? "").trim(), "utf8").digest("hex");
|
|
74486
|
+
}
|
|
74487
|
+
|
|
74488
|
+
// shown-ledger.ts
|
|
74489
|
+
var SHOWN_LEDGER_FILE = "shown-ledger.jsonl";
|
|
74490
|
+
var SHOWN_LEDGER_KEEP = 2000;
|
|
74491
|
+
var SHOWN_LEDGER_ROTATE_AT = 4000;
|
|
74492
|
+
function shownLedgerPath(stateDir) {
|
|
74493
|
+
return join29(resolveOutboxDir(stateDir), SHOWN_LEDGER_FILE);
|
|
74494
|
+
}
|
|
74495
|
+
function appendShownBlock(turnNonce, text4, stateDir, now = Date.now()) {
|
|
74496
|
+
if (turnNonce == null || turnNonce === "")
|
|
74497
|
+
return;
|
|
74498
|
+
const trimmed = typeof text4 === "string" ? text4.trim() : "";
|
|
74499
|
+
if (trimmed.length === 0)
|
|
74500
|
+
return;
|
|
74501
|
+
const dir = resolveOutboxDir(stateDir);
|
|
74502
|
+
const path2 = shownLedgerPath(stateDir);
|
|
74503
|
+
try {
|
|
74504
|
+
mkdirSync26(dir, { recursive: true });
|
|
74505
|
+
const entry = { turnNonce, hash: ledgerHashHex(trimmed), ts: now };
|
|
74506
|
+
appendFileSync5(path2, JSON.stringify(entry) + `
|
|
74507
|
+
`, { mode: 384 });
|
|
74508
|
+
compactIfLarge(path2);
|
|
74509
|
+
} catch {}
|
|
74510
|
+
}
|
|
74511
|
+
function readShownHashes(turnNonce, stateDir) {
|
|
74512
|
+
const set = new Set;
|
|
74513
|
+
if (turnNonce == null || turnNonce === "")
|
|
74514
|
+
return set;
|
|
74515
|
+
const path2 = shownLedgerPath(stateDir);
|
|
74516
|
+
if (!existsSync25(path2))
|
|
74517
|
+
return set;
|
|
74518
|
+
try {
|
|
74519
|
+
for (const line of readFileSync25(path2, "utf8").split(`
|
|
74520
|
+
`)) {
|
|
74521
|
+
if (!line)
|
|
74522
|
+
continue;
|
|
74523
|
+
try {
|
|
74524
|
+
const e = JSON.parse(line);
|
|
74525
|
+
if (e.turnNonce === turnNonce && typeof e.hash === "string")
|
|
74526
|
+
set.add(e.hash);
|
|
74527
|
+
} catch {}
|
|
74528
|
+
}
|
|
74529
|
+
} catch {}
|
|
74530
|
+
return set;
|
|
74531
|
+
}
|
|
74532
|
+
function isShownBlock(turnNonce, text4, stateDir) {
|
|
74533
|
+
if (turnNonce == null || turnNonce === "")
|
|
74534
|
+
return false;
|
|
74535
|
+
const trimmed = typeof text4 === "string" ? text4.trim() : "";
|
|
74536
|
+
if (trimmed.length === 0)
|
|
74537
|
+
return false;
|
|
74538
|
+
return readShownHashes(turnNonce, stateDir).has(ledgerHashHex(trimmed));
|
|
74539
|
+
}
|
|
74540
|
+
function compactIfLarge(path2) {
|
|
74541
|
+
try {
|
|
74542
|
+
const lines = readFileSync25(path2, "utf8").split(`
|
|
74543
|
+
`).filter((l) => l.length > 0);
|
|
74544
|
+
if (lines.length <= SHOWN_LEDGER_ROTATE_AT)
|
|
74545
|
+
return;
|
|
74546
|
+
const kept = lines.slice(lines.length - SHOWN_LEDGER_KEEP);
|
|
74547
|
+
const tmp = `${path2}.${process.pid}.compact`;
|
|
74548
|
+
writeFileSync23(tmp, kept.join(`
|
|
74549
|
+
`) + `
|
|
74550
|
+
`, { mode: 384 });
|
|
74551
|
+
renameSync9(tmp, path2);
|
|
74552
|
+
} catch {}
|
|
74553
|
+
}
|
|
74554
|
+
|
|
74092
74555
|
// registry/subagents-schema.ts
|
|
74093
74556
|
function countRunningBackgroundSubagents(db2) {
|
|
74094
74557
|
const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
|
|
@@ -74206,7 +74669,14 @@ function journalExternalDelivery(args, stateDir, now = Date.now()) {
|
|
|
74206
74669
|
const nonce = args.turnNonce;
|
|
74207
74670
|
if (nonce == null || nonce === "")
|
|
74208
74671
|
return;
|
|
74209
|
-
appendDelivered({
|
|
74672
|
+
appendDelivered({
|
|
74673
|
+
turnNonce: nonce,
|
|
74674
|
+
textSha256: sha256Hex(args.text),
|
|
74675
|
+
tgMessageId: args.tgMessageId,
|
|
74676
|
+
ts: now,
|
|
74677
|
+
deliverySource: args.deliverySource ?? "reply-tool",
|
|
74678
|
+
...args.replyAlreadyDeliveredThisTurn == null ? {} : { replyAlreadyDeliveredThisTurn: args.replyAlreadyDeliveredThisTurn }
|
|
74679
|
+
}, stateDir);
|
|
74210
74680
|
clearOutboxRecord(nonce, stateDir);
|
|
74211
74681
|
}
|
|
74212
74682
|
|
|
@@ -74599,8 +75069,8 @@ function monotonicNowMs2() {
|
|
|
74599
75069
|
}
|
|
74600
75070
|
|
|
74601
75071
|
// silent-end.ts
|
|
74602
|
-
import { existsSync as
|
|
74603
|
-
import { dirname as dirname11, join as
|
|
75072
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26, writeFileSync as writeFileSync24, unlinkSync as unlinkSync13, mkdirSync as mkdirSync27 } from "node:fs";
|
|
75073
|
+
import { dirname as dirname11, join as join30 } from "node:path";
|
|
74604
75074
|
import { homedir as homedir11 } from "node:os";
|
|
74605
75075
|
var SILENT_END_MAX_RETRIES2 = 2;
|
|
74606
75076
|
var SILENT_END_STALE_RECORD_MAX_AGE_MS2 = 30 * 60000;
|
|
@@ -74615,10 +75085,10 @@ function resolveStateDir3(deps) {
|
|
|
74615
75085
|
if (env != null && env !== "")
|
|
74616
75086
|
return env;
|
|
74617
75087
|
const home2 = process.env.HOME ?? homedir11();
|
|
74618
|
-
return
|
|
75088
|
+
return join30(home2, ".claude", "channels", "telegram");
|
|
74619
75089
|
}
|
|
74620
75090
|
function resolveStatePath3(deps) {
|
|
74621
|
-
return
|
|
75091
|
+
return join30(resolveStateDir3(deps), "silent-end-pending.json");
|
|
74622
75092
|
}
|
|
74623
75093
|
function emitLog2(deps, line) {
|
|
74624
75094
|
if (deps?.log != null)
|
|
@@ -74630,8 +75100,8 @@ function writeSilentEndState2(args, deps) {
|
|
|
74630
75100
|
const statePath = resolveStatePath3(deps);
|
|
74631
75101
|
let retryCount = 0;
|
|
74632
75102
|
try {
|
|
74633
|
-
if (
|
|
74634
|
-
const prev = JSON.parse(
|
|
75103
|
+
if (existsSync26(statePath)) {
|
|
75104
|
+
const prev = JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74635
75105
|
if (prev.turnKey === args.turnKey && typeof prev.retryCount === "number") {
|
|
74636
75106
|
retryCount = prev.retryCount;
|
|
74637
75107
|
}
|
|
@@ -74647,8 +75117,8 @@ function writeSilentEndState2(args, deps) {
|
|
|
74647
75117
|
timestamp: Date.now()
|
|
74648
75118
|
};
|
|
74649
75119
|
try {
|
|
74650
|
-
|
|
74651
|
-
|
|
75120
|
+
mkdirSync27(dirname11(statePath), { recursive: true });
|
|
75121
|
+
writeFileSync24(statePath, JSON.stringify(state3), "utf8");
|
|
74652
75122
|
emitLog2(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
|
|
74653
75123
|
`);
|
|
74654
75124
|
} catch (err) {
|
|
@@ -74658,10 +75128,10 @@ function writeSilentEndState2(args, deps) {
|
|
|
74658
75128
|
}
|
|
74659
75129
|
function clearSilentEndState2(turnKey3, deps) {
|
|
74660
75130
|
const statePath = resolveStatePath3(deps);
|
|
74661
|
-
if (!
|
|
75131
|
+
if (!existsSync26(statePath))
|
|
74662
75132
|
return;
|
|
74663
75133
|
try {
|
|
74664
|
-
const prev = JSON.parse(
|
|
75134
|
+
const prev = JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74665
75135
|
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
74666
75136
|
return;
|
|
74667
75137
|
unlinkSync13(statePath);
|
|
@@ -74683,6 +75153,12 @@ function decideCapturedProseDelivery(args, deps) {
|
|
|
74683
75153
|
const text4 = typeof state3.pendingText === "string" ? state3.pendingText : "";
|
|
74684
75154
|
if (text4.trim().length < minChars)
|
|
74685
75155
|
return { deliver: false, reason: "no-substantive-prose" };
|
|
75156
|
+
if (deps?.isBlockShown?.(state3.turnId, text4) === true) {
|
|
75157
|
+
return { deliver: false, reason: "ephemeral-shown" };
|
|
75158
|
+
}
|
|
75159
|
+
if (deps?.backstopDeliveredNonceHit?.(state3.turnId) === true) {
|
|
75160
|
+
return { deliver: false, reason: "already-delivered" };
|
|
75161
|
+
}
|
|
74686
75162
|
return { deliver: true, text: text4, reason: "captured-prose" };
|
|
74687
75163
|
}
|
|
74688
75164
|
function settleCapturedProseDelivery(outcome, effects) {
|
|
@@ -74695,10 +75171,10 @@ function settleCapturedProseDelivery(outcome, effects) {
|
|
|
74695
75171
|
}
|
|
74696
75172
|
function readSilentEndState2(deps) {
|
|
74697
75173
|
const statePath = resolveStatePath3(deps);
|
|
74698
|
-
if (!
|
|
75174
|
+
if (!existsSync26(statePath))
|
|
74699
75175
|
return null;
|
|
74700
75176
|
try {
|
|
74701
|
-
return JSON.parse(
|
|
75177
|
+
return JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74702
75178
|
} catch {
|
|
74703
75179
|
return null;
|
|
74704
75180
|
}
|
|
@@ -75377,7 +75853,7 @@ ${url}`;
|
|
|
75377
75853
|
}
|
|
75378
75854
|
outboundDedup.record(chat_id, threadId, decision.mergedText, Date.now(), turn2?.registryKey ?? null);
|
|
75379
75855
|
if (isFinalAnswerReply({ text: decision.mergedText, disableNotification: modelDisableNotification })) {
|
|
75380
|
-
journalExternalDelivery({ turnNonce: turn2?.turnId ?? null, text: decision.mergedText, tgMessageId: decision.messageId });
|
|
75856
|
+
journalExternalDelivery({ turnNonce: turn2?.turnId ?? null, text: decision.mergedText, tgMessageId: decision.messageId, replyAlreadyDeliveredThisTurn: true });
|
|
75381
75857
|
}
|
|
75382
75858
|
silentAnchorEditDone = true;
|
|
75383
75859
|
} catch (err) {
|
|
@@ -75655,7 +76131,7 @@ ${url}`;
|
|
|
75655
76131
|
const t = getCurrentTurn();
|
|
75656
76132
|
outboundDedup.record(chat_id, threadId, text4, Date.now(), t?.registryKey ?? null);
|
|
75657
76133
|
if (shouldJournalReplySiteDelivery({ text: rawText, disableNotification: modelDisableNotification })) {
|
|
75658
|
-
journalExternalDelivery({ turnNonce: t?.turnId ?? null, text: text4, tgMessageId: sentIds[sentIds.length - 1] });
|
|
76134
|
+
journalExternalDelivery({ turnNonce: t?.turnId ?? null, text: text4, tgMessageId: sentIds[sentIds.length - 1], replyAlreadyDeliveredThisTurn: true });
|
|
75659
76135
|
}
|
|
75660
76136
|
}
|
|
75661
76137
|
return { content: [{ type: "text", text: result }] };
|
|
@@ -75709,7 +76185,7 @@ async function deliverCapturedProse(deps, args) {
|
|
|
75709
76185
|
} catch {}
|
|
75710
76186
|
}
|
|
75711
76187
|
outboundDedup.record(chatId, threadId, text4, now, registryKey);
|
|
75712
|
-
journalExternalDelivery({ turnNonce: originTurnId, text: text4, tgMessageId: sentIds[sentIds.length - 1] });
|
|
76188
|
+
journalExternalDelivery({ turnNonce: originTurnId, text: text4, tgMessageId: sentIds[sentIds.length - 1], replyAlreadyDeliveredThisTurn: false });
|
|
75713
76189
|
process.stderr.write(`telegram gateway: captured-prose delivery \u2014 sent ${out.length} chars recovered from ` + `transcript scan (chat=${chatId} origin=${originTurnId})
|
|
75714
76190
|
`);
|
|
75715
76191
|
outcome = "sent";
|
|
@@ -75818,34 +76294,6 @@ function endsWithSilentMarker(text4) {
|
|
|
75818
76294
|
return false;
|
|
75819
76295
|
return isSilentFlushMarker(lines[lines.length - 1]);
|
|
75820
76296
|
}
|
|
75821
|
-
var FLUSH_SUBSTANTIVE_MIN_CHARS = 200;
|
|
75822
|
-
function selectFlushDeliveryText(blocks, followedByToolUse) {
|
|
75823
|
-
const candidates = blocks.map((b, i) => ({ text: b.trim(), followedByToolUse: followedByToolUse?.[i] })).filter((c) => c.text.length > 0);
|
|
75824
|
-
if (candidates.length === 0)
|
|
75825
|
-
return "";
|
|
75826
|
-
if (candidates.length === 1)
|
|
75827
|
-
return candidates[0].text;
|
|
75828
|
-
const answer = candidates[candidates.length - 1].text;
|
|
75829
|
-
const preceding = candidates.slice(0, -1);
|
|
75830
|
-
const allNarration = preceding.every((c) => c.followedByToolUse === true ? isNarrationBlock(c.text) || c.text.trim().length < FLUSH_SUBSTANTIVE_MIN_CHARS : c.followedByToolUse === false ? false : isNarrationBlock(c.text));
|
|
75831
|
-
return allNarration ? answer : candidates.map((c) => c.text).join(`
|
|
75832
|
-
|
|
75833
|
-
`);
|
|
75834
|
-
}
|
|
75835
|
-
var NARRATION_OPENER = /^(let me\b|lemme\b|i'?ll\b|i will\b|i am going to\b|i'?m going to\b|i'?m about to\b|going to\b|first,?\s+(?:let me|i'?ll|i will)\b|now,?\s+(?:let me|i'?ll|i will)\b|next,?\s+(?:let me|i'?ll|i will)\b|let'?s\b)/i;
|
|
75836
|
-
var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
|
|
75837
|
-
function isTrailingNarrationLine(block) {
|
|
75838
|
-
const t = block.trim();
|
|
75839
|
-
if (t.length === 0 || t.length >= FLUSH_SUBSTANTIVE_MIN_CHARS)
|
|
75840
|
-
return false;
|
|
75841
|
-
if (t.includes(`
|
|
75842
|
-
`))
|
|
75843
|
-
return false;
|
|
75844
|
-
return NARRATION_TRAILER.test(t);
|
|
75845
|
-
}
|
|
75846
|
-
function isNarrationBlock(block) {
|
|
75847
|
-
return NARRATION_OPENER.test(block.trimStart()) || isTrailingNarrationLine(block);
|
|
75848
|
-
}
|
|
75849
76297
|
function decideTurnFlush(input) {
|
|
75850
76298
|
const flushEnabled = input.flushEnabled !== false;
|
|
75851
76299
|
if (!flushEnabled)
|
|
@@ -75865,10 +76313,14 @@ function decideTurnFlush(input) {
|
|
|
75865
76313
|
return { kind: "skip", reason: "silent-marker" };
|
|
75866
76314
|
if (endsWithSilentMarker(joined))
|
|
75867
76315
|
return { kind: "skip", reason: "silent-marker" };
|
|
75868
|
-
|
|
75869
|
-
|
|
75870
|
-
|
|
75871
|
-
};
|
|
76316
|
+
const selected = selectBackstopDelivery(input.capturedText.map((text4, i) => ({
|
|
76317
|
+
text: text4,
|
|
76318
|
+
followedByToolUse: input.capturedBlockMeta?.[i]
|
|
76319
|
+
})));
|
|
76320
|
+
if (selected == null || selected.text.trim().length === 0) {
|
|
76321
|
+
return { kind: "skip", reason: "empty-text" };
|
|
76322
|
+
}
|
|
76323
|
+
return { kind: "flush", text: selected.text };
|
|
75872
76324
|
}
|
|
75873
76325
|
|
|
75874
76326
|
// answer-stream.ts
|
|
@@ -76258,20 +76710,20 @@ var INTERRUPTED_VIA = new Set([
|
|
|
76258
76710
|
init_rich_send();
|
|
76259
76711
|
|
|
76260
76712
|
// runtime-metrics.ts
|
|
76261
|
-
import { mkdirSync as
|
|
76262
|
-
import { dirname as dirname12, join as
|
|
76713
|
+
import { mkdirSync as mkdirSync29, appendFileSync as appendFileSync6 } from "node:fs";
|
|
76714
|
+
import { dirname as dirname12, join as join32 } from "node:path";
|
|
76263
76715
|
function resolveJsonlPath2() {
|
|
76264
76716
|
const override = process.env.SWITCHROOM_RUNTIME_METRICS_PATH;
|
|
76265
76717
|
if (override && override.trim() !== "")
|
|
76266
76718
|
return override.trim();
|
|
76267
76719
|
const base = process.env.SWITCHROOM_RUNTIME_STATE_DIR ?? "/state/agent";
|
|
76268
|
-
return
|
|
76720
|
+
return join32(base, "runtime-metrics.jsonl");
|
|
76269
76721
|
}
|
|
76270
76722
|
function appendJsonl2(line) {
|
|
76271
76723
|
const path2 = resolveJsonlPath2();
|
|
76272
76724
|
try {
|
|
76273
|
-
|
|
76274
|
-
|
|
76725
|
+
mkdirSync29(dirname12(path2), { recursive: true });
|
|
76726
|
+
appendFileSync6(path2, line + `
|
|
76275
76727
|
`, "utf-8");
|
|
76276
76728
|
} catch (err) {
|
|
76277
76729
|
process.stderr.write(`runtime-metrics: jsonl write failed: ${err.message}
|
|
@@ -76761,28 +77213,28 @@ function detectStatusSurfaceDegraded(t) {
|
|
|
76761
77213
|
// gateway/turn-active-marker.ts
|
|
76762
77214
|
import {
|
|
76763
77215
|
closeSync as closeSync5,
|
|
76764
|
-
existsSync as
|
|
76765
|
-
mkdirSync as
|
|
77216
|
+
existsSync as existsSync29,
|
|
77217
|
+
mkdirSync as mkdirSync30,
|
|
76766
77218
|
openSync as openSync5,
|
|
76767
|
-
readFileSync as
|
|
77219
|
+
readFileSync as readFileSync27,
|
|
76768
77220
|
statSync as statSync11,
|
|
76769
77221
|
unlinkSync as unlinkSync14,
|
|
76770
77222
|
utimesSync,
|
|
76771
|
-
writeFileSync as
|
|
77223
|
+
writeFileSync as writeFileSync25
|
|
76772
77224
|
} from "node:fs";
|
|
76773
|
-
import { join as
|
|
77225
|
+
import { join as join33 } from "node:path";
|
|
76774
77226
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
76775
77227
|
var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
|
|
76776
77228
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
76777
77229
|
try {
|
|
76778
|
-
|
|
76779
|
-
|
|
77230
|
+
mkdirSync30(stateDir, { recursive: true });
|
|
77231
|
+
writeFileSync25(join33(stateDir, TURN_ACTIVE_MARKER_FILE), JSON.stringify(marker, null, 2) + `
|
|
76780
77232
|
`, { mode: 384 });
|
|
76781
77233
|
} catch {}
|
|
76782
77234
|
}
|
|
76783
77235
|
function touchTurnActiveMarker(stateDir) {
|
|
76784
|
-
const path2 =
|
|
76785
|
-
if (!
|
|
77236
|
+
const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
77237
|
+
if (!existsSync29(path2))
|
|
76786
77238
|
return;
|
|
76787
77239
|
const now = new Date;
|
|
76788
77240
|
try {
|
|
@@ -76796,11 +77248,11 @@ function touchTurnActiveMarker(stateDir) {
|
|
|
76796
77248
|
}
|
|
76797
77249
|
function removeTurnActiveMarker(stateDir) {
|
|
76798
77250
|
try {
|
|
76799
|
-
unlinkSync14(
|
|
77251
|
+
unlinkSync14(join33(stateDir, TURN_ACTIVE_MARKER_FILE));
|
|
76800
77252
|
} catch {}
|
|
76801
77253
|
}
|
|
76802
77254
|
function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
76803
|
-
const path2 =
|
|
77255
|
+
const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
76804
77256
|
try {
|
|
76805
77257
|
const st = statSync11(path2);
|
|
76806
77258
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -77222,7 +77674,10 @@ function handleSessionEvent(deps, ev) {
|
|
|
77222
77674
|
const turn = getCurrentTurn();
|
|
77223
77675
|
if (turn == null)
|
|
77224
77676
|
return;
|
|
77225
|
-
|
|
77677
|
+
if (!isEphemeralTool(ev.toolName)) {
|
|
77678
|
+
turn.capturedBlockMeta.fill(true);
|
|
77679
|
+
clearAnswerReadyFlushTimeout(turn);
|
|
77680
|
+
}
|
|
77226
77681
|
resolvePendingNarrativeOnTool(turn, ev.toolName, ev.input);
|
|
77227
77682
|
turn.toolCallCount++;
|
|
77228
77683
|
touchTurnActiveMarker(STATE_DIR);
|
|
@@ -77257,7 +77712,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
77257
77712
|
const turn = getCurrentTurn();
|
|
77258
77713
|
if (turn == null)
|
|
77259
77714
|
return;
|
|
77260
|
-
|
|
77715
|
+
if (!isEphemeralTool(ev.toolName)) {
|
|
77716
|
+
clearAnswerReadyFlushTimeout(turn);
|
|
77717
|
+
}
|
|
77261
77718
|
resetOrphanedReplyTimeout();
|
|
77262
77719
|
if (isTelegramSurfaceTool(ev.toolName))
|
|
77263
77720
|
return;
|
|
@@ -77635,6 +78092,11 @@ function handleSessionEvent(deps, ev) {
|
|
|
77635
78092
|
}
|
|
77636
78093
|
} catch {}
|
|
77637
78094
|
}
|
|
78095
|
+
if (backstopAlreadyDelivered(turn.turnId, STATE_DIR)) {
|
|
78096
|
+
process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already delivered by a prior backstop (durable journal)
|
|
78097
|
+
`);
|
|
78098
|
+
return;
|
|
78099
|
+
}
|
|
77638
78100
|
if (!backstopLatchClaimed) {
|
|
77639
78101
|
process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already claimed the delivery latch
|
|
77640
78102
|
`);
|
|
@@ -77697,6 +78159,19 @@ function handleSessionEvent(deps, ev) {
|
|
|
77697
78159
|
chunkCount,
|
|
77698
78160
|
cardMessageId: backstopCardMessageId
|
|
77699
78161
|
});
|
|
78162
|
+
if (delivered) {
|
|
78163
|
+
try {
|
|
78164
|
+
journalExternalDelivery({
|
|
78165
|
+
turnNonce: turn.turnId,
|
|
78166
|
+
text: capturedText,
|
|
78167
|
+
tgMessageId: sentIds.length > 0 ? sentIds[0] : undefined,
|
|
78168
|
+
deliverySource: "flush"
|
|
78169
|
+
}, STATE_DIR);
|
|
78170
|
+
} catch (err) {
|
|
78171
|
+
process.stderr.write(`telegram gateway: turn-flush delivered but journal write failed (non-fatal): ${err.message}
|
|
78172
|
+
`);
|
|
78173
|
+
}
|
|
78174
|
+
}
|
|
77700
78175
|
if (OBLIGATION_LEDGER_ENABLED) {
|
|
77701
78176
|
if (delivered) {
|
|
77702
78177
|
obligationLedger.close(turn.turnId);
|
|
@@ -77757,6 +78232,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
77757
78232
|
turnKey: tKey,
|
|
77758
78233
|
turnId: turn.turnId,
|
|
77759
78234
|
minChars: proseMinChars
|
|
78235
|
+
}, {
|
|
78236
|
+
isBlockShown: (nonce, text4) => isShownBlock(nonce ?? null, text4),
|
|
78237
|
+
backstopDeliveredNonceHit: (nonce) => backstopAlreadyDelivered(nonce ?? "", STATE_DIR)
|
|
77760
78238
|
}) : { deliver: false, reason: "no-state" };
|
|
77761
78239
|
if (proseDecision.deliver && proseDecision.text != null) {
|
|
77762
78240
|
process.stderr.write(`telegram gateway: captured-prose delivery engaged on first silent-end chat=${chatId} turnKey=${tKey} (#3227)
|
|
@@ -77896,6 +78374,7 @@ class NarrativeFlushController {
|
|
|
77896
78374
|
this.scheduler.disarm();
|
|
77897
78375
|
if (this.pending != null) {
|
|
77898
78376
|
this.effects.show(this.pending);
|
|
78377
|
+
this.markShown(this.pending);
|
|
77899
78378
|
}
|
|
77900
78379
|
this.pending = text4;
|
|
77901
78380
|
this.scheduler.arm(() => this.onTimerFire(), this.flushMs);
|
|
@@ -77920,6 +78399,7 @@ class NarrativeFlushController {
|
|
|
77920
78399
|
if (replyText != null && isDraftOfReply(pending, replyText))
|
|
77921
78400
|
return;
|
|
77922
78401
|
this.effects.show(pending);
|
|
78402
|
+
this.markShown(pending);
|
|
77923
78403
|
}
|
|
77924
78404
|
flushAtTurnEnd(lastReplyText) {
|
|
77925
78405
|
this.scheduler.disarm();
|
|
@@ -77938,6 +78418,13 @@ class NarrativeFlushController {
|
|
|
77938
78418
|
this.pending = null;
|
|
77939
78419
|
this.timerShown = null;
|
|
77940
78420
|
}
|
|
78421
|
+
markShown(text4) {
|
|
78422
|
+
if (this.effects.markDurableNarration == null)
|
|
78423
|
+
return;
|
|
78424
|
+
if (!isStructuralNarration(text4, true))
|
|
78425
|
+
return;
|
|
78426
|
+
this.effects.markDurableNarration(text4);
|
|
78427
|
+
}
|
|
77941
78428
|
maybeRetract(replyText) {
|
|
77942
78429
|
const shown = this.timerShown;
|
|
77943
78430
|
if (shown == null)
|
|
@@ -78089,7 +78576,12 @@ function createNarrativeLane(deps) {
|
|
|
78089
78576
|
let handle = null;
|
|
78090
78577
|
return new NarrativeFlushController({
|
|
78091
78578
|
show: (text4) => showNarrativeStep(turn, text4),
|
|
78092
|
-
retractShown: (text4) => retractNarrativeLine(turn, text4)
|
|
78579
|
+
retractShown: (text4) => retractNarrativeLine(turn, text4),
|
|
78580
|
+
markDurableNarration: (text4) => {
|
|
78581
|
+
if (turn.turnId == null)
|
|
78582
|
+
return;
|
|
78583
|
+
appendShownBlock(turn.turnId, text4);
|
|
78584
|
+
}
|
|
78093
78585
|
}, {
|
|
78094
78586
|
arm: (fn, ms) => {
|
|
78095
78587
|
if (handle != null)
|
|
@@ -78687,19 +79179,19 @@ function resolveAgentDirFromEnv() {
|
|
|
78687
79179
|
}
|
|
78688
79180
|
|
|
78689
79181
|
// active-reactions.ts
|
|
78690
|
-
import { readFileSync as
|
|
78691
|
-
import { join as
|
|
79182
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync26, renameSync as renameSync10, existsSync as existsSync30, unlinkSync as unlinkSync15 } from "node:fs";
|
|
79183
|
+
import { join as join34 } from "node:path";
|
|
78692
79184
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
78693
79185
|
function reactionsPath(agentDir) {
|
|
78694
|
-
return
|
|
79186
|
+
return join34(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
78695
79187
|
}
|
|
78696
79188
|
function readActiveReactions(agentDir) {
|
|
78697
79189
|
const p = reactionsPath(agentDir);
|
|
78698
|
-
if (!
|
|
79190
|
+
if (!existsSync30(p))
|
|
78699
79191
|
return [];
|
|
78700
79192
|
let raw;
|
|
78701
79193
|
try {
|
|
78702
|
-
raw =
|
|
79194
|
+
raw = readFileSync28(p, "utf-8");
|
|
78703
79195
|
} catch {
|
|
78704
79196
|
return [];
|
|
78705
79197
|
}
|
|
@@ -78731,9 +79223,9 @@ function writeActiveReactions(agentDir, reactions) {
|
|
|
78731
79223
|
}
|
|
78732
79224
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
78733
79225
|
try {
|
|
78734
|
-
|
|
79226
|
+
writeFileSync26(tmp, JSON.stringify(reactions) + `
|
|
78735
79227
|
`, "utf-8");
|
|
78736
|
-
|
|
79228
|
+
renameSync10(tmp, p);
|
|
78737
79229
|
} catch {}
|
|
78738
79230
|
}
|
|
78739
79231
|
function addActiveReaction(agentDir, reaction) {
|
|
@@ -78755,19 +79247,19 @@ function clearActiveReactions(agentDir) {
|
|
|
78755
79247
|
}
|
|
78756
79248
|
|
|
78757
79249
|
// active-reactions.ts
|
|
78758
|
-
import { readFileSync as
|
|
78759
|
-
import { join as
|
|
79250
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync27, renameSync as renameSync11, existsSync as existsSync31, unlinkSync as unlinkSync16 } from "node:fs";
|
|
79251
|
+
import { join as join35 } from "node:path";
|
|
78760
79252
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
78761
79253
|
function reactionsPath2(agentDir) {
|
|
78762
|
-
return
|
|
79254
|
+
return join35(agentDir, ACTIVE_REACTIONS_FILENAME2);
|
|
78763
79255
|
}
|
|
78764
79256
|
function readActiveReactions2(agentDir) {
|
|
78765
79257
|
const p = reactionsPath2(agentDir);
|
|
78766
|
-
if (!
|
|
79258
|
+
if (!existsSync31(p))
|
|
78767
79259
|
return [];
|
|
78768
79260
|
let raw;
|
|
78769
79261
|
try {
|
|
78770
|
-
raw =
|
|
79262
|
+
raw = readFileSync29(p, "utf-8");
|
|
78771
79263
|
} catch {
|
|
78772
79264
|
return [];
|
|
78773
79265
|
}
|
|
@@ -79635,17 +80127,17 @@ async function approvalRecord(args, opts) {
|
|
|
79635
80127
|
}
|
|
79636
80128
|
|
|
79637
80129
|
// quota-check.ts
|
|
79638
|
-
import { readFileSync as
|
|
79639
|
-
import { join as
|
|
80130
|
+
import { readFileSync as readFileSync30, existsSync as existsSync32 } from "fs";
|
|
80131
|
+
import { join as join36 } from "path";
|
|
79640
80132
|
var OAUTH_BETA2 = "oauth-2025-04-20";
|
|
79641
80133
|
var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
|
|
79642
80134
|
var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
|
|
79643
80135
|
function readOauthToken2(claudeConfigDir) {
|
|
79644
|
-
const tokenFile =
|
|
79645
|
-
if (!
|
|
80136
|
+
const tokenFile = join36(claudeConfigDir, ".oauth-token");
|
|
80137
|
+
if (!existsSync32(tokenFile))
|
|
79646
80138
|
return null;
|
|
79647
80139
|
try {
|
|
79648
|
-
const raw =
|
|
80140
|
+
const raw = readFileSync30(tokenFile, "utf-8").trim();
|
|
79649
80141
|
return raw.length > 0 ? raw : null;
|
|
79650
80142
|
} catch {
|
|
79651
80143
|
return null;
|
|
@@ -80981,15 +81473,15 @@ async function menuWithBannerStatic(deps, banner) {
|
|
|
80981
81473
|
}
|
|
80982
81474
|
|
|
80983
81475
|
// gateway/session-model-file.ts
|
|
80984
|
-
import { readFileSync as
|
|
80985
|
-
import { join as
|
|
81476
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync28, renameSync as renameSync12, rmSync as rmSync4 } from "node:fs";
|
|
81477
|
+
import { join as join37 } from "node:path";
|
|
80986
81478
|
var SESSION_MODEL_FILE = ".session-model";
|
|
80987
81479
|
var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
|
|
80988
81480
|
var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
|
|
80989
81481
|
function atomicWrite(path2, content3) {
|
|
80990
81482
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
80991
|
-
|
|
80992
|
-
|
|
81483
|
+
writeFileSync28(tmp, content3, "utf8");
|
|
81484
|
+
renameSync12(tmp, path2);
|
|
80993
81485
|
}
|
|
80994
81486
|
function serializeSessionModel(rec) {
|
|
80995
81487
|
return `${JSON.stringify({
|
|
@@ -81004,28 +81496,28 @@ function writeSessionModelFile(agentDir, model, configuredDefaultAtWrite) {
|
|
|
81004
81496
|
throw new Error(`refusing to persist non-canonical session model token: ${JSON.stringify(model)}`);
|
|
81005
81497
|
}
|
|
81006
81498
|
try {
|
|
81007
|
-
rmSync4(
|
|
81499
|
+
rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
81008
81500
|
} catch {}
|
|
81009
|
-
atomicWrite(
|
|
81501
|
+
atomicWrite(join37(agentDir, SESSION_MODEL_FILE), serializeSessionModel({ model, configuredDefaultAtWrite, ts: Date.now() }));
|
|
81010
81502
|
}
|
|
81011
81503
|
function readSessionModelFileRaw(agentDir) {
|
|
81012
81504
|
try {
|
|
81013
|
-
return
|
|
81505
|
+
return readFileSync31(join37(agentDir, SESSION_MODEL_FILE), "utf8");
|
|
81014
81506
|
} catch {
|
|
81015
81507
|
return null;
|
|
81016
81508
|
}
|
|
81017
81509
|
}
|
|
81018
81510
|
function clearSessionModelFile(agentDir) {
|
|
81019
81511
|
try {
|
|
81020
|
-
rmSync4(
|
|
81512
|
+
rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
81021
81513
|
} catch {}
|
|
81022
81514
|
}
|
|
81023
81515
|
function consumeSessionModelCarrierOnHealthyBoot(agentDir) {
|
|
81024
81516
|
try {
|
|
81025
|
-
rmSync4(
|
|
81517
|
+
rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
81026
81518
|
} catch {}
|
|
81027
81519
|
try {
|
|
81028
|
-
rmSync4(
|
|
81520
|
+
rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
81029
81521
|
} catch {}
|
|
81030
81522
|
}
|
|
81031
81523
|
function restoreSessionModelFileRaw(agentDir, raw) {
|
|
@@ -81034,12 +81526,12 @@ function restoreSessionModelFileRaw(agentDir, raw) {
|
|
|
81034
81526
|
return;
|
|
81035
81527
|
}
|
|
81036
81528
|
try {
|
|
81037
|
-
atomicWrite(
|
|
81529
|
+
atomicWrite(join37(agentDir, SESSION_MODEL_FILE), raw);
|
|
81038
81530
|
} catch {}
|
|
81039
81531
|
}
|
|
81040
81532
|
function readConfiguredDefaultModel(agentDir) {
|
|
81041
81533
|
try {
|
|
81042
|
-
const v =
|
|
81534
|
+
const v = readFileSync31(join37(agentDir, CONFIGURED_DEFAULT_MODEL_FILE), "utf8").trim();
|
|
81043
81535
|
return v.length > 0 ? v : null;
|
|
81044
81536
|
} catch {
|
|
81045
81537
|
return null;
|
|
@@ -81051,12 +81543,12 @@ function writeSessionEffortFile(agentDir, level, configuredDefaultAtWrite) {
|
|
|
81051
81543
|
if (!EFFORT_LEVEL_RE.test(level)) {
|
|
81052
81544
|
throw new Error(`refusing to persist non-allowlisted effort level: ${JSON.stringify(level)}`);
|
|
81053
81545
|
}
|
|
81054
|
-
atomicWrite(
|
|
81546
|
+
atomicWrite(join37(agentDir, SESSION_EFFORT_FILE), `${JSON.stringify({ level, configuredDefaultAtWrite: configuredDefaultAtWrite ?? "", ts: Date.now() })}
|
|
81055
81547
|
`);
|
|
81056
81548
|
}
|
|
81057
81549
|
function clearSessionEffortFile(agentDir) {
|
|
81058
81550
|
try {
|
|
81059
|
-
rmSync4(
|
|
81551
|
+
rmSync4(join37(agentDir, SESSION_EFFORT_FILE), { force: true });
|
|
81060
81552
|
} catch {}
|
|
81061
81553
|
}
|
|
81062
81554
|
var PREMIUM_RECOVERY_FILE = ".premium-recovery";
|
|
@@ -81079,13 +81571,13 @@ function writePremiumRecoveryFile(agentDir, premiumModel, chats) {
|
|
|
81079
81571
|
if (clean.length === 0) {
|
|
81080
81572
|
throw new Error("refusing to persist premium-recovery marker with no chats to notify");
|
|
81081
81573
|
}
|
|
81082
|
-
atomicWrite(
|
|
81574
|
+
atomicWrite(join37(agentDir, PREMIUM_RECOVERY_FILE), `${JSON.stringify({ premiumModel, chats: clean, ts: Date.now() })}
|
|
81083
81575
|
`);
|
|
81084
81576
|
}
|
|
81085
81577
|
function readPremiumRecoveryFile(agentDir) {
|
|
81086
81578
|
let raw;
|
|
81087
81579
|
try {
|
|
81088
|
-
raw =
|
|
81580
|
+
raw = readFileSync31(join37(agentDir, PREMIUM_RECOVERY_FILE), "utf8");
|
|
81089
81581
|
} catch {
|
|
81090
81582
|
return null;
|
|
81091
81583
|
}
|
|
@@ -81098,7 +81590,7 @@ function readPremiumRecoveryFile(agentDir) {
|
|
|
81098
81590
|
}
|
|
81099
81591
|
function clearPremiumRecoveryFile(agentDir) {
|
|
81100
81592
|
try {
|
|
81101
|
-
rmSync4(
|
|
81593
|
+
rmSync4(join37(agentDir, PREMIUM_RECOVERY_FILE), { force: true });
|
|
81102
81594
|
} catch {}
|
|
81103
81595
|
}
|
|
81104
81596
|
|
|
@@ -81387,7 +81879,7 @@ async function discoverModels(agentName3, opts = {}) {
|
|
|
81387
81879
|
}
|
|
81388
81880
|
|
|
81389
81881
|
// ../src/agents/scaffold.ts
|
|
81390
|
-
import { dirname as dirname14, isAbsolute, join as
|
|
81882
|
+
import { dirname as dirname14, isAbsolute, join as join40, relative, resolve as resolve8 } from "node:path";
|
|
81391
81883
|
init_atomic();
|
|
81392
81884
|
|
|
81393
81885
|
// ../src/agents/agent-uid.ts
|
|
@@ -81404,7 +81896,7 @@ init_merge();
|
|
|
81404
81896
|
init_timezone();
|
|
81405
81897
|
|
|
81406
81898
|
// ../src/cli/agent-config.ts
|
|
81407
|
-
import { join as
|
|
81899
|
+
import { join as join38 } from "node:path";
|
|
81408
81900
|
import { homedir as homedir12 } from "node:os";
|
|
81409
81901
|
|
|
81410
81902
|
// ../src/cli/helpers.ts
|
|
@@ -81425,12 +81917,12 @@ var WEBKITE_VAULT_KEYS = new Set([
|
|
|
81425
81917
|
init_overlay_loader();
|
|
81426
81918
|
|
|
81427
81919
|
// ../src/cli/agent-config.ts
|
|
81428
|
-
var AUDIT_ROOT =
|
|
81920
|
+
var AUDIT_ROOT = join38(homedir12(), ".switchroom", "audit");
|
|
81429
81921
|
|
|
81430
81922
|
// ../src/agents/profiles.ts
|
|
81431
81923
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
81432
|
-
import { readFileSync as
|
|
81433
|
-
import { resolve as resolve7, join as
|
|
81924
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync29, existsSync as existsSync33, readdirSync as readdirSync7, statSync as statSync12, copyFileSync, mkdirSync as mkdirSync31, realpathSync as realpathSync2 } from "node:fs";
|
|
81925
|
+
import { resolve as resolve7, join as join39, sep as pathSep } from "node:path";
|
|
81434
81926
|
function resolveProfilesRoot() {
|
|
81435
81927
|
const envOverride = process.env.SWITCHROOM_PROFILES_ROOT?.trim();
|
|
81436
81928
|
if (envOverride) {
|
|
@@ -81441,7 +81933,7 @@ function resolveProfilesRoot() {
|
|
|
81441
81933
|
resolve7(import.meta.dirname, "profiles")
|
|
81442
81934
|
];
|
|
81443
81935
|
for (const candidate of candidates) {
|
|
81444
|
-
if (
|
|
81936
|
+
if (existsSync33(candidate)) {
|
|
81445
81937
|
return candidate;
|
|
81446
81938
|
}
|
|
81447
81939
|
}
|
|
@@ -81457,9 +81949,9 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
|
|
|
81457
81949
|
var SHARED_FRAGMENTS_DIR = resolve7(PROFILES_ROOT, "_shared");
|
|
81458
81950
|
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
|
|
81459
81951
|
for (const name of SHARED_FRAGMENTS) {
|
|
81460
|
-
const fragPath =
|
|
81461
|
-
if (
|
|
81462
|
-
import_handlebars.default.registerPartial(name,
|
|
81952
|
+
const fragPath = join39(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
81953
|
+
if (existsSync33(fragPath)) {
|
|
81954
|
+
import_handlebars.default.registerPartial(name, readFileSync32(fragPath, "utf-8"));
|
|
81463
81955
|
}
|
|
81464
81956
|
}
|
|
81465
81957
|
|
|
@@ -82066,7 +82558,7 @@ init_overlay_loader();
|
|
|
82066
82558
|
init_merge();
|
|
82067
82559
|
init_timezone();
|
|
82068
82560
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
82069
|
-
import { readFileSync as
|
|
82561
|
+
import { readFileSync as readFileSync33, existsSync as existsSync34 } from "node:fs";
|
|
82070
82562
|
import { homedir as homedir13 } from "node:os";
|
|
82071
82563
|
import { resolve as resolve9 } from "node:path";
|
|
82072
82564
|
|
|
@@ -82142,7 +82634,7 @@ function findConfigFile2(startDir) {
|
|
|
82142
82634
|
resolve9(userDir, "clerk.yml")
|
|
82143
82635
|
].filter(Boolean);
|
|
82144
82636
|
for (const path2 of searchPaths) {
|
|
82145
|
-
if (
|
|
82637
|
+
if (existsSync34(path2)) {
|
|
82146
82638
|
return path2;
|
|
82147
82639
|
}
|
|
82148
82640
|
}
|
|
@@ -82150,12 +82642,12 @@ function findConfigFile2(startDir) {
|
|
|
82150
82642
|
}
|
|
82151
82643
|
function loadConfig2(configPath) {
|
|
82152
82644
|
const filePath = configPath ?? findConfigFile2();
|
|
82153
|
-
if (!
|
|
82645
|
+
if (!existsSync34(filePath)) {
|
|
82154
82646
|
throw new ConfigError2(`Config file not found: ${filePath}`);
|
|
82155
82647
|
}
|
|
82156
82648
|
let raw;
|
|
82157
82649
|
try {
|
|
82158
|
-
raw =
|
|
82650
|
+
raw = readFileSync33(filePath, "utf-8");
|
|
82159
82651
|
} catch (err) {
|
|
82160
82652
|
throw new ConfigError2(`Failed to read config file: ${filePath}`, [
|
|
82161
82653
|
` ${err.message}`
|
|
@@ -82685,15 +83177,15 @@ function topicForRecipient(args) {
|
|
|
82685
83177
|
}
|
|
82686
83178
|
|
|
82687
83179
|
// ../src/agents/perf.ts
|
|
82688
|
-
import { existsSync as
|
|
83180
|
+
import { existsSync as existsSync35, readFileSync as readFileSync34 } from "node:fs";
|
|
82689
83181
|
function readTurnUsages(jsonlPath, lastN) {
|
|
82690
|
-
if (!
|
|
83182
|
+
if (!existsSync35(jsonlPath))
|
|
82691
83183
|
return [];
|
|
82692
83184
|
if (lastN <= 0)
|
|
82693
83185
|
return [];
|
|
82694
83186
|
let raw;
|
|
82695
83187
|
try {
|
|
82696
|
-
raw =
|
|
83188
|
+
raw = readFileSync34(jsonlPath, "utf-8");
|
|
82697
83189
|
} catch {
|
|
82698
83190
|
return [];
|
|
82699
83191
|
}
|
|
@@ -82784,8 +83276,8 @@ function numField(obj, key) {
|
|
|
82784
83276
|
}
|
|
82785
83277
|
|
|
82786
83278
|
// gateway/context-occupancy.ts
|
|
82787
|
-
import { mkdirSync as
|
|
82788
|
-
import { join as
|
|
83279
|
+
import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync30 } from "node:fs";
|
|
83280
|
+
import { join as join41 } from "node:path";
|
|
82789
83281
|
var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
|
|
82790
83282
|
var TIGHT_FRACTION = 0.8;
|
|
82791
83283
|
function buildContextOccupancy(occupancy, cap, now) {
|
|
@@ -82808,9 +83300,9 @@ function buildContextOccupancy(occupancy, cap, now) {
|
|
|
82808
83300
|
}
|
|
82809
83301
|
function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
|
|
82810
83302
|
try {
|
|
82811
|
-
const path2 =
|
|
82812
|
-
(deps?.mkdir ?? ((p, o) =>
|
|
82813
|
-
(deps?.writeFile ?? ((p, d) =>
|
|
83303
|
+
const path2 = join41(stateDir, CONTEXT_OCCUPANCY_FILENAME);
|
|
83304
|
+
(deps?.mkdir ?? ((p, o) => mkdirSync32(p, o)))(stateDir, { recursive: true });
|
|
83305
|
+
(deps?.writeFile ?? ((p, d) => writeFileSync30(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
|
|
82814
83306
|
`);
|
|
82815
83307
|
} catch {}
|
|
82816
83308
|
}
|
|
@@ -82964,7 +83456,7 @@ function nextCompactNotify(state6, ev) {
|
|
|
82964
83456
|
}
|
|
82965
83457
|
|
|
82966
83458
|
// gateway/hostd-dispatch.ts
|
|
82967
|
-
import { existsSync as
|
|
83459
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
82968
83460
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
82969
83461
|
init_loader();
|
|
82970
83462
|
var _hostdEnabled2;
|
|
@@ -82988,13 +83480,13 @@ function hostdSocketPath2(agentName3) {
|
|
|
82988
83480
|
function hostdWillBeUsed2(agentName3) {
|
|
82989
83481
|
if (!isHostdEnabled2())
|
|
82990
83482
|
return false;
|
|
82991
|
-
return
|
|
83483
|
+
return existsSync36(hostdSocketPath2(agentName3));
|
|
82992
83484
|
}
|
|
82993
83485
|
async function tryHostdDispatch2(agentName3, req, timeoutMs = 5000) {
|
|
82994
83486
|
if (!isHostdEnabled2())
|
|
82995
83487
|
return "not-configured";
|
|
82996
83488
|
const sockPath = hostdSocketPath2(agentName3);
|
|
82997
|
-
if (!
|
|
83489
|
+
if (!existsSync36(sockPath))
|
|
82998
83490
|
return "not-configured";
|
|
82999
83491
|
try {
|
|
83000
83492
|
return await hostdRequest({ socketPath: sockPath, timeoutMs }, req);
|
|
@@ -83023,7 +83515,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
|
|
|
83023
83515
|
if (!isHostdEnabled2())
|
|
83024
83516
|
return "not-configured";
|
|
83025
83517
|
const sockPath = hostdSocketPath2(agentName3);
|
|
83026
|
-
if (!
|
|
83518
|
+
if (!existsSync36(sockPath))
|
|
83027
83519
|
return "not-configured";
|
|
83028
83520
|
const now = opts.now ?? Date.now;
|
|
83029
83521
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -83142,7 +83634,7 @@ function createDmPinSweeper(deps) {
|
|
|
83142
83634
|
|
|
83143
83635
|
// gateway/webhook-ingest-server.ts
|
|
83144
83636
|
import net4 from "node:net";
|
|
83145
|
-
import { chmodSync as chmodSync10, existsSync as
|
|
83637
|
+
import { chmodSync as chmodSync10, existsSync as existsSync37, unlinkSync as unlinkSync17 } from "node:fs";
|
|
83146
83638
|
var MAX_REQUEST_BYTES = 1024 * 1024;
|
|
83147
83639
|
function fdOf(conn) {
|
|
83148
83640
|
const handle = conn._handle;
|
|
@@ -83154,7 +83646,7 @@ function startWebhookIngestServer(opts) {
|
|
|
83154
83646
|
const log = opts.log ?? ((s) => process.stderr.write(s));
|
|
83155
83647
|
const allowed = new Set(opts.allowedUids);
|
|
83156
83648
|
try {
|
|
83157
|
-
if (
|
|
83649
|
+
if (existsSync37(opts.socketPath))
|
|
83158
83650
|
unlinkSync17(opts.socketPath);
|
|
83159
83651
|
} catch (err) {
|
|
83160
83652
|
log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
|
|
@@ -83247,7 +83739,7 @@ function startWebhookIngestServer(opts) {
|
|
|
83247
83739
|
server.close();
|
|
83248
83740
|
} catch {}
|
|
83249
83741
|
try {
|
|
83250
|
-
if (
|
|
83742
|
+
if (existsSync37(opts.socketPath))
|
|
83251
83743
|
unlinkSync17(opts.socketPath);
|
|
83252
83744
|
} catch {}
|
|
83253
83745
|
}
|
|
@@ -83255,20 +83747,20 @@ function startWebhookIngestServer(opts) {
|
|
|
83255
83747
|
}
|
|
83256
83748
|
|
|
83257
83749
|
// ../src/web/webhook-gateway-record.ts
|
|
83258
|
-
import { appendFileSync as
|
|
83259
|
-
import { join as
|
|
83750
|
+
import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync35 } from "fs";
|
|
83751
|
+
import { join as join44 } from "path";
|
|
83260
83752
|
import { homedir as homedir15 } from "os";
|
|
83261
83753
|
|
|
83262
83754
|
// ../src/web/webhook-handler.ts
|
|
83263
|
-
import { appendFileSync as
|
|
83264
|
-
import { join as
|
|
83755
|
+
import { appendFileSync as appendFileSync7, existsSync as existsSync38, mkdirSync as mkdirSync33, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "fs";
|
|
83756
|
+
import { join as join42 } from "path";
|
|
83265
83757
|
var DEDUP_MAX = 1000;
|
|
83266
83758
|
var DEDUP_TTL_MS = 24 * 60 * 60 * 1000;
|
|
83267
83759
|
function loadDedupFile(path2) {
|
|
83268
83760
|
try {
|
|
83269
|
-
if (!
|
|
83761
|
+
if (!existsSync38(path2))
|
|
83270
83762
|
return {};
|
|
83271
|
-
const raw = JSON.parse(
|
|
83763
|
+
const raw = JSON.parse(readFileSync35(path2, "utf-8"));
|
|
83272
83764
|
return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
|
|
83273
83765
|
} catch {
|
|
83274
83766
|
return {};
|
|
@@ -83282,7 +83774,7 @@ function saveDedupFile(path2, deliveries, now) {
|
|
|
83282
83774
|
}
|
|
83283
83775
|
const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
|
|
83284
83776
|
const final = Object.fromEntries(sorted);
|
|
83285
|
-
|
|
83777
|
+
writeFileSync31(path2, JSON.stringify({ deliveries: final }), {
|
|
83286
83778
|
mode: 384
|
|
83287
83779
|
});
|
|
83288
83780
|
}
|
|
@@ -83290,8 +83782,8 @@ var agentDedupCache = new Map;
|
|
|
83290
83782
|
function createFileDedupStore(resolveAgentDir) {
|
|
83291
83783
|
return {
|
|
83292
83784
|
check(agent, deliveryId, now) {
|
|
83293
|
-
const telegramDir =
|
|
83294
|
-
const filePath =
|
|
83785
|
+
const telegramDir = join42(resolveAgentDir(agent), "telegram");
|
|
83786
|
+
const filePath = join42(telegramDir, "webhook-dedup.json");
|
|
83295
83787
|
if (!agentDedupCache.has(agent)) {
|
|
83296
83788
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
83297
83789
|
}
|
|
@@ -83301,7 +83793,7 @@ function createFileDedupStore(resolveAgentDir) {
|
|
|
83301
83793
|
}
|
|
83302
83794
|
deliveries[deliveryId] = now;
|
|
83303
83795
|
try {
|
|
83304
|
-
|
|
83796
|
+
mkdirSync33(telegramDir, { recursive: true });
|
|
83305
83797
|
saveDedupFile(filePath, deliveries, now);
|
|
83306
83798
|
} catch {}
|
|
83307
83799
|
return;
|
|
@@ -83312,8 +83804,8 @@ var tokenBuckets = new Map;
|
|
|
83312
83804
|
var throttleIssueWindow = new Map;
|
|
83313
83805
|
|
|
83314
83806
|
// ../src/web/webhook-dispatch.ts
|
|
83315
|
-
import { existsSync as
|
|
83316
|
-
import { join as
|
|
83807
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync34, readFileSync as readFileSync36, writeFileSync as writeFileSync32 } from "fs";
|
|
83808
|
+
import { join as join43 } from "path";
|
|
83317
83809
|
import { homedir as homedir14 } from "os";
|
|
83318
83810
|
|
|
83319
83811
|
// ../src/agent-scheduler/ipc-client.ts
|
|
@@ -83612,9 +84104,9 @@ function cooldownKey(source, eventType, repo, number, ruleIndex) {
|
|
|
83612
84104
|
}
|
|
83613
84105
|
function loadCooldownFile(path2) {
|
|
83614
84106
|
try {
|
|
83615
|
-
if (!
|
|
84107
|
+
if (!existsSync39(path2))
|
|
83616
84108
|
return {};
|
|
83617
|
-
const raw = JSON.parse(
|
|
84109
|
+
const raw = JSON.parse(readFileSync36(path2, "utf-8"));
|
|
83618
84110
|
return typeof raw.dispatches === "object" && raw.dispatches !== null ? raw.dispatches : {};
|
|
83619
84111
|
} catch {
|
|
83620
84112
|
return {};
|
|
@@ -83622,7 +84114,7 @@ function loadCooldownFile(path2) {
|
|
|
83622
84114
|
}
|
|
83623
84115
|
function saveCooldownFile(path2, dispatches) {
|
|
83624
84116
|
try {
|
|
83625
|
-
|
|
84117
|
+
writeFileSync32(path2, JSON.stringify({ dispatches }), {
|
|
83626
84118
|
mode: 384
|
|
83627
84119
|
});
|
|
83628
84120
|
} catch {}
|
|
@@ -83633,8 +84125,8 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
83633
84125
|
isCoolingDown(agent, key, cooldownMs, now) {
|
|
83634
84126
|
if (cooldownMs <= 0)
|
|
83635
84127
|
return false;
|
|
83636
|
-
const telegramDir =
|
|
83637
|
-
const filePath =
|
|
84128
|
+
const telegramDir = join43(resolveAgentDir(agent), "telegram");
|
|
84129
|
+
const filePath = join43(telegramDir, "webhook-cooldown.json");
|
|
83638
84130
|
if (!cache.has(agent)) {
|
|
83639
84131
|
cache.set(agent, loadCooldownFile(filePath));
|
|
83640
84132
|
}
|
|
@@ -83645,7 +84137,7 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
83645
84137
|
}
|
|
83646
84138
|
dispatches[key] = now;
|
|
83647
84139
|
try {
|
|
83648
|
-
|
|
84140
|
+
mkdirSync34(telegramDir, { recursive: true });
|
|
83649
84141
|
saveCooldownFile(filePath, dispatches);
|
|
83650
84142
|
} catch {}
|
|
83651
84143
|
return false;
|
|
@@ -83691,9 +84183,9 @@ async function defaultInject(socketPath, agentName3, inbound) {
|
|
|
83691
84183
|
}
|
|
83692
84184
|
function injectWebhookInbound(agent, prompt, ctx, deps = {}) {
|
|
83693
84185
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83694
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84186
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
|
|
83695
84187
|
const now = (deps.now ?? Date.now)();
|
|
83696
|
-
const socketPath =
|
|
84188
|
+
const socketPath = join43(resolveAgentDir(agent), "telegram", "gateway.sock");
|
|
83697
84189
|
const inbound = {
|
|
83698
84190
|
type: "inbound",
|
|
83699
84191
|
chatId: ctx.chatId,
|
|
@@ -83765,7 +84257,7 @@ function evaluateDispatch(args, deps = {}) {
|
|
|
83765
84257
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83766
84258
|
const now = (deps.now ?? Date.now)();
|
|
83767
84259
|
const nowDate = deps.nowDate ?? (() => new Date(now));
|
|
83768
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84260
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
|
|
83769
84261
|
const cooldownStore = deps.cooldownStore ?? createFileCooldownStore(resolveAgentDir);
|
|
83770
84262
|
if (!DISPATCH_SOURCES.includes(args.source))
|
|
83771
84263
|
return 0;
|
|
@@ -83843,10 +84335,10 @@ var CONSOLIDATION_COMPLETED_EVENT = "consolidation.completed";
|
|
|
83843
84335
|
function recordWebhookEvent(rec, deps = {}) {
|
|
83844
84336
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83845
84337
|
const now = rec.ts || (deps.now ?? Date.now)();
|
|
83846
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84338
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join44(homedir15(), ".switchroom", "agents", a));
|
|
83847
84339
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
83848
84340
|
const agent = rec.agent;
|
|
83849
|
-
const telegramDir =
|
|
84341
|
+
const telegramDir = join44(resolveAgentDir(agent), "telegram");
|
|
83850
84342
|
if (rec.source === "github" && rec.delivery_id) {
|
|
83851
84343
|
const originalTs = dedupStore.check(agent, rec.delivery_id, now);
|
|
83852
84344
|
if (originalTs !== undefined) {
|
|
@@ -83855,9 +84347,9 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83855
84347
|
return { status: "deduped", ts: originalTs };
|
|
83856
84348
|
}
|
|
83857
84349
|
}
|
|
83858
|
-
const logPath =
|
|
84350
|
+
const logPath = join44(telegramDir, "webhook-events.jsonl");
|
|
83859
84351
|
try {
|
|
83860
|
-
|
|
84352
|
+
mkdirSync35(telegramDir, { recursive: true });
|
|
83861
84353
|
const record = {
|
|
83862
84354
|
ts: now,
|
|
83863
84355
|
source: rec.source,
|
|
@@ -83865,7 +84357,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83865
84357
|
rendered_text: rec.rendered_text,
|
|
83866
84358
|
payload: rec.payload
|
|
83867
84359
|
};
|
|
83868
|
-
|
|
84360
|
+
appendFileSync8(logPath, JSON.stringify(record) + `
|
|
83869
84361
|
`, { mode: 384 });
|
|
83870
84362
|
} catch (err) {
|
|
83871
84363
|
log(`webhook-gateway: agent='${agent}' source='${rec.source}' write failed: ${err.message}
|
|
@@ -83967,7 +84459,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83967
84459
|
|
|
83968
84460
|
// gateway/ipc-server.ts
|
|
83969
84461
|
init_format();
|
|
83970
|
-
import { renameSync as
|
|
84462
|
+
import { renameSync as renameSync14, unlinkSync as unlinkSync18, chmodSync as chmodSync11 } from "fs";
|
|
83971
84463
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
83972
84464
|
var VALID_OPERATOR_KINDS = new Set([
|
|
83973
84465
|
"credentials-expired",
|
|
@@ -84176,7 +84668,7 @@ function createIpcServer(options) {
|
|
|
84176
84668
|
heartbeatTimeoutMs = 30000
|
|
84177
84669
|
} = options;
|
|
84178
84670
|
try {
|
|
84179
|
-
|
|
84671
|
+
renameSync14(socketPath, socketPath + ".bak");
|
|
84180
84672
|
} catch {}
|
|
84181
84673
|
try {
|
|
84182
84674
|
unlinkSync18(socketPath + ".bak");
|
|
@@ -84566,7 +85058,7 @@ function createIpcServer(options) {
|
|
|
84566
85058
|
clientBySocketId.clear();
|
|
84567
85059
|
server.stop(true);
|
|
84568
85060
|
try {
|
|
84569
|
-
|
|
85061
|
+
renameSync14(socketPath, socketPath + ".bak");
|
|
84570
85062
|
} catch {}
|
|
84571
85063
|
}
|
|
84572
85064
|
};
|
|
@@ -88501,27 +88993,27 @@ function skillProposalKeyboard(id) {
|
|
|
88501
88993
|
// ../src/self-improve/skill-proposals.ts
|
|
88502
88994
|
import {
|
|
88503
88995
|
closeSync as closeSync7,
|
|
88504
|
-
existsSync as
|
|
88505
|
-
mkdirSync as
|
|
88996
|
+
existsSync as existsSync40,
|
|
88997
|
+
mkdirSync as mkdirSync36,
|
|
88506
88998
|
openSync as openSync7,
|
|
88507
|
-
readFileSync as
|
|
88999
|
+
readFileSync as readFileSync37,
|
|
88508
89000
|
writeSync as writeSync5
|
|
88509
89001
|
} from "node:fs";
|
|
88510
|
-
import { join as
|
|
89002
|
+
import { join as join45 } from "node:path";
|
|
88511
89003
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
88512
89004
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
88513
89005
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
88514
89006
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
88515
89007
|
var PROPOSAL_SIM_THRESHOLD = 0.5;
|
|
88516
89008
|
function proposalsPath2(stateDir) {
|
|
88517
|
-
return
|
|
89009
|
+
return join45(stateDir, PROPOSALS_FILE2);
|
|
88518
89010
|
}
|
|
88519
89011
|
function rejectedPath2(stateDir) {
|
|
88520
|
-
return
|
|
89012
|
+
return join45(stateDir, REJECTED_FILE2);
|
|
88521
89013
|
}
|
|
88522
89014
|
function ensureDir3(stateDir) {
|
|
88523
|
-
if (!
|
|
88524
|
-
|
|
89015
|
+
if (!existsSync40(stateDir)) {
|
|
89016
|
+
mkdirSync36(stateDir, { recursive: true, mode: 493 });
|
|
88525
89017
|
}
|
|
88526
89018
|
}
|
|
88527
89019
|
function appendLine2(path2, obj) {
|
|
@@ -88534,11 +89026,11 @@ function appendLine2(path2, obj) {
|
|
|
88534
89026
|
}
|
|
88535
89027
|
}
|
|
88536
89028
|
function readLines2(path2, isValid2) {
|
|
88537
|
-
if (!
|
|
89029
|
+
if (!existsSync40(path2))
|
|
88538
89030
|
return [];
|
|
88539
89031
|
let raw;
|
|
88540
89032
|
try {
|
|
88541
|
-
raw =
|
|
89033
|
+
raw = readFileSync37(path2, "utf-8");
|
|
88542
89034
|
} catch {
|
|
88543
89035
|
return [];
|
|
88544
89036
|
}
|
|
@@ -89135,11 +89627,11 @@ function escapeBody2(s) {
|
|
|
89135
89627
|
}
|
|
89136
89628
|
|
|
89137
89629
|
// gateway/pid-file.ts
|
|
89138
|
-
import { writeFileSync as
|
|
89630
|
+
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync19, renameSync as renameSync15 } from "node:fs";
|
|
89139
89631
|
function writePidFile(path2, record) {
|
|
89140
89632
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89141
|
-
|
|
89142
|
-
|
|
89633
|
+
writeFileSync33(tmp, JSON.stringify(record), "utf-8");
|
|
89634
|
+
renameSync15(tmp, path2);
|
|
89143
89635
|
}
|
|
89144
89636
|
function clearPidFile(path2) {
|
|
89145
89637
|
try {
|
|
@@ -89154,10 +89646,10 @@ import {
|
|
|
89154
89646
|
writeFile as writeFileAsync,
|
|
89155
89647
|
readFile as readFileAsync
|
|
89156
89648
|
} from "node:fs/promises";
|
|
89157
|
-
import { readFileSync as
|
|
89649
|
+
import { readFileSync as readFileSync39 } from "node:fs";
|
|
89158
89650
|
function readCurrentBootId() {
|
|
89159
89651
|
try {
|
|
89160
|
-
const stat =
|
|
89652
|
+
const stat = readFileSync39("/proc/1/stat", "utf-8");
|
|
89161
89653
|
const lastParen = stat.lastIndexOf(")");
|
|
89162
89654
|
if (lastParen < 0)
|
|
89163
89655
|
return null;
|
|
@@ -89360,15 +89852,15 @@ function safeCount(fn) {
|
|
|
89360
89852
|
}
|
|
89361
89853
|
|
|
89362
89854
|
// gateway/session-marker.ts
|
|
89363
|
-
import { writeFileSync as
|
|
89855
|
+
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync16, unlinkSync as unlinkSync20 } from "node:fs";
|
|
89364
89856
|
function writeSessionMarker(path2, marker) {
|
|
89365
89857
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89366
|
-
|
|
89367
|
-
|
|
89858
|
+
writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
|
|
89859
|
+
renameSync16(tmp, path2);
|
|
89368
89860
|
}
|
|
89369
89861
|
function readSessionMarker(path2) {
|
|
89370
89862
|
try {
|
|
89371
|
-
const raw =
|
|
89863
|
+
const raw = readFileSync40(path2, "utf-8");
|
|
89372
89864
|
const parsed = JSON.parse(raw);
|
|
89373
89865
|
if (typeof parsed.pid === "number" && typeof parsed.startedAtMs === "number" && Number.isFinite(parsed.pid) && Number.isFinite(parsed.startedAtMs)) {
|
|
89374
89866
|
return { pid: parsed.pid, startedAtMs: parsed.startedAtMs };
|
|
@@ -89390,16 +89882,16 @@ function shouldFireRestartBanner(input) {
|
|
|
89390
89882
|
}
|
|
89391
89883
|
|
|
89392
89884
|
// gateway/clean-shutdown-marker.ts
|
|
89393
|
-
import { writeFileSync as
|
|
89885
|
+
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync17, unlinkSync as unlinkSync21 } from "node:fs";
|
|
89394
89886
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
89395
89887
|
function writeCleanShutdownMarker(path2, marker) {
|
|
89396
89888
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89397
|
-
|
|
89398
|
-
|
|
89889
|
+
writeFileSync35(tmp, JSON.stringify(marker), "utf-8");
|
|
89890
|
+
renameSync17(tmp, path2);
|
|
89399
89891
|
}
|
|
89400
89892
|
function readCleanShutdownMarker(path2) {
|
|
89401
89893
|
try {
|
|
89402
|
-
const raw =
|
|
89894
|
+
const raw = readFileSync41(path2, "utf-8");
|
|
89403
89895
|
const parsed = JSON.parse(raw);
|
|
89404
89896
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.signal === "string" && parsed.signal.length > 0) {
|
|
89405
89897
|
const out = { ts: parsed.ts, signal: parsed.signal };
|
|
@@ -89771,16 +90263,16 @@ function classifyAdminGate(text4, myAgentName) {
|
|
|
89771
90263
|
|
|
89772
90264
|
// subagent-watcher.ts
|
|
89773
90265
|
import {
|
|
89774
|
-
existsSync as
|
|
90266
|
+
existsSync as existsSync41,
|
|
89775
90267
|
openSync as openSync8,
|
|
89776
90268
|
readSync as readSync2,
|
|
89777
90269
|
statSync as statSync13,
|
|
89778
90270
|
closeSync as closeSync8,
|
|
89779
90271
|
watch,
|
|
89780
90272
|
readdirSync as readdirSync8,
|
|
89781
|
-
readFileSync as
|
|
90273
|
+
readFileSync as readFileSync42
|
|
89782
90274
|
} from "fs";
|
|
89783
|
-
import { join as
|
|
90275
|
+
import { join as join46 } from "path";
|
|
89784
90276
|
|
|
89785
90277
|
// session-tail.ts
|
|
89786
90278
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -90130,7 +90622,7 @@ function backfillJsonlAgentId(db3, jsonlPath, agentId, log) {
|
|
|
90130
90622
|
const metaPath = jsonlPath.replace(/\.jsonl$/, ".meta.json");
|
|
90131
90623
|
let meta;
|
|
90132
90624
|
try {
|
|
90133
|
-
const raw =
|
|
90625
|
+
const raw = readFileSync42(metaPath, "utf8");
|
|
90134
90626
|
meta = JSON.parse(raw);
|
|
90135
90627
|
} catch {
|
|
90136
90628
|
log?.(`subagent-watcher: backfill skip ${agentId} \u2014 meta.json not readable at ${metaPath}`);
|
|
@@ -90585,7 +91077,7 @@ function startSubagentWatcher(config) {
|
|
|
90585
91077
|
clearTimeout(ref.ref);
|
|
90586
91078
|
});
|
|
90587
91079
|
const fs2 = config.fs ?? {
|
|
90588
|
-
existsSync:
|
|
91080
|
+
existsSync: existsSync41,
|
|
90589
91081
|
readdirSync: readdirSync8,
|
|
90590
91082
|
statSync: statSync13,
|
|
90591
91083
|
openSync: openSync8,
|
|
@@ -91103,8 +91595,8 @@ function startSubagentWatcher(config) {
|
|
|
91103
91595
|
if (stopped)
|
|
91104
91596
|
return;
|
|
91105
91597
|
pruneVanishedDirWatchers();
|
|
91106
|
-
const claudeHome =
|
|
91107
|
-
const projectsRoot =
|
|
91598
|
+
const claudeHome = join46(agentDir, ".claude");
|
|
91599
|
+
const projectsRoot = join46(claudeHome, "projects");
|
|
91108
91600
|
if (!fs2.existsSync(projectsRoot))
|
|
91109
91601
|
return;
|
|
91110
91602
|
let projectDirs;
|
|
@@ -91138,7 +91630,7 @@ function startSubagentWatcher(config) {
|
|
|
91138
91630
|
continue;
|
|
91139
91631
|
}
|
|
91140
91632
|
warnedForeignSlugs.delete(pDir);
|
|
91141
|
-
const projectPath =
|
|
91633
|
+
const projectPath = join46(projectsRoot, pDir);
|
|
91142
91634
|
let sessionDirs;
|
|
91143
91635
|
try {
|
|
91144
91636
|
sessionDirs = fs2.readdirSync(projectPath);
|
|
@@ -91148,7 +91640,7 @@ function startSubagentWatcher(config) {
|
|
|
91148
91640
|
for (const sDir of sessionDirs) {
|
|
91149
91641
|
if (sDir.endsWith(".jsonl"))
|
|
91150
91642
|
continue;
|
|
91151
|
-
const subagentsPath =
|
|
91643
|
+
const subagentsPath = join46(projectPath, sDir, "subagents");
|
|
91152
91644
|
if (!fs2.existsSync(subagentsPath))
|
|
91153
91645
|
continue;
|
|
91154
91646
|
const watchAndScan = (dirPath) => {
|
|
@@ -91157,7 +91649,7 @@ function startSubagentWatcher(config) {
|
|
|
91157
91649
|
const w = fs2.watch(dirPath, (_event, filename) => {
|
|
91158
91650
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
91159
91651
|
return;
|
|
91160
|
-
const filePath =
|
|
91652
|
+
const filePath = join46(dirPath, filename.toString());
|
|
91161
91653
|
if (!knownFiles.has(filePath)) {
|
|
91162
91654
|
scanSubagentsDir(dirPath);
|
|
91163
91655
|
}
|
|
@@ -91171,7 +91663,7 @@ function startSubagentWatcher(config) {
|
|
|
91171
91663
|
scanSubagentsDir(dirPath);
|
|
91172
91664
|
};
|
|
91173
91665
|
watchAndScan(subagentsPath);
|
|
91174
|
-
const workflowsPath =
|
|
91666
|
+
const workflowsPath = join46(subagentsPath, "workflows");
|
|
91175
91667
|
if (fs2.existsSync(workflowsPath)) {
|
|
91176
91668
|
let wfDirs;
|
|
91177
91669
|
try {
|
|
@@ -91181,7 +91673,7 @@ function startSubagentWatcher(config) {
|
|
|
91181
91673
|
}
|
|
91182
91674
|
for (const wfDir of wfDirs) {
|
|
91183
91675
|
try {
|
|
91184
|
-
const wfPath =
|
|
91676
|
+
const wfPath = join46(workflowsPath, wfDir);
|
|
91185
91677
|
if (!fs2.statSync(wfPath).isDirectory())
|
|
91186
91678
|
continue;
|
|
91187
91679
|
watchAndScan(wfPath);
|
|
@@ -91201,7 +91693,7 @@ function startSubagentWatcher(config) {
|
|
|
91201
91693
|
for (const e of entries) {
|
|
91202
91694
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
91203
91695
|
continue;
|
|
91204
|
-
const filePath =
|
|
91696
|
+
const filePath = join46(subagentsPath, e);
|
|
91205
91697
|
if (knownFiles.has(filePath))
|
|
91206
91698
|
continue;
|
|
91207
91699
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -91329,37 +91821,37 @@ function startSubagentWatcher(config) {
|
|
|
91329
91821
|
|
|
91330
91822
|
// ../src/worktree/registry.ts
|
|
91331
91823
|
import {
|
|
91332
|
-
mkdirSync as
|
|
91333
|
-
writeFileSync as
|
|
91334
|
-
readFileSync as
|
|
91824
|
+
mkdirSync as mkdirSync37,
|
|
91825
|
+
writeFileSync as writeFileSync36,
|
|
91826
|
+
readFileSync as readFileSync43,
|
|
91335
91827
|
readdirSync as readdirSync9,
|
|
91336
91828
|
unlinkSync as unlinkSync22,
|
|
91337
|
-
existsSync as
|
|
91338
|
-
renameSync as
|
|
91829
|
+
existsSync as existsSync42,
|
|
91830
|
+
renameSync as renameSync18
|
|
91339
91831
|
} from "node:fs";
|
|
91340
|
-
import { join as
|
|
91832
|
+
import { join as join47, resolve as resolve10 } from "node:path";
|
|
91341
91833
|
import { homedir as homedir16 } from "node:os";
|
|
91342
91834
|
function registryDir() {
|
|
91343
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
91835
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join47(homedir16(), ".switchroom", "worktrees"));
|
|
91344
91836
|
}
|
|
91345
91837
|
function recordPath(id) {
|
|
91346
|
-
return
|
|
91838
|
+
return join47(registryDir(), `${id}.json`);
|
|
91347
91839
|
}
|
|
91348
91840
|
function ensureDir4() {
|
|
91349
|
-
|
|
91841
|
+
mkdirSync37(registryDir(), { recursive: true });
|
|
91350
91842
|
}
|
|
91351
91843
|
function writeRecord(record) {
|
|
91352
91844
|
ensureDir4();
|
|
91353
91845
|
const target = recordPath(record.id);
|
|
91354
91846
|
const tmp = `${target}.tmp${process.pid}`;
|
|
91355
|
-
|
|
91847
|
+
writeFileSync36(tmp, JSON.stringify(record, null, 2) + `
|
|
91356
91848
|
`, { mode: 384 });
|
|
91357
|
-
|
|
91849
|
+
renameSync18(tmp, target);
|
|
91358
91850
|
}
|
|
91359
91851
|
function readRecord(id) {
|
|
91360
91852
|
const path2 = recordPath(id);
|
|
91361
91853
|
try {
|
|
91362
|
-
const raw =
|
|
91854
|
+
const raw = readFileSync43(path2, "utf8");
|
|
91363
91855
|
return JSON.parse(raw);
|
|
91364
91856
|
} catch {
|
|
91365
91857
|
return null;
|
|
@@ -91389,7 +91881,7 @@ function touchHeartbeat(id, onAfterRead) {
|
|
|
91389
91881
|
writeRecord({ ...rec, heartbeatAt: new Date().toISOString() });
|
|
91390
91882
|
}
|
|
91391
91883
|
function recordExists(id) {
|
|
91392
|
-
return
|
|
91884
|
+
return existsSync42(recordPath(id));
|
|
91393
91885
|
}
|
|
91394
91886
|
|
|
91395
91887
|
// worktree-watch-cwds.ts
|
|
@@ -91521,15 +92013,15 @@ function determineRestartReason(opts) {
|
|
|
91521
92013
|
init_boot_card();
|
|
91522
92014
|
|
|
91523
92015
|
// gateway/update-announce.ts
|
|
91524
|
-
import { existsSync as
|
|
91525
|
-
import { join as
|
|
92016
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync41, openSync as openSync9, closeSync as closeSync9, readFileSync as readFileSync50 } from "node:fs";
|
|
92017
|
+
import { join as join52 } from "node:path";
|
|
91526
92018
|
import { homedir as homedir18 } from "node:os";
|
|
91527
92019
|
|
|
91528
92020
|
// ../src/host-control/audit-reader.ts
|
|
91529
92021
|
import { homedir as homedir17 } from "node:os";
|
|
91530
|
-
import { join as
|
|
92022
|
+
import { join as join51 } from "node:path";
|
|
91531
92023
|
function defaultAuditLogPath(home2 = homedir17()) {
|
|
91532
|
-
return
|
|
92024
|
+
return join51(home2, ".switchroom", "host-control-audit.log");
|
|
91533
92025
|
}
|
|
91534
92026
|
function parseAuditLine(line) {
|
|
91535
92027
|
const trimmed = line.trim();
|
|
@@ -91652,8 +92144,8 @@ function readAndFilter(raw, filters, limit) {
|
|
|
91652
92144
|
var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
|
|
91653
92145
|
function readLastTerminalUpdateAudit(opts = {}) {
|
|
91654
92146
|
const path2 = opts.auditLogPath ?? defaultAuditLogPath();
|
|
91655
|
-
const exists = opts.exists ??
|
|
91656
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
92147
|
+
const exists = opts.exists ?? existsSync47;
|
|
92148
|
+
const readFile = opts.readFile ?? ((p) => readFileSync50(p, "utf-8"));
|
|
91657
92149
|
if (!exists(path2))
|
|
91658
92150
|
return null;
|
|
91659
92151
|
let raw;
|
|
@@ -91714,15 +92206,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
91714
92206
|
`);
|
|
91715
92207
|
}
|
|
91716
92208
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
91717
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
91718
|
-
const dir =
|
|
92209
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join52(homedir18(), ".switchroom");
|
|
92210
|
+
const dir = join52(stateDir, "update-announced");
|
|
91719
92211
|
try {
|
|
91720
|
-
|
|
92212
|
+
mkdirSync41(dir, { recursive: true });
|
|
91721
92213
|
} catch {
|
|
91722
92214
|
return false;
|
|
91723
92215
|
}
|
|
91724
92216
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
91725
|
-
const path2 =
|
|
92217
|
+
const path2 = join52(dir, safeId);
|
|
91726
92218
|
try {
|
|
91727
92219
|
const fd = openSync9(path2, "wx");
|
|
91728
92220
|
closeSync9(fd);
|
|
@@ -91742,7 +92234,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
|
|
|
91742
92234
|
|
|
91743
92235
|
// issues-card.ts
|
|
91744
92236
|
init_card_format();
|
|
91745
|
-
import { readFileSync as
|
|
92237
|
+
import { readFileSync as readFileSync51, writeFileSync as writeFileSync41 } from "node:fs";
|
|
91746
92238
|
var SEVERITY_EMOJI = {
|
|
91747
92239
|
info: "\u2139\ufe0f",
|
|
91748
92240
|
warn: "\u26a0\ufe0f",
|
|
@@ -91834,7 +92326,7 @@ function extractRetryAfterSecs2(err) {
|
|
|
91834
92326
|
var COOLDOWN_JITTER_MS2 = 500;
|
|
91835
92327
|
function readPersistedMessageId(path2, log) {
|
|
91836
92328
|
try {
|
|
91837
|
-
const raw =
|
|
92329
|
+
const raw = readFileSync51(path2, "utf8");
|
|
91838
92330
|
const parsed = JSON.parse(raw);
|
|
91839
92331
|
const v = parsed.messageId;
|
|
91840
92332
|
if (typeof v === "number" && Number.isInteger(v) && v > 0)
|
|
@@ -91850,7 +92342,7 @@ function readPersistedMessageId(path2, log) {
|
|
|
91850
92342
|
}
|
|
91851
92343
|
function writePersistedMessageId(path2, messageId, log) {
|
|
91852
92344
|
try {
|
|
91853
|
-
|
|
92345
|
+
writeFileSync41(path2, JSON.stringify({ messageId }) + `
|
|
91854
92346
|
`, { mode: 384 });
|
|
91855
92347
|
} catch (err) {
|
|
91856
92348
|
log(`issues-card: persist write failed (${err.message})`);
|
|
@@ -91943,24 +92435,24 @@ function createIssuesCardHandle(opts) {
|
|
|
91943
92435
|
}
|
|
91944
92436
|
|
|
91945
92437
|
// issues-watcher.ts
|
|
91946
|
-
import { existsSync as
|
|
91947
|
-
import { join as
|
|
92438
|
+
import { existsSync as existsSync49, statSync as statSync16 } from "node:fs";
|
|
92439
|
+
import { join as join54 } from "node:path";
|
|
91948
92440
|
|
|
91949
92441
|
// ../src/issues/store.ts
|
|
91950
92442
|
import {
|
|
91951
92443
|
closeSync as closeSync10,
|
|
91952
|
-
existsSync as
|
|
91953
|
-
mkdirSync as
|
|
92444
|
+
existsSync as existsSync48,
|
|
92445
|
+
mkdirSync as mkdirSync42,
|
|
91954
92446
|
openSync as openSync10,
|
|
91955
92447
|
readdirSync as readdirSync11,
|
|
91956
|
-
readFileSync as
|
|
91957
|
-
renameSync as
|
|
92448
|
+
readFileSync as readFileSync52,
|
|
92449
|
+
renameSync as renameSync21,
|
|
91958
92450
|
statSync as statSync15,
|
|
91959
92451
|
unlinkSync as unlinkSync23,
|
|
91960
|
-
writeFileSync as
|
|
92452
|
+
writeFileSync as writeFileSync42,
|
|
91961
92453
|
writeSync as writeSync6
|
|
91962
92454
|
} from "node:fs";
|
|
91963
|
-
import { join as
|
|
92455
|
+
import { join as join53 } from "node:path";
|
|
91964
92456
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
91965
92457
|
import { execSync } from "node:child_process";
|
|
91966
92458
|
|
|
@@ -91979,12 +92471,12 @@ init_redact();
|
|
|
91979
92471
|
var ISSUES_FILE = "issues.jsonl";
|
|
91980
92472
|
var ISSUES_LOCK = "issues.lock";
|
|
91981
92473
|
function readAll(stateDir) {
|
|
91982
|
-
const path2 =
|
|
91983
|
-
if (!
|
|
92474
|
+
const path2 = join53(stateDir, ISSUES_FILE);
|
|
92475
|
+
if (!existsSync48(path2))
|
|
91984
92476
|
return [];
|
|
91985
92477
|
let raw;
|
|
91986
92478
|
try {
|
|
91987
|
-
raw =
|
|
92479
|
+
raw = readFileSync52(path2, "utf-8");
|
|
91988
92480
|
} catch {
|
|
91989
92481
|
return [];
|
|
91990
92482
|
}
|
|
@@ -92016,7 +92508,7 @@ function list2(stateDir, opts = {}) {
|
|
|
92016
92508
|
});
|
|
92017
92509
|
}
|
|
92018
92510
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
92019
|
-
if (!
|
|
92511
|
+
if (!existsSync48(join53(stateDir, ISSUES_FILE)))
|
|
92020
92512
|
return 0;
|
|
92021
92513
|
return withLock(stateDir, () => {
|
|
92022
92514
|
const all2 = readAll(stateDir);
|
|
@@ -92034,14 +92526,14 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
92034
92526
|
});
|
|
92035
92527
|
}
|
|
92036
92528
|
function writeAll(stateDir, events) {
|
|
92037
|
-
const path2 =
|
|
92529
|
+
const path2 = join53(stateDir, ISSUES_FILE);
|
|
92038
92530
|
sweepOrphanTmpFiles(stateDir);
|
|
92039
92531
|
const tmp = `${path2}.tmp-${process.pid}-${randomBytes8(4).toString("hex")}`;
|
|
92040
92532
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
92041
92533
|
`) + `
|
|
92042
92534
|
`;
|
|
92043
|
-
|
|
92044
|
-
|
|
92535
|
+
writeFileSync42(tmp, body, "utf-8");
|
|
92536
|
+
renameSync21(tmp, path2);
|
|
92045
92537
|
}
|
|
92046
92538
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
92047
92539
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -92056,7 +92548,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
92056
92548
|
for (const entry of entries) {
|
|
92057
92549
|
if (!entry.startsWith(TMP_PREFIX))
|
|
92058
92550
|
continue;
|
|
92059
|
-
const tmpPath2 =
|
|
92551
|
+
const tmpPath2 = join53(stateDir, entry);
|
|
92060
92552
|
try {
|
|
92061
92553
|
const stat = statSync15(tmpPath2);
|
|
92062
92554
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -92068,7 +92560,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
92068
92560
|
var LOCK_RETRY_MS = 25;
|
|
92069
92561
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
92070
92562
|
function withLock(stateDir, fn) {
|
|
92071
|
-
const lockPath =
|
|
92563
|
+
const lockPath = join53(stateDir, ISSUES_LOCK);
|
|
92072
92564
|
const startedAt = Date.now();
|
|
92073
92565
|
let fd = null;
|
|
92074
92566
|
while (fd === null) {
|
|
@@ -92103,7 +92595,7 @@ function withLock(stateDir, fn) {
|
|
|
92103
92595
|
function tryStealStaleLock(lockPath) {
|
|
92104
92596
|
let pidStr;
|
|
92105
92597
|
try {
|
|
92106
|
-
pidStr =
|
|
92598
|
+
pidStr = readFileSync52(lockPath, "utf-8").trim();
|
|
92107
92599
|
} catch {
|
|
92108
92600
|
return true;
|
|
92109
92601
|
}
|
|
@@ -92153,7 +92645,7 @@ function isIssueEvent(v) {
|
|
|
92153
92645
|
// issues-watcher.ts
|
|
92154
92646
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
92155
92647
|
function startIssuesWatcher(opts) {
|
|
92156
|
-
const path2 =
|
|
92648
|
+
const path2 = join54(opts.stateDir, ISSUES_FILE);
|
|
92157
92649
|
const log = opts.log ?? (() => {});
|
|
92158
92650
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
92159
92651
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -92201,7 +92693,7 @@ function startIssuesWatcher(opts) {
|
|
|
92201
92693
|
};
|
|
92202
92694
|
}
|
|
92203
92695
|
function defaultSignatureProvider(path2) {
|
|
92204
|
-
if (!
|
|
92696
|
+
if (!existsSync49(path2))
|
|
92205
92697
|
return null;
|
|
92206
92698
|
try {
|
|
92207
92699
|
const stat = statSync16(path2);
|
|
@@ -92912,8 +93404,8 @@ function readBashCommand(inputPreview) {
|
|
|
92912
93404
|
}
|
|
92913
93405
|
|
|
92914
93406
|
// gateway/scoped-grant-store.ts
|
|
92915
|
-
import { readFileSync as
|
|
92916
|
-
import { join as
|
|
93407
|
+
import { readFileSync as readFileSync53, writeFileSync as writeFileSync43 } from "node:fs";
|
|
93408
|
+
import { join as join55 } from "node:path";
|
|
92917
93409
|
|
|
92918
93410
|
// scoped-approval.ts
|
|
92919
93411
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -92955,11 +93447,11 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
92955
93447
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
92956
93448
|
}
|
|
92957
93449
|
function createScopedGrantStore(stateDir, env = process.env) {
|
|
92958
|
-
const filePath =
|
|
93450
|
+
const filePath = join55(stateDir, "scoped-grants.json");
|
|
92959
93451
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
92960
93452
|
function read() {
|
|
92961
93453
|
try {
|
|
92962
|
-
const raw =
|
|
93454
|
+
const raw = readFileSync53(filePath, "utf-8");
|
|
92963
93455
|
const parsed = JSON.parse(raw);
|
|
92964
93456
|
return Array.isArray(parsed) ? parsed : [];
|
|
92965
93457
|
} catch {
|
|
@@ -92977,7 +93469,7 @@ function createScopedGrantStore(stateDir, env = process.env) {
|
|
|
92977
93469
|
if (!enabled7)
|
|
92978
93470
|
return;
|
|
92979
93471
|
try {
|
|
92980
|
-
|
|
93472
|
+
writeFileSync43(filePath, JSON.stringify(serializeScopedGrants(store2)), {
|
|
92981
93473
|
encoding: "utf-8",
|
|
92982
93474
|
mode: 384
|
|
92983
93475
|
});
|
|
@@ -93328,8 +93820,8 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
93328
93820
|
|
|
93329
93821
|
// credits-watch.ts
|
|
93330
93822
|
init_card_format();
|
|
93331
|
-
import { readFileSync as
|
|
93332
|
-
import { join as
|
|
93823
|
+
import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync50, mkdirSync as mkdirSync43 } from "fs";
|
|
93824
|
+
import { join as join56 } from "path";
|
|
93333
93825
|
var STATE_FILE = "credits-watch.json";
|
|
93334
93826
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
93335
93827
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -93351,12 +93843,12 @@ function emptyCreditState() {
|
|
|
93351
93843
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
93352
93844
|
}
|
|
93353
93845
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
93354
|
-
const path2 =
|
|
93355
|
-
if (!
|
|
93846
|
+
const path2 = join56(claudeConfigDir, ".claude.json");
|
|
93847
|
+
if (!existsSync50(path2))
|
|
93356
93848
|
return null;
|
|
93357
93849
|
let raw;
|
|
93358
93850
|
try {
|
|
93359
|
-
raw =
|
|
93851
|
+
raw = readFileSync54(path2, "utf-8");
|
|
93360
93852
|
} catch {
|
|
93361
93853
|
return null;
|
|
93362
93854
|
}
|
|
@@ -93434,11 +93926,11 @@ function humanizeReason(reason) {
|
|
|
93434
93926
|
}
|
|
93435
93927
|
}
|
|
93436
93928
|
function loadCreditState(stateDir) {
|
|
93437
|
-
const path2 =
|
|
93438
|
-
if (!
|
|
93929
|
+
const path2 = join56(stateDir, STATE_FILE);
|
|
93930
|
+
if (!existsSync50(path2))
|
|
93439
93931
|
return emptyCreditState();
|
|
93440
93932
|
try {
|
|
93441
|
-
const raw =
|
|
93933
|
+
const raw = readFileSync54(path2, "utf-8");
|
|
93442
93934
|
const parsed = JSON.parse(raw);
|
|
93443
93935
|
if (parsed && typeof parsed === "object" && (parsed.lastNotifiedReason === null || typeof parsed.lastNotifiedReason === "string") && typeof parsed.lastNotifiedAt === "number" && Number.isFinite(parsed.lastNotifiedAt)) {
|
|
93444
93936
|
return {
|
|
@@ -93450,17 +93942,17 @@ function loadCreditState(stateDir) {
|
|
|
93450
93942
|
return emptyCreditState();
|
|
93451
93943
|
}
|
|
93452
93944
|
function saveCreditState(stateDir, state7) {
|
|
93453
|
-
|
|
93454
|
-
const path2 =
|
|
93455
|
-
|
|
93945
|
+
mkdirSync43(stateDir, { recursive: true });
|
|
93946
|
+
const path2 = join56(stateDir, STATE_FILE);
|
|
93947
|
+
writeFileSync44(path2, JSON.stringify(state7, null, 2) + `
|
|
93456
93948
|
`, { mode: 384 });
|
|
93457
93949
|
}
|
|
93458
93950
|
|
|
93459
93951
|
// quota-watch.ts
|
|
93460
93952
|
init_auth_snapshot_format();
|
|
93461
93953
|
init_card_format();
|
|
93462
|
-
import { readFileSync as
|
|
93463
|
-
import { join as
|
|
93954
|
+
import { readFileSync as readFileSync55, writeFileSync as writeFileSync45, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
|
|
93955
|
+
import { join as join57 } from "path";
|
|
93464
93956
|
var STATE_FILE2 = "quota-watch.json";
|
|
93465
93957
|
function emptyQuotaWatchState() {
|
|
93466
93958
|
return {};
|
|
@@ -93698,11 +94190,11 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
93698
94190
|
`);
|
|
93699
94191
|
}
|
|
93700
94192
|
function loadQuotaWatchState(stateDir) {
|
|
93701
|
-
const path2 =
|
|
93702
|
-
if (!
|
|
94193
|
+
const path2 = join57(stateDir, STATE_FILE2);
|
|
94194
|
+
if (!existsSync51(path2))
|
|
93703
94195
|
return emptyQuotaWatchState();
|
|
93704
94196
|
try {
|
|
93705
|
-
const raw =
|
|
94197
|
+
const raw = readFileSync55(path2, "utf-8");
|
|
93706
94198
|
const parsed = JSON.parse(raw);
|
|
93707
94199
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
93708
94200
|
return emptyQuotaWatchState();
|
|
@@ -93719,9 +94211,9 @@ function loadQuotaWatchState(stateDir) {
|
|
|
93719
94211
|
}
|
|
93720
94212
|
}
|
|
93721
94213
|
function saveQuotaWatchState(stateDir, state7) {
|
|
93722
|
-
|
|
93723
|
-
const path2 =
|
|
93724
|
-
|
|
94214
|
+
mkdirSync44(stateDir, { recursive: true });
|
|
94215
|
+
const path2 = join57(stateDir, STATE_FILE2);
|
|
94216
|
+
writeFileSync45(path2, JSON.stringify(state7, null, 2) + `
|
|
93725
94217
|
`, { mode: 384 });
|
|
93726
94218
|
}
|
|
93727
94219
|
function patchQuotaWatchState(current, accountLabel, accountState) {
|
|
@@ -93769,27 +94261,27 @@ init_auth_snapshot_format2();
|
|
|
93769
94261
|
// gateway/turn-active-marker.ts
|
|
93770
94262
|
import {
|
|
93771
94263
|
closeSync as closeSync11,
|
|
93772
|
-
existsSync as
|
|
93773
|
-
mkdirSync as
|
|
94264
|
+
existsSync as existsSync52,
|
|
94265
|
+
mkdirSync as mkdirSync45,
|
|
93774
94266
|
openSync as openSync11,
|
|
93775
|
-
readFileSync as
|
|
94267
|
+
readFileSync as readFileSync56,
|
|
93776
94268
|
statSync as statSync17,
|
|
93777
94269
|
unlinkSync as unlinkSync24,
|
|
93778
94270
|
utimesSync as utimesSync2,
|
|
93779
|
-
writeFileSync as
|
|
94271
|
+
writeFileSync as writeFileSync46
|
|
93780
94272
|
} from "node:fs";
|
|
93781
|
-
import { join as
|
|
94273
|
+
import { join as join58 } from "node:path";
|
|
93782
94274
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
93783
94275
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
93784
94276
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
93785
94277
|
function removeTurnActiveMarker2(stateDir) {
|
|
93786
94278
|
try {
|
|
93787
|
-
unlinkSync24(
|
|
94279
|
+
unlinkSync24(join58(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
93788
94280
|
} catch {}
|
|
93789
94281
|
}
|
|
93790
94282
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
93791
|
-
const path2 =
|
|
93792
|
-
if (!
|
|
94283
|
+
const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
94284
|
+
if (!existsSync52(path2))
|
|
93793
94285
|
return false;
|
|
93794
94286
|
const now = opts.now ?? Date.now();
|
|
93795
94287
|
try {
|
|
@@ -93801,7 +94293,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
93801
94293
|
return false;
|
|
93802
94294
|
let payload = null;
|
|
93803
94295
|
try {
|
|
93804
|
-
payload =
|
|
94296
|
+
payload = readFileSync56(path2, "utf8");
|
|
93805
94297
|
} catch {}
|
|
93806
94298
|
unlinkSync24(path2);
|
|
93807
94299
|
if (opts.onRemove) {
|
|
@@ -93819,7 +94311,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
93819
94311
|
}
|
|
93820
94312
|
}
|
|
93821
94313
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
93822
|
-
const path2 =
|
|
94314
|
+
const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
93823
94315
|
try {
|
|
93824
94316
|
const st = statSync17(path2);
|
|
93825
94317
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -93832,19 +94324,19 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
93832
94324
|
}
|
|
93833
94325
|
|
|
93834
94326
|
// gateway/gateway-heartbeat.ts
|
|
93835
|
-
import { mkdirSync as
|
|
93836
|
-
import { join as
|
|
94327
|
+
import { mkdirSync as mkdirSync46, utimesSync as utimesSync3, writeFileSync as writeFileSync47 } from "node:fs";
|
|
94328
|
+
import { join as join59 } from "node:path";
|
|
93837
94329
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
93838
94330
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
93839
94331
|
function touchGatewayHeartbeat(stateDir) {
|
|
93840
|
-
const path2 =
|
|
94332
|
+
const path2 = join59(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
93841
94333
|
const now = new Date;
|
|
93842
94334
|
try {
|
|
93843
94335
|
utimesSync3(path2, now, now);
|
|
93844
94336
|
} catch {
|
|
93845
94337
|
try {
|
|
93846
|
-
|
|
93847
|
-
|
|
94338
|
+
mkdirSync46(stateDir, { recursive: true });
|
|
94339
|
+
writeFileSync47(path2, `${Date.now()}
|
|
93848
94340
|
`, { mode: 384 });
|
|
93849
94341
|
} catch {}
|
|
93850
94342
|
}
|
|
@@ -93887,14 +94379,32 @@ async function sweepOutbox(deps) {
|
|
|
93887
94379
|
textAlreadyDelivered: resolved != null && deps.textAlreadyDelivered(resolved.chatId, resolved.threadId, record2.text),
|
|
93888
94380
|
routable: resolved != null,
|
|
93889
94381
|
routePrefix,
|
|
93890
|
-
quietMs: deps.quietMs ?? OUTBOX_QUIET_MS
|
|
94382
|
+
quietMs: deps.quietMs ?? OUTBOX_QUIET_MS,
|
|
94383
|
+
shownLedgerHit: isShownBlock(record2.turnNonce, record2.text, deps.stateDir)
|
|
93891
94384
|
});
|
|
93892
94385
|
if (decision.action !== "send" && decision.action !== "send-delayed") {
|
|
93893
94386
|
summary.skipped++;
|
|
93894
|
-
if (decision.action === "skip-
|
|
94387
|
+
if (decision.action === "skip-ephemeral-shown") {
|
|
94388
|
+
appendDelivered({
|
|
94389
|
+
turnNonce: record2.turnNonce,
|
|
94390
|
+
textSha256: record2.textSha256,
|
|
94391
|
+
ts: now,
|
|
94392
|
+
deliverySource: "sweep",
|
|
94393
|
+
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
94394
|
+
}, deps.stateDir);
|
|
94395
|
+
clearOutboxRecord(record2.turnNonce, deps.stateDir);
|
|
94396
|
+
log(`outbox-sweep: suppressed ephemeral-shown nonce=${record2.turnNonce}
|
|
94397
|
+
`);
|
|
94398
|
+
} else if (decision.action === "skip-journaled") {
|
|
93895
94399
|
clearOutboxRecord(record2.turnNonce, deps.stateDir);
|
|
93896
94400
|
} else if (decision.action === "skip-dedup") {
|
|
93897
|
-
appendDelivered({
|
|
94401
|
+
appendDelivered({
|
|
94402
|
+
turnNonce: record2.turnNonce,
|
|
94403
|
+
textSha256: record2.textSha256,
|
|
94404
|
+
ts: now,
|
|
94405
|
+
deliverySource: "sweep",
|
|
94406
|
+
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
94407
|
+
}, deps.stateDir);
|
|
93898
94408
|
clearOutboxRecord(record2.turnNonce, deps.stateDir);
|
|
93899
94409
|
}
|
|
93900
94410
|
continue;
|
|
@@ -93907,7 +94417,14 @@ async function sweepOutbox(deps) {
|
|
|
93907
94417
|
const resolvedChat = resolved;
|
|
93908
94418
|
try {
|
|
93909
94419
|
const messageId = await deps.send(resolvedChat.chatId, resolvedChat.threadId, decision.text ?? record2.text);
|
|
93910
|
-
appendDelivered({
|
|
94420
|
+
appendDelivered({
|
|
94421
|
+
turnNonce: record2.turnNonce,
|
|
94422
|
+
textSha256: record2.textSha256,
|
|
94423
|
+
tgMessageId: messageId,
|
|
94424
|
+
ts: now,
|
|
94425
|
+
deliverySource: "sweep",
|
|
94426
|
+
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
94427
|
+
}, deps.stateDir);
|
|
93911
94428
|
removeClaimed(record2.turnNonce, deps.stateDir);
|
|
93912
94429
|
summary.delivered++;
|
|
93913
94430
|
log(`outbox-sweep: delivered nonce=${record2.turnNonce} via=${resolvedChat.via} ` + `source=${record2.source} chars=${record2.text.length}${decision.action === "send-delayed" ? " (delayed)" : ""}
|
|
@@ -93966,10 +94483,10 @@ function startOutboxSweep(deps) {
|
|
|
93966
94483
|
}
|
|
93967
94484
|
|
|
93968
94485
|
// ../src/build-info.ts
|
|
93969
|
-
var VERSION = "0.19.
|
|
93970
|
-
var COMMIT_SHA = "
|
|
93971
|
-
var COMMIT_DATE = "2026-07-
|
|
93972
|
-
var LATEST_PR =
|
|
94486
|
+
var VERSION = "0.19.15";
|
|
94487
|
+
var COMMIT_SHA = "20691874";
|
|
94488
|
+
var COMMIT_DATE = "2026-07-24T12:46:35+10:00";
|
|
94489
|
+
var LATEST_PR = 3518;
|
|
93973
94490
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
93974
94491
|
|
|
93975
94492
|
// gateway/boot-version.ts
|
|
@@ -94047,11 +94564,11 @@ init_peercred();
|
|
|
94047
94564
|
import * as net5 from "node:net";
|
|
94048
94565
|
import * as fs2 from "node:fs";
|
|
94049
94566
|
import { homedir as homedir19 } from "node:os";
|
|
94050
|
-
import { join as
|
|
94567
|
+
import { join as join60 } from "node:path";
|
|
94051
94568
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
94052
94569
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
94053
|
-
var LEGACY_SOCKET_PATH2 =
|
|
94054
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
94570
|
+
var LEGACY_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "vault-broker.sock");
|
|
94571
|
+
var OPERATOR_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "broker-operator", "sock");
|
|
94055
94572
|
function defaultBrokerSocketPath2() {
|
|
94056
94573
|
if (fs2.existsSync(OPERATOR_SOCKET_PATH2))
|
|
94057
94574
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -94933,8 +95450,8 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
94933
95450
|
}
|
|
94934
95451
|
|
|
94935
95452
|
// registry/turns-schema.ts
|
|
94936
|
-
import { chmodSync as chmodSync12, mkdirSync as
|
|
94937
|
-
import { join as
|
|
95453
|
+
import { chmodSync as chmodSync12, mkdirSync as mkdirSync47 } from "fs";
|
|
95454
|
+
import { join as join61 } from "path";
|
|
94938
95455
|
var DatabaseClass3 = null;
|
|
94939
95456
|
function loadDatabaseClass3() {
|
|
94940
95457
|
if (DatabaseClass3 != null)
|
|
@@ -95006,9 +95523,9 @@ function applySchema(db3) {
|
|
|
95006
95523
|
}
|
|
95007
95524
|
function openTurnsDb(agentDir) {
|
|
95008
95525
|
const Database = loadDatabaseClass3();
|
|
95009
|
-
const dir =
|
|
95010
|
-
|
|
95011
|
-
const path2 =
|
|
95526
|
+
const dir = join61(agentDir, "telegram");
|
|
95527
|
+
mkdirSync47(dir, { recursive: true, mode: 448 });
|
|
95528
|
+
const path2 = join61(dir, "registry.db");
|
|
95012
95529
|
const db3 = new Database(path2, { create: true });
|
|
95013
95530
|
applySchema(db3);
|
|
95014
95531
|
try {
|
|
@@ -95352,7 +95869,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
95352
95869
|
}
|
|
95353
95870
|
|
|
95354
95871
|
// gateway/bridge-dead-watchdog.ts
|
|
95355
|
-
import { readFileSync as
|
|
95872
|
+
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync22, unlinkSync as unlinkSync25 } from "node:fs";
|
|
95356
95873
|
|
|
95357
95874
|
// gateway/cron-session.ts
|
|
95358
95875
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -95385,7 +95902,7 @@ function readFreshCrashLogTail(path2, opts = {}) {
|
|
|
95385
95902
|
const nowMs3 = opts.nowMs ?? Date.now();
|
|
95386
95903
|
const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
|
|
95387
95904
|
const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
|
|
95388
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
95905
|
+
const readFile = opts.readFile ?? ((p) => readFileSync58(p, "utf8"));
|
|
95389
95906
|
let raw;
|
|
95390
95907
|
try {
|
|
95391
95908
|
raw = readFile(path2);
|
|
@@ -95406,13 +95923,13 @@ function readFreshCrashLogTail(path2, opts = {}) {
|
|
|
95406
95923
|
}
|
|
95407
95924
|
function writeBridgeDeadEscalationMarker(path2, marker) {
|
|
95408
95925
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
95409
|
-
|
|
95410
|
-
|
|
95926
|
+
writeFileSync48(tmp, JSON.stringify(marker), "utf8");
|
|
95927
|
+
renameSync22(tmp, path2);
|
|
95411
95928
|
}
|
|
95412
95929
|
function consumeBridgeDeadEscalationMarker(path2, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
|
|
95413
95930
|
let marker = null;
|
|
95414
95931
|
try {
|
|
95415
|
-
const parsed = JSON.parse(
|
|
95932
|
+
const parsed = JSON.parse(readFileSync58(path2, "utf8"));
|
|
95416
95933
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
|
|
95417
95934
|
const age = nowMs3 - parsed.ts;
|
|
95418
95935
|
if (age >= 0 && age < maxAgeMs) {
|
|
@@ -95565,7 +96082,7 @@ function createBridgeDeadWatchdog(opts) {
|
|
|
95565
96082
|
}
|
|
95566
96083
|
|
|
95567
96084
|
// gateway/boot-probes.ts
|
|
95568
|
-
import { readFileSync as
|
|
96085
|
+
import { readFileSync as readFileSync59, readdirSync as readdirSync12, existsSync as existsSync54 } from "fs";
|
|
95569
96086
|
init_quota_cache();
|
|
95570
96087
|
init_quota_check();
|
|
95571
96088
|
import { execFile as execFileCb2 } from "child_process";
|
|
@@ -95573,7 +96090,7 @@ import { promisify as promisify2 } from "util";
|
|
|
95573
96090
|
var execFile2 = promisify2(execFileCb2);
|
|
95574
96091
|
var realProcFs2 = {
|
|
95575
96092
|
readdir: (p) => readdirSync12(p),
|
|
95576
|
-
readFile: (p) =>
|
|
96093
|
+
readFile: (p) => readFileSync59(p, "utf-8")
|
|
95577
96094
|
};
|
|
95578
96095
|
function findAgentProcessInContainer2(fs3 = realProcFs2) {
|
|
95579
96096
|
let entries;
|
|
@@ -95823,7 +96340,7 @@ if (isGatewayMain) {
|
|
|
95823
96340
|
shutdownAnalytics();
|
|
95824
96341
|
});
|
|
95825
96342
|
}
|
|
95826
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
96343
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join62(homedir20(), ".claude", "channels", "telegram");
|
|
95827
96344
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
95828
96345
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
95829
96346
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -95862,7 +96379,7 @@ function alwaysAllowDrainDeps() {
|
|
|
95862
96379
|
return {
|
|
95863
96380
|
readConfigText: () => {
|
|
95864
96381
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
95865
|
-
return
|
|
96382
|
+
return readFileSync60(cfgPath, "utf8");
|
|
95866
96383
|
},
|
|
95867
96384
|
resolveAllowList: (_configText, agentName3) => {
|
|
95868
96385
|
const cfg = loadConfig2();
|
|
@@ -95923,11 +96440,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
95923
96440
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
95924
96441
|
timer3.unref?.();
|
|
95925
96442
|
}
|
|
95926
|
-
var ACCESS_FILE =
|
|
95927
|
-
var APPROVED_DIR =
|
|
95928
|
-
var ENV_FILE =
|
|
95929
|
-
var INBOX_DIR =
|
|
95930
|
-
var PEOPLE_FILE =
|
|
96443
|
+
var ACCESS_FILE = join62(STATE_DIR, "access.json");
|
|
96444
|
+
var APPROVED_DIR = join62(STATE_DIR, "approved");
|
|
96445
|
+
var ENV_FILE = join62(STATE_DIR, ".env");
|
|
96446
|
+
var INBOX_DIR = join62(STATE_DIR, "inbox");
|
|
96447
|
+
var PEOPLE_FILE = join62(STATE_DIR, "people.json");
|
|
95931
96448
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
95932
96449
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
95933
96450
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -95992,7 +96509,7 @@ function formatBootVersion() {
|
|
|
95992
96509
|
}
|
|
95993
96510
|
try {
|
|
95994
96511
|
chmodSync14(ENV_FILE, 384);
|
|
95995
|
-
for (const line of
|
|
96512
|
+
for (const line of readFileSync60(ENV_FILE, "utf8").split(`
|
|
95996
96513
|
`)) {
|
|
95997
96514
|
const m = line.match(/^(\w+)=(.*)$/);
|
|
95998
96515
|
if (m && process.env[m[1]] === undefined)
|
|
@@ -96013,7 +96530,7 @@ var bot;
|
|
|
96013
96530
|
var lastGetUpdatesHeartbeatMs = Date.now();
|
|
96014
96531
|
var GRAMMY_VERSION = (() => {
|
|
96015
96532
|
try {
|
|
96016
|
-
const raw =
|
|
96533
|
+
const raw = readFileSync60(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
|
|
96017
96534
|
return JSON.parse(raw).version ?? "unknown";
|
|
96018
96535
|
} catch {
|
|
96019
96536
|
return "unknown";
|
|
@@ -96076,7 +96593,7 @@ function assertSendable(f) {
|
|
|
96076
96593
|
} catch {
|
|
96077
96594
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
96078
96595
|
}
|
|
96079
|
-
const inbox =
|
|
96596
|
+
const inbox = join62(stateReal, "inbox");
|
|
96080
96597
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
96081
96598
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
96082
96599
|
}
|
|
@@ -96095,7 +96612,7 @@ function assertSendable(f) {
|
|
|
96095
96612
|
}
|
|
96096
96613
|
function readAccessFile() {
|
|
96097
96614
|
try {
|
|
96098
|
-
const raw =
|
|
96615
|
+
const raw = readFileSync60(ACCESS_FILE, "utf8");
|
|
96099
96616
|
const parsed = JSON.parse(raw);
|
|
96100
96617
|
const allowFrom = validateStringArray("allowFrom", parsed.allowFrom ?? []);
|
|
96101
96618
|
const groups = {};
|
|
@@ -96135,7 +96652,7 @@ function readAccessFile() {
|
|
|
96135
96652
|
if (err.code === "ENOENT")
|
|
96136
96653
|
return defaultAccess();
|
|
96137
96654
|
try {
|
|
96138
|
-
|
|
96655
|
+
renameSync23(ACCESS_FILE, `${ACCESS_FILE}.corrupt-${Date.now()}`);
|
|
96139
96656
|
} catch {}
|
|
96140
96657
|
process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
|
|
96141
96658
|
`);
|
|
@@ -96157,7 +96674,7 @@ function loadAccess() {
|
|
|
96157
96674
|
}
|
|
96158
96675
|
function readPeopleFile() {
|
|
96159
96676
|
try {
|
|
96160
|
-
const raw =
|
|
96677
|
+
const raw = readFileSync60(PEOPLE_FILE, "utf8");
|
|
96161
96678
|
const parsed = JSON.parse(raw);
|
|
96162
96679
|
if (!Array.isArray(parsed.entries))
|
|
96163
96680
|
return [];
|
|
@@ -96179,11 +96696,11 @@ function assertAllowedChat(chat_id) {
|
|
|
96179
96696
|
function saveAccess(a) {
|
|
96180
96697
|
if (STATIC)
|
|
96181
96698
|
return;
|
|
96182
|
-
|
|
96699
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
96183
96700
|
const tmp = ACCESS_FILE + ".tmp";
|
|
96184
|
-
|
|
96701
|
+
writeFileSync50(tmp, JSON.stringify(a, null, 2) + `
|
|
96185
96702
|
`, { mode: 384 });
|
|
96186
|
-
|
|
96703
|
+
renameSync23(tmp, ACCESS_FILE);
|
|
96187
96704
|
}
|
|
96188
96705
|
function pruneExpired(a) {
|
|
96189
96706
|
const now = Date.now();
|
|
@@ -96201,7 +96718,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
96201
96718
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
96202
96719
|
try {
|
|
96203
96720
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
96204
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
96721
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join62(STATE_DIR, "history.db")}
|
|
96205
96722
|
`);
|
|
96206
96723
|
} catch (err) {
|
|
96207
96724
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -96220,12 +96737,12 @@ if (isGatewayMain)
|
|
|
96220
96737
|
let markerTurnKey = null;
|
|
96221
96738
|
let markerAgeMs = null;
|
|
96222
96739
|
try {
|
|
96223
|
-
const markerPath =
|
|
96224
|
-
if (
|
|
96740
|
+
const markerPath = join62(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
96741
|
+
if (existsSync56(markerPath)) {
|
|
96225
96742
|
const st = statSync20(markerPath);
|
|
96226
96743
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
96227
96744
|
try {
|
|
96228
|
-
const payload = JSON.parse(
|
|
96745
|
+
const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
|
|
96229
96746
|
if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
|
|
96230
96747
|
markerTurnKey = payload.turnKey;
|
|
96231
96748
|
}
|
|
@@ -96245,10 +96762,10 @@ if (isGatewayMain)
|
|
|
96245
96762
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
96246
96763
|
`);
|
|
96247
96764
|
} else {
|
|
96248
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
96765
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join62(agentDir, "telegram", "registry.db")}
|
|
96249
96766
|
`);
|
|
96250
96767
|
}
|
|
96251
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
96768
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join62(STATE_DIR, "bridge-dead-escalation.json"));
|
|
96252
96769
|
if (bridgeDeadMarker != null) {
|
|
96253
96770
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
96254
96771
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -96261,7 +96778,7 @@ if (isGatewayMain)
|
|
|
96261
96778
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
96262
96779
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
96263
96780
|
if (pending2 != null && selfAgent) {
|
|
96264
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
96781
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
|
|
96265
96782
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
96266
96783
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
96267
96784
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -96374,7 +96891,7 @@ if (isGatewayMain)
|
|
|
96374
96891
|
`);
|
|
96375
96892
|
}
|
|
96376
96893
|
}
|
|
96377
|
-
const pendingEnvPath =
|
|
96894
|
+
const pendingEnvPath = join62(agentDir, ".pending-turn.env");
|
|
96378
96895
|
try {
|
|
96379
96896
|
if (pending2 != null) {
|
|
96380
96897
|
const lines = [
|
|
@@ -96388,13 +96905,13 @@ if (isGatewayMain)
|
|
|
96388
96905
|
pending2.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending2.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
|
|
96389
96906
|
];
|
|
96390
96907
|
const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
|
|
96391
|
-
|
|
96908
|
+
writeFileSync50(pendingEnvTmp, lines.join(`
|
|
96392
96909
|
`) + `
|
|
96393
96910
|
`, { mode: 384 });
|
|
96394
|
-
|
|
96911
|
+
renameSync23(pendingEnvTmp, pendingEnvPath);
|
|
96395
96912
|
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
96396
96913
|
`);
|
|
96397
|
-
} else if (
|
|
96914
|
+
} else if (existsSync56(pendingEnvPath)) {
|
|
96398
96915
|
rmSync6(pendingEnvPath, { force: true });
|
|
96399
96916
|
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
96400
96917
|
`);
|
|
@@ -96502,7 +97019,7 @@ function checkApprovals() {
|
|
|
96502
97019
|
return;
|
|
96503
97020
|
}
|
|
96504
97021
|
for (const senderId of files) {
|
|
96505
|
-
const file =
|
|
97022
|
+
const file = join62(APPROVED_DIR, senderId);
|
|
96506
97023
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync6(file, { force: true }), (err) => {
|
|
96507
97024
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
96508
97025
|
`);
|
|
@@ -96675,12 +97192,12 @@ function noteAgentOutputAt(key, ts) {
|
|
|
96675
97192
|
lastAgentOutputAt.delete(oldest);
|
|
96676
97193
|
}
|
|
96677
97194
|
}
|
|
96678
|
-
var OBLIGATION_STORE_PATH =
|
|
97195
|
+
var OBLIGATION_STORE_PATH = join62(STATE_DIR, "obligations.json");
|
|
96679
97196
|
var obligationStoreFs = {
|
|
96680
|
-
readFileSync: (p) =>
|
|
96681
|
-
writeFileSync: (p, d) =>
|
|
96682
|
-
renameSync: (a, b) =>
|
|
96683
|
-
existsSync: (p) =>
|
|
97197
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
97198
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
97199
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
97200
|
+
existsSync: (p) => existsSync56(p)
|
|
96684
97201
|
};
|
|
96685
97202
|
var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX, {
|
|
96686
97203
|
onChange: STATIC || !OBLIGATION_LEDGER_ENABLED ? undefined : (snapshot) => persistObligations(OBLIGATION_STORE_PATH, obligationStoreFs, snapshot)
|
|
@@ -97459,9 +97976,9 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
97459
97976
|
return;
|
|
97460
97977
|
}
|
|
97461
97978
|
},
|
|
97462
|
-
rename: (from, to) =>
|
|
97979
|
+
rename: (from, to) => renameSync23(from, to)
|
|
97463
97980
|
});
|
|
97464
|
-
|
|
97981
|
+
appendFileSync9(turnsPath, rec);
|
|
97465
97982
|
} catch {}
|
|
97466
97983
|
}
|
|
97467
97984
|
function maybeProactiveCompact() {
|
|
@@ -98087,7 +98604,7 @@ function sweepStaleAlwaysAllowCorrelations(now = Date.now()) {
|
|
|
98087
98604
|
var MENTAL_MODEL_CORRELATION_TTL_MS = 720000;
|
|
98088
98605
|
var pendingMentalModelCorrelations = createSweepableStore((entry, now) => now - entry.createdAt > MENTAL_MODEL_CORRELATION_TTL_MS);
|
|
98089
98606
|
function mentalModelCorrelationKey(agentName3, unifiedDiff) {
|
|
98090
|
-
return `${agentName3}::${
|
|
98607
|
+
return `${agentName3}::${createHash6("sha256").update(unifiedDiff).digest("hex")}`;
|
|
98091
98608
|
}
|
|
98092
98609
|
function sweepStaleMentalModelCorrelations(now = Date.now()) {
|
|
98093
98610
|
pendingMentalModelCorrelations.sweep(now);
|
|
@@ -99023,28 +99540,28 @@ var statusPinState = new Map;
|
|
|
99023
99540
|
var statusPinChatIds = new Map;
|
|
99024
99541
|
var statusPinPinnedAt = new Map;
|
|
99025
99542
|
var statusPinRightsCache = new PinRightsCache2;
|
|
99026
|
-
var STATUS_PIN_STORE_PATH =
|
|
99543
|
+
var STATUS_PIN_STORE_PATH = join62(STATE_DIR, "status-pins.json");
|
|
99027
99544
|
var statusPinStoreFs = {
|
|
99028
|
-
readFileSync: (p) =>
|
|
99029
|
-
writeFileSync: (p, d) =>
|
|
99030
|
-
renameSync: (a, b) =>
|
|
99031
|
-
existsSync: (p) =>
|
|
99545
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99546
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99547
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99548
|
+
existsSync: (p) => existsSync56(p)
|
|
99032
99549
|
};
|
|
99033
99550
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
99034
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
99551
|
+
var ACTIVITY_CARD_STORE_PATH = join62(STATE_DIR, "activity-cards-pending.json");
|
|
99035
99552
|
var activityCardStoreFs = {
|
|
99036
|
-
readFileSync: (p) =>
|
|
99037
|
-
writeFileSync: (p, d) =>
|
|
99038
|
-
renameSync: (a, b) =>
|
|
99039
|
-
existsSync: (p) =>
|
|
99553
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99554
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99555
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99556
|
+
existsSync: (p) => existsSync56(p)
|
|
99040
99557
|
};
|
|
99041
99558
|
var activityCardPersistEnabled = !STATIC;
|
|
99042
|
-
var QUEUED_CARD_STORE_PATH =
|
|
99559
|
+
var QUEUED_CARD_STORE_PATH = join62(STATE_DIR, "queued-cards-pending.json");
|
|
99043
99560
|
var queuedCardStoreFs = {
|
|
99044
|
-
readFileSync: (p) =>
|
|
99045
|
-
writeFileSync: (p, d) =>
|
|
99046
|
-
renameSync: (a, b) =>
|
|
99047
|
-
existsSync: (p) =>
|
|
99561
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99562
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99563
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99564
|
+
existsSync: (p) => existsSync56(p)
|
|
99048
99565
|
};
|
|
99049
99566
|
var queuedCardPersistEnabled = !STATIC;
|
|
99050
99567
|
function persistQueuedCard(key, chatId, threadId, messageId) {
|
|
@@ -99417,12 +99934,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
99417
99934
|
var completeProgressCardTurn = null;
|
|
99418
99935
|
var subagentWatcher = null;
|
|
99419
99936
|
var workerActivityFeed = null;
|
|
99420
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
99937
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join62(STATE_DIR, "gateway.sock");
|
|
99421
99938
|
if (isGatewayMain)
|
|
99422
|
-
|
|
99423
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
99424
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
99425
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
99939
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
99940
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join62(STATE_DIR, "gateway.pid.json");
|
|
99941
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join62(STATE_DIR, "gateway-session.json");
|
|
99942
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
|
|
99426
99943
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
99427
99944
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
99428
99945
|
var activeBootCard = null;
|
|
@@ -99451,7 +99968,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
99451
99968
|
bot: botApi,
|
|
99452
99969
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
99453
99970
|
`),
|
|
99454
|
-
persistPath:
|
|
99971
|
+
persistPath: join62(stateDir, "issues-card.json")
|
|
99455
99972
|
});
|
|
99456
99973
|
activeIssuesWatcher = startIssuesWatcher({
|
|
99457
99974
|
stateDir,
|
|
@@ -99649,13 +100166,13 @@ if (isGatewayMain)
|
|
|
99649
100166
|
var inboundSpool;
|
|
99650
100167
|
if (isGatewayMain)
|
|
99651
100168
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
99652
|
-
path:
|
|
100169
|
+
path: join62(STATE_DIR, "inbound-spool.jsonl"),
|
|
99653
100170
|
fs: {
|
|
99654
|
-
appendFileSync: (p, d) =>
|
|
99655
|
-
readFileSync: (p) =>
|
|
99656
|
-
writeFileSync: (p, d) =>
|
|
99657
|
-
renameSync: (a, b) =>
|
|
99658
|
-
existsSync: (p) =>
|
|
100171
|
+
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
100172
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
100173
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
100174
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
100175
|
+
existsSync: (p) => existsSync56(p),
|
|
99659
100176
|
statSizeSync: (p) => statSync20(p).size
|
|
99660
100177
|
},
|
|
99661
100178
|
onDegraded: (info) => {
|
|
@@ -99717,13 +100234,13 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
99717
100234
|
let transcriptText;
|
|
99718
100235
|
try {
|
|
99719
100236
|
const projectsDir = getProjectsDirForCwd();
|
|
99720
|
-
const path2 =
|
|
99721
|
-
if (!
|
|
100237
|
+
const path2 = join62(projectsDir, `${sessionId}.jsonl`);
|
|
100238
|
+
if (!existsSync56(path2)) {
|
|
99722
100239
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path2}); skipping
|
|
99723
100240
|
`);
|
|
99724
100241
|
return;
|
|
99725
100242
|
}
|
|
99726
|
-
transcriptText =
|
|
100243
|
+
transcriptText = readFileSync60(path2, "utf8");
|
|
99727
100244
|
} catch (err) {
|
|
99728
100245
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
|
|
99729
100246
|
`);
|
|
@@ -99882,8 +100399,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
99882
100399
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
99883
100400
|
isShuttingDown: () => shuttingDown,
|
|
99884
100401
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
99885
|
-
crashLogPath:
|
|
99886
|
-
markerPath:
|
|
100402
|
+
crashLogPath: join62(STATE_DIR, "bridge-crash.log"),
|
|
100403
|
+
markerPath: join62(STATE_DIR, "bridge-dead-escalation.json"),
|
|
99887
100404
|
log: (line) => process.stderr.write(`${line}
|
|
99888
100405
|
`),
|
|
99889
100406
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -99989,8 +100506,8 @@ if (isGatewayMain)
|
|
|
99989
100506
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
99990
100507
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
99991
100508
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
99992
|
-
configSnapshotPath:
|
|
99993
|
-
bootCardStatePath:
|
|
100509
|
+
configSnapshotPath: join62(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
100510
|
+
bootCardStatePath: join62(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
99994
100511
|
floodStatePath: FLOOD_STATE_PATH,
|
|
99995
100512
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
99996
100513
|
}, ackMsgId).then((handle) => {
|
|
@@ -100672,7 +101189,7 @@ if (isGatewayMain)
|
|
|
100672
101189
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
100673
101190
|
if (Number.isInteger(receiverUid))
|
|
100674
101191
|
allowedUids.push(receiverUid);
|
|
100675
|
-
const socketPath =
|
|
101192
|
+
const socketPath = join62(STATE_DIR, "webhook.sock");
|
|
100676
101193
|
const webhookInject = (agentName3, inbound) => {
|
|
100677
101194
|
const msg = inbound;
|
|
100678
101195
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -100900,9 +101417,9 @@ function redactOutboundText(text5, site) {
|
|
|
100900
101417
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
100901
101418
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
100902
101419
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
100903
|
-
persistPath:
|
|
101420
|
+
persistPath: join62(STATE_DIR, "voice-ondemand.json")
|
|
100904
101421
|
});
|
|
100905
|
-
var VOICE_CACHE_DIR =
|
|
101422
|
+
var VOICE_CACHE_DIR = join62(STATE_DIR, "voice-cache");
|
|
100906
101423
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
100907
101424
|
runJob: async (job) => {
|
|
100908
101425
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -101304,11 +101821,11 @@ async function executeSendGif(rawArgs) {
|
|
|
101304
101821
|
};
|
|
101305
101822
|
}
|
|
101306
101823
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
101307
|
-
const accountPath =
|
|
101824
|
+
const accountPath = join62(STATE_DIR, "telegraph-account.json");
|
|
101308
101825
|
let account = null;
|
|
101309
101826
|
try {
|
|
101310
|
-
if (
|
|
101311
|
-
const raw =
|
|
101827
|
+
if (existsSync56(accountPath)) {
|
|
101828
|
+
const raw = readFileSync60(accountPath, "utf-8");
|
|
101312
101829
|
const parsed = JSON.parse(raw);
|
|
101313
101830
|
if (parsed.shortName && parsed.accessToken) {
|
|
101314
101831
|
account = parsed;
|
|
@@ -101327,8 +101844,8 @@ async function publishToTelegraph(text5, shortName, authorName) {
|
|
|
101327
101844
|
}
|
|
101328
101845
|
account = created.value;
|
|
101329
101846
|
try {
|
|
101330
|
-
|
|
101331
|
-
|
|
101847
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
101848
|
+
writeFileSync50(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
|
|
101332
101849
|
} catch (err) {
|
|
101333
101850
|
process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
|
|
101334
101851
|
`);
|
|
@@ -101444,7 +101961,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
|
|
|
101444
101961
|
}
|
|
101445
101962
|
function readLiveSwitchroomConfigText() {
|
|
101446
101963
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
101447
|
-
return
|
|
101964
|
+
return readFileSync60(cfgPath, "utf8");
|
|
101448
101965
|
}
|
|
101449
101966
|
async function executeReact(args) {
|
|
101450
101967
|
if (!args.chat_id)
|
|
@@ -101483,9 +102000,9 @@ async function executeDownloadAttachment(args) {
|
|
|
101483
102000
|
fileUniqueId: file.file_unique_id,
|
|
101484
102001
|
now: Date.now()
|
|
101485
102002
|
});
|
|
101486
|
-
|
|
102003
|
+
mkdirSync49(INBOX_DIR, { recursive: true, mode: 448 });
|
|
101487
102004
|
assertInsideInbox2(INBOX_DIR, dlPath);
|
|
101488
|
-
|
|
102005
|
+
writeFileSync50(dlPath, buf, { mode: 384 });
|
|
101489
102006
|
return { content: [{ type: "text", text: dlPath }] };
|
|
101490
102007
|
}
|
|
101491
102008
|
async function executeEditMessage(args) {
|
|
@@ -102845,14 +103362,14 @@ function restartMarkerPath() {
|
|
|
102845
103362
|
const agentDir = resolveAgentDirFromEnv();
|
|
102846
103363
|
if (!agentDir)
|
|
102847
103364
|
return null;
|
|
102848
|
-
return
|
|
103365
|
+
return join62(agentDir, "restart-pending.json");
|
|
102849
103366
|
}
|
|
102850
103367
|
function writeRestartMarker(marker) {
|
|
102851
103368
|
const p = restartMarkerPath();
|
|
102852
103369
|
if (!p)
|
|
102853
103370
|
return;
|
|
102854
103371
|
try {
|
|
102855
|
-
|
|
103372
|
+
writeFileSync50(p, JSON.stringify(marker));
|
|
102856
103373
|
lastPlannedRestartAt = Date.now();
|
|
102857
103374
|
process.stderr.write(`telegram gateway: restart-marker: write chat_id=${marker.chat_id} thread_id=${marker.thread_id ?? "-"} ack=${marker.ack_message_id ?? "-"} path=${p}
|
|
102858
103375
|
`);
|
|
@@ -102871,7 +103388,7 @@ function readRestartMarker() {
|
|
|
102871
103388
|
if (!p)
|
|
102872
103389
|
return null;
|
|
102873
103390
|
try {
|
|
102874
|
-
return JSON.parse(
|
|
103391
|
+
return JSON.parse(readFileSync60(p, "utf8"));
|
|
102875
103392
|
} catch {
|
|
102876
103393
|
return null;
|
|
102877
103394
|
}
|
|
@@ -103020,7 +103537,7 @@ var _dockerReachable;
|
|
|
103020
103537
|
function isDockerReachable() {
|
|
103021
103538
|
if (_dockerReachable !== undefined)
|
|
103022
103539
|
return _dockerReachable;
|
|
103023
|
-
if (!
|
|
103540
|
+
if (!existsSync56("/var/run/docker.sock")) {
|
|
103024
103541
|
_dockerReachable = false;
|
|
103025
103542
|
return _dockerReachable;
|
|
103026
103543
|
}
|
|
@@ -103037,12 +103554,12 @@ function _resetDockerReachableCache() {
|
|
|
103037
103554
|
}
|
|
103038
103555
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
103039
103556
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
103040
|
-
const logPath =
|
|
103557
|
+
const logPath = join62(STATE_DIR, "detached-spawn.log");
|
|
103041
103558
|
let outFd = null;
|
|
103042
103559
|
try {
|
|
103043
|
-
|
|
103560
|
+
mkdirSync49(STATE_DIR, { recursive: true });
|
|
103044
103561
|
outFd = openSync12(logPath, "a");
|
|
103045
|
-
|
|
103562
|
+
writeFileSync50(logPath, `
|
|
103046
103563
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
103047
103564
|
`, { flag: "a" });
|
|
103048
103565
|
} catch {}
|
|
@@ -103068,7 +103585,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
103068
103585
|
return;
|
|
103069
103586
|
let tail = "";
|
|
103070
103587
|
try {
|
|
103071
|
-
const full =
|
|
103588
|
+
const full = readFileSync60(logPath, "utf8");
|
|
103072
103589
|
tail = full.split(`
|
|
103073
103590
|
`).slice(-30).join(`
|
|
103074
103591
|
`).trim();
|
|
@@ -103330,10 +103847,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
103330
103847
|
}
|
|
103331
103848
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
103332
103849
|
try {
|
|
103333
|
-
const auditPath =
|
|
103334
|
-
if (!
|
|
103850
|
+
const auditPath = join62(homedir20(), ".switchroom", "vault-audit.log");
|
|
103851
|
+
if (!existsSync56(auditPath))
|
|
103335
103852
|
return [];
|
|
103336
|
-
const raw =
|
|
103853
|
+
const raw = readFileSync60(auditPath, "utf8");
|
|
103337
103854
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
103338
103855
|
} catch {
|
|
103339
103856
|
return [];
|
|
@@ -103384,7 +103901,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
103384
103901
|
try {
|
|
103385
103902
|
const agentDir = resolveAgentDirFromEnv();
|
|
103386
103903
|
if (agentDir) {
|
|
103387
|
-
const raw =
|
|
103904
|
+
const raw = readFileSync60(join62(agentDir, ".claude", ".claude.json"), "utf8");
|
|
103388
103905
|
claudeJson = JSON.parse(raw);
|
|
103389
103906
|
}
|
|
103390
103907
|
} catch {}
|
|
@@ -103513,7 +104030,7 @@ function buildModelDeps(restartCtx) {
|
|
|
103513
104030
|
try {
|
|
103514
104031
|
const agentDir = resolveAgentDirFromEnv();
|
|
103515
104032
|
if (agentDir) {
|
|
103516
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
104033
|
+
const local = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
|
|
103517
104034
|
if (local.ok)
|
|
103518
104035
|
return formatQuotaLine2(local.data);
|
|
103519
104036
|
}
|
|
@@ -103759,9 +104276,9 @@ function effortMenuReplyMarkup(reply) {
|
|
|
103759
104276
|
function flushAgentHandoff(agentDir) {
|
|
103760
104277
|
let removed = 0;
|
|
103761
104278
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
103762
|
-
const p =
|
|
104279
|
+
const p = join62(agentDir, fname);
|
|
103763
104280
|
try {
|
|
103764
|
-
if (
|
|
104281
|
+
if (existsSync56(p)) {
|
|
103765
104282
|
unlinkSync27(p);
|
|
103766
104283
|
removed++;
|
|
103767
104284
|
}
|
|
@@ -103817,7 +104334,7 @@ async function handleNewCommand(ctx) {
|
|
|
103817
104334
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
103818
104335
|
if (agentDir != null) {
|
|
103819
104336
|
try {
|
|
103820
|
-
|
|
104337
|
+
writeFileSync50(join62(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
103821
104338
|
`, "utf8");
|
|
103822
104339
|
} catch (err) {
|
|
103823
104340
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -103930,16 +104447,16 @@ function buildFolderPickerDeps() {
|
|
|
103930
104447
|
};
|
|
103931
104448
|
}
|
|
103932
104449
|
var lockoutOps = {
|
|
103933
|
-
readFileSync: (p, enc) =>
|
|
103934
|
-
writeFileSync: (p, data, opts) =>
|
|
103935
|
-
existsSync: (p) =>
|
|
103936
|
-
mkdirSync: (p, opts) =>
|
|
103937
|
-
joinPath: (...parts) =>
|
|
104450
|
+
readFileSync: (p, enc) => readFileSync60(p, enc),
|
|
104451
|
+
writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
|
|
104452
|
+
existsSync: (p) => existsSync56(p),
|
|
104453
|
+
mkdirSync: (p, opts) => mkdirSync49(p, opts),
|
|
104454
|
+
joinPath: (...parts) => join62(...parts)
|
|
103938
104455
|
};
|
|
103939
104456
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
103940
104457
|
function isAuthBrokerSocketReachable() {
|
|
103941
104458
|
try {
|
|
103942
|
-
return
|
|
104459
|
+
return existsSync56(resolveAuthBrokerSocketPath2());
|
|
103943
104460
|
} catch {
|
|
103944
104461
|
return false;
|
|
103945
104462
|
}
|
|
@@ -104194,7 +104711,7 @@ async function runCreditWatch() {
|
|
|
104194
104711
|
if (!agentDir)
|
|
104195
104712
|
return;
|
|
104196
104713
|
const agentName3 = getMyAgentName();
|
|
104197
|
-
const claudeConfigDir =
|
|
104714
|
+
const claudeConfigDir = join62(agentDir, ".claude");
|
|
104198
104715
|
const stateDir = STATE_DIR;
|
|
104199
104716
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
104200
104717
|
const prev = loadCreditState(stateDir);
|
|
@@ -105950,7 +106467,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
105950
106467
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
105951
106468
|
return;
|
|
105952
106469
|
}
|
|
105953
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
106470
|
+
const result = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
|
|
105954
106471
|
if (!result.ok) {
|
|
105955
106472
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
105956
106473
|
return;
|
|
@@ -106336,7 +106853,7 @@ ${interimLabel}` : interimLabel
|
|
|
106336
106853
|
const unifiedDiff = (() => {
|
|
106337
106854
|
try {
|
|
106338
106855
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
106339
|
-
const raw =
|
|
106856
|
+
const raw = readFileSync60(cfgPath, "utf8");
|
|
106340
106857
|
return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
|
|
106341
106858
|
} catch (err) {
|
|
106342
106859
|
process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
|
|
@@ -106614,6 +107131,7 @@ ${labelWithResume}` : labelWithResume,
|
|
|
106614
107131
|
handleChecklistUpdate(ctx, "checklist_tasks_added", checklistHandlerDeps);
|
|
106615
107132
|
});
|
|
106616
107133
|
bot2.on("message:pinned_message", (ctx) => handlePinnedMessage(ctx, pinnedMessageHandlerDeps));
|
|
107134
|
+
bot2.on("message:rich_message", (ctx) => handleRichMessageMessage(ctx, mediaEnvelopeDeps));
|
|
106617
107135
|
installUnhandledMessageCatchAll(bot2, (ctx, text5) => routeInbound(ctx, text5, undefined, undefined, inboundRouterDeps), (line) => process.stderr.write(line));
|
|
106618
107136
|
bot2.on("message_reaction", (ctx) => {
|
|
106619
107137
|
handleMessageReaction(ctx);
|
|
@@ -107192,7 +107710,7 @@ async function startGateway() {
|
|
|
107192
107710
|
return;
|
|
107193
107711
|
}
|
|
107194
107712
|
})();
|
|
107195
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
107713
|
+
const resolvedAgentDirForBootCard = agentDir ?? join62(homedir20(), ".switchroom", "agents", agentSlug);
|
|
107196
107714
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
107197
107715
|
agentName: agentDisplayName,
|
|
107198
107716
|
agentSlug,
|
|
@@ -107206,8 +107724,8 @@ async function startGateway() {
|
|
|
107206
107724
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
107207
107725
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
107208
107726
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
107209
|
-
configSnapshotPath:
|
|
107210
|
-
bootCardStatePath:
|
|
107727
|
+
configSnapshotPath: join62(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
107728
|
+
bootCardStatePath: join62(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
107211
107729
|
floodStatePath: FLOOD_STATE_PATH,
|
|
107212
107730
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
107213
107731
|
}, ackMsgId);
|
|
@@ -107238,10 +107756,10 @@ async function startGateway() {
|
|
|
107238
107756
|
try {
|
|
107239
107757
|
const smAgentDir = resolveAgentDirFromEnv();
|
|
107240
107758
|
if (smAgentDir) {
|
|
107241
|
-
const activePath =
|
|
107242
|
-
if (
|
|
107759
|
+
const activePath = join62(smAgentDir, ".active-session-model");
|
|
107760
|
+
if (existsSync56(activePath)) {
|
|
107243
107761
|
try {
|
|
107244
|
-
const launched =
|
|
107762
|
+
const launched = readFileSync60(activePath, "utf8").trim();
|
|
107245
107763
|
const configured = (() => {
|
|
107246
107764
|
const d = switchroomExecJson(["agent", "list"]);
|
|
107247
107765
|
const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
|
|
@@ -107274,24 +107792,24 @@ async function startGateway() {
|
|
|
107274
107792
|
deliverModelSwitchBootNotice({
|
|
107275
107793
|
...modelBootCardDeps,
|
|
107276
107794
|
confirmation,
|
|
107277
|
-
hasSessionModelAlert:
|
|
107795
|
+
hasSessionModelAlert: existsSync56(join62(smAgentDir, ".session-model-alert"))
|
|
107278
107796
|
});
|
|
107279
107797
|
}
|
|
107280
107798
|
} catch {}
|
|
107281
107799
|
}
|
|
107282
|
-
const activeEffortPath =
|
|
107283
|
-
if (
|
|
107800
|
+
const activeEffortPath = join62(smAgentDir, ".active-session-effort");
|
|
107801
|
+
if (existsSync56(activeEffortPath)) {
|
|
107284
107802
|
try {
|
|
107285
|
-
const launchedEffort =
|
|
107803
|
+
const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
|
|
107286
107804
|
const configuredEffort = getConfiguredEffortForPersist();
|
|
107287
107805
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
107288
107806
|
} catch {}
|
|
107289
107807
|
}
|
|
107290
|
-
const alertPath =
|
|
107291
|
-
if (
|
|
107808
|
+
const alertPath = join62(smAgentDir, ".session-model-alert");
|
|
107809
|
+
if (existsSync56(alertPath)) {
|
|
107292
107810
|
let alertText = null;
|
|
107293
107811
|
try {
|
|
107294
|
-
alertText =
|
|
107812
|
+
alertText = readFileSync60(alertPath, "utf8").trim();
|
|
107295
107813
|
} catch {
|
|
107296
107814
|
alertText = null;
|
|
107297
107815
|
}
|