switchroom 0.19.14 → 0.19.16
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 +1 -1
- package/package.json +1 -1
- package/telegram-plugin/bridge/bridge.ts +1 -1
- package/telegram-plugin/dist/bridge/bridge.js +31 -2
- package/telegram-plugin/dist/gateway/gateway.js +1690 -932
- package/telegram-plugin/dist/server.js +31 -2
- package/telegram-plugin/gateway/background-shell-liveness.ts +65 -0
- package/telegram-plugin/gateway/forward-origin.ts +6 -1
- package/telegram-plugin/gateway/gateway.ts +10 -57
- package/telegram-plugin/gateway/narrative-lane.ts +11 -0
- package/telegram-plugin/gateway/outbound-send-path.ts +25 -23
- package/telegram-plugin/gateway/outbox-listen-markup.ts +67 -0
- package/telegram-plugin/gateway/outbox-sweep.ts +124 -20
- package/telegram-plugin/gateway/rich-message-handler.ts +241 -0
- package/telegram-plugin/gateway/silence-poke-session-event.ts +89 -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-scan.mjs +136 -82
- package/telegram-plugin/narrative-flush.ts +35 -0
- package/telegram-plugin/outbox.ts +73 -3
- package/telegram-plugin/session-tail.ts +88 -1
- package/telegram-plugin/shown-ledger.ts +145 -0
- package/telegram-plugin/silence-poke.ts +118 -1
- package/telegram-plugin/silent-end.ts +42 -0
- package/telegram-plugin/tests/background-shell-liveness.test.ts +72 -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/feed-survival.test.ts +7 -1
- package/telegram-plugin/tests/fixtures/bg-shell-liveness-3519.jsonl +3 -0
- package/telegram-plugin/tests/forward-origin.test.ts +20 -0
- package/telegram-plugin/tests/forwarded-rich-message-coalesce.test.ts +290 -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-sweep-listen-button.test.ts +253 -0
- package/telegram-plugin/tests/session-tail.test.ts +91 -1
- package/telegram-plugin/tests/silence-poke.test.ts +280 -0
- 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/tts-normalize.test.ts +66 -0
- package/telegram-plugin/tests/turn-flush-safety.test.ts +35 -3
- package/telegram-plugin/tests/voice-normalize-text.test.ts +82 -1
- package/telegram-plugin/tts-normalize.ts +12 -0
- package/telegram-plugin/turn-flush-safety.ts +66 -53
- package/telegram-plugin/voice-normalize-text.ts +100 -0
- package/telegram-plugin/voice-ondemand.ts +71 -0
|
@@ -8869,12 +8869,12 @@ var require_mod4 = __commonJS((exports) => {
|
|
|
8869
8869
|
// flood-circuit-breaker.ts
|
|
8870
8870
|
import {
|
|
8871
8871
|
existsSync as existsSync2,
|
|
8872
|
-
readFileSync as
|
|
8873
|
-
writeFileSync as
|
|
8874
|
-
mkdirSync as
|
|
8872
|
+
readFileSync as readFileSync3,
|
|
8873
|
+
writeFileSync as writeFileSync4,
|
|
8874
|
+
mkdirSync as mkdirSync5,
|
|
8875
8875
|
chmodSync,
|
|
8876
8876
|
unlinkSync as unlinkSync2,
|
|
8877
|
-
renameSync as
|
|
8877
|
+
renameSync as renameSync5
|
|
8878
8878
|
} from "node:fs";
|
|
8879
8879
|
function floodWaitRemainingMs(state, now) {
|
|
8880
8880
|
if (!state)
|
|
@@ -8884,7 +8884,7 @@ function floodWaitRemainingMs(state, now) {
|
|
|
8884
8884
|
function readFloodStateResult(path) {
|
|
8885
8885
|
let text;
|
|
8886
8886
|
try {
|
|
8887
|
-
text =
|
|
8887
|
+
text = readFileSync3(path, "utf-8");
|
|
8888
8888
|
} catch (err) {
|
|
8889
8889
|
const code = err?.code;
|
|
8890
8890
|
if (code === "ENOENT" || code === "ENOTDIR")
|
|
@@ -13554,7 +13554,7 @@ __export(exports_tmux, {
|
|
|
13554
13554
|
captureAgentPane: () => captureAgentPane
|
|
13555
13555
|
});
|
|
13556
13556
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
13557
|
-
import { chmodSync as chmodSync2, mkdirSync as
|
|
13557
|
+
import { chmodSync as chmodSync2, mkdirSync as mkdirSync6, readdirSync as readdirSync2, statSync as statSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
13558
13558
|
import { resolve } from "node:path";
|
|
13559
13559
|
function captureAgentPane(opts) {
|
|
13560
13560
|
const { agentName, agentDir, reason } = opts;
|
|
@@ -13566,7 +13566,7 @@ function captureAgentPane(opts) {
|
|
|
13566
13566
|
const reasonSlug = sanitizeReason(reason);
|
|
13567
13567
|
const outPath = resolve(outDir, `${ts}-${reasonSlug}.txt`);
|
|
13568
13568
|
try {
|
|
13569
|
-
|
|
13569
|
+
mkdirSync6(outDir, { recursive: true, mode: 448 });
|
|
13570
13570
|
} catch (err) {
|
|
13571
13571
|
const msg = `mkdir crash-reports failed: ${err.message}`;
|
|
13572
13572
|
console.error(`[tmux-capture] ${agentName}: ${msg}`);
|
|
@@ -13605,7 +13605,7 @@ function captureAgentPane(opts) {
|
|
|
13605
13605
|
` + `
|
|
13606
13606
|
`;
|
|
13607
13607
|
try {
|
|
13608
|
-
|
|
13608
|
+
writeFileSync5(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
|
|
13609
13609
|
mode: 384
|
|
13610
13610
|
});
|
|
13611
13611
|
} catch (err) {
|
|
@@ -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";
|
|
@@ -39416,13 +39416,218 @@ class VoiceOnDemandCache {
|
|
|
39416
39416
|
}
|
|
39417
39417
|
}
|
|
39418
39418
|
|
|
39419
|
+
// voice-ondemand.ts
|
|
39420
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
39421
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, renameSync as renameSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
39422
|
+
import { dirname as dirname3 } from "path";
|
|
39423
|
+
var VOICE_ONDEMAND_CALLBACK_PREFIX = "voice:";
|
|
39424
|
+
var VOICE_ONDEMAND_TTL_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
39425
|
+
var VOICE_ONDEMAND_MAX_ENTRIES2 = 500;
|
|
39426
|
+
|
|
39427
|
+
class VoiceOnDemandCache2 {
|
|
39428
|
+
store = new Map;
|
|
39429
|
+
ttlMs;
|
|
39430
|
+
maxEntries;
|
|
39431
|
+
now;
|
|
39432
|
+
persistPath;
|
|
39433
|
+
constructor(options = {}) {
|
|
39434
|
+
this.ttlMs = options.ttlMs ?? VOICE_ONDEMAND_TTL_MS2;
|
|
39435
|
+
this.maxEntries = options.maxEntries ?? VOICE_ONDEMAND_MAX_ENTRIES2;
|
|
39436
|
+
this.now = options.now ?? Date.now;
|
|
39437
|
+
this.persistPath = options.persistPath;
|
|
39438
|
+
if (this.persistPath !== undefined)
|
|
39439
|
+
this.load();
|
|
39440
|
+
}
|
|
39441
|
+
put(token, payload) {
|
|
39442
|
+
this.store.delete(token);
|
|
39443
|
+
this.store.set(token, {
|
|
39444
|
+
createdAt: this.now(),
|
|
39445
|
+
...payload,
|
|
39446
|
+
expiresAt: this.now() + this.ttlMs
|
|
39447
|
+
});
|
|
39448
|
+
while (this.store.size > this.maxEntries) {
|
|
39449
|
+
const oldest = this.store.keys().next().value;
|
|
39450
|
+
if (oldest === undefined)
|
|
39451
|
+
break;
|
|
39452
|
+
this.store.delete(oldest);
|
|
39453
|
+
}
|
|
39454
|
+
this.flush();
|
|
39455
|
+
}
|
|
39456
|
+
get(token) {
|
|
39457
|
+
const entry = this.store.get(token);
|
|
39458
|
+
if (entry == null)
|
|
39459
|
+
return null;
|
|
39460
|
+
if (entry.expiresAt <= this.now()) {
|
|
39461
|
+
this.store.delete(token);
|
|
39462
|
+
this.flush();
|
|
39463
|
+
return null;
|
|
39464
|
+
}
|
|
39465
|
+
const { text, voice, speed, filePath, telegramFileId } = entry;
|
|
39466
|
+
return {
|
|
39467
|
+
text,
|
|
39468
|
+
speed,
|
|
39469
|
+
...voice !== undefined ? { voice } : {},
|
|
39470
|
+
...filePath !== undefined ? { filePath } : {},
|
|
39471
|
+
...telegramFileId !== undefined ? { telegramFileId } : {}
|
|
39472
|
+
};
|
|
39473
|
+
}
|
|
39474
|
+
setFilePath(token, filePath) {
|
|
39475
|
+
const entry = this.store.get(token);
|
|
39476
|
+
if (entry == null || entry.expiresAt <= this.now())
|
|
39477
|
+
return;
|
|
39478
|
+
entry.filePath = filePath;
|
|
39479
|
+
this.flush();
|
|
39480
|
+
}
|
|
39481
|
+
setTelegramFileId(token, fileId) {
|
|
39482
|
+
if (fileId.length === 0)
|
|
39483
|
+
return;
|
|
39484
|
+
const entry = this.store.get(token);
|
|
39485
|
+
if (entry == null || entry.expiresAt <= this.now())
|
|
39486
|
+
return;
|
|
39487
|
+
entry.telegramFileId = fileId;
|
|
39488
|
+
this.flush();
|
|
39489
|
+
}
|
|
39490
|
+
prune(tokens) {
|
|
39491
|
+
let changed = false;
|
|
39492
|
+
for (const token of tokens) {
|
|
39493
|
+
if (this.store.delete(token))
|
|
39494
|
+
changed = true;
|
|
39495
|
+
}
|
|
39496
|
+
if (changed)
|
|
39497
|
+
this.flush();
|
|
39498
|
+
}
|
|
39499
|
+
get size() {
|
|
39500
|
+
return this.store.size;
|
|
39501
|
+
}
|
|
39502
|
+
load() {
|
|
39503
|
+
if (this.persistPath === undefined)
|
|
39504
|
+
return;
|
|
39505
|
+
let raw;
|
|
39506
|
+
try {
|
|
39507
|
+
raw = readFileSync2(this.persistPath, "utf8");
|
|
39508
|
+
} catch {
|
|
39509
|
+
return;
|
|
39510
|
+
}
|
|
39511
|
+
try {
|
|
39512
|
+
const parsed = JSON.parse(raw);
|
|
39513
|
+
if (parsed == null || parsed.version !== 1 || typeof parsed.entries !== "object")
|
|
39514
|
+
return;
|
|
39515
|
+
const nowMs = this.now();
|
|
39516
|
+
for (const [token, entry] of Object.entries(parsed.entries)) {
|
|
39517
|
+
if (entry == null || typeof entry.expiresAt !== "number" || typeof entry.text !== "string" || typeof entry.speed !== "number") {
|
|
39518
|
+
continue;
|
|
39519
|
+
}
|
|
39520
|
+
if (entry.expiresAt <= nowMs)
|
|
39521
|
+
continue;
|
|
39522
|
+
this.store.set(token, entry);
|
|
39523
|
+
}
|
|
39524
|
+
while (this.store.size > this.maxEntries) {
|
|
39525
|
+
const oldest = this.store.keys().next().value;
|
|
39526
|
+
if (oldest === undefined)
|
|
39527
|
+
break;
|
|
39528
|
+
this.store.delete(oldest);
|
|
39529
|
+
}
|
|
39530
|
+
} catch (err) {
|
|
39531
|
+
process.stderr.write(`voice-ondemand: failed to parse persisted cache ${this.persistPath}: ${String(err)}
|
|
39532
|
+
`);
|
|
39533
|
+
}
|
|
39534
|
+
}
|
|
39535
|
+
flush() {
|
|
39536
|
+
if (this.persistPath === undefined)
|
|
39537
|
+
return;
|
|
39538
|
+
const doc = {
|
|
39539
|
+
version: 1,
|
|
39540
|
+
entries: Object.fromEntries(this.store)
|
|
39541
|
+
};
|
|
39542
|
+
const tmp = `${this.persistPath}.tmp`;
|
|
39543
|
+
try {
|
|
39544
|
+
mkdirSync3(dirname3(this.persistPath), { recursive: true });
|
|
39545
|
+
writeFileSync2(tmp, JSON.stringify(doc), "utf8");
|
|
39546
|
+
renameSync3(tmp, this.persistPath);
|
|
39547
|
+
} catch (err) {
|
|
39548
|
+
process.stderr.write(`voice-ondemand: failed to persist cache ${this.persistPath}: ${String(err)}
|
|
39549
|
+
`);
|
|
39550
|
+
}
|
|
39551
|
+
}
|
|
39552
|
+
}
|
|
39553
|
+
function mintVoiceOnDemandToken() {
|
|
39554
|
+
return randomBytes2(4).toString("hex");
|
|
39555
|
+
}
|
|
39556
|
+
function isVoiceOnDemandCallback(data) {
|
|
39557
|
+
return data.startsWith(VOICE_ONDEMAND_CALLBACK_PREFIX);
|
|
39558
|
+
}
|
|
39559
|
+
function parseVoiceOnDemandToken(data) {
|
|
39560
|
+
if (!isVoiceOnDemandCallback(data))
|
|
39561
|
+
return null;
|
|
39562
|
+
const token = data.slice(VOICE_ONDEMAND_CALLBACK_PREFIX.length);
|
|
39563
|
+
return token.length > 0 ? token : null;
|
|
39564
|
+
}
|
|
39565
|
+
function buildListenKeyboard(token) {
|
|
39566
|
+
return {
|
|
39567
|
+
inline_keyboard: [
|
|
39568
|
+
[{ text: "\uD83D\uDD0A Listen", callback_data: `${VOICE_ONDEMAND_CALLBACK_PREFIX}${token}` }]
|
|
39569
|
+
]
|
|
39570
|
+
};
|
|
39571
|
+
}
|
|
39572
|
+
function mayInjectListenButton(rawKeyboard) {
|
|
39573
|
+
if (rawKeyboard == null)
|
|
39574
|
+
return true;
|
|
39575
|
+
return !rawKeyboard.some((row) => Array.isArray(row) && row.length > 0);
|
|
39576
|
+
}
|
|
39577
|
+
function planListenButton(params) {
|
|
39578
|
+
const plan = params.voiceOutPlan;
|
|
39579
|
+
const useOnDemandButton = plan != null && plan.replyMode === "on-demand" && plan.engine === "kokoro";
|
|
39580
|
+
if (!useOnDemandButton)
|
|
39581
|
+
return null;
|
|
39582
|
+
if (!(plan.ttsChunks.length > 0 && plan.ttsChunks[0].length > 0))
|
|
39583
|
+
return null;
|
|
39584
|
+
if (!mayInjectListenButton(params.rawKeyboard))
|
|
39585
|
+
return null;
|
|
39586
|
+
const token = mintVoiceOnDemandToken();
|
|
39587
|
+
return {
|
|
39588
|
+
replyMarkup: buildListenKeyboard(token),
|
|
39589
|
+
token,
|
|
39590
|
+
payload: {
|
|
39591
|
+
text: plan.ttsChunks[0],
|
|
39592
|
+
...plan.voice != null ? { voice: plan.voice } : {},
|
|
39593
|
+
speed: plan.speed
|
|
39594
|
+
}
|
|
39595
|
+
};
|
|
39596
|
+
}
|
|
39597
|
+
|
|
39598
|
+
// gateway/outbox-listen-markup.ts
|
|
39599
|
+
function makeOutboxListenMarkupResolver(deps) {
|
|
39600
|
+
return (_chatId, _threadId, text) => {
|
|
39601
|
+
const voiceOutPlan = deps.resolveVoiceOutPlan(text);
|
|
39602
|
+
const listenPlan = planListenButton({ voiceOutPlan, rawKeyboard: undefined });
|
|
39603
|
+
if (listenPlan == null)
|
|
39604
|
+
return;
|
|
39605
|
+
const payload = listenPlan.payload;
|
|
39606
|
+
deps.cachePut(listenPlan.token, payload);
|
|
39607
|
+
if (deps.eagerVoiceEnabled()) {
|
|
39608
|
+
deps.enqueuePreSynth({
|
|
39609
|
+
token: listenPlan.token,
|
|
39610
|
+
text: payload.text,
|
|
39611
|
+
...payload.voice != null ? { voice: payload.voice } : {},
|
|
39612
|
+
speed: payload.speed
|
|
39613
|
+
});
|
|
39614
|
+
}
|
|
39615
|
+
return listenPlan.replyMarkup;
|
|
39616
|
+
};
|
|
39617
|
+
}
|
|
39618
|
+
|
|
39419
39619
|
// voice-presynth.ts
|
|
39420
|
-
import { readdirSync, statSync as statSync2, unlinkSync, mkdirSync as
|
|
39620
|
+
import { readdirSync, statSync as statSync2, unlinkSync, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3, renameSync as renameSync4 } from "fs";
|
|
39421
39621
|
import { join as join2 } from "path";
|
|
39422
39622
|
var VOICE_FILE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
39423
39623
|
var VOICE_CACHE_MAX_BYTES = 500 * 1024 * 1024;
|
|
39424
39624
|
var PRESYNTH_MAX_PENDING = 50;
|
|
39425
39625
|
var VOICE_SWEEP_INTERVAL_MS = 60 * 60 * 1000;
|
|
39626
|
+
function eagerVoiceEnabled() {
|
|
39627
|
+
const kill = process.env.SWITCHROOM_DISABLE_EAGER_VOICE;
|
|
39628
|
+
return !(kill === "1" || kill === "true");
|
|
39629
|
+
}
|
|
39630
|
+
|
|
39426
39631
|
class PreSynthQueue {
|
|
39427
39632
|
pending = [];
|
|
39428
39633
|
running = false;
|
|
@@ -39474,11 +39679,11 @@ function voiceCacheFilePath(dir, token) {
|
|
|
39474
39679
|
return join2(dir, `${token}.ogg`);
|
|
39475
39680
|
}
|
|
39476
39681
|
function writeVoiceCacheFile(dir, token, audio) {
|
|
39477
|
-
|
|
39682
|
+
mkdirSync4(dir, { recursive: true, mode: 448 });
|
|
39478
39683
|
const final = voiceCacheFilePath(dir, token);
|
|
39479
39684
|
const tmp = `${final}.tmp`;
|
|
39480
|
-
|
|
39481
|
-
|
|
39685
|
+
writeFileSync3(tmp, audio);
|
|
39686
|
+
renameSync4(tmp, final);
|
|
39482
39687
|
return final;
|
|
39483
39688
|
}
|
|
39484
39689
|
function sweepVoiceCacheDir(options) {
|
|
@@ -39535,6 +39740,49 @@ function sweepVoiceCacheDir(options) {
|
|
|
39535
39740
|
|
|
39536
39741
|
// voice-normalize-text.ts
|
|
39537
39742
|
var CODE_BLOCK_PLACEHOLDER = "code block omitted";
|
|
39743
|
+
var HTML_ENTITIES = {
|
|
39744
|
+
amp: "&",
|
|
39745
|
+
lt: "<",
|
|
39746
|
+
gt: ">",
|
|
39747
|
+
quot: '"',
|
|
39748
|
+
apos: "'",
|
|
39749
|
+
nbsp: " "
|
|
39750
|
+
};
|
|
39751
|
+
var METACHAR_SPOKEN = {
|
|
39752
|
+
"#": " hash ",
|
|
39753
|
+
"*": " asterisk ",
|
|
39754
|
+
_: " underscore ",
|
|
39755
|
+
"~": " tilde ",
|
|
39756
|
+
"`": " backtick ",
|
|
39757
|
+
"|": " bar "
|
|
39758
|
+
};
|
|
39759
|
+
function decodeHtmlEntitiesOnce(input) {
|
|
39760
|
+
const toChar = (cp, raw) => {
|
|
39761
|
+
if (!(cp > 0 && cp <= 1114111))
|
|
39762
|
+
return raw;
|
|
39763
|
+
const ch = String.fromCodePoint(cp);
|
|
39764
|
+
return METACHAR_SPOKEN[ch] ?? ch;
|
|
39765
|
+
};
|
|
39766
|
+
return input.replace(/&#x([0-9a-f]+);/gi, (m, hex) => toChar(parseInt(hex, 16), m)).replace(/&#(\d+);/g, (m, dec) => toChar(Number(dec), m)).replace(/&([a-z][a-z0-9]*);/gi, (m, name) => {
|
|
39767
|
+
const ch = HTML_ENTITIES[name.toLowerCase()];
|
|
39768
|
+
if (ch === undefined)
|
|
39769
|
+
return m;
|
|
39770
|
+
return METACHAR_SPOKEN[ch] ?? ch;
|
|
39771
|
+
});
|
|
39772
|
+
}
|
|
39773
|
+
function decodeHtmlEntities(input) {
|
|
39774
|
+
let s = input;
|
|
39775
|
+
for (let i = 0;i < 10; i++) {
|
|
39776
|
+
const next = decodeHtmlEntitiesOnce(s);
|
|
39777
|
+
if (next === s)
|
|
39778
|
+
break;
|
|
39779
|
+
s = next;
|
|
39780
|
+
}
|
|
39781
|
+
return s;
|
|
39782
|
+
}
|
|
39783
|
+
function stripBackslashEscapes(input) {
|
|
39784
|
+
return input.replace(/\\([\s\S])/g, "$1").replace(/\\/g, "");
|
|
39785
|
+
}
|
|
39538
39786
|
var ONES = [
|
|
39539
39787
|
"zero",
|
|
39540
39788
|
"one",
|
|
@@ -39701,6 +39949,8 @@ function normalizeForSpeech(input) {
|
|
|
39701
39949
|
return "";
|
|
39702
39950
|
let s = input.replace(/\r\n?/g, `
|
|
39703
39951
|
`);
|
|
39952
|
+
s = decodeHtmlEntities(s);
|
|
39953
|
+
s = stripBackslashEscapes(s);
|
|
39704
39954
|
s = s.replace(/[\u{1F000}-\u{1FAFF}\u{1F1E6}-\u{1F1FF}\u{2600}-\u{27BF}\u{2B00}-\u{2BFF}\u{FE00}-\u{FE0F}\u{200D}\u{2B50}\u{3030}\u{303D}\u{3297}\u{3299}\u{24C2}]/gu, "");
|
|
39705
39955
|
s = s.replace(/:([a-z0-9][a-z0-9_+-]*):/gi, " ");
|
|
39706
39956
|
s = s.replace(/(^|\n)[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?\n[ \t]*\2[ \t]*(?=\n|$)/g, `$1${CODE_BLOCK_PLACEHOLDER}.`);
|
|
@@ -39800,6 +40050,65 @@ function normalizeForSpeech(input) {
|
|
|
39800
40050
|
return s.trim();
|
|
39801
40051
|
}
|
|
39802
40052
|
|
|
40053
|
+
// voice-normalize-text.ts
|
|
40054
|
+
var HTML_ENTITIES2 = {
|
|
40055
|
+
amp: "&",
|
|
40056
|
+
lt: "<",
|
|
40057
|
+
gt: ">",
|
|
40058
|
+
quot: '"',
|
|
40059
|
+
apos: "'",
|
|
40060
|
+
nbsp: " "
|
|
40061
|
+
};
|
|
40062
|
+
var METACHAR_SPOKEN2 = {
|
|
40063
|
+
"#": " hash ",
|
|
40064
|
+
"*": " asterisk ",
|
|
40065
|
+
_: " underscore ",
|
|
40066
|
+
"~": " tilde ",
|
|
40067
|
+
"`": " backtick ",
|
|
40068
|
+
"|": " bar "
|
|
40069
|
+
};
|
|
40070
|
+
function decodeHtmlEntitiesOnce2(input) {
|
|
40071
|
+
const toChar = (cp, raw) => {
|
|
40072
|
+
if (!(cp > 0 && cp <= 1114111))
|
|
40073
|
+
return raw;
|
|
40074
|
+
const ch = String.fromCodePoint(cp);
|
|
40075
|
+
return METACHAR_SPOKEN2[ch] ?? ch;
|
|
40076
|
+
};
|
|
40077
|
+
return input.replace(/&#x([0-9a-f]+);/gi, (m, hex) => toChar(parseInt(hex, 16), m)).replace(/&#(\d+);/g, (m, dec) => toChar(Number(dec), m)).replace(/&([a-z][a-z0-9]*);/gi, (m, name) => {
|
|
40078
|
+
const ch = HTML_ENTITIES2[name.toLowerCase()];
|
|
40079
|
+
if (ch === undefined)
|
|
40080
|
+
return m;
|
|
40081
|
+
return METACHAR_SPOKEN2[ch] ?? ch;
|
|
40082
|
+
});
|
|
40083
|
+
}
|
|
40084
|
+
function decodeHtmlEntities2(input) {
|
|
40085
|
+
let s = input;
|
|
40086
|
+
for (let i = 0;i < 10; i++) {
|
|
40087
|
+
const next = decodeHtmlEntitiesOnce2(s);
|
|
40088
|
+
if (next === s)
|
|
40089
|
+
break;
|
|
40090
|
+
s = next;
|
|
40091
|
+
}
|
|
40092
|
+
return s;
|
|
40093
|
+
}
|
|
40094
|
+
function stripBackslashEscapes2(input) {
|
|
40095
|
+
return input.replace(/\\([\s\S])/g, "$1").replace(/\\/g, "");
|
|
40096
|
+
}
|
|
40097
|
+
var ACRONYMS2 = new Set([
|
|
40098
|
+
"CI",
|
|
40099
|
+
"PR",
|
|
40100
|
+
"API",
|
|
40101
|
+
"URL",
|
|
40102
|
+
"GPU",
|
|
40103
|
+
"CPU",
|
|
40104
|
+
"TTS",
|
|
40105
|
+
"STT",
|
|
40106
|
+
"HTTP",
|
|
40107
|
+
"JSON",
|
|
40108
|
+
"SQL",
|
|
40109
|
+
"UI"
|
|
40110
|
+
]);
|
|
40111
|
+
|
|
39803
40112
|
// tts-normalize.ts
|
|
39804
40113
|
var NULL = "\x00";
|
|
39805
40114
|
var INLINE_PH = `${NULL}TN_INLINE`;
|
|
@@ -39980,6 +40289,8 @@ function normalizeForTts(text) {
|
|
|
39980
40289
|
return text;
|
|
39981
40290
|
let s = text.replace(/\r\n?/g, `
|
|
39982
40291
|
`);
|
|
40292
|
+
s = decodeHtmlEntities2(s);
|
|
40293
|
+
s = stripBackslashEscapes2(s);
|
|
39983
40294
|
s = s.replace(/(^|\n)[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?\n[ \t]*\2[ \t]*(?=\n|$)/g, "$1code block omitted.");
|
|
39984
40295
|
s = s.replace(/(^|\n)[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*$/g, "$1code block omitted.");
|
|
39985
40296
|
const { parked, parts } = parkInline(s);
|
|
@@ -40819,6 +41130,141 @@ function forwardOriginDateIso(o) {
|
|
|
40819
41130
|
return new Date(o.date * 1000).toISOString();
|
|
40820
41131
|
}
|
|
40821
41132
|
|
|
41133
|
+
// gateway/rich-message-handler.ts
|
|
41134
|
+
var MAX_DEPTH = 32;
|
|
41135
|
+
function renderRichText(rt, depth = 0) {
|
|
41136
|
+
if (depth > MAX_DEPTH || rt == null)
|
|
41137
|
+
return "";
|
|
41138
|
+
if (typeof rt === "string")
|
|
41139
|
+
return rt;
|
|
41140
|
+
if (Array.isArray(rt))
|
|
41141
|
+
return rt.map((t) => renderRichText(t, depth + 1)).join("");
|
|
41142
|
+
if (typeof rt !== "object")
|
|
41143
|
+
return "";
|
|
41144
|
+
const node = rt;
|
|
41145
|
+
if (node.type === "custom_emoji")
|
|
41146
|
+
return node.alternative_text ?? "";
|
|
41147
|
+
if (node.type === "mathematical_expression") {
|
|
41148
|
+
return typeof node.expression === "string" ? node.expression : "";
|
|
41149
|
+
}
|
|
41150
|
+
if (node.type === "anchor")
|
|
41151
|
+
return "";
|
|
41152
|
+
if ("text" in node)
|
|
41153
|
+
return renderRichText(node.text, depth + 1);
|
|
41154
|
+
return "";
|
|
41155
|
+
}
|
|
41156
|
+
function renderCaption(caption, depth) {
|
|
41157
|
+
if (caption == null || typeof caption !== "object")
|
|
41158
|
+
return renderRichText(caption, depth);
|
|
41159
|
+
const c = caption;
|
|
41160
|
+
const text = renderRichText(c.text, depth);
|
|
41161
|
+
const credit = renderRichText(c.credit, depth);
|
|
41162
|
+
return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41163
|
+
}
|
|
41164
|
+
function renderBlocks(blocks, depth) {
|
|
41165
|
+
if (depth > MAX_DEPTH || !Array.isArray(blocks))
|
|
41166
|
+
return "";
|
|
41167
|
+
return blocks.map((b) => renderRichBlock(b, depth + 1)).filter((s) => s.length > 0).join(`
|
|
41168
|
+
`);
|
|
41169
|
+
}
|
|
41170
|
+
function renderRichBlock(block, depth = 0) {
|
|
41171
|
+
if (depth > MAX_DEPTH || block == null || typeof block !== "object")
|
|
41172
|
+
return "";
|
|
41173
|
+
const b = block;
|
|
41174
|
+
switch (b.type) {
|
|
41175
|
+
case "paragraph":
|
|
41176
|
+
case "heading":
|
|
41177
|
+
case "footer":
|
|
41178
|
+
return renderRichText(b.text, depth);
|
|
41179
|
+
case "pre": {
|
|
41180
|
+
const body = renderRichText(b.text, depth);
|
|
41181
|
+
return body.length > 0 ? `\`\`\`${b.language ?? ""}
|
|
41182
|
+
${body}
|
|
41183
|
+
\`\`\`` : "";
|
|
41184
|
+
}
|
|
41185
|
+
case "divider":
|
|
41186
|
+
return "---";
|
|
41187
|
+
case "mathematical_expression":
|
|
41188
|
+
return typeof b.expression === "string" ? b.expression : "";
|
|
41189
|
+
case "anchor":
|
|
41190
|
+
return "";
|
|
41191
|
+
case "list": {
|
|
41192
|
+
if (!Array.isArray(b.items))
|
|
41193
|
+
return "";
|
|
41194
|
+
return b.items.map((item) => {
|
|
41195
|
+
const body = renderBlocks(item?.blocks, depth);
|
|
41196
|
+
const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
|
|
41197
|
+
const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
|
|
41198
|
+
return body.length > 0 ? `${label} ${check}${body}` : "";
|
|
41199
|
+
}).filter((s) => s.length > 0).join(`
|
|
41200
|
+
`);
|
|
41201
|
+
}
|
|
41202
|
+
case "blockquote": {
|
|
41203
|
+
const body = renderBlocks(b.blocks, depth);
|
|
41204
|
+
const credit = renderRichText(b.credit, depth);
|
|
41205
|
+
const quoted = body.split(`
|
|
41206
|
+
`).map((line) => `> ${line}`).join(`
|
|
41207
|
+
`);
|
|
41208
|
+
return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
|
|
41209
|
+
`);
|
|
41210
|
+
}
|
|
41211
|
+
case "pullquote": {
|
|
41212
|
+
const body = renderRichText(b.text, depth);
|
|
41213
|
+
const credit = renderRichText(b.credit, depth);
|
|
41214
|
+
return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41215
|
+
}
|
|
41216
|
+
case "details": {
|
|
41217
|
+
const summary = renderRichText(b.summary, depth);
|
|
41218
|
+
const body = renderBlocks(b.blocks, depth);
|
|
41219
|
+
return [summary, body].filter((s) => s.length > 0).join(`
|
|
41220
|
+
`);
|
|
41221
|
+
}
|
|
41222
|
+
case "collage":
|
|
41223
|
+
case "slideshow": {
|
|
41224
|
+
const body = renderBlocks(b.blocks, depth);
|
|
41225
|
+
const caption = renderCaption(b.caption, depth);
|
|
41226
|
+
return [body, caption].filter((s) => s.length > 0).join(`
|
|
41227
|
+
`);
|
|
41228
|
+
}
|
|
41229
|
+
case "table": {
|
|
41230
|
+
if (!Array.isArray(b.cells))
|
|
41231
|
+
return "";
|
|
41232
|
+
const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
|
|
41233
|
+
`);
|
|
41234
|
+
const caption = renderRichText(b.caption, depth);
|
|
41235
|
+
return [caption, rows].filter((s) => s.length > 0).join(`
|
|
41236
|
+
`);
|
|
41237
|
+
}
|
|
41238
|
+
case "map":
|
|
41239
|
+
case "animation":
|
|
41240
|
+
case "audio":
|
|
41241
|
+
case "photo":
|
|
41242
|
+
case "video":
|
|
41243
|
+
case "voice_note": {
|
|
41244
|
+
const caption = renderCaption(b.caption, depth);
|
|
41245
|
+
const tag = `[${b.type}]`;
|
|
41246
|
+
return caption.length > 0 ? `${tag} ${caption}` : tag;
|
|
41247
|
+
}
|
|
41248
|
+
case "thinking":
|
|
41249
|
+
return "";
|
|
41250
|
+
default: {
|
|
41251
|
+
const text = renderRichText(b.text, depth);
|
|
41252
|
+
if (text.length > 0)
|
|
41253
|
+
return text;
|
|
41254
|
+
return renderBlocks(b.blocks, depth);
|
|
41255
|
+
}
|
|
41256
|
+
}
|
|
41257
|
+
}
|
|
41258
|
+
function extractRichMessageText(rich) {
|
|
41259
|
+
if (rich == null || typeof rich !== "object")
|
|
41260
|
+
return;
|
|
41261
|
+
const blocks = rich.blocks;
|
|
41262
|
+
const rendered = renderBlocks(blocks, 0).replace(/\n{3,}/g, `
|
|
41263
|
+
|
|
41264
|
+
`).trim();
|
|
41265
|
+
return rendered.length > 0 ? rendered : undefined;
|
|
41266
|
+
}
|
|
41267
|
+
|
|
40822
41268
|
// gateway/unhandled-message.ts
|
|
40823
41269
|
var MESSAGE_ENVELOPE_KEYS = new Set([
|
|
40824
41270
|
"message_id",
|
|
@@ -40847,7 +41293,13 @@ var MESSAGE_ENVELOPE_KEYS = new Set([
|
|
|
40847
41293
|
"show_caption_above_media",
|
|
40848
41294
|
"entities",
|
|
40849
41295
|
"caption_entities",
|
|
40850
|
-
"paid_star_count"
|
|
41296
|
+
"paid_star_count",
|
|
41297
|
+
"forward_from",
|
|
41298
|
+
"forward_from_chat",
|
|
41299
|
+
"forward_from_message_id",
|
|
41300
|
+
"forward_signature",
|
|
41301
|
+
"forward_sender_name",
|
|
41302
|
+
"forward_date"
|
|
40851
41303
|
]);
|
|
40852
41304
|
var SERVICE_NOISE_KEYS = new Set([
|
|
40853
41305
|
"new_chat_members",
|
|
@@ -40892,7 +41344,7 @@ function planUnhandledMessage(msg) {
|
|
|
40892
41344
|
return { action: "log-only", contentKeys };
|
|
40893
41345
|
}
|
|
40894
41346
|
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})`;
|
|
41347
|
+
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
41348
|
return { action: "turn", text, contentKeys };
|
|
40897
41349
|
}
|
|
40898
41350
|
var TAP_MAX_LINES_PER_MINUTE = 300;
|
|
@@ -41091,6 +41543,153 @@ async function handlePassportDataMessage(ctx, deps) {
|
|
|
41091
41543
|
await deps.handleRefusal(ctx, "passport_data", PASSPORT_REFUSAL_TEXT);
|
|
41092
41544
|
}
|
|
41093
41545
|
|
|
41546
|
+
// gateway/rich-message-handler.ts
|
|
41547
|
+
var RICH_MESSAGE_EMPTY_TEXT = "(rich message with no extractable text)";
|
|
41548
|
+
var MAX_DEPTH2 = 32;
|
|
41549
|
+
function renderRichText2(rt, depth = 0) {
|
|
41550
|
+
if (depth > MAX_DEPTH2 || rt == null)
|
|
41551
|
+
return "";
|
|
41552
|
+
if (typeof rt === "string")
|
|
41553
|
+
return rt;
|
|
41554
|
+
if (Array.isArray(rt))
|
|
41555
|
+
return rt.map((t) => renderRichText2(t, depth + 1)).join("");
|
|
41556
|
+
if (typeof rt !== "object")
|
|
41557
|
+
return "";
|
|
41558
|
+
const node = rt;
|
|
41559
|
+
if (node.type === "custom_emoji")
|
|
41560
|
+
return node.alternative_text ?? "";
|
|
41561
|
+
if (node.type === "mathematical_expression") {
|
|
41562
|
+
return typeof node.expression === "string" ? node.expression : "";
|
|
41563
|
+
}
|
|
41564
|
+
if (node.type === "anchor")
|
|
41565
|
+
return "";
|
|
41566
|
+
if ("text" in node)
|
|
41567
|
+
return renderRichText2(node.text, depth + 1);
|
|
41568
|
+
return "";
|
|
41569
|
+
}
|
|
41570
|
+
function renderCaption2(caption, depth) {
|
|
41571
|
+
if (caption == null || typeof caption !== "object")
|
|
41572
|
+
return renderRichText2(caption, depth);
|
|
41573
|
+
const c = caption;
|
|
41574
|
+
const text = renderRichText2(c.text, depth);
|
|
41575
|
+
const credit = renderRichText2(c.credit, depth);
|
|
41576
|
+
return [text, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41577
|
+
}
|
|
41578
|
+
function renderBlocks2(blocks, depth) {
|
|
41579
|
+
if (depth > MAX_DEPTH2 || !Array.isArray(blocks))
|
|
41580
|
+
return "";
|
|
41581
|
+
return blocks.map((b) => renderRichBlock2(b, depth + 1)).filter((s) => s.length > 0).join(`
|
|
41582
|
+
`);
|
|
41583
|
+
}
|
|
41584
|
+
function renderRichBlock2(block, depth = 0) {
|
|
41585
|
+
if (depth > MAX_DEPTH2 || block == null || typeof block !== "object")
|
|
41586
|
+
return "";
|
|
41587
|
+
const b = block;
|
|
41588
|
+
switch (b.type) {
|
|
41589
|
+
case "paragraph":
|
|
41590
|
+
case "heading":
|
|
41591
|
+
case "footer":
|
|
41592
|
+
return renderRichText2(b.text, depth);
|
|
41593
|
+
case "pre": {
|
|
41594
|
+
const body = renderRichText2(b.text, depth);
|
|
41595
|
+
return body.length > 0 ? `\`\`\`${b.language ?? ""}
|
|
41596
|
+
${body}
|
|
41597
|
+
\`\`\`` : "";
|
|
41598
|
+
}
|
|
41599
|
+
case "divider":
|
|
41600
|
+
return "---";
|
|
41601
|
+
case "mathematical_expression":
|
|
41602
|
+
return typeof b.expression === "string" ? b.expression : "";
|
|
41603
|
+
case "anchor":
|
|
41604
|
+
return "";
|
|
41605
|
+
case "list": {
|
|
41606
|
+
if (!Array.isArray(b.items))
|
|
41607
|
+
return "";
|
|
41608
|
+
return b.items.map((item) => {
|
|
41609
|
+
const body = renderBlocks2(item?.blocks, depth);
|
|
41610
|
+
const check = item?.has_checkbox ? item.is_checked ? "[x] " : "[ ] " : "";
|
|
41611
|
+
const label = typeof item?.label === "string" && item.label.length > 0 ? item.label : "-";
|
|
41612
|
+
return body.length > 0 ? `${label} ${check}${body}` : "";
|
|
41613
|
+
}).filter((s) => s.length > 0).join(`
|
|
41614
|
+
`);
|
|
41615
|
+
}
|
|
41616
|
+
case "blockquote": {
|
|
41617
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41618
|
+
const credit = renderRichText2(b.credit, depth);
|
|
41619
|
+
const quoted = body.split(`
|
|
41620
|
+
`).map((line) => `> ${line}`).join(`
|
|
41621
|
+
`);
|
|
41622
|
+
return [quoted, credit ? `> \u2014 ${credit}` : ""].filter((s) => s.length > 0).join(`
|
|
41623
|
+
`);
|
|
41624
|
+
}
|
|
41625
|
+
case "pullquote": {
|
|
41626
|
+
const body = renderRichText2(b.text, depth);
|
|
41627
|
+
const credit = renderRichText2(b.credit, depth);
|
|
41628
|
+
return [body, credit ? `\u2014 ${credit}` : ""].filter(Boolean).join(" ");
|
|
41629
|
+
}
|
|
41630
|
+
case "details": {
|
|
41631
|
+
const summary = renderRichText2(b.summary, depth);
|
|
41632
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41633
|
+
return [summary, body].filter((s) => s.length > 0).join(`
|
|
41634
|
+
`);
|
|
41635
|
+
}
|
|
41636
|
+
case "collage":
|
|
41637
|
+
case "slideshow": {
|
|
41638
|
+
const body = renderBlocks2(b.blocks, depth);
|
|
41639
|
+
const caption = renderCaption2(b.caption, depth);
|
|
41640
|
+
return [body, caption].filter((s) => s.length > 0).join(`
|
|
41641
|
+
`);
|
|
41642
|
+
}
|
|
41643
|
+
case "table": {
|
|
41644
|
+
if (!Array.isArray(b.cells))
|
|
41645
|
+
return "";
|
|
41646
|
+
const rows = b.cells.map((row) => Array.isArray(row) ? row.map((cell) => renderRichText2(cell?.text, depth)).join(" | ") : "").filter((s) => s.length > 0).join(`
|
|
41647
|
+
`);
|
|
41648
|
+
const caption = renderRichText2(b.caption, depth);
|
|
41649
|
+
return [caption, rows].filter((s) => s.length > 0).join(`
|
|
41650
|
+
`);
|
|
41651
|
+
}
|
|
41652
|
+
case "map":
|
|
41653
|
+
case "animation":
|
|
41654
|
+
case "audio":
|
|
41655
|
+
case "photo":
|
|
41656
|
+
case "video":
|
|
41657
|
+
case "voice_note": {
|
|
41658
|
+
const caption = renderCaption2(b.caption, depth);
|
|
41659
|
+
const tag = `[${b.type}]`;
|
|
41660
|
+
return caption.length > 0 ? `${tag} ${caption}` : tag;
|
|
41661
|
+
}
|
|
41662
|
+
case "thinking":
|
|
41663
|
+
return "";
|
|
41664
|
+
default: {
|
|
41665
|
+
const text = renderRichText2(b.text, depth);
|
|
41666
|
+
if (text.length > 0)
|
|
41667
|
+
return text;
|
|
41668
|
+
return renderBlocks2(b.blocks, depth);
|
|
41669
|
+
}
|
|
41670
|
+
}
|
|
41671
|
+
}
|
|
41672
|
+
function extractRichMessageText2(rich) {
|
|
41673
|
+
if (rich == null || typeof rich !== "object")
|
|
41674
|
+
return;
|
|
41675
|
+
const blocks = rich.blocks;
|
|
41676
|
+
const rendered = renderBlocks2(blocks, 0).replace(/\n{3,}/g, `
|
|
41677
|
+
|
|
41678
|
+
`).trim();
|
|
41679
|
+
return rendered.length > 0 ? rendered : undefined;
|
|
41680
|
+
}
|
|
41681
|
+
async function handleRichMessageMessage(ctx, deps) {
|
|
41682
|
+
try {
|
|
41683
|
+
const text = extractRichMessageText2(ctx.message.rich_message) ?? RICH_MESSAGE_EMPTY_TEXT;
|
|
41684
|
+
deps.log(`telegram gateway: inbound rich_message from chat=${ctx.chat?.id ?? "?"} chars=${text.length}
|
|
41685
|
+
`);
|
|
41686
|
+
await deps.handleInbound(ctx, text, undefined);
|
|
41687
|
+
} catch (err) {
|
|
41688
|
+
deps.log(`telegram gateway: rich_message handler error: ${err.message}
|
|
41689
|
+
`);
|
|
41690
|
+
}
|
|
41691
|
+
}
|
|
41692
|
+
|
|
41094
41693
|
// gateway/stop-command.ts
|
|
41095
41694
|
function parseStopKeyword2(text) {
|
|
41096
41695
|
return /^stop[.!]?$/i.test(text.trim());
|
|
@@ -42712,6 +43311,8 @@ function buildForwardOriginMeta(origins) {
|
|
|
42712
43311
|
if (o.date != null) {
|
|
42713
43312
|
out[`forwarded_date${suffix}`] = fmtLocalStamp(o.date * 1000, resolveEnvTimezone());
|
|
42714
43313
|
}
|
|
43314
|
+
if (o.messageId != null)
|
|
43315
|
+
out[`forwarded_message_id${suffix}`] = String(o.messageId);
|
|
42715
43316
|
});
|
|
42716
43317
|
return out;
|
|
42717
43318
|
}
|
|
@@ -43339,7 +43940,7 @@ async function handleAnimationMessage(ctx, deps) {
|
|
|
43339
43940
|
}
|
|
43340
43941
|
|
|
43341
43942
|
// gateway/photo-message-handler.ts
|
|
43342
|
-
import { mkdirSync as
|
|
43943
|
+
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync6 } from "node:fs";
|
|
43343
43944
|
|
|
43344
43945
|
// attachment-path.ts
|
|
43345
43946
|
import { join as join4, basename as basename3, resolve as resolve2, sep } from "node:path";
|
|
@@ -43400,9 +44001,9 @@ async function handlePhotoMessage(ctx, deps) {
|
|
|
43400
44001
|
fileUniqueId: best.file_unique_id,
|
|
43401
44002
|
now: Date.now()
|
|
43402
44003
|
});
|
|
43403
|
-
|
|
44004
|
+
mkdirSync7(deps.inboxDir, { recursive: true, mode: 448 });
|
|
43404
44005
|
assertInsideInbox(deps.inboxDir, dlPath);
|
|
43405
|
-
|
|
44006
|
+
writeFileSync6(dlPath, buf, { mode: 384 });
|
|
43406
44007
|
return dlPath;
|
|
43407
44008
|
} catch (err) {
|
|
43408
44009
|
const msg = err instanceof Error ? err.message : "unknown error";
|
|
@@ -44470,165 +45071,6 @@ async function handleAskCallback(ctx, data, deps) {
|
|
|
44470
45071
|
// gateway/voice-ondemand-callback-handler.ts
|
|
44471
45072
|
import { readFileSync as readFileSync8 } from "node:fs";
|
|
44472
45073
|
|
|
44473
|
-
// voice-ondemand.ts
|
|
44474
|
-
import { randomBytes as randomBytes2 } from "crypto";
|
|
44475
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync6, renameSync as renameSync5, mkdirSync as mkdirSync7 } from "fs";
|
|
44476
|
-
import { dirname as dirname3 } from "path";
|
|
44477
|
-
var VOICE_ONDEMAND_CALLBACK_PREFIX = "voice:";
|
|
44478
|
-
var VOICE_ONDEMAND_TTL_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
44479
|
-
var VOICE_ONDEMAND_MAX_ENTRIES2 = 500;
|
|
44480
|
-
|
|
44481
|
-
class VoiceOnDemandCache2 {
|
|
44482
|
-
store = new Map;
|
|
44483
|
-
ttlMs;
|
|
44484
|
-
maxEntries;
|
|
44485
|
-
now;
|
|
44486
|
-
persistPath;
|
|
44487
|
-
constructor(options = {}) {
|
|
44488
|
-
this.ttlMs = options.ttlMs ?? VOICE_ONDEMAND_TTL_MS2;
|
|
44489
|
-
this.maxEntries = options.maxEntries ?? VOICE_ONDEMAND_MAX_ENTRIES2;
|
|
44490
|
-
this.now = options.now ?? Date.now;
|
|
44491
|
-
this.persistPath = options.persistPath;
|
|
44492
|
-
if (this.persistPath !== undefined)
|
|
44493
|
-
this.load();
|
|
44494
|
-
}
|
|
44495
|
-
put(token, payload) {
|
|
44496
|
-
this.store.delete(token);
|
|
44497
|
-
this.store.set(token, {
|
|
44498
|
-
createdAt: this.now(),
|
|
44499
|
-
...payload,
|
|
44500
|
-
expiresAt: this.now() + this.ttlMs
|
|
44501
|
-
});
|
|
44502
|
-
while (this.store.size > this.maxEntries) {
|
|
44503
|
-
const oldest = this.store.keys().next().value;
|
|
44504
|
-
if (oldest === undefined)
|
|
44505
|
-
break;
|
|
44506
|
-
this.store.delete(oldest);
|
|
44507
|
-
}
|
|
44508
|
-
this.flush();
|
|
44509
|
-
}
|
|
44510
|
-
get(token) {
|
|
44511
|
-
const entry = this.store.get(token);
|
|
44512
|
-
if (entry == null)
|
|
44513
|
-
return null;
|
|
44514
|
-
if (entry.expiresAt <= this.now()) {
|
|
44515
|
-
this.store.delete(token);
|
|
44516
|
-
this.flush();
|
|
44517
|
-
return null;
|
|
44518
|
-
}
|
|
44519
|
-
const { text, voice, speed, filePath, telegramFileId } = entry;
|
|
44520
|
-
return {
|
|
44521
|
-
text,
|
|
44522
|
-
speed,
|
|
44523
|
-
...voice !== undefined ? { voice } : {},
|
|
44524
|
-
...filePath !== undefined ? { filePath } : {},
|
|
44525
|
-
...telegramFileId !== undefined ? { telegramFileId } : {}
|
|
44526
|
-
};
|
|
44527
|
-
}
|
|
44528
|
-
setFilePath(token, filePath) {
|
|
44529
|
-
const entry = this.store.get(token);
|
|
44530
|
-
if (entry == null || entry.expiresAt <= this.now())
|
|
44531
|
-
return;
|
|
44532
|
-
entry.filePath = filePath;
|
|
44533
|
-
this.flush();
|
|
44534
|
-
}
|
|
44535
|
-
setTelegramFileId(token, fileId) {
|
|
44536
|
-
if (fileId.length === 0)
|
|
44537
|
-
return;
|
|
44538
|
-
const entry = this.store.get(token);
|
|
44539
|
-
if (entry == null || entry.expiresAt <= this.now())
|
|
44540
|
-
return;
|
|
44541
|
-
entry.telegramFileId = fileId;
|
|
44542
|
-
this.flush();
|
|
44543
|
-
}
|
|
44544
|
-
prune(tokens) {
|
|
44545
|
-
let changed = false;
|
|
44546
|
-
for (const token of tokens) {
|
|
44547
|
-
if (this.store.delete(token))
|
|
44548
|
-
changed = true;
|
|
44549
|
-
}
|
|
44550
|
-
if (changed)
|
|
44551
|
-
this.flush();
|
|
44552
|
-
}
|
|
44553
|
-
get size() {
|
|
44554
|
-
return this.store.size;
|
|
44555
|
-
}
|
|
44556
|
-
load() {
|
|
44557
|
-
if (this.persistPath === undefined)
|
|
44558
|
-
return;
|
|
44559
|
-
let raw;
|
|
44560
|
-
try {
|
|
44561
|
-
raw = readFileSync4(this.persistPath, "utf8");
|
|
44562
|
-
} catch {
|
|
44563
|
-
return;
|
|
44564
|
-
}
|
|
44565
|
-
try {
|
|
44566
|
-
const parsed = JSON.parse(raw);
|
|
44567
|
-
if (parsed == null || parsed.version !== 1 || typeof parsed.entries !== "object")
|
|
44568
|
-
return;
|
|
44569
|
-
const nowMs = this.now();
|
|
44570
|
-
for (const [token, entry] of Object.entries(parsed.entries)) {
|
|
44571
|
-
if (entry == null || typeof entry.expiresAt !== "number" || typeof entry.text !== "string" || typeof entry.speed !== "number") {
|
|
44572
|
-
continue;
|
|
44573
|
-
}
|
|
44574
|
-
if (entry.expiresAt <= nowMs)
|
|
44575
|
-
continue;
|
|
44576
|
-
this.store.set(token, entry);
|
|
44577
|
-
}
|
|
44578
|
-
while (this.store.size > this.maxEntries) {
|
|
44579
|
-
const oldest = this.store.keys().next().value;
|
|
44580
|
-
if (oldest === undefined)
|
|
44581
|
-
break;
|
|
44582
|
-
this.store.delete(oldest);
|
|
44583
|
-
}
|
|
44584
|
-
} catch (err) {
|
|
44585
|
-
process.stderr.write(`voice-ondemand: failed to parse persisted cache ${this.persistPath}: ${String(err)}
|
|
44586
|
-
`);
|
|
44587
|
-
}
|
|
44588
|
-
}
|
|
44589
|
-
flush() {
|
|
44590
|
-
if (this.persistPath === undefined)
|
|
44591
|
-
return;
|
|
44592
|
-
const doc = {
|
|
44593
|
-
version: 1,
|
|
44594
|
-
entries: Object.fromEntries(this.store)
|
|
44595
|
-
};
|
|
44596
|
-
const tmp = `${this.persistPath}.tmp`;
|
|
44597
|
-
try {
|
|
44598
|
-
mkdirSync7(dirname3(this.persistPath), { recursive: true });
|
|
44599
|
-
writeFileSync6(tmp, JSON.stringify(doc), "utf8");
|
|
44600
|
-
renameSync5(tmp, this.persistPath);
|
|
44601
|
-
} catch (err) {
|
|
44602
|
-
process.stderr.write(`voice-ondemand: failed to persist cache ${this.persistPath}: ${String(err)}
|
|
44603
|
-
`);
|
|
44604
|
-
}
|
|
44605
|
-
}
|
|
44606
|
-
}
|
|
44607
|
-
function mintVoiceOnDemandToken() {
|
|
44608
|
-
return randomBytes2(4).toString("hex");
|
|
44609
|
-
}
|
|
44610
|
-
function isVoiceOnDemandCallback(data) {
|
|
44611
|
-
return data.startsWith(VOICE_ONDEMAND_CALLBACK_PREFIX);
|
|
44612
|
-
}
|
|
44613
|
-
function parseVoiceOnDemandToken(data) {
|
|
44614
|
-
if (!isVoiceOnDemandCallback(data))
|
|
44615
|
-
return null;
|
|
44616
|
-
const token = data.slice(VOICE_ONDEMAND_CALLBACK_PREFIX.length);
|
|
44617
|
-
return token.length > 0 ? token : null;
|
|
44618
|
-
}
|
|
44619
|
-
function buildListenKeyboard(token) {
|
|
44620
|
-
return {
|
|
44621
|
-
inline_keyboard: [
|
|
44622
|
-
[{ text: "\uD83D\uDD0A Listen", callback_data: `${VOICE_ONDEMAND_CALLBACK_PREFIX}${token}` }]
|
|
44623
|
-
]
|
|
44624
|
-
};
|
|
44625
|
-
}
|
|
44626
|
-
function mayInjectListenButton(rawKeyboard) {
|
|
44627
|
-
if (rawKeyboard == null)
|
|
44628
|
-
return true;
|
|
44629
|
-
return !rawKeyboard.some((row) => Array.isArray(row) && row.length > 0);
|
|
44630
|
-
}
|
|
44631
|
-
|
|
44632
45074
|
// voice-send.ts
|
|
44633
45075
|
function extractVoiceFileId(sent) {
|
|
44634
45076
|
const id = sent?.voice?.file_id;
|
|
@@ -44941,6 +45383,8 @@ function normalizeForTts2(text) {
|
|
|
44941
45383
|
return text;
|
|
44942
45384
|
let s = text.replace(/\r\n?/g, `
|
|
44943
45385
|
`);
|
|
45386
|
+
s = decodeHtmlEntities2(s);
|
|
45387
|
+
s = stripBackslashEscapes2(s);
|
|
44944
45388
|
s = s.replace(/(^|\n)[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?\n[ \t]*\2[ \t]*(?=\n|$)/g, "$1code block omitted.");
|
|
44945
45389
|
s = s.replace(/(^|\n)[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*$/g, "$1code block omitted.");
|
|
44946
45390
|
const { parked, parts } = parkInline2(s);
|
|
@@ -51276,202 +51720,6 @@ function createSessionModelSource(options = {}) {
|
|
|
51276
51720
|
};
|
|
51277
51721
|
}
|
|
51278
51722
|
|
|
51279
|
-
// tool-labels.ts
|
|
51280
|
-
var MAX_LABEL_CHARS = 60;
|
|
51281
|
-
var MAX_BASH_CHARS = 40;
|
|
51282
|
-
var MAX_DESCRIPTION_CHARS = 160;
|
|
51283
|
-
function basename6(p) {
|
|
51284
|
-
if (!p)
|
|
51285
|
-
return "";
|
|
51286
|
-
const parts = p.split("/").filter(Boolean);
|
|
51287
|
-
return parts.length > 0 ? parts[parts.length - 1] : p;
|
|
51288
|
-
}
|
|
51289
|
-
function shortenGrepPath(p) {
|
|
51290
|
-
if (!p)
|
|
51291
|
-
return "repo";
|
|
51292
|
-
const hadTrailingSlash = /\/+$/.test(p);
|
|
51293
|
-
const trimmed = p.replace(/\/+$/, "");
|
|
51294
|
-
const parts = trimmed.split("/").filter(Boolean);
|
|
51295
|
-
if (parts.length === 0)
|
|
51296
|
-
return "repo";
|
|
51297
|
-
const last = parts[parts.length - 1];
|
|
51298
|
-
if (hadTrailingSlash)
|
|
51299
|
-
return `${last}/`;
|
|
51300
|
-
if (last.startsWith(".") && !last.slice(1).includes("."))
|
|
51301
|
-
return last;
|
|
51302
|
-
if (!last.includes("."))
|
|
51303
|
-
return `${last}/`;
|
|
51304
|
-
return last;
|
|
51305
|
-
}
|
|
51306
|
-
function hostFromUrl(u) {
|
|
51307
|
-
if (!u)
|
|
51308
|
-
return "";
|
|
51309
|
-
try {
|
|
51310
|
-
return new URL(u).host;
|
|
51311
|
-
} catch {
|
|
51312
|
-
return truncate3(u);
|
|
51313
|
-
}
|
|
51314
|
-
}
|
|
51315
|
-
function truncate3(s, n = MAX_LABEL_CHARS) {
|
|
51316
|
-
if (s.length <= n)
|
|
51317
|
-
return s;
|
|
51318
|
-
return s.slice(0, n - 1) + "\u2026";
|
|
51319
|
-
}
|
|
51320
|
-
function stripHtml(s) {
|
|
51321
|
-
return s.replace(/<\/?[a-zA-Z][^>]*>/g, "");
|
|
51322
|
-
}
|
|
51323
|
-
function firstLine(s) {
|
|
51324
|
-
const idx = s.indexOf(`
|
|
51325
|
-
`);
|
|
51326
|
-
return idx === -1 ? s : s.slice(0, idx);
|
|
51327
|
-
}
|
|
51328
|
-
function toolLabel(tool, input, preamble, precomputedLabel) {
|
|
51329
|
-
if (precomputedLabel && precomputedLabel.trim().length > 0) {
|
|
51330
|
-
return truncate3(firstLine(precomputedLabel.trim()), MAX_DESCRIPTION_CHARS);
|
|
51331
|
-
}
|
|
51332
|
-
if (!input || typeof input !== "object")
|
|
51333
|
-
return "";
|
|
51334
|
-
const str = (k) => typeof input[k] === "string" ? input[k] : undefined;
|
|
51335
|
-
const preambleLabel = () => {
|
|
51336
|
-
if (!preamble)
|
|
51337
|
-
return null;
|
|
51338
|
-
if (preamble.includes(`
|
|
51339
|
-
`))
|
|
51340
|
-
return null;
|
|
51341
|
-
const trimmed = preamble.trim();
|
|
51342
|
-
if (!trimmed)
|
|
51343
|
-
return null;
|
|
51344
|
-
if (trimmed.length > MAX_DESCRIPTION_CHARS)
|
|
51345
|
-
return null;
|
|
51346
|
-
return trimmed;
|
|
51347
|
-
};
|
|
51348
|
-
switch (tool) {
|
|
51349
|
-
case "Read":
|
|
51350
|
-
case "Write":
|
|
51351
|
-
case "NotebookEdit":
|
|
51352
|
-
case "Edit": {
|
|
51353
|
-
const pre = preambleLabel();
|
|
51354
|
-
if (pre)
|
|
51355
|
-
return pre;
|
|
51356
|
-
return truncate3(basename6(str("file_path") ?? ""));
|
|
51357
|
-
}
|
|
51358
|
-
case "Bash":
|
|
51359
|
-
case "BashOutput": {
|
|
51360
|
-
const description = str("description");
|
|
51361
|
-
if (description)
|
|
51362
|
-
return truncate3(firstLine(description), MAX_DESCRIPTION_CHARS);
|
|
51363
|
-
const pre = preambleLabel();
|
|
51364
|
-
if (pre)
|
|
51365
|
-
return pre;
|
|
51366
|
-
const cmd = str("command") ?? str("bash_id") ?? "";
|
|
51367
|
-
return truncate3(firstLine(cmd), MAX_BASH_CHARS);
|
|
51368
|
-
}
|
|
51369
|
-
case "KillShell":
|
|
51370
|
-
return truncate3(str("shell_id") ?? "");
|
|
51371
|
-
case "Glob": {
|
|
51372
|
-
const pre = preambleLabel();
|
|
51373
|
-
if (pre)
|
|
51374
|
-
return pre;
|
|
51375
|
-
return truncate3(str("pattern") ?? "");
|
|
51376
|
-
}
|
|
51377
|
-
case "Grep": {
|
|
51378
|
-
const pre = preambleLabel();
|
|
51379
|
-
if (pre)
|
|
51380
|
-
return pre;
|
|
51381
|
-
const pat = str("pattern") ?? "";
|
|
51382
|
-
if (!pat)
|
|
51383
|
-
return "";
|
|
51384
|
-
const path = str("path");
|
|
51385
|
-
const where = shortenGrepPath(path ?? "");
|
|
51386
|
-
return truncate3(`"${pat}" (in ${where})`);
|
|
51387
|
-
}
|
|
51388
|
-
case "WebFetch":
|
|
51389
|
-
return truncate3(hostFromUrl(str("url") ?? ""));
|
|
51390
|
-
case "WebSearch": {
|
|
51391
|
-
const q = str("query") ?? "";
|
|
51392
|
-
return q ? truncate3(`"${q}"`) : "";
|
|
51393
|
-
}
|
|
51394
|
-
case "Task":
|
|
51395
|
-
case "Agent": {
|
|
51396
|
-
const desc = str("description") ?? str("subagent_type") ?? "";
|
|
51397
|
-
return truncate3(desc);
|
|
51398
|
-
}
|
|
51399
|
-
case "TodoWrite":
|
|
51400
|
-
case "TaskCreate":
|
|
51401
|
-
case "TaskUpdate":
|
|
51402
|
-
case "TaskList":
|
|
51403
|
-
case "TaskGet":
|
|
51404
|
-
case "TaskStop":
|
|
51405
|
-
case "TaskOutput":
|
|
51406
|
-
return "";
|
|
51407
|
-
case "Skill":
|
|
51408
|
-
return truncate3(str("skill") ?? "");
|
|
51409
|
-
case "SlashCommand":
|
|
51410
|
-
return truncate3(str("command") ?? "");
|
|
51411
|
-
case "ToolSearch": {
|
|
51412
|
-
const q = str("query") ?? "";
|
|
51413
|
-
if (!q)
|
|
51414
|
-
return "";
|
|
51415
|
-
const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i);
|
|
51416
|
-
if (selectMatch) {
|
|
51417
|
-
const names = selectMatch[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0).join(", ");
|
|
51418
|
-
return truncate3(`Loading schema: ${names}`);
|
|
51419
|
-
}
|
|
51420
|
-
return truncate3(`Searching tools: ${q}`);
|
|
51421
|
-
}
|
|
51422
|
-
default:
|
|
51423
|
-
if (tool.startsWith("mcp__")) {
|
|
51424
|
-
const description = str("description");
|
|
51425
|
-
if (description)
|
|
51426
|
-
return truncate3(firstLine(stripHtml(description)), MAX_DESCRIPTION_CHARS);
|
|
51427
|
-
const label = mcpBaseLabel(tool);
|
|
51428
|
-
const query = str("query") ?? str("text") ?? str("name");
|
|
51429
|
-
if (label && query) {
|
|
51430
|
-
const budget = Math.max(8, MAX_LABEL_CHARS - label.length - 4);
|
|
51431
|
-
const preview = truncate3(firstLine(stripHtml(query)), budget);
|
|
51432
|
-
return `${label} (${preview})`;
|
|
51433
|
-
}
|
|
51434
|
-
if (label)
|
|
51435
|
-
return truncate3(label);
|
|
51436
|
-
}
|
|
51437
|
-
for (const k of ["description", "file_path", "path", "url", "query", "pattern", "command"]) {
|
|
51438
|
-
const v = str(k);
|
|
51439
|
-
if (v != null && v.length > 0) {
|
|
51440
|
-
if (k === "file_path" || k === "path")
|
|
51441
|
-
return truncate3(basename6(v));
|
|
51442
|
-
if (k === "url")
|
|
51443
|
-
return truncate3(hostFromUrl(v));
|
|
51444
|
-
if (k === "description")
|
|
51445
|
-
return truncate3(firstLine(v), MAX_DESCRIPTION_CHARS);
|
|
51446
|
-
return truncate3(firstLine(v));
|
|
51447
|
-
}
|
|
51448
|
-
}
|
|
51449
|
-
return "";
|
|
51450
|
-
}
|
|
51451
|
-
}
|
|
51452
|
-
function mcpBaseLabel(tool) {
|
|
51453
|
-
if (!tool.startsWith("mcp__"))
|
|
51454
|
-
return "";
|
|
51455
|
-
const parts = tool.slice("mcp__".length).split("__");
|
|
51456
|
-
if (parts.length < 2)
|
|
51457
|
-
return "";
|
|
51458
|
-
const rawServer = parts[0];
|
|
51459
|
-
const action = parts.slice(1).join("__");
|
|
51460
|
-
if (!rawServer || !action)
|
|
51461
|
-
return "";
|
|
51462
|
-
return `${prettifyServer(rawServer)}: ${action}`;
|
|
51463
|
-
}
|
|
51464
|
-
function prettifyServer(name) {
|
|
51465
|
-
const LABELS = {
|
|
51466
|
-
"switchroom-telegram": "Telegram"
|
|
51467
|
-
};
|
|
51468
|
-
if (LABELS[name])
|
|
51469
|
-
return LABELS[name];
|
|
51470
|
-
if (!name)
|
|
51471
|
-
return name;
|
|
51472
|
-
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
51473
|
-
}
|
|
51474
|
-
|
|
51475
51723
|
// typing-wrap.ts
|
|
51476
51724
|
function createTypingWrapper(deps) {
|
|
51477
51725
|
const debounceMs = deps.debounceMs ?? 500;
|
|
@@ -61243,7 +61491,7 @@ function prefixLines(text4, prefix) {
|
|
|
61243
61491
|
`);
|
|
61244
61492
|
}
|
|
61245
61493
|
function renderBlockquote(node2) {
|
|
61246
|
-
const inner =
|
|
61494
|
+
const inner = renderBlocks3(node2.children);
|
|
61247
61495
|
if (node2.expandable) {
|
|
61248
61496
|
const lines = inner.split(`
|
|
61249
61497
|
`);
|
|
@@ -61339,7 +61587,7 @@ function renderBlock(node2) {
|
|
|
61339
61587
|
function renderBlocksJoined(blocks, sep2) {
|
|
61340
61588
|
return blocks.map(renderBlock).join(sep2);
|
|
61341
61589
|
}
|
|
61342
|
-
function
|
|
61590
|
+
function renderBlocks3(blocks) {
|
|
61343
61591
|
return renderBlocksJoined(blocks, `
|
|
61344
61592
|
|
|
61345
61593
|
`);
|
|
@@ -62963,7 +63211,7 @@ function loadInitialFloodWindows(floodStateFilePath, floodWindowsFilePath, now)
|
|
|
62963
63211
|
}
|
|
62964
63212
|
|
|
62965
63213
|
// attachment-path.ts
|
|
62966
|
-
import { join as join17, basename as
|
|
63214
|
+
import { join as join17, basename as basename6, resolve as resolve6, sep as sep2 } from "node:path";
|
|
62967
63215
|
function sanitizeExtension2(ext) {
|
|
62968
63216
|
if (ext == null)
|
|
62969
63217
|
return "bin";
|
|
@@ -62992,7 +63240,7 @@ function assertInsideInbox2(inboxDir, candidatePath) {
|
|
|
62992
63240
|
const inboxReal = resolve6(inboxDir);
|
|
62993
63241
|
const candidateReal = resolve6(candidatePath);
|
|
62994
63242
|
if (candidateReal !== inboxReal && !candidateReal.startsWith(inboxReal + sep2)) {
|
|
62995
|
-
throw new Error(`attachment path escape: ${
|
|
63243
|
+
throw new Error(`attachment path escape: ${basename6(candidatePath)} resolved outside ${inboxDir}`);
|
|
62996
63244
|
}
|
|
62997
63245
|
}
|
|
62998
63246
|
|
|
@@ -67805,6 +68053,8 @@ __export(exports_silence_poke, {
|
|
|
67805
68053
|
noteThinking: () => noteThinking,
|
|
67806
68054
|
noteProduction: () => noteProduction,
|
|
67807
68055
|
noteOutbound: () => noteOutbound2,
|
|
68056
|
+
noteBackgroundShellDead: () => noteBackgroundShellDead,
|
|
68057
|
+
noteBackgroundShellAlive: () => noteBackgroundShellAlive,
|
|
67808
68058
|
longestInFlightTool: () => longestInFlightTool,
|
|
67809
68059
|
formatFrameworkFallbackText: () => formatFrameworkFallbackText,
|
|
67810
68060
|
endTurn: () => endTurn,
|
|
@@ -67812,6 +68062,7 @@ __export(exports_silence_poke, {
|
|
|
67812
68062
|
__setDepsForTests: () => __setDepsForTests,
|
|
67813
68063
|
__resetAllForTests: () => __resetAllForTests2,
|
|
67814
68064
|
__getStateForTests: () => __getStateForTests,
|
|
68065
|
+
__bgMarkerParserConfirmedForTests: () => __bgMarkerParserConfirmedForTests,
|
|
67815
68066
|
DEFAULT_THRESHOLDS: () => DEFAULT_THRESHOLDS,
|
|
67816
68067
|
DEFAULT_POLL_INTERVAL_MS: () => DEFAULT_POLL_INTERVAL_MS
|
|
67817
68068
|
});
|
|
@@ -67882,6 +68133,7 @@ var DEFAULT_POLL_INTERVAL_MS = 5000;
|
|
|
67882
68133
|
var state2 = new Map;
|
|
67883
68134
|
var timer = null;
|
|
67884
68135
|
var activeDeps = null;
|
|
68136
|
+
var bgMarkerParserConfirmed = false;
|
|
67885
68137
|
function silencePokeEnabled() {
|
|
67886
68138
|
const v = process.env.SWITCHROOM_DISABLE_SILENCE_POKE;
|
|
67887
68139
|
return !(v === "1" || v === "true");
|
|
@@ -67895,9 +68147,24 @@ function startTurn(key, now) {
|
|
|
67895
68147
|
lastThinkingAt: null,
|
|
67896
68148
|
fallbackFired: false,
|
|
67897
68149
|
floorFired: false,
|
|
67898
|
-
inFlightTools: new Map
|
|
68150
|
+
inFlightTools: new Map,
|
|
68151
|
+
sawBashThisTurn: false,
|
|
68152
|
+
aliveShells: new Set
|
|
67899
68153
|
});
|
|
67900
68154
|
}
|
|
68155
|
+
function noteBackgroundShellAlive(key, shellId) {
|
|
68156
|
+
bgMarkerParserConfirmed = true;
|
|
68157
|
+
const s = state2.get(key);
|
|
68158
|
+
if (s == null)
|
|
68159
|
+
return;
|
|
68160
|
+
s.aliveShells.add(shellId);
|
|
68161
|
+
}
|
|
68162
|
+
function noteBackgroundShellDead(key, shellId) {
|
|
68163
|
+
const s = state2.get(key);
|
|
68164
|
+
if (s == null)
|
|
68165
|
+
return;
|
|
68166
|
+
s.aliveShells.delete(shellId);
|
|
68167
|
+
}
|
|
67901
68168
|
function noteOutbound2(key, now) {
|
|
67902
68169
|
const s = state2.get(key);
|
|
67903
68170
|
if (s == null)
|
|
@@ -67923,6 +68190,8 @@ function noteToolStart(key, toolUseId, name, label, now) {
|
|
|
67923
68190
|
if (s == null)
|
|
67924
68191
|
return;
|
|
67925
68192
|
s.inFlightTools.set(toolUseId, { name, startedAt: now, label });
|
|
68193
|
+
if (name === "Bash")
|
|
68194
|
+
s.sawBashThisTurn = true;
|
|
67926
68195
|
}
|
|
67927
68196
|
function noteToolEnd(key, toolUseId, _now) {
|
|
67928
68197
|
const s = state2.get(key);
|
|
@@ -68037,6 +68306,10 @@ function tick(now) {
|
|
|
68037
68306
|
if (!forceDisable && activeDeps.isLegitimatelyWorking != null) {
|
|
68038
68307
|
if (activeDeps.isLegitimatelyWorking(key))
|
|
68039
68308
|
continue;
|
|
68309
|
+
if (s.aliveShells.size > 0)
|
|
68310
|
+
continue;
|
|
68311
|
+
if (!bgMarkerParserConfirmed && s.sawBashThisTurn)
|
|
68312
|
+
continue;
|
|
68040
68313
|
} else if (!forceDisable && activeDeps.deferFallbackWhileToolInFlight === true && s.inFlightTools.size > 0) {
|
|
68041
68314
|
continue;
|
|
68042
68315
|
}
|
|
@@ -68119,6 +68392,10 @@ function __getStateForTests(key) {
|
|
|
68119
68392
|
function __resetAllForTests2() {
|
|
68120
68393
|
state2.clear();
|
|
68121
68394
|
stopTimer();
|
|
68395
|
+
bgMarkerParserConfirmed = false;
|
|
68396
|
+
}
|
|
68397
|
+
function __bgMarkerParserConfirmedForTests() {
|
|
68398
|
+
return bgMarkerParserConfirmed;
|
|
68122
68399
|
}
|
|
68123
68400
|
|
|
68124
68401
|
// pending-work-progress.ts
|
|
@@ -68491,7 +68768,7 @@ function resolveAnswerLaneConfig(input) {
|
|
|
68491
68768
|
|
|
68492
68769
|
// session-tail.ts
|
|
68493
68770
|
import { homedir as homedir7 } from "os";
|
|
68494
|
-
import { basename as
|
|
68771
|
+
import { basename as basename7, join as join23 } from "path";
|
|
68495
68772
|
|
|
68496
68773
|
// operator-events.ts
|
|
68497
68774
|
init_format();
|
|
@@ -68928,6 +69205,29 @@ function extractToolResultErrorText(content3) {
|
|
|
68928
69205
|
}
|
|
68929
69206
|
return "";
|
|
68930
69207
|
}
|
|
69208
|
+
function parseBackgroundTaskId(obj) {
|
|
69209
|
+
const tur = obj.toolUseResult;
|
|
69210
|
+
if (typeof tur === "object" && tur != null) {
|
|
69211
|
+
const id = tur.backgroundTaskId;
|
|
69212
|
+
if (typeof id === "string" && id.length > 0)
|
|
69213
|
+
return id;
|
|
69214
|
+
}
|
|
69215
|
+
return null;
|
|
69216
|
+
}
|
|
69217
|
+
function parseBackgroundLaunchString(content3) {
|
|
69218
|
+
const text4 = typeof content3 === "string" ? content3 : extractToolResultErrorText(content3);
|
|
69219
|
+
const m = text4.match(/Command running in background with ID: (\w+)/);
|
|
69220
|
+
return m != null ? m[1] : null;
|
|
69221
|
+
}
|
|
69222
|
+
function parseTaskNotification(content3) {
|
|
69223
|
+
if (!content3.includes("<task-notification>"))
|
|
69224
|
+
return null;
|
|
69225
|
+
const idM = content3.match(/<task-id>([^<]+)<\/task-id>/);
|
|
69226
|
+
const stM = content3.match(/<status>([^<]+)<\/status>/);
|
|
69227
|
+
if (idM == null || stM == null)
|
|
69228
|
+
return null;
|
|
69229
|
+
return { taskId: idM[1].trim(), status: stM[1].trim() };
|
|
69230
|
+
}
|
|
68931
69231
|
function projectAssistantTextBlocks(content3, make) {
|
|
68932
69232
|
const out = new Map;
|
|
68933
69233
|
let lastToolUseIdx = -1;
|
|
@@ -69024,6 +69324,10 @@ function projectTranscriptLine(line) {
|
|
|
69024
69324
|
const op = obj.operation;
|
|
69025
69325
|
if (op === "enqueue") {
|
|
69026
69326
|
const content3 = obj.content ?? "";
|
|
69327
|
+
const notif = parseTaskNotification(content3);
|
|
69328
|
+
if (notif != null) {
|
|
69329
|
+
return [{ kind: "task_notification", taskId: notif.taskId, status: notif.status }];
|
|
69330
|
+
}
|
|
69027
69331
|
const { chatId, messageId, threadId } = parseChannelMeta(content3);
|
|
69028
69332
|
return [{ kind: "enqueue", chatId, messageId, threadId, rawContent: content3 }];
|
|
69029
69333
|
}
|
|
@@ -69081,6 +69385,7 @@ function projectTranscriptLine(line) {
|
|
|
69081
69385
|
const content3 = message?.content;
|
|
69082
69386
|
if (!Array.isArray(content3))
|
|
69083
69387
|
return [];
|
|
69388
|
+
const backgroundTaskId = parseBackgroundTaskId(obj);
|
|
69084
69389
|
const events = [];
|
|
69085
69390
|
for (const c of content3) {
|
|
69086
69391
|
if (c.type === "tool_result") {
|
|
@@ -69090,7 +69395,8 @@ function projectTranscriptLine(line) {
|
|
|
69090
69395
|
toolUseId: c.tool_use_id ?? "",
|
|
69091
69396
|
toolName: null,
|
|
69092
69397
|
isError: isError2,
|
|
69093
|
-
errorText: isError2 ? extractToolResultErrorText(c.content) : undefined
|
|
69398
|
+
errorText: isError2 ? extractToolResultErrorText(c.content) : undefined,
|
|
69399
|
+
backgroundTaskId: backgroundTaskId ?? parseBackgroundLaunchString(c.content) ?? undefined
|
|
69094
69400
|
});
|
|
69095
69401
|
}
|
|
69096
69402
|
}
|
|
@@ -74010,6 +74316,33 @@ function readDeliveredNonces(stateDir) {
|
|
|
74010
74316
|
} catch {}
|
|
74011
74317
|
return set;
|
|
74012
74318
|
}
|
|
74319
|
+
function isBackstopDeliveredEntry(e) {
|
|
74320
|
+
if (e.deliverySource === "sweep" || e.deliverySource === "flush")
|
|
74321
|
+
return true;
|
|
74322
|
+
if (e.deliverySource === "reply-tool" && e.replyAlreadyDeliveredThisTurn === false)
|
|
74323
|
+
return true;
|
|
74324
|
+
return false;
|
|
74325
|
+
}
|
|
74326
|
+
function backstopAlreadyDelivered(nonce, stateDir) {
|
|
74327
|
+
if (nonce == null || nonce === "")
|
|
74328
|
+
return false;
|
|
74329
|
+
const path2 = join28(resolveOutboxDir(stateDir), JOURNAL_FILE);
|
|
74330
|
+
if (!existsSync24(path2))
|
|
74331
|
+
return false;
|
|
74332
|
+
try {
|
|
74333
|
+
for (const line of readFileSync24(path2, "utf8").split(`
|
|
74334
|
+
`)) {
|
|
74335
|
+
if (!line)
|
|
74336
|
+
continue;
|
|
74337
|
+
try {
|
|
74338
|
+
const e = JSON.parse(line);
|
|
74339
|
+
if (e.turnNonce === nonce && isBackstopDeliveredEntry(e))
|
|
74340
|
+
return true;
|
|
74341
|
+
} catch {}
|
|
74342
|
+
}
|
|
74343
|
+
} catch {}
|
|
74344
|
+
return false;
|
|
74345
|
+
}
|
|
74013
74346
|
var JOURNAL_KEEP = 2000;
|
|
74014
74347
|
var JOURNAL_ROTATE_AT = 4000;
|
|
74015
74348
|
function appendDelivered(entry, stateDir) {
|
|
@@ -74053,10 +74386,13 @@ function decideOutboxSweep(input) {
|
|
|
74053
74386
|
routable,
|
|
74054
74387
|
routePrefix = "",
|
|
74055
74388
|
quietMs = OUTBOX_QUIET_MS,
|
|
74056
|
-
maxAgeMs = OUTBOX_MAX_AGE_MS
|
|
74389
|
+
maxAgeMs = OUTBOX_MAX_AGE_MS,
|
|
74390
|
+
shownLedgerHit = false
|
|
74057
74391
|
} = input;
|
|
74058
74392
|
if (deliveredNonces.has(record.turnNonce))
|
|
74059
74393
|
return { action: "skip-journaled" };
|
|
74394
|
+
if (shownLedgerHit)
|
|
74395
|
+
return { action: "skip-ephemeral-shown" };
|
|
74060
74396
|
const age = now - record.createdAt;
|
|
74061
74397
|
if (age < quietMs)
|
|
74062
74398
|
return { action: "skip-quiet" };
|
|
@@ -74089,6 +74425,149 @@ function extractTaskId(anchorContent) {
|
|
|
74089
74425
|
return m ? m[1] : null;
|
|
74090
74426
|
}
|
|
74091
74427
|
|
|
74428
|
+
// shown-ledger.ts
|
|
74429
|
+
import {
|
|
74430
|
+
existsSync as existsSync25,
|
|
74431
|
+
mkdirSync as mkdirSync26,
|
|
74432
|
+
readFileSync as readFileSync25,
|
|
74433
|
+
renameSync as renameSync9,
|
|
74434
|
+
writeFileSync as writeFileSync23,
|
|
74435
|
+
appendFileSync as appendFileSync5
|
|
74436
|
+
} from "node:fs";
|
|
74437
|
+
import { join as join29 } from "node:path";
|
|
74438
|
+
|
|
74439
|
+
// hooks/narration-classify.mjs
|
|
74440
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
74441
|
+
var SUBSTANTIVE_MIN_CHARS = 200;
|
|
74442
|
+
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;
|
|
74443
|
+
var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
|
|
74444
|
+
function isTrailingNarrationLine(block) {
|
|
74445
|
+
const t = typeof block === "string" ? block.trim() : "";
|
|
74446
|
+
if (t.length === 0 || t.length >= SUBSTANTIVE_MIN_CHARS)
|
|
74447
|
+
return false;
|
|
74448
|
+
if (t.includes(`
|
|
74449
|
+
`))
|
|
74450
|
+
return false;
|
|
74451
|
+
return NARRATION_TRAILER.test(t);
|
|
74452
|
+
}
|
|
74453
|
+
function isNarrationBlock(block) {
|
|
74454
|
+
const s = typeof block === "string" ? block : "";
|
|
74455
|
+
return NARRATION_OPENER.test(s.trimStart()) || isTrailingNarrationLine(s);
|
|
74456
|
+
}
|
|
74457
|
+
function isStructuralNarration(text4, followedByToolUse) {
|
|
74458
|
+
if (followedByToolUse !== true)
|
|
74459
|
+
return false;
|
|
74460
|
+
const t = typeof text4 === "string" ? text4.trim() : "";
|
|
74461
|
+
if (t.length === 0)
|
|
74462
|
+
return true;
|
|
74463
|
+
return isNarrationBlock(t) || t.length < SUBSTANTIVE_MIN_CHARS;
|
|
74464
|
+
}
|
|
74465
|
+
var EPHEMERAL_TOOLS = new Set([
|
|
74466
|
+
"react",
|
|
74467
|
+
"send_typing",
|
|
74468
|
+
"pin_message",
|
|
74469
|
+
"delete_message",
|
|
74470
|
+
"edit_message"
|
|
74471
|
+
]);
|
|
74472
|
+
function isEphemeralTool(name) {
|
|
74473
|
+
if (typeof name !== "string")
|
|
74474
|
+
return false;
|
|
74475
|
+
const suffix = name.replace(/^mcp__[^_].*?telegram__/, "");
|
|
74476
|
+
return EPHEMERAL_TOOLS.has(suffix);
|
|
74477
|
+
}
|
|
74478
|
+
function selectBackstopDelivery(blocks) {
|
|
74479
|
+
const nonEmpty = (Array.isArray(blocks) ? blocks : []).map((b) => ({
|
|
74480
|
+
text: typeof b?.text === "string" ? b.text.trim() : "",
|
|
74481
|
+
followedByToolUse: b?.followedByToolUse
|
|
74482
|
+
})).filter((b) => b.text.length > 0);
|
|
74483
|
+
if (nonEmpty.length === 0)
|
|
74484
|
+
return null;
|
|
74485
|
+
const run3 = [];
|
|
74486
|
+
for (let i = nonEmpty.length - 1;i >= 0; i--) {
|
|
74487
|
+
if (nonEmpty[i].followedByToolUse === true)
|
|
74488
|
+
break;
|
|
74489
|
+
run3.unshift(nonEmpty[i].text);
|
|
74490
|
+
}
|
|
74491
|
+
if (run3.length > 0)
|
|
74492
|
+
return { text: run3.join(`
|
|
74493
|
+
|
|
74494
|
+
`) };
|
|
74495
|
+
const last = nonEmpty[nonEmpty.length - 1];
|
|
74496
|
+
if (last.text.length >= SUBSTANTIVE_MIN_CHARS)
|
|
74497
|
+
return { text: last.text };
|
|
74498
|
+
return null;
|
|
74499
|
+
}
|
|
74500
|
+
function ledgerHashHex(text4) {
|
|
74501
|
+
return createHash4("sha256").update(String(text4 ?? "").trim(), "utf8").digest("hex");
|
|
74502
|
+
}
|
|
74503
|
+
|
|
74504
|
+
// shown-ledger.ts
|
|
74505
|
+
var SHOWN_LEDGER_FILE = "shown-ledger.jsonl";
|
|
74506
|
+
var SHOWN_LEDGER_KEEP = 2000;
|
|
74507
|
+
var SHOWN_LEDGER_ROTATE_AT = 4000;
|
|
74508
|
+
function shownLedgerPath(stateDir) {
|
|
74509
|
+
return join29(resolveOutboxDir(stateDir), SHOWN_LEDGER_FILE);
|
|
74510
|
+
}
|
|
74511
|
+
function appendShownBlock(turnNonce, text4, stateDir, now = Date.now()) {
|
|
74512
|
+
if (turnNonce == null || turnNonce === "")
|
|
74513
|
+
return;
|
|
74514
|
+
const trimmed = typeof text4 === "string" ? text4.trim() : "";
|
|
74515
|
+
if (trimmed.length === 0)
|
|
74516
|
+
return;
|
|
74517
|
+
const dir = resolveOutboxDir(stateDir);
|
|
74518
|
+
const path2 = shownLedgerPath(stateDir);
|
|
74519
|
+
try {
|
|
74520
|
+
mkdirSync26(dir, { recursive: true });
|
|
74521
|
+
const entry = { turnNonce, hash: ledgerHashHex(trimmed), ts: now };
|
|
74522
|
+
appendFileSync5(path2, JSON.stringify(entry) + `
|
|
74523
|
+
`, { mode: 384 });
|
|
74524
|
+
compactIfLarge(path2);
|
|
74525
|
+
} catch {}
|
|
74526
|
+
}
|
|
74527
|
+
function readShownHashes(turnNonce, stateDir) {
|
|
74528
|
+
const set = new Set;
|
|
74529
|
+
if (turnNonce == null || turnNonce === "")
|
|
74530
|
+
return set;
|
|
74531
|
+
const path2 = shownLedgerPath(stateDir);
|
|
74532
|
+
if (!existsSync25(path2))
|
|
74533
|
+
return set;
|
|
74534
|
+
try {
|
|
74535
|
+
for (const line of readFileSync25(path2, "utf8").split(`
|
|
74536
|
+
`)) {
|
|
74537
|
+
if (!line)
|
|
74538
|
+
continue;
|
|
74539
|
+
try {
|
|
74540
|
+
const e = JSON.parse(line);
|
|
74541
|
+
if (e.turnNonce === turnNonce && typeof e.hash === "string")
|
|
74542
|
+
set.add(e.hash);
|
|
74543
|
+
} catch {}
|
|
74544
|
+
}
|
|
74545
|
+
} catch {}
|
|
74546
|
+
return set;
|
|
74547
|
+
}
|
|
74548
|
+
function isShownBlock(turnNonce, text4, stateDir) {
|
|
74549
|
+
if (turnNonce == null || turnNonce === "")
|
|
74550
|
+
return false;
|
|
74551
|
+
const trimmed = typeof text4 === "string" ? text4.trim() : "";
|
|
74552
|
+
if (trimmed.length === 0)
|
|
74553
|
+
return false;
|
|
74554
|
+
return readShownHashes(turnNonce, stateDir).has(ledgerHashHex(trimmed));
|
|
74555
|
+
}
|
|
74556
|
+
function compactIfLarge(path2) {
|
|
74557
|
+
try {
|
|
74558
|
+
const lines = readFileSync25(path2, "utf8").split(`
|
|
74559
|
+
`).filter((l) => l.length > 0);
|
|
74560
|
+
if (lines.length <= SHOWN_LEDGER_ROTATE_AT)
|
|
74561
|
+
return;
|
|
74562
|
+
const kept = lines.slice(lines.length - SHOWN_LEDGER_KEEP);
|
|
74563
|
+
const tmp = `${path2}.${process.pid}.compact`;
|
|
74564
|
+
writeFileSync23(tmp, kept.join(`
|
|
74565
|
+
`) + `
|
|
74566
|
+
`, { mode: 384 });
|
|
74567
|
+
renameSync9(tmp, path2);
|
|
74568
|
+
} catch {}
|
|
74569
|
+
}
|
|
74570
|
+
|
|
74092
74571
|
// registry/subagents-schema.ts
|
|
74093
74572
|
function countRunningBackgroundSubagents(db2) {
|
|
74094
74573
|
const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
|
|
@@ -74211,7 +74690,7 @@ function journalExternalDelivery(args, stateDir, now = Date.now()) {
|
|
|
74211
74690
|
textSha256: sha256Hex(args.text),
|
|
74212
74691
|
tgMessageId: args.tgMessageId,
|
|
74213
74692
|
ts: now,
|
|
74214
|
-
deliverySource: "reply-tool",
|
|
74693
|
+
deliverySource: args.deliverySource ?? "reply-tool",
|
|
74215
74694
|
...args.replyAlreadyDeliveredThisTurn == null ? {} : { replyAlreadyDeliveredThisTurn: args.replyAlreadyDeliveredThisTurn }
|
|
74216
74695
|
}, stateDir);
|
|
74217
74696
|
clearOutboxRecord(nonce, stateDir);
|
|
@@ -74445,7 +74924,7 @@ function deriveTelegraphTitle2(text4) {
|
|
|
74445
74924
|
var VOICE_FILE_TTL_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
74446
74925
|
var VOICE_CACHE_MAX_BYTES2 = 500 * 1024 * 1024;
|
|
74447
74926
|
var VOICE_SWEEP_INTERVAL_MS2 = 60 * 60 * 1000;
|
|
74448
|
-
function
|
|
74927
|
+
function eagerVoiceEnabled2() {
|
|
74449
74928
|
const kill = process.env.SWITCHROOM_DISABLE_EAGER_VOICE;
|
|
74450
74929
|
return !(kill === "1" || kill === "true");
|
|
74451
74930
|
}
|
|
@@ -74606,8 +75085,8 @@ function monotonicNowMs2() {
|
|
|
74606
75085
|
}
|
|
74607
75086
|
|
|
74608
75087
|
// silent-end.ts
|
|
74609
|
-
import { existsSync as
|
|
74610
|
-
import { dirname as dirname11, join as
|
|
75088
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26, writeFileSync as writeFileSync24, unlinkSync as unlinkSync13, mkdirSync as mkdirSync27 } from "node:fs";
|
|
75089
|
+
import { dirname as dirname11, join as join30 } from "node:path";
|
|
74611
75090
|
import { homedir as homedir11 } from "node:os";
|
|
74612
75091
|
var SILENT_END_MAX_RETRIES2 = 2;
|
|
74613
75092
|
var SILENT_END_STALE_RECORD_MAX_AGE_MS2 = 30 * 60000;
|
|
@@ -74622,10 +75101,10 @@ function resolveStateDir3(deps) {
|
|
|
74622
75101
|
if (env != null && env !== "")
|
|
74623
75102
|
return env;
|
|
74624
75103
|
const home2 = process.env.HOME ?? homedir11();
|
|
74625
|
-
return
|
|
75104
|
+
return join30(home2, ".claude", "channels", "telegram");
|
|
74626
75105
|
}
|
|
74627
75106
|
function resolveStatePath3(deps) {
|
|
74628
|
-
return
|
|
75107
|
+
return join30(resolveStateDir3(deps), "silent-end-pending.json");
|
|
74629
75108
|
}
|
|
74630
75109
|
function emitLog2(deps, line) {
|
|
74631
75110
|
if (deps?.log != null)
|
|
@@ -74637,8 +75116,8 @@ function writeSilentEndState2(args, deps) {
|
|
|
74637
75116
|
const statePath = resolveStatePath3(deps);
|
|
74638
75117
|
let retryCount = 0;
|
|
74639
75118
|
try {
|
|
74640
|
-
if (
|
|
74641
|
-
const prev = JSON.parse(
|
|
75119
|
+
if (existsSync26(statePath)) {
|
|
75120
|
+
const prev = JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74642
75121
|
if (prev.turnKey === args.turnKey && typeof prev.retryCount === "number") {
|
|
74643
75122
|
retryCount = prev.retryCount;
|
|
74644
75123
|
}
|
|
@@ -74654,8 +75133,8 @@ function writeSilentEndState2(args, deps) {
|
|
|
74654
75133
|
timestamp: Date.now()
|
|
74655
75134
|
};
|
|
74656
75135
|
try {
|
|
74657
|
-
|
|
74658
|
-
|
|
75136
|
+
mkdirSync27(dirname11(statePath), { recursive: true });
|
|
75137
|
+
writeFileSync24(statePath, JSON.stringify(state3), "utf8");
|
|
74659
75138
|
emitLog2(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
|
|
74660
75139
|
`);
|
|
74661
75140
|
} catch (err) {
|
|
@@ -74665,10 +75144,10 @@ function writeSilentEndState2(args, deps) {
|
|
|
74665
75144
|
}
|
|
74666
75145
|
function clearSilentEndState2(turnKey3, deps) {
|
|
74667
75146
|
const statePath = resolveStatePath3(deps);
|
|
74668
|
-
if (!
|
|
75147
|
+
if (!existsSync26(statePath))
|
|
74669
75148
|
return;
|
|
74670
75149
|
try {
|
|
74671
|
-
const prev = JSON.parse(
|
|
75150
|
+
const prev = JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74672
75151
|
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
74673
75152
|
return;
|
|
74674
75153
|
unlinkSync13(statePath);
|
|
@@ -74690,6 +75169,12 @@ function decideCapturedProseDelivery(args, deps) {
|
|
|
74690
75169
|
const text4 = typeof state3.pendingText === "string" ? state3.pendingText : "";
|
|
74691
75170
|
if (text4.trim().length < minChars)
|
|
74692
75171
|
return { deliver: false, reason: "no-substantive-prose" };
|
|
75172
|
+
if (deps?.isBlockShown?.(state3.turnId, text4) === true) {
|
|
75173
|
+
return { deliver: false, reason: "ephemeral-shown" };
|
|
75174
|
+
}
|
|
75175
|
+
if (deps?.backstopDeliveredNonceHit?.(state3.turnId) === true) {
|
|
75176
|
+
return { deliver: false, reason: "already-delivered" };
|
|
75177
|
+
}
|
|
74693
75178
|
return { deliver: true, text: text4, reason: "captured-prose" };
|
|
74694
75179
|
}
|
|
74695
75180
|
function settleCapturedProseDelivery(outcome, effects) {
|
|
@@ -74702,10 +75187,10 @@ function settleCapturedProseDelivery(outcome, effects) {
|
|
|
74702
75187
|
}
|
|
74703
75188
|
function readSilentEndState2(deps) {
|
|
74704
75189
|
const statePath = resolveStatePath3(deps);
|
|
74705
|
-
if (!
|
|
75190
|
+
if (!existsSync26(statePath))
|
|
74706
75191
|
return null;
|
|
74707
75192
|
try {
|
|
74708
|
-
return JSON.parse(
|
|
75193
|
+
return JSON.parse(readFileSync26(statePath, "utf8"));
|
|
74709
75194
|
} catch {
|
|
74710
75195
|
return null;
|
|
74711
75196
|
}
|
|
@@ -75229,24 +75714,23 @@ ${url}`;
|
|
|
75229
75714
|
replyButtonMeta = extractAgentButtonMeta(redactedKeyboard);
|
|
75230
75715
|
replyMarkup = { inline_keyboard: wrapAgentCallbacks(redactedKeyboard) };
|
|
75231
75716
|
}
|
|
75232
|
-
if (useOnDemandButton
|
|
75233
|
-
|
|
75234
|
-
|
|
75717
|
+
if (useOnDemandButton) {
|
|
75718
|
+
const listenPlan = planListenButton({ voiceOutPlan, rawKeyboard });
|
|
75719
|
+
if (listenPlan == null) {
|
|
75720
|
+
const hasSpeakableText = voiceOutPlan.ttsChunks.length > 0 && voiceOutPlan.ttsChunks[0].length > 0;
|
|
75721
|
+
if (hasSpeakableText && !mayInjectListenButton(rawKeyboard)) {
|
|
75722
|
+
process.stderr.write(`telegram gateway: voice-out on-demand: agent supplied inline_keyboard \u2014 skipping Listen button (single_use collision gate)
|
|
75235
75723
|
`);
|
|
75724
|
+
}
|
|
75236
75725
|
} else {
|
|
75237
|
-
|
|
75238
|
-
|
|
75239
|
-
|
|
75240
|
-
...voiceOutPlan.voice != null ? { voice: voiceOutPlan.voice } : {},
|
|
75241
|
-
speed: voiceOutPlan.speed
|
|
75242
|
-
});
|
|
75243
|
-
replyMarkup = buildListenKeyboard(token);
|
|
75244
|
-
if (eagerVoiceEnabled()) {
|
|
75726
|
+
voiceOnDemandCache.put(listenPlan.token, listenPlan.payload);
|
|
75727
|
+
replyMarkup = listenPlan.replyMarkup;
|
|
75728
|
+
if (eagerVoiceEnabled2()) {
|
|
75245
75729
|
voicePreSynthQueue.enqueue({
|
|
75246
|
-
token,
|
|
75247
|
-
text:
|
|
75248
|
-
...
|
|
75249
|
-
speed:
|
|
75730
|
+
token: listenPlan.token,
|
|
75731
|
+
text: listenPlan.payload.text,
|
|
75732
|
+
...listenPlan.payload.voice != null ? { voice: listenPlan.payload.voice } : {},
|
|
75733
|
+
speed: listenPlan.payload.speed
|
|
75250
75734
|
});
|
|
75251
75735
|
}
|
|
75252
75736
|
}
|
|
@@ -75825,34 +76309,6 @@ function endsWithSilentMarker(text4) {
|
|
|
75825
76309
|
return false;
|
|
75826
76310
|
return isSilentFlushMarker(lines[lines.length - 1]);
|
|
75827
76311
|
}
|
|
75828
|
-
var FLUSH_SUBSTANTIVE_MIN_CHARS = 200;
|
|
75829
|
-
function selectFlushDeliveryText(blocks, followedByToolUse) {
|
|
75830
|
-
const candidates = blocks.map((b, i) => ({ text: b.trim(), followedByToolUse: followedByToolUse?.[i] })).filter((c) => c.text.length > 0);
|
|
75831
|
-
if (candidates.length === 0)
|
|
75832
|
-
return "";
|
|
75833
|
-
if (candidates.length === 1)
|
|
75834
|
-
return candidates[0].text;
|
|
75835
|
-
const answer = candidates[candidates.length - 1].text;
|
|
75836
|
-
const preceding = candidates.slice(0, -1);
|
|
75837
|
-
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));
|
|
75838
|
-
return allNarration ? answer : candidates.map((c) => c.text).join(`
|
|
75839
|
-
|
|
75840
|
-
`);
|
|
75841
|
-
}
|
|
75842
|
-
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;
|
|
75843
|
-
var NARRATION_TRAILER = /(?:\.{3}|\u2026|:)\s*$/;
|
|
75844
|
-
function isTrailingNarrationLine(block) {
|
|
75845
|
-
const t = block.trim();
|
|
75846
|
-
if (t.length === 0 || t.length >= FLUSH_SUBSTANTIVE_MIN_CHARS)
|
|
75847
|
-
return false;
|
|
75848
|
-
if (t.includes(`
|
|
75849
|
-
`))
|
|
75850
|
-
return false;
|
|
75851
|
-
return NARRATION_TRAILER.test(t);
|
|
75852
|
-
}
|
|
75853
|
-
function isNarrationBlock(block) {
|
|
75854
|
-
return NARRATION_OPENER.test(block.trimStart()) || isTrailingNarrationLine(block);
|
|
75855
|
-
}
|
|
75856
76312
|
function decideTurnFlush(input) {
|
|
75857
76313
|
const flushEnabled = input.flushEnabled !== false;
|
|
75858
76314
|
if (!flushEnabled)
|
|
@@ -75872,10 +76328,14 @@ function decideTurnFlush(input) {
|
|
|
75872
76328
|
return { kind: "skip", reason: "silent-marker" };
|
|
75873
76329
|
if (endsWithSilentMarker(joined))
|
|
75874
76330
|
return { kind: "skip", reason: "silent-marker" };
|
|
75875
|
-
|
|
75876
|
-
|
|
75877
|
-
|
|
75878
|
-
};
|
|
76331
|
+
const selected = selectBackstopDelivery(input.capturedText.map((text4, i) => ({
|
|
76332
|
+
text: text4,
|
|
76333
|
+
followedByToolUse: input.capturedBlockMeta?.[i]
|
|
76334
|
+
})));
|
|
76335
|
+
if (selected == null || selected.text.trim().length === 0) {
|
|
76336
|
+
return { kind: "skip", reason: "empty-text" };
|
|
76337
|
+
}
|
|
76338
|
+
return { kind: "flush", text: selected.text };
|
|
75879
76339
|
}
|
|
75880
76340
|
|
|
75881
76341
|
// answer-stream.ts
|
|
@@ -76265,20 +76725,20 @@ var INTERRUPTED_VIA = new Set([
|
|
|
76265
76725
|
init_rich_send();
|
|
76266
76726
|
|
|
76267
76727
|
// runtime-metrics.ts
|
|
76268
|
-
import { mkdirSync as
|
|
76269
|
-
import { dirname as dirname12, join as
|
|
76728
|
+
import { mkdirSync as mkdirSync29, appendFileSync as appendFileSync6 } from "node:fs";
|
|
76729
|
+
import { dirname as dirname12, join as join32 } from "node:path";
|
|
76270
76730
|
function resolveJsonlPath2() {
|
|
76271
76731
|
const override = process.env.SWITCHROOM_RUNTIME_METRICS_PATH;
|
|
76272
76732
|
if (override && override.trim() !== "")
|
|
76273
76733
|
return override.trim();
|
|
76274
76734
|
const base = process.env.SWITCHROOM_RUNTIME_STATE_DIR ?? "/state/agent";
|
|
76275
|
-
return
|
|
76735
|
+
return join32(base, "runtime-metrics.jsonl");
|
|
76276
76736
|
}
|
|
76277
76737
|
function appendJsonl2(line) {
|
|
76278
76738
|
const path2 = resolveJsonlPath2();
|
|
76279
76739
|
try {
|
|
76280
|
-
|
|
76281
|
-
|
|
76740
|
+
mkdirSync29(dirname12(path2), { recursive: true });
|
|
76741
|
+
appendFileSync6(path2, line + `
|
|
76282
76742
|
`, "utf-8");
|
|
76283
76743
|
} catch (err) {
|
|
76284
76744
|
process.stderr.write(`runtime-metrics: jsonl write failed: ${err.message}
|
|
@@ -76768,28 +77228,28 @@ function detectStatusSurfaceDegraded(t) {
|
|
|
76768
77228
|
// gateway/turn-active-marker.ts
|
|
76769
77229
|
import {
|
|
76770
77230
|
closeSync as closeSync5,
|
|
76771
|
-
existsSync as
|
|
76772
|
-
mkdirSync as
|
|
77231
|
+
existsSync as existsSync29,
|
|
77232
|
+
mkdirSync as mkdirSync30,
|
|
76773
77233
|
openSync as openSync5,
|
|
76774
|
-
readFileSync as
|
|
77234
|
+
readFileSync as readFileSync27,
|
|
76775
77235
|
statSync as statSync11,
|
|
76776
77236
|
unlinkSync as unlinkSync14,
|
|
76777
77237
|
utimesSync,
|
|
76778
|
-
writeFileSync as
|
|
77238
|
+
writeFileSync as writeFileSync25
|
|
76779
77239
|
} from "node:fs";
|
|
76780
|
-
import { join as
|
|
77240
|
+
import { join as join33 } from "node:path";
|
|
76781
77241
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
76782
77242
|
var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
|
|
76783
77243
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
76784
77244
|
try {
|
|
76785
|
-
|
|
76786
|
-
|
|
77245
|
+
mkdirSync30(stateDir, { recursive: true });
|
|
77246
|
+
writeFileSync25(join33(stateDir, TURN_ACTIVE_MARKER_FILE), JSON.stringify(marker, null, 2) + `
|
|
76787
77247
|
`, { mode: 384 });
|
|
76788
77248
|
} catch {}
|
|
76789
77249
|
}
|
|
76790
77250
|
function touchTurnActiveMarker(stateDir) {
|
|
76791
|
-
const path2 =
|
|
76792
|
-
if (!
|
|
77251
|
+
const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
77252
|
+
if (!existsSync29(path2))
|
|
76793
77253
|
return;
|
|
76794
77254
|
const now = new Date;
|
|
76795
77255
|
try {
|
|
@@ -76803,11 +77263,11 @@ function touchTurnActiveMarker(stateDir) {
|
|
|
76803
77263
|
}
|
|
76804
77264
|
function removeTurnActiveMarker(stateDir) {
|
|
76805
77265
|
try {
|
|
76806
|
-
unlinkSync14(
|
|
77266
|
+
unlinkSync14(join33(stateDir, TURN_ACTIVE_MARKER_FILE));
|
|
76807
77267
|
} catch {}
|
|
76808
77268
|
}
|
|
76809
77269
|
function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
76810
|
-
const path2 =
|
|
77270
|
+
const path2 = join33(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
76811
77271
|
try {
|
|
76812
77272
|
const st = statSync11(path2);
|
|
76813
77273
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -77229,7 +77689,10 @@ function handleSessionEvent(deps, ev) {
|
|
|
77229
77689
|
const turn = getCurrentTurn();
|
|
77230
77690
|
if (turn == null)
|
|
77231
77691
|
return;
|
|
77232
|
-
|
|
77692
|
+
if (!isEphemeralTool(ev.toolName)) {
|
|
77693
|
+
turn.capturedBlockMeta.fill(true);
|
|
77694
|
+
clearAnswerReadyFlushTimeout(turn);
|
|
77695
|
+
}
|
|
77233
77696
|
resolvePendingNarrativeOnTool(turn, ev.toolName, ev.input);
|
|
77234
77697
|
turn.toolCallCount++;
|
|
77235
77698
|
touchTurnActiveMarker(STATE_DIR);
|
|
@@ -77264,7 +77727,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
77264
77727
|
const turn = getCurrentTurn();
|
|
77265
77728
|
if (turn == null)
|
|
77266
77729
|
return;
|
|
77267
|
-
|
|
77730
|
+
if (!isEphemeralTool(ev.toolName)) {
|
|
77731
|
+
clearAnswerReadyFlushTimeout(turn);
|
|
77732
|
+
}
|
|
77268
77733
|
resetOrphanedReplyTimeout();
|
|
77269
77734
|
if (isTelegramSurfaceTool(ev.toolName))
|
|
77270
77735
|
return;
|
|
@@ -77642,6 +78107,11 @@ function handleSessionEvent(deps, ev) {
|
|
|
77642
78107
|
}
|
|
77643
78108
|
} catch {}
|
|
77644
78109
|
}
|
|
78110
|
+
if (backstopAlreadyDelivered(turn.turnId, STATE_DIR)) {
|
|
78111
|
+
process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already delivered by a prior backstop (durable journal)
|
|
78112
|
+
`);
|
|
78113
|
+
return;
|
|
78114
|
+
}
|
|
77645
78115
|
if (!backstopLatchClaimed) {
|
|
77646
78116
|
process.stderr.write(`telegram gateway: turn-flush skipped \u2014 turn ${turn.turnId} already claimed the delivery latch
|
|
77647
78117
|
`);
|
|
@@ -77704,6 +78174,19 @@ function handleSessionEvent(deps, ev) {
|
|
|
77704
78174
|
chunkCount,
|
|
77705
78175
|
cardMessageId: backstopCardMessageId
|
|
77706
78176
|
});
|
|
78177
|
+
if (delivered) {
|
|
78178
|
+
try {
|
|
78179
|
+
journalExternalDelivery({
|
|
78180
|
+
turnNonce: turn.turnId,
|
|
78181
|
+
text: capturedText,
|
|
78182
|
+
tgMessageId: sentIds.length > 0 ? sentIds[0] : undefined,
|
|
78183
|
+
deliverySource: "flush"
|
|
78184
|
+
}, STATE_DIR);
|
|
78185
|
+
} catch (err) {
|
|
78186
|
+
process.stderr.write(`telegram gateway: turn-flush delivered but journal write failed (non-fatal): ${err.message}
|
|
78187
|
+
`);
|
|
78188
|
+
}
|
|
78189
|
+
}
|
|
77707
78190
|
if (OBLIGATION_LEDGER_ENABLED) {
|
|
77708
78191
|
if (delivered) {
|
|
77709
78192
|
obligationLedger.close(turn.turnId);
|
|
@@ -77764,6 +78247,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
77764
78247
|
turnKey: tKey,
|
|
77765
78248
|
turnId: turn.turnId,
|
|
77766
78249
|
minChars: proseMinChars
|
|
78250
|
+
}, {
|
|
78251
|
+
isBlockShown: (nonce, text4) => isShownBlock(nonce ?? null, text4),
|
|
78252
|
+
backstopDeliveredNonceHit: (nonce) => backstopAlreadyDelivered(nonce ?? "", STATE_DIR)
|
|
77767
78253
|
}) : { deliver: false, reason: "no-state" };
|
|
77768
78254
|
if (proseDecision.deliver && proseDecision.text != null) {
|
|
77769
78255
|
process.stderr.write(`telegram gateway: captured-prose delivery engaged on first silent-end chat=${chatId} turnKey=${tKey} (#3227)
|
|
@@ -77903,6 +78389,7 @@ class NarrativeFlushController {
|
|
|
77903
78389
|
this.scheduler.disarm();
|
|
77904
78390
|
if (this.pending != null) {
|
|
77905
78391
|
this.effects.show(this.pending);
|
|
78392
|
+
this.markShown(this.pending);
|
|
77906
78393
|
}
|
|
77907
78394
|
this.pending = text4;
|
|
77908
78395
|
this.scheduler.arm(() => this.onTimerFire(), this.flushMs);
|
|
@@ -77927,6 +78414,7 @@ class NarrativeFlushController {
|
|
|
77927
78414
|
if (replyText != null && isDraftOfReply(pending, replyText))
|
|
77928
78415
|
return;
|
|
77929
78416
|
this.effects.show(pending);
|
|
78417
|
+
this.markShown(pending);
|
|
77930
78418
|
}
|
|
77931
78419
|
flushAtTurnEnd(lastReplyText) {
|
|
77932
78420
|
this.scheduler.disarm();
|
|
@@ -77945,6 +78433,13 @@ class NarrativeFlushController {
|
|
|
77945
78433
|
this.pending = null;
|
|
77946
78434
|
this.timerShown = null;
|
|
77947
78435
|
}
|
|
78436
|
+
markShown(text4) {
|
|
78437
|
+
if (this.effects.markDurableNarration == null)
|
|
78438
|
+
return;
|
|
78439
|
+
if (!isStructuralNarration(text4, true))
|
|
78440
|
+
return;
|
|
78441
|
+
this.effects.markDurableNarration(text4);
|
|
78442
|
+
}
|
|
77948
78443
|
maybeRetract(replyText) {
|
|
77949
78444
|
const shown = this.timerShown;
|
|
77950
78445
|
if (shown == null)
|
|
@@ -78096,7 +78591,12 @@ function createNarrativeLane(deps) {
|
|
|
78096
78591
|
let handle = null;
|
|
78097
78592
|
return new NarrativeFlushController({
|
|
78098
78593
|
show: (text4) => showNarrativeStep(turn, text4),
|
|
78099
|
-
retractShown: (text4) => retractNarrativeLine(turn, text4)
|
|
78594
|
+
retractShown: (text4) => retractNarrativeLine(turn, text4),
|
|
78595
|
+
markDurableNarration: (text4) => {
|
|
78596
|
+
if (turn.turnId == null)
|
|
78597
|
+
return;
|
|
78598
|
+
appendShownBlock(turn.turnId, text4);
|
|
78599
|
+
}
|
|
78100
78600
|
}, {
|
|
78101
78601
|
arm: (fn, ms) => {
|
|
78102
78602
|
if (handle != null)
|
|
@@ -78694,19 +79194,19 @@ function resolveAgentDirFromEnv() {
|
|
|
78694
79194
|
}
|
|
78695
79195
|
|
|
78696
79196
|
// active-reactions.ts
|
|
78697
|
-
import { readFileSync as
|
|
78698
|
-
import { join as
|
|
79197
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync26, renameSync as renameSync10, existsSync as existsSync30, unlinkSync as unlinkSync15 } from "node:fs";
|
|
79198
|
+
import { join as join34 } from "node:path";
|
|
78699
79199
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
78700
79200
|
function reactionsPath(agentDir) {
|
|
78701
|
-
return
|
|
79201
|
+
return join34(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
78702
79202
|
}
|
|
78703
79203
|
function readActiveReactions(agentDir) {
|
|
78704
79204
|
const p = reactionsPath(agentDir);
|
|
78705
|
-
if (!
|
|
79205
|
+
if (!existsSync30(p))
|
|
78706
79206
|
return [];
|
|
78707
79207
|
let raw;
|
|
78708
79208
|
try {
|
|
78709
|
-
raw =
|
|
79209
|
+
raw = readFileSync28(p, "utf-8");
|
|
78710
79210
|
} catch {
|
|
78711
79211
|
return [];
|
|
78712
79212
|
}
|
|
@@ -78738,9 +79238,9 @@ function writeActiveReactions(agentDir, reactions) {
|
|
|
78738
79238
|
}
|
|
78739
79239
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
78740
79240
|
try {
|
|
78741
|
-
|
|
79241
|
+
writeFileSync26(tmp, JSON.stringify(reactions) + `
|
|
78742
79242
|
`, "utf-8");
|
|
78743
|
-
|
|
79243
|
+
renameSync10(tmp, p);
|
|
78744
79244
|
} catch {}
|
|
78745
79245
|
}
|
|
78746
79246
|
function addActiveReaction(agentDir, reaction) {
|
|
@@ -78762,19 +79262,19 @@ function clearActiveReactions(agentDir) {
|
|
|
78762
79262
|
}
|
|
78763
79263
|
|
|
78764
79264
|
// active-reactions.ts
|
|
78765
|
-
import { readFileSync as
|
|
78766
|
-
import { join as
|
|
79265
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync27, renameSync as renameSync11, existsSync as existsSync31, unlinkSync as unlinkSync16 } from "node:fs";
|
|
79266
|
+
import { join as join35 } from "node:path";
|
|
78767
79267
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
78768
79268
|
function reactionsPath2(agentDir) {
|
|
78769
|
-
return
|
|
79269
|
+
return join35(agentDir, ACTIVE_REACTIONS_FILENAME2);
|
|
78770
79270
|
}
|
|
78771
79271
|
function readActiveReactions2(agentDir) {
|
|
78772
79272
|
const p = reactionsPath2(agentDir);
|
|
78773
|
-
if (!
|
|
79273
|
+
if (!existsSync31(p))
|
|
78774
79274
|
return [];
|
|
78775
79275
|
let raw;
|
|
78776
79276
|
try {
|
|
78777
|
-
raw =
|
|
79277
|
+
raw = readFileSync29(p, "utf-8");
|
|
78778
79278
|
} catch {
|
|
78779
79279
|
return [];
|
|
78780
79280
|
}
|
|
@@ -79642,17 +80142,17 @@ async function approvalRecord(args, opts) {
|
|
|
79642
80142
|
}
|
|
79643
80143
|
|
|
79644
80144
|
// quota-check.ts
|
|
79645
|
-
import { readFileSync as
|
|
79646
|
-
import { join as
|
|
80145
|
+
import { readFileSync as readFileSync30, existsSync as existsSync32 } from "fs";
|
|
80146
|
+
import { join as join36 } from "path";
|
|
79647
80147
|
var OAUTH_BETA2 = "oauth-2025-04-20";
|
|
79648
80148
|
var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
|
|
79649
80149
|
var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
|
|
79650
80150
|
function readOauthToken2(claudeConfigDir) {
|
|
79651
|
-
const tokenFile =
|
|
79652
|
-
if (!
|
|
80151
|
+
const tokenFile = join36(claudeConfigDir, ".oauth-token");
|
|
80152
|
+
if (!existsSync32(tokenFile))
|
|
79653
80153
|
return null;
|
|
79654
80154
|
try {
|
|
79655
|
-
const raw =
|
|
80155
|
+
const raw = readFileSync30(tokenFile, "utf-8").trim();
|
|
79656
80156
|
return raw.length > 0 ? raw : null;
|
|
79657
80157
|
} catch {
|
|
79658
80158
|
return null;
|
|
@@ -80988,15 +81488,15 @@ async function menuWithBannerStatic(deps, banner) {
|
|
|
80988
81488
|
}
|
|
80989
81489
|
|
|
80990
81490
|
// gateway/session-model-file.ts
|
|
80991
|
-
import { readFileSync as
|
|
80992
|
-
import { join as
|
|
81491
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync28, renameSync as renameSync12, rmSync as rmSync4 } from "node:fs";
|
|
81492
|
+
import { join as join37 } from "node:path";
|
|
80993
81493
|
var SESSION_MODEL_FILE = ".session-model";
|
|
80994
81494
|
var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
|
|
80995
81495
|
var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
|
|
80996
81496
|
function atomicWrite(path2, content3) {
|
|
80997
81497
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
80998
|
-
|
|
80999
|
-
|
|
81498
|
+
writeFileSync28(tmp, content3, "utf8");
|
|
81499
|
+
renameSync12(tmp, path2);
|
|
81000
81500
|
}
|
|
81001
81501
|
function serializeSessionModel(rec) {
|
|
81002
81502
|
return `${JSON.stringify({
|
|
@@ -81011,28 +81511,28 @@ function writeSessionModelFile(agentDir, model, configuredDefaultAtWrite) {
|
|
|
81011
81511
|
throw new Error(`refusing to persist non-canonical session model token: ${JSON.stringify(model)}`);
|
|
81012
81512
|
}
|
|
81013
81513
|
try {
|
|
81014
|
-
rmSync4(
|
|
81514
|
+
rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
81015
81515
|
} catch {}
|
|
81016
|
-
atomicWrite(
|
|
81516
|
+
atomicWrite(join37(agentDir, SESSION_MODEL_FILE), serializeSessionModel({ model, configuredDefaultAtWrite, ts: Date.now() }));
|
|
81017
81517
|
}
|
|
81018
81518
|
function readSessionModelFileRaw(agentDir) {
|
|
81019
81519
|
try {
|
|
81020
|
-
return
|
|
81520
|
+
return readFileSync31(join37(agentDir, SESSION_MODEL_FILE), "utf8");
|
|
81021
81521
|
} catch {
|
|
81022
81522
|
return null;
|
|
81023
81523
|
}
|
|
81024
81524
|
}
|
|
81025
81525
|
function clearSessionModelFile(agentDir) {
|
|
81026
81526
|
try {
|
|
81027
|
-
rmSync4(
|
|
81527
|
+
rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
81028
81528
|
} catch {}
|
|
81029
81529
|
}
|
|
81030
81530
|
function consumeSessionModelCarrierOnHealthyBoot(agentDir) {
|
|
81031
81531
|
try {
|
|
81032
|
-
rmSync4(
|
|
81532
|
+
rmSync4(join37(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
81033
81533
|
} catch {}
|
|
81034
81534
|
try {
|
|
81035
|
-
rmSync4(
|
|
81535
|
+
rmSync4(join37(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
81036
81536
|
} catch {}
|
|
81037
81537
|
}
|
|
81038
81538
|
function restoreSessionModelFileRaw(agentDir, raw) {
|
|
@@ -81041,12 +81541,12 @@ function restoreSessionModelFileRaw(agentDir, raw) {
|
|
|
81041
81541
|
return;
|
|
81042
81542
|
}
|
|
81043
81543
|
try {
|
|
81044
|
-
atomicWrite(
|
|
81544
|
+
atomicWrite(join37(agentDir, SESSION_MODEL_FILE), raw);
|
|
81045
81545
|
} catch {}
|
|
81046
81546
|
}
|
|
81047
81547
|
function readConfiguredDefaultModel(agentDir) {
|
|
81048
81548
|
try {
|
|
81049
|
-
const v =
|
|
81549
|
+
const v = readFileSync31(join37(agentDir, CONFIGURED_DEFAULT_MODEL_FILE), "utf8").trim();
|
|
81050
81550
|
return v.length > 0 ? v : null;
|
|
81051
81551
|
} catch {
|
|
81052
81552
|
return null;
|
|
@@ -81058,12 +81558,12 @@ function writeSessionEffortFile(agentDir, level, configuredDefaultAtWrite) {
|
|
|
81058
81558
|
if (!EFFORT_LEVEL_RE.test(level)) {
|
|
81059
81559
|
throw new Error(`refusing to persist non-allowlisted effort level: ${JSON.stringify(level)}`);
|
|
81060
81560
|
}
|
|
81061
|
-
atomicWrite(
|
|
81561
|
+
atomicWrite(join37(agentDir, SESSION_EFFORT_FILE), `${JSON.stringify({ level, configuredDefaultAtWrite: configuredDefaultAtWrite ?? "", ts: Date.now() })}
|
|
81062
81562
|
`);
|
|
81063
81563
|
}
|
|
81064
81564
|
function clearSessionEffortFile(agentDir) {
|
|
81065
81565
|
try {
|
|
81066
|
-
rmSync4(
|
|
81566
|
+
rmSync4(join37(agentDir, SESSION_EFFORT_FILE), { force: true });
|
|
81067
81567
|
} catch {}
|
|
81068
81568
|
}
|
|
81069
81569
|
var PREMIUM_RECOVERY_FILE = ".premium-recovery";
|
|
@@ -81086,13 +81586,13 @@ function writePremiumRecoveryFile(agentDir, premiumModel, chats) {
|
|
|
81086
81586
|
if (clean.length === 0) {
|
|
81087
81587
|
throw new Error("refusing to persist premium-recovery marker with no chats to notify");
|
|
81088
81588
|
}
|
|
81089
|
-
atomicWrite(
|
|
81589
|
+
atomicWrite(join37(agentDir, PREMIUM_RECOVERY_FILE), `${JSON.stringify({ premiumModel, chats: clean, ts: Date.now() })}
|
|
81090
81590
|
`);
|
|
81091
81591
|
}
|
|
81092
81592
|
function readPremiumRecoveryFile(agentDir) {
|
|
81093
81593
|
let raw;
|
|
81094
81594
|
try {
|
|
81095
|
-
raw =
|
|
81595
|
+
raw = readFileSync31(join37(agentDir, PREMIUM_RECOVERY_FILE), "utf8");
|
|
81096
81596
|
} catch {
|
|
81097
81597
|
return null;
|
|
81098
81598
|
}
|
|
@@ -81105,7 +81605,7 @@ function readPremiumRecoveryFile(agentDir) {
|
|
|
81105
81605
|
}
|
|
81106
81606
|
function clearPremiumRecoveryFile(agentDir) {
|
|
81107
81607
|
try {
|
|
81108
|
-
rmSync4(
|
|
81608
|
+
rmSync4(join37(agentDir, PREMIUM_RECOVERY_FILE), { force: true });
|
|
81109
81609
|
} catch {}
|
|
81110
81610
|
}
|
|
81111
81611
|
|
|
@@ -81394,7 +81894,7 @@ async function discoverModels(agentName3, opts = {}) {
|
|
|
81394
81894
|
}
|
|
81395
81895
|
|
|
81396
81896
|
// ../src/agents/scaffold.ts
|
|
81397
|
-
import { dirname as dirname14, isAbsolute, join as
|
|
81897
|
+
import { dirname as dirname14, isAbsolute, join as join40, relative, resolve as resolve8 } from "node:path";
|
|
81398
81898
|
init_atomic();
|
|
81399
81899
|
|
|
81400
81900
|
// ../src/agents/agent-uid.ts
|
|
@@ -81411,7 +81911,7 @@ init_merge();
|
|
|
81411
81911
|
init_timezone();
|
|
81412
81912
|
|
|
81413
81913
|
// ../src/cli/agent-config.ts
|
|
81414
|
-
import { join as
|
|
81914
|
+
import { join as join38 } from "node:path";
|
|
81415
81915
|
import { homedir as homedir12 } from "node:os";
|
|
81416
81916
|
|
|
81417
81917
|
// ../src/cli/helpers.ts
|
|
@@ -81432,12 +81932,12 @@ var WEBKITE_VAULT_KEYS = new Set([
|
|
|
81432
81932
|
init_overlay_loader();
|
|
81433
81933
|
|
|
81434
81934
|
// ../src/cli/agent-config.ts
|
|
81435
|
-
var AUDIT_ROOT =
|
|
81935
|
+
var AUDIT_ROOT = join38(homedir12(), ".switchroom", "audit");
|
|
81436
81936
|
|
|
81437
81937
|
// ../src/agents/profiles.ts
|
|
81438
81938
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
81439
|
-
import { readFileSync as
|
|
81440
|
-
import { resolve as resolve7, join as
|
|
81939
|
+
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";
|
|
81940
|
+
import { resolve as resolve7, join as join39, sep as pathSep } from "node:path";
|
|
81441
81941
|
function resolveProfilesRoot() {
|
|
81442
81942
|
const envOverride = process.env.SWITCHROOM_PROFILES_ROOT?.trim();
|
|
81443
81943
|
if (envOverride) {
|
|
@@ -81448,7 +81948,7 @@ function resolveProfilesRoot() {
|
|
|
81448
81948
|
resolve7(import.meta.dirname, "profiles")
|
|
81449
81949
|
];
|
|
81450
81950
|
for (const candidate of candidates) {
|
|
81451
|
-
if (
|
|
81951
|
+
if (existsSync33(candidate)) {
|
|
81452
81952
|
return candidate;
|
|
81453
81953
|
}
|
|
81454
81954
|
}
|
|
@@ -81464,9 +81964,9 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
|
|
|
81464
81964
|
var SHARED_FRAGMENTS_DIR = resolve7(PROFILES_ROOT, "_shared");
|
|
81465
81965
|
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
|
|
81466
81966
|
for (const name of SHARED_FRAGMENTS) {
|
|
81467
|
-
const fragPath =
|
|
81468
|
-
if (
|
|
81469
|
-
import_handlebars.default.registerPartial(name,
|
|
81967
|
+
const fragPath = join39(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
81968
|
+
if (existsSync33(fragPath)) {
|
|
81969
|
+
import_handlebars.default.registerPartial(name, readFileSync32(fragPath, "utf-8"));
|
|
81470
81970
|
}
|
|
81471
81971
|
}
|
|
81472
81972
|
|
|
@@ -82073,7 +82573,7 @@ init_overlay_loader();
|
|
|
82073
82573
|
init_merge();
|
|
82074
82574
|
init_timezone();
|
|
82075
82575
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
82076
|
-
import { readFileSync as
|
|
82576
|
+
import { readFileSync as readFileSync33, existsSync as existsSync34 } from "node:fs";
|
|
82077
82577
|
import { homedir as homedir13 } from "node:os";
|
|
82078
82578
|
import { resolve as resolve9 } from "node:path";
|
|
82079
82579
|
|
|
@@ -82149,7 +82649,7 @@ function findConfigFile2(startDir) {
|
|
|
82149
82649
|
resolve9(userDir, "clerk.yml")
|
|
82150
82650
|
].filter(Boolean);
|
|
82151
82651
|
for (const path2 of searchPaths) {
|
|
82152
|
-
if (
|
|
82652
|
+
if (existsSync34(path2)) {
|
|
82153
82653
|
return path2;
|
|
82154
82654
|
}
|
|
82155
82655
|
}
|
|
@@ -82157,12 +82657,12 @@ function findConfigFile2(startDir) {
|
|
|
82157
82657
|
}
|
|
82158
82658
|
function loadConfig2(configPath) {
|
|
82159
82659
|
const filePath = configPath ?? findConfigFile2();
|
|
82160
|
-
if (!
|
|
82660
|
+
if (!existsSync34(filePath)) {
|
|
82161
82661
|
throw new ConfigError2(`Config file not found: ${filePath}`);
|
|
82162
82662
|
}
|
|
82163
82663
|
let raw;
|
|
82164
82664
|
try {
|
|
82165
|
-
raw =
|
|
82665
|
+
raw = readFileSync33(filePath, "utf-8");
|
|
82166
82666
|
} catch (err) {
|
|
82167
82667
|
throw new ConfigError2(`Failed to read config file: ${filePath}`, [
|
|
82168
82668
|
` ${err.message}`
|
|
@@ -82692,15 +83192,15 @@ function topicForRecipient(args) {
|
|
|
82692
83192
|
}
|
|
82693
83193
|
|
|
82694
83194
|
// ../src/agents/perf.ts
|
|
82695
|
-
import { existsSync as
|
|
83195
|
+
import { existsSync as existsSync35, readFileSync as readFileSync34 } from "node:fs";
|
|
82696
83196
|
function readTurnUsages(jsonlPath, lastN) {
|
|
82697
|
-
if (!
|
|
83197
|
+
if (!existsSync35(jsonlPath))
|
|
82698
83198
|
return [];
|
|
82699
83199
|
if (lastN <= 0)
|
|
82700
83200
|
return [];
|
|
82701
83201
|
let raw;
|
|
82702
83202
|
try {
|
|
82703
|
-
raw =
|
|
83203
|
+
raw = readFileSync34(jsonlPath, "utf-8");
|
|
82704
83204
|
} catch {
|
|
82705
83205
|
return [];
|
|
82706
83206
|
}
|
|
@@ -82791,8 +83291,8 @@ function numField(obj, key) {
|
|
|
82791
83291
|
}
|
|
82792
83292
|
|
|
82793
83293
|
// gateway/context-occupancy.ts
|
|
82794
|
-
import { mkdirSync as
|
|
82795
|
-
import { join as
|
|
83294
|
+
import { mkdirSync as mkdirSync32, writeFileSync as writeFileSync30 } from "node:fs";
|
|
83295
|
+
import { join as join41 } from "node:path";
|
|
82796
83296
|
var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
|
|
82797
83297
|
var TIGHT_FRACTION = 0.8;
|
|
82798
83298
|
function buildContextOccupancy(occupancy, cap, now) {
|
|
@@ -82815,9 +83315,9 @@ function buildContextOccupancy(occupancy, cap, now) {
|
|
|
82815
83315
|
}
|
|
82816
83316
|
function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
|
|
82817
83317
|
try {
|
|
82818
|
-
const path2 =
|
|
82819
|
-
(deps?.mkdir ?? ((p, o) =>
|
|
82820
|
-
(deps?.writeFile ?? ((p, d) =>
|
|
83318
|
+
const path2 = join41(stateDir, CONTEXT_OCCUPANCY_FILENAME);
|
|
83319
|
+
(deps?.mkdir ?? ((p, o) => mkdirSync32(p, o)))(stateDir, { recursive: true });
|
|
83320
|
+
(deps?.writeFile ?? ((p, d) => writeFileSync30(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
|
|
82821
83321
|
`);
|
|
82822
83322
|
} catch {}
|
|
82823
83323
|
}
|
|
@@ -82971,7 +83471,7 @@ function nextCompactNotify(state6, ev) {
|
|
|
82971
83471
|
}
|
|
82972
83472
|
|
|
82973
83473
|
// gateway/hostd-dispatch.ts
|
|
82974
|
-
import { existsSync as
|
|
83474
|
+
import { existsSync as existsSync36 } from "node:fs";
|
|
82975
83475
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
82976
83476
|
init_loader();
|
|
82977
83477
|
var _hostdEnabled2;
|
|
@@ -82995,13 +83495,13 @@ function hostdSocketPath2(agentName3) {
|
|
|
82995
83495
|
function hostdWillBeUsed2(agentName3) {
|
|
82996
83496
|
if (!isHostdEnabled2())
|
|
82997
83497
|
return false;
|
|
82998
|
-
return
|
|
83498
|
+
return existsSync36(hostdSocketPath2(agentName3));
|
|
82999
83499
|
}
|
|
83000
83500
|
async function tryHostdDispatch2(agentName3, req, timeoutMs = 5000) {
|
|
83001
83501
|
if (!isHostdEnabled2())
|
|
83002
83502
|
return "not-configured";
|
|
83003
83503
|
const sockPath = hostdSocketPath2(agentName3);
|
|
83004
|
-
if (!
|
|
83504
|
+
if (!existsSync36(sockPath))
|
|
83005
83505
|
return "not-configured";
|
|
83006
83506
|
try {
|
|
83007
83507
|
return await hostdRequest({ socketPath: sockPath, timeoutMs }, req);
|
|
@@ -83030,7 +83530,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
|
|
|
83030
83530
|
if (!isHostdEnabled2())
|
|
83031
83531
|
return "not-configured";
|
|
83032
83532
|
const sockPath = hostdSocketPath2(agentName3);
|
|
83033
|
-
if (!
|
|
83533
|
+
if (!existsSync36(sockPath))
|
|
83034
83534
|
return "not-configured";
|
|
83035
83535
|
const now = opts.now ?? Date.now;
|
|
83036
83536
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -83149,7 +83649,7 @@ function createDmPinSweeper(deps) {
|
|
|
83149
83649
|
|
|
83150
83650
|
// gateway/webhook-ingest-server.ts
|
|
83151
83651
|
import net4 from "node:net";
|
|
83152
|
-
import { chmodSync as chmodSync10, existsSync as
|
|
83652
|
+
import { chmodSync as chmodSync10, existsSync as existsSync37, unlinkSync as unlinkSync17 } from "node:fs";
|
|
83153
83653
|
var MAX_REQUEST_BYTES = 1024 * 1024;
|
|
83154
83654
|
function fdOf(conn) {
|
|
83155
83655
|
const handle = conn._handle;
|
|
@@ -83161,7 +83661,7 @@ function startWebhookIngestServer(opts) {
|
|
|
83161
83661
|
const log = opts.log ?? ((s) => process.stderr.write(s));
|
|
83162
83662
|
const allowed = new Set(opts.allowedUids);
|
|
83163
83663
|
try {
|
|
83164
|
-
if (
|
|
83664
|
+
if (existsSync37(opts.socketPath))
|
|
83165
83665
|
unlinkSync17(opts.socketPath);
|
|
83166
83666
|
} catch (err) {
|
|
83167
83667
|
log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
|
|
@@ -83254,7 +83754,7 @@ function startWebhookIngestServer(opts) {
|
|
|
83254
83754
|
server.close();
|
|
83255
83755
|
} catch {}
|
|
83256
83756
|
try {
|
|
83257
|
-
if (
|
|
83757
|
+
if (existsSync37(opts.socketPath))
|
|
83258
83758
|
unlinkSync17(opts.socketPath);
|
|
83259
83759
|
} catch {}
|
|
83260
83760
|
}
|
|
@@ -83262,20 +83762,20 @@ function startWebhookIngestServer(opts) {
|
|
|
83262
83762
|
}
|
|
83263
83763
|
|
|
83264
83764
|
// ../src/web/webhook-gateway-record.ts
|
|
83265
|
-
import { appendFileSync as
|
|
83266
|
-
import { join as
|
|
83765
|
+
import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync35 } from "fs";
|
|
83766
|
+
import { join as join44 } from "path";
|
|
83267
83767
|
import { homedir as homedir15 } from "os";
|
|
83268
83768
|
|
|
83269
83769
|
// ../src/web/webhook-handler.ts
|
|
83270
|
-
import { appendFileSync as
|
|
83271
|
-
import { join as
|
|
83770
|
+
import { appendFileSync as appendFileSync7, existsSync as existsSync38, mkdirSync as mkdirSync33, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "fs";
|
|
83771
|
+
import { join as join42 } from "path";
|
|
83272
83772
|
var DEDUP_MAX = 1000;
|
|
83273
83773
|
var DEDUP_TTL_MS = 24 * 60 * 60 * 1000;
|
|
83274
83774
|
function loadDedupFile(path2) {
|
|
83275
83775
|
try {
|
|
83276
|
-
if (!
|
|
83776
|
+
if (!existsSync38(path2))
|
|
83277
83777
|
return {};
|
|
83278
|
-
const raw = JSON.parse(
|
|
83778
|
+
const raw = JSON.parse(readFileSync35(path2, "utf-8"));
|
|
83279
83779
|
return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
|
|
83280
83780
|
} catch {
|
|
83281
83781
|
return {};
|
|
@@ -83289,7 +83789,7 @@ function saveDedupFile(path2, deliveries, now) {
|
|
|
83289
83789
|
}
|
|
83290
83790
|
const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
|
|
83291
83791
|
const final = Object.fromEntries(sorted);
|
|
83292
|
-
|
|
83792
|
+
writeFileSync31(path2, JSON.stringify({ deliveries: final }), {
|
|
83293
83793
|
mode: 384
|
|
83294
83794
|
});
|
|
83295
83795
|
}
|
|
@@ -83297,8 +83797,8 @@ var agentDedupCache = new Map;
|
|
|
83297
83797
|
function createFileDedupStore(resolveAgentDir) {
|
|
83298
83798
|
return {
|
|
83299
83799
|
check(agent, deliveryId, now) {
|
|
83300
|
-
const telegramDir =
|
|
83301
|
-
const filePath =
|
|
83800
|
+
const telegramDir = join42(resolveAgentDir(agent), "telegram");
|
|
83801
|
+
const filePath = join42(telegramDir, "webhook-dedup.json");
|
|
83302
83802
|
if (!agentDedupCache.has(agent)) {
|
|
83303
83803
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
83304
83804
|
}
|
|
@@ -83308,7 +83808,7 @@ function createFileDedupStore(resolveAgentDir) {
|
|
|
83308
83808
|
}
|
|
83309
83809
|
deliveries[deliveryId] = now;
|
|
83310
83810
|
try {
|
|
83311
|
-
|
|
83811
|
+
mkdirSync33(telegramDir, { recursive: true });
|
|
83312
83812
|
saveDedupFile(filePath, deliveries, now);
|
|
83313
83813
|
} catch {}
|
|
83314
83814
|
return;
|
|
@@ -83319,8 +83819,8 @@ var tokenBuckets = new Map;
|
|
|
83319
83819
|
var throttleIssueWindow = new Map;
|
|
83320
83820
|
|
|
83321
83821
|
// ../src/web/webhook-dispatch.ts
|
|
83322
|
-
import { existsSync as
|
|
83323
|
-
import { join as
|
|
83822
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync34, readFileSync as readFileSync36, writeFileSync as writeFileSync32 } from "fs";
|
|
83823
|
+
import { join as join43 } from "path";
|
|
83324
83824
|
import { homedir as homedir14 } from "os";
|
|
83325
83825
|
|
|
83326
83826
|
// ../src/agent-scheduler/ipc-client.ts
|
|
@@ -83619,9 +84119,9 @@ function cooldownKey(source, eventType, repo, number, ruleIndex) {
|
|
|
83619
84119
|
}
|
|
83620
84120
|
function loadCooldownFile(path2) {
|
|
83621
84121
|
try {
|
|
83622
|
-
if (!
|
|
84122
|
+
if (!existsSync39(path2))
|
|
83623
84123
|
return {};
|
|
83624
|
-
const raw = JSON.parse(
|
|
84124
|
+
const raw = JSON.parse(readFileSync36(path2, "utf-8"));
|
|
83625
84125
|
return typeof raw.dispatches === "object" && raw.dispatches !== null ? raw.dispatches : {};
|
|
83626
84126
|
} catch {
|
|
83627
84127
|
return {};
|
|
@@ -83629,7 +84129,7 @@ function loadCooldownFile(path2) {
|
|
|
83629
84129
|
}
|
|
83630
84130
|
function saveCooldownFile(path2, dispatches) {
|
|
83631
84131
|
try {
|
|
83632
|
-
|
|
84132
|
+
writeFileSync32(path2, JSON.stringify({ dispatches }), {
|
|
83633
84133
|
mode: 384
|
|
83634
84134
|
});
|
|
83635
84135
|
} catch {}
|
|
@@ -83640,8 +84140,8 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
83640
84140
|
isCoolingDown(agent, key, cooldownMs, now) {
|
|
83641
84141
|
if (cooldownMs <= 0)
|
|
83642
84142
|
return false;
|
|
83643
|
-
const telegramDir =
|
|
83644
|
-
const filePath =
|
|
84143
|
+
const telegramDir = join43(resolveAgentDir(agent), "telegram");
|
|
84144
|
+
const filePath = join43(telegramDir, "webhook-cooldown.json");
|
|
83645
84145
|
if (!cache.has(agent)) {
|
|
83646
84146
|
cache.set(agent, loadCooldownFile(filePath));
|
|
83647
84147
|
}
|
|
@@ -83652,7 +84152,7 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
83652
84152
|
}
|
|
83653
84153
|
dispatches[key] = now;
|
|
83654
84154
|
try {
|
|
83655
|
-
|
|
84155
|
+
mkdirSync34(telegramDir, { recursive: true });
|
|
83656
84156
|
saveCooldownFile(filePath, dispatches);
|
|
83657
84157
|
} catch {}
|
|
83658
84158
|
return false;
|
|
@@ -83698,9 +84198,9 @@ async function defaultInject(socketPath, agentName3, inbound) {
|
|
|
83698
84198
|
}
|
|
83699
84199
|
function injectWebhookInbound(agent, prompt, ctx, deps = {}) {
|
|
83700
84200
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83701
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84201
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
|
|
83702
84202
|
const now = (deps.now ?? Date.now)();
|
|
83703
|
-
const socketPath =
|
|
84203
|
+
const socketPath = join43(resolveAgentDir(agent), "telegram", "gateway.sock");
|
|
83704
84204
|
const inbound = {
|
|
83705
84205
|
type: "inbound",
|
|
83706
84206
|
chatId: ctx.chatId,
|
|
@@ -83772,7 +84272,7 @@ function evaluateDispatch(args, deps = {}) {
|
|
|
83772
84272
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83773
84273
|
const now = (deps.now ?? Date.now)();
|
|
83774
84274
|
const nowDate = deps.nowDate ?? (() => new Date(now));
|
|
83775
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84275
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir14(), ".switchroom", "agents", a));
|
|
83776
84276
|
const cooldownStore = deps.cooldownStore ?? createFileCooldownStore(resolveAgentDir);
|
|
83777
84277
|
if (!DISPATCH_SOURCES.includes(args.source))
|
|
83778
84278
|
return 0;
|
|
@@ -83850,10 +84350,10 @@ var CONSOLIDATION_COMPLETED_EVENT = "consolidation.completed";
|
|
|
83850
84350
|
function recordWebhookEvent(rec, deps = {}) {
|
|
83851
84351
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
83852
84352
|
const now = rec.ts || (deps.now ?? Date.now)();
|
|
83853
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
84353
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join44(homedir15(), ".switchroom", "agents", a));
|
|
83854
84354
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
83855
84355
|
const agent = rec.agent;
|
|
83856
|
-
const telegramDir =
|
|
84356
|
+
const telegramDir = join44(resolveAgentDir(agent), "telegram");
|
|
83857
84357
|
if (rec.source === "github" && rec.delivery_id) {
|
|
83858
84358
|
const originalTs = dedupStore.check(agent, rec.delivery_id, now);
|
|
83859
84359
|
if (originalTs !== undefined) {
|
|
@@ -83862,9 +84362,9 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83862
84362
|
return { status: "deduped", ts: originalTs };
|
|
83863
84363
|
}
|
|
83864
84364
|
}
|
|
83865
|
-
const logPath =
|
|
84365
|
+
const logPath = join44(telegramDir, "webhook-events.jsonl");
|
|
83866
84366
|
try {
|
|
83867
|
-
|
|
84367
|
+
mkdirSync35(telegramDir, { recursive: true });
|
|
83868
84368
|
const record = {
|
|
83869
84369
|
ts: now,
|
|
83870
84370
|
source: rec.source,
|
|
@@ -83872,7 +84372,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83872
84372
|
rendered_text: rec.rendered_text,
|
|
83873
84373
|
payload: rec.payload
|
|
83874
84374
|
};
|
|
83875
|
-
|
|
84375
|
+
appendFileSync8(logPath, JSON.stringify(record) + `
|
|
83876
84376
|
`, { mode: 384 });
|
|
83877
84377
|
} catch (err) {
|
|
83878
84378
|
log(`webhook-gateway: agent='${agent}' source='${rec.source}' write failed: ${err.message}
|
|
@@ -83974,7 +84474,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
83974
84474
|
|
|
83975
84475
|
// gateway/ipc-server.ts
|
|
83976
84476
|
init_format();
|
|
83977
|
-
import { renameSync as
|
|
84477
|
+
import { renameSync as renameSync14, unlinkSync as unlinkSync18, chmodSync as chmodSync11 } from "fs";
|
|
83978
84478
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
83979
84479
|
var VALID_OPERATOR_KINDS = new Set([
|
|
83980
84480
|
"credentials-expired",
|
|
@@ -84183,7 +84683,7 @@ function createIpcServer(options) {
|
|
|
84183
84683
|
heartbeatTimeoutMs = 30000
|
|
84184
84684
|
} = options;
|
|
84185
84685
|
try {
|
|
84186
|
-
|
|
84686
|
+
renameSync14(socketPath, socketPath + ".bak");
|
|
84187
84687
|
} catch {}
|
|
84188
84688
|
try {
|
|
84189
84689
|
unlinkSync18(socketPath + ".bak");
|
|
@@ -84573,7 +85073,7 @@ function createIpcServer(options) {
|
|
|
84573
85073
|
clientBySocketId.clear();
|
|
84574
85074
|
server.stop(true);
|
|
84575
85075
|
try {
|
|
84576
|
-
|
|
85076
|
+
renameSync14(socketPath, socketPath + ".bak");
|
|
84577
85077
|
} catch {}
|
|
84578
85078
|
}
|
|
84579
85079
|
};
|
|
@@ -84883,15 +85383,15 @@ function buildMs365CardText(p) {
|
|
|
84883
85383
|
const lines = [];
|
|
84884
85384
|
lines.push(`\uD83D\uDCC4 Microsoft 365 write approval`);
|
|
84885
85385
|
lines.push("");
|
|
84886
|
-
lines.push(`Agent: ${
|
|
84887
|
-
lines.push(`Tool: ${
|
|
84888
|
-
lines.push(`Item: ${
|
|
85386
|
+
lines.push(`Agent: ${truncate3(p.agentName, 64)}`);
|
|
85387
|
+
lines.push(`Tool: ${truncate3(p.toolName.replace(/^mcp__/, ""), 96)}`);
|
|
85388
|
+
lines.push(`Item: ${truncate3(p.itemDisplayName, 256)}`);
|
|
84889
85389
|
if (p.itemId !== "(new)") {
|
|
84890
|
-
lines.push(`ID: ${
|
|
85390
|
+
lines.push(`ID: ${truncate3(p.itemId, 96)}`);
|
|
84891
85391
|
}
|
|
84892
|
-
lines.push(`Account: ${
|
|
85392
|
+
lines.push(`Account: ${truncate3(p.accountEmail, 96)}`);
|
|
84893
85393
|
if (p.eventWhen) {
|
|
84894
|
-
lines.push(`When: ${
|
|
85394
|
+
lines.push(`When: ${truncate3(p.eventWhen, 96)}`);
|
|
84895
85395
|
}
|
|
84896
85396
|
if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
|
|
84897
85397
|
const before = p.sizeBytesBefore ?? 0;
|
|
@@ -84901,27 +85401,27 @@ function buildMs365CardText(p) {
|
|
|
84901
85401
|
lines.push(`Size: ${humanBytes(before)} \u2192 ${humanBytes(after)} (${sign}${humanBytes(delta)})`);
|
|
84902
85402
|
}
|
|
84903
85403
|
if (p.deepLink) {
|
|
84904
|
-
lines.push(`Link: ${
|
|
85404
|
+
lines.push(`Link: ${truncate3(p.deepLink, 256)}`);
|
|
84905
85405
|
}
|
|
84906
85406
|
if (p.changes && p.changes.length > 0) {
|
|
84907
85407
|
lines.push("");
|
|
84908
85408
|
lines.push("Changes:");
|
|
84909
85409
|
for (const c of p.changes.slice(0, 8)) {
|
|
84910
|
-
const before = c.before !== undefined ?
|
|
84911
|
-
const after = c.after !== undefined ?
|
|
85410
|
+
const before = c.before !== undefined ? truncate3(c.before, 96) : "(none)";
|
|
85411
|
+
const after = c.after !== undefined ? truncate3(c.after, 96) : "(cleared)";
|
|
84912
85412
|
lines.push(`\u2022 ${c.field}: ${before} \u2192 ${after}`);
|
|
84913
85413
|
}
|
|
84914
85414
|
}
|
|
84915
85415
|
if (p.agentRationale) {
|
|
84916
85416
|
lines.push("");
|
|
84917
|
-
lines.push(`\uD83D\uDCAC ${
|
|
85417
|
+
lines.push(`\uD83D\uDCAC ${truncate3(p.agentRationale, 512)}`);
|
|
84918
85418
|
}
|
|
84919
85419
|
lines.push("");
|
|
84920
85420
|
lines.push(p.changes && p.changes.length > 0 ? "\u26a0\ufe0f Attestation (RFC \u00a78 v1.5): the diff above is derived from live Graph state + the mutation payload. Verify before approving." : "\u26a0\ufe0f Weak attestation (RFC \u00a78 v1): operator should click through to verify the actual change before approving. Structural diff coming v1.5.");
|
|
84921
85421
|
return hardenCardBreaks(lines.join(`
|
|
84922
85422
|
`));
|
|
84923
85423
|
}
|
|
84924
|
-
function
|
|
85424
|
+
function truncate3(s, n) {
|
|
84925
85425
|
const oneLine = s.replace(/[\r\n\t]+/g, " ");
|
|
84926
85426
|
if (oneLine.length <= n)
|
|
84927
85427
|
return oneLine;
|
|
@@ -88233,6 +88733,246 @@ function buildSilencePokeOptions(deps) {
|
|
|
88233
88733
|
};
|
|
88234
88734
|
}
|
|
88235
88735
|
|
|
88736
|
+
// tool-labels.ts
|
|
88737
|
+
var MAX_LABEL_CHARS = 60;
|
|
88738
|
+
var MAX_BASH_CHARS = 40;
|
|
88739
|
+
var MAX_DESCRIPTION_CHARS = 160;
|
|
88740
|
+
function basename8(p) {
|
|
88741
|
+
if (!p)
|
|
88742
|
+
return "";
|
|
88743
|
+
const parts = p.split("/").filter(Boolean);
|
|
88744
|
+
return parts.length > 0 ? parts[parts.length - 1] : p;
|
|
88745
|
+
}
|
|
88746
|
+
function shortenGrepPath(p) {
|
|
88747
|
+
if (!p)
|
|
88748
|
+
return "repo";
|
|
88749
|
+
const hadTrailingSlash = /\/+$/.test(p);
|
|
88750
|
+
const trimmed = p.replace(/\/+$/, "");
|
|
88751
|
+
const parts = trimmed.split("/").filter(Boolean);
|
|
88752
|
+
if (parts.length === 0)
|
|
88753
|
+
return "repo";
|
|
88754
|
+
const last = parts[parts.length - 1];
|
|
88755
|
+
if (hadTrailingSlash)
|
|
88756
|
+
return `${last}/`;
|
|
88757
|
+
if (last.startsWith(".") && !last.slice(1).includes("."))
|
|
88758
|
+
return last;
|
|
88759
|
+
if (!last.includes("."))
|
|
88760
|
+
return `${last}/`;
|
|
88761
|
+
return last;
|
|
88762
|
+
}
|
|
88763
|
+
function hostFromUrl(u) {
|
|
88764
|
+
if (!u)
|
|
88765
|
+
return "";
|
|
88766
|
+
try {
|
|
88767
|
+
return new URL(u).host;
|
|
88768
|
+
} catch {
|
|
88769
|
+
return truncate4(u);
|
|
88770
|
+
}
|
|
88771
|
+
}
|
|
88772
|
+
function truncate4(s, n = MAX_LABEL_CHARS) {
|
|
88773
|
+
if (s.length <= n)
|
|
88774
|
+
return s;
|
|
88775
|
+
return s.slice(0, n - 1) + "\u2026";
|
|
88776
|
+
}
|
|
88777
|
+
function stripHtml(s) {
|
|
88778
|
+
return s.replace(/<\/?[a-zA-Z][^>]*>/g, "");
|
|
88779
|
+
}
|
|
88780
|
+
function firstLine(s) {
|
|
88781
|
+
const idx = s.indexOf(`
|
|
88782
|
+
`);
|
|
88783
|
+
return idx === -1 ? s : s.slice(0, idx);
|
|
88784
|
+
}
|
|
88785
|
+
function toolLabel(tool, input, preamble, precomputedLabel) {
|
|
88786
|
+
if (precomputedLabel && precomputedLabel.trim().length > 0) {
|
|
88787
|
+
return truncate4(firstLine(precomputedLabel.trim()), MAX_DESCRIPTION_CHARS);
|
|
88788
|
+
}
|
|
88789
|
+
if (!input || typeof input !== "object")
|
|
88790
|
+
return "";
|
|
88791
|
+
const str = (k) => typeof input[k] === "string" ? input[k] : undefined;
|
|
88792
|
+
const preambleLabel = () => {
|
|
88793
|
+
if (!preamble)
|
|
88794
|
+
return null;
|
|
88795
|
+
if (preamble.includes(`
|
|
88796
|
+
`))
|
|
88797
|
+
return null;
|
|
88798
|
+
const trimmed = preamble.trim();
|
|
88799
|
+
if (!trimmed)
|
|
88800
|
+
return null;
|
|
88801
|
+
if (trimmed.length > MAX_DESCRIPTION_CHARS)
|
|
88802
|
+
return null;
|
|
88803
|
+
return trimmed;
|
|
88804
|
+
};
|
|
88805
|
+
switch (tool) {
|
|
88806
|
+
case "Read":
|
|
88807
|
+
case "Write":
|
|
88808
|
+
case "NotebookEdit":
|
|
88809
|
+
case "Edit": {
|
|
88810
|
+
const pre = preambleLabel();
|
|
88811
|
+
if (pre)
|
|
88812
|
+
return pre;
|
|
88813
|
+
return truncate4(basename8(str("file_path") ?? ""));
|
|
88814
|
+
}
|
|
88815
|
+
case "Bash":
|
|
88816
|
+
case "BashOutput": {
|
|
88817
|
+
const description = str("description");
|
|
88818
|
+
if (description)
|
|
88819
|
+
return truncate4(firstLine(description), MAX_DESCRIPTION_CHARS);
|
|
88820
|
+
const pre = preambleLabel();
|
|
88821
|
+
if (pre)
|
|
88822
|
+
return pre;
|
|
88823
|
+
const cmd = str("command") ?? str("bash_id") ?? "";
|
|
88824
|
+
return truncate4(firstLine(cmd), MAX_BASH_CHARS);
|
|
88825
|
+
}
|
|
88826
|
+
case "KillShell":
|
|
88827
|
+
return truncate4(str("shell_id") ?? "");
|
|
88828
|
+
case "Glob": {
|
|
88829
|
+
const pre = preambleLabel();
|
|
88830
|
+
if (pre)
|
|
88831
|
+
return pre;
|
|
88832
|
+
return truncate4(str("pattern") ?? "");
|
|
88833
|
+
}
|
|
88834
|
+
case "Grep": {
|
|
88835
|
+
const pre = preambleLabel();
|
|
88836
|
+
if (pre)
|
|
88837
|
+
return pre;
|
|
88838
|
+
const pat = str("pattern") ?? "";
|
|
88839
|
+
if (!pat)
|
|
88840
|
+
return "";
|
|
88841
|
+
const path2 = str("path");
|
|
88842
|
+
const where = shortenGrepPath(path2 ?? "");
|
|
88843
|
+
return truncate4(`"${pat}" (in ${where})`);
|
|
88844
|
+
}
|
|
88845
|
+
case "WebFetch":
|
|
88846
|
+
return truncate4(hostFromUrl(str("url") ?? ""));
|
|
88847
|
+
case "WebSearch": {
|
|
88848
|
+
const q = str("query") ?? "";
|
|
88849
|
+
return q ? truncate4(`"${q}"`) : "";
|
|
88850
|
+
}
|
|
88851
|
+
case "Task":
|
|
88852
|
+
case "Agent": {
|
|
88853
|
+
const desc = str("description") ?? str("subagent_type") ?? "";
|
|
88854
|
+
return truncate4(desc);
|
|
88855
|
+
}
|
|
88856
|
+
case "TodoWrite":
|
|
88857
|
+
case "TaskCreate":
|
|
88858
|
+
case "TaskUpdate":
|
|
88859
|
+
case "TaskList":
|
|
88860
|
+
case "TaskGet":
|
|
88861
|
+
case "TaskStop":
|
|
88862
|
+
case "TaskOutput":
|
|
88863
|
+
return "";
|
|
88864
|
+
case "Skill":
|
|
88865
|
+
return truncate4(str("skill") ?? "");
|
|
88866
|
+
case "SlashCommand":
|
|
88867
|
+
return truncate4(str("command") ?? "");
|
|
88868
|
+
case "ToolSearch": {
|
|
88869
|
+
const q = str("query") ?? "";
|
|
88870
|
+
if (!q)
|
|
88871
|
+
return "";
|
|
88872
|
+
const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i);
|
|
88873
|
+
if (selectMatch) {
|
|
88874
|
+
const names = selectMatch[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0).join(", ");
|
|
88875
|
+
return truncate4(`Loading schema: ${names}`);
|
|
88876
|
+
}
|
|
88877
|
+
return truncate4(`Searching tools: ${q}`);
|
|
88878
|
+
}
|
|
88879
|
+
default:
|
|
88880
|
+
if (tool.startsWith("mcp__")) {
|
|
88881
|
+
const description = str("description");
|
|
88882
|
+
if (description)
|
|
88883
|
+
return truncate4(firstLine(stripHtml(description)), MAX_DESCRIPTION_CHARS);
|
|
88884
|
+
const label = mcpBaseLabel(tool);
|
|
88885
|
+
const query3 = str("query") ?? str("text") ?? str("name");
|
|
88886
|
+
if (label && query3) {
|
|
88887
|
+
const budget = Math.max(8, MAX_LABEL_CHARS - label.length - 4);
|
|
88888
|
+
const preview = truncate4(firstLine(stripHtml(query3)), budget);
|
|
88889
|
+
return `${label} (${preview})`;
|
|
88890
|
+
}
|
|
88891
|
+
if (label)
|
|
88892
|
+
return truncate4(label);
|
|
88893
|
+
}
|
|
88894
|
+
for (const k of ["description", "file_path", "path", "url", "query", "pattern", "command"]) {
|
|
88895
|
+
const v = str(k);
|
|
88896
|
+
if (v != null && v.length > 0) {
|
|
88897
|
+
if (k === "file_path" || k === "path")
|
|
88898
|
+
return truncate4(basename8(v));
|
|
88899
|
+
if (k === "url")
|
|
88900
|
+
return truncate4(hostFromUrl(v));
|
|
88901
|
+
if (k === "description")
|
|
88902
|
+
return truncate4(firstLine(v), MAX_DESCRIPTION_CHARS);
|
|
88903
|
+
return truncate4(firstLine(v));
|
|
88904
|
+
}
|
|
88905
|
+
}
|
|
88906
|
+
return "";
|
|
88907
|
+
}
|
|
88908
|
+
}
|
|
88909
|
+
function mcpBaseLabel(tool) {
|
|
88910
|
+
if (!tool.startsWith("mcp__"))
|
|
88911
|
+
return "";
|
|
88912
|
+
const parts = tool.slice("mcp__".length).split("__");
|
|
88913
|
+
if (parts.length < 2)
|
|
88914
|
+
return "";
|
|
88915
|
+
const rawServer = parts[0];
|
|
88916
|
+
const action = parts.slice(1).join("__");
|
|
88917
|
+
if (!rawServer || !action)
|
|
88918
|
+
return "";
|
|
88919
|
+
return `${prettifyServer(rawServer)}: ${action}`;
|
|
88920
|
+
}
|
|
88921
|
+
function prettifyServer(name) {
|
|
88922
|
+
const LABELS = {
|
|
88923
|
+
"switchroom-telegram": "Telegram"
|
|
88924
|
+
};
|
|
88925
|
+
if (LABELS[name])
|
|
88926
|
+
return LABELS[name];
|
|
88927
|
+
if (!name)
|
|
88928
|
+
return name;
|
|
88929
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
88930
|
+
}
|
|
88931
|
+
|
|
88932
|
+
// gateway/background-shell-liveness.ts
|
|
88933
|
+
var TERMINAL_STATUSES = new Set(["completed", "failed", "killed"]);
|
|
88934
|
+
function applyBackgroundShellLiveness(registry, key, ev) {
|
|
88935
|
+
if (ev.kind === "tool_result") {
|
|
88936
|
+
if (ev.backgroundTaskId != null && ev.backgroundTaskId.length > 0) {
|
|
88937
|
+
registry.noteBackgroundShellAlive(key, ev.backgroundTaskId);
|
|
88938
|
+
}
|
|
88939
|
+
return;
|
|
88940
|
+
}
|
|
88941
|
+
if (ev.kind === "task_notification") {
|
|
88942
|
+
if (ev.taskId.length > 0 && TERMINAL_STATUSES.has(ev.status)) {
|
|
88943
|
+
registry.noteBackgroundShellDead(key, ev.taskId);
|
|
88944
|
+
}
|
|
88945
|
+
return;
|
|
88946
|
+
}
|
|
88947
|
+
if (ev.kind === "tool_use" && ev.toolName === "KillShell") {
|
|
88948
|
+
const killId = ev.input?.shell_id;
|
|
88949
|
+
if (typeof killId === "string" && killId.length > 0) {
|
|
88950
|
+
registry.noteBackgroundShellDead(key, killId);
|
|
88951
|
+
}
|
|
88952
|
+
}
|
|
88953
|
+
}
|
|
88954
|
+
|
|
88955
|
+
// gateway/silence-poke-session-event.ts
|
|
88956
|
+
function applySilencePokeSessionEvent(silencePoke, pendingProgress, key, ev) {
|
|
88957
|
+
if (ev.kind === "thinking") {
|
|
88958
|
+
silencePoke.noteThinking(key, Date.now());
|
|
88959
|
+
} else if (ev.kind === "tool_use") {
|
|
88960
|
+
if (ev.toolUseId != null && ev.toolUseId.length > 0 && !isTelegramSurfaceTool(ev.toolName)) {
|
|
88961
|
+
const label = toolLabel(ev.toolName, ev.input, undefined, ev.precomputedLabel);
|
|
88962
|
+
silencePoke.noteToolStart(key, ev.toolUseId, ev.toolName, label.length > 0 ? label : null, Date.now());
|
|
88963
|
+
const evInput = ev.input;
|
|
88964
|
+
if (ev.toolName === "Agent" || ev.toolName === "Task" || ev.toolName === "Bash" && evInput?.run_in_background === true) {
|
|
88965
|
+
pendingProgress.noteAsyncDispatch(key);
|
|
88966
|
+
}
|
|
88967
|
+
}
|
|
88968
|
+
} else if (ev.kind === "tool_result") {
|
|
88969
|
+
if (ev.toolUseId != null && ev.toolUseId.length > 0) {
|
|
88970
|
+
silencePoke.noteToolEnd(key, ev.toolUseId, Date.now());
|
|
88971
|
+
}
|
|
88972
|
+
}
|
|
88973
|
+
applyBackgroundShellLiveness(silencePoke, key, ev);
|
|
88974
|
+
}
|
|
88975
|
+
|
|
88236
88976
|
// gateway/inbound-delivery-machine-dispatch.ts
|
|
88237
88977
|
function dispatchEffects(effects, ctx) {
|
|
88238
88978
|
for (const effect of effects) {
|
|
@@ -88508,27 +89248,27 @@ function skillProposalKeyboard(id) {
|
|
|
88508
89248
|
// ../src/self-improve/skill-proposals.ts
|
|
88509
89249
|
import {
|
|
88510
89250
|
closeSync as closeSync7,
|
|
88511
|
-
existsSync as
|
|
88512
|
-
mkdirSync as
|
|
89251
|
+
existsSync as existsSync40,
|
|
89252
|
+
mkdirSync as mkdirSync36,
|
|
88513
89253
|
openSync as openSync7,
|
|
88514
|
-
readFileSync as
|
|
89254
|
+
readFileSync as readFileSync37,
|
|
88515
89255
|
writeSync as writeSync5
|
|
88516
89256
|
} from "node:fs";
|
|
88517
|
-
import { join as
|
|
89257
|
+
import { join as join45 } from "node:path";
|
|
88518
89258
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
88519
89259
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
88520
89260
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
88521
89261
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
88522
89262
|
var PROPOSAL_SIM_THRESHOLD = 0.5;
|
|
88523
89263
|
function proposalsPath2(stateDir) {
|
|
88524
|
-
return
|
|
89264
|
+
return join45(stateDir, PROPOSALS_FILE2);
|
|
88525
89265
|
}
|
|
88526
89266
|
function rejectedPath2(stateDir) {
|
|
88527
|
-
return
|
|
89267
|
+
return join45(stateDir, REJECTED_FILE2);
|
|
88528
89268
|
}
|
|
88529
89269
|
function ensureDir3(stateDir) {
|
|
88530
|
-
if (!
|
|
88531
|
-
|
|
89270
|
+
if (!existsSync40(stateDir)) {
|
|
89271
|
+
mkdirSync36(stateDir, { recursive: true, mode: 493 });
|
|
88532
89272
|
}
|
|
88533
89273
|
}
|
|
88534
89274
|
function appendLine2(path2, obj) {
|
|
@@ -88541,11 +89281,11 @@ function appendLine2(path2, obj) {
|
|
|
88541
89281
|
}
|
|
88542
89282
|
}
|
|
88543
89283
|
function readLines2(path2, isValid2) {
|
|
88544
|
-
if (!
|
|
89284
|
+
if (!existsSync40(path2))
|
|
88545
89285
|
return [];
|
|
88546
89286
|
let raw;
|
|
88547
89287
|
try {
|
|
88548
|
-
raw =
|
|
89288
|
+
raw = readFileSync37(path2, "utf-8");
|
|
88549
89289
|
} catch {
|
|
88550
89290
|
return [];
|
|
88551
89291
|
}
|
|
@@ -89142,11 +89882,11 @@ function escapeBody2(s) {
|
|
|
89142
89882
|
}
|
|
89143
89883
|
|
|
89144
89884
|
// gateway/pid-file.ts
|
|
89145
|
-
import { writeFileSync as
|
|
89885
|
+
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync19, renameSync as renameSync15 } from "node:fs";
|
|
89146
89886
|
function writePidFile(path2, record) {
|
|
89147
89887
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89148
|
-
|
|
89149
|
-
|
|
89888
|
+
writeFileSync33(tmp, JSON.stringify(record), "utf-8");
|
|
89889
|
+
renameSync15(tmp, path2);
|
|
89150
89890
|
}
|
|
89151
89891
|
function clearPidFile(path2) {
|
|
89152
89892
|
try {
|
|
@@ -89161,10 +89901,10 @@ import {
|
|
|
89161
89901
|
writeFile as writeFileAsync,
|
|
89162
89902
|
readFile as readFileAsync
|
|
89163
89903
|
} from "node:fs/promises";
|
|
89164
|
-
import { readFileSync as
|
|
89904
|
+
import { readFileSync as readFileSync39 } from "node:fs";
|
|
89165
89905
|
function readCurrentBootId() {
|
|
89166
89906
|
try {
|
|
89167
|
-
const stat =
|
|
89907
|
+
const stat = readFileSync39("/proc/1/stat", "utf-8");
|
|
89168
89908
|
const lastParen = stat.lastIndexOf(")");
|
|
89169
89909
|
if (lastParen < 0)
|
|
89170
89910
|
return null;
|
|
@@ -89367,15 +90107,15 @@ function safeCount(fn) {
|
|
|
89367
90107
|
}
|
|
89368
90108
|
|
|
89369
90109
|
// gateway/session-marker.ts
|
|
89370
|
-
import { writeFileSync as
|
|
90110
|
+
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync16, unlinkSync as unlinkSync20 } from "node:fs";
|
|
89371
90111
|
function writeSessionMarker(path2, marker) {
|
|
89372
90112
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89373
|
-
|
|
89374
|
-
|
|
90113
|
+
writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
|
|
90114
|
+
renameSync16(tmp, path2);
|
|
89375
90115
|
}
|
|
89376
90116
|
function readSessionMarker(path2) {
|
|
89377
90117
|
try {
|
|
89378
|
-
const raw =
|
|
90118
|
+
const raw = readFileSync40(path2, "utf-8");
|
|
89379
90119
|
const parsed = JSON.parse(raw);
|
|
89380
90120
|
if (typeof parsed.pid === "number" && typeof parsed.startedAtMs === "number" && Number.isFinite(parsed.pid) && Number.isFinite(parsed.startedAtMs)) {
|
|
89381
90121
|
return { pid: parsed.pid, startedAtMs: parsed.startedAtMs };
|
|
@@ -89397,16 +90137,16 @@ function shouldFireRestartBanner(input) {
|
|
|
89397
90137
|
}
|
|
89398
90138
|
|
|
89399
90139
|
// gateway/clean-shutdown-marker.ts
|
|
89400
|
-
import { writeFileSync as
|
|
90140
|
+
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync17, unlinkSync as unlinkSync21 } from "node:fs";
|
|
89401
90141
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
89402
90142
|
function writeCleanShutdownMarker(path2, marker) {
|
|
89403
90143
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
89404
|
-
|
|
89405
|
-
|
|
90144
|
+
writeFileSync35(tmp, JSON.stringify(marker), "utf-8");
|
|
90145
|
+
renameSync17(tmp, path2);
|
|
89406
90146
|
}
|
|
89407
90147
|
function readCleanShutdownMarker(path2) {
|
|
89408
90148
|
try {
|
|
89409
|
-
const raw =
|
|
90149
|
+
const raw = readFileSync41(path2, "utf-8");
|
|
89410
90150
|
const parsed = JSON.parse(raw);
|
|
89411
90151
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.signal === "string" && parsed.signal.length > 0) {
|
|
89412
90152
|
const out = { ts: parsed.ts, signal: parsed.signal };
|
|
@@ -89778,16 +90518,16 @@ function classifyAdminGate(text4, myAgentName) {
|
|
|
89778
90518
|
|
|
89779
90519
|
// subagent-watcher.ts
|
|
89780
90520
|
import {
|
|
89781
|
-
existsSync as
|
|
90521
|
+
existsSync as existsSync41,
|
|
89782
90522
|
openSync as openSync8,
|
|
89783
90523
|
readSync as readSync2,
|
|
89784
90524
|
statSync as statSync13,
|
|
89785
90525
|
closeSync as closeSync8,
|
|
89786
90526
|
watch,
|
|
89787
90527
|
readdirSync as readdirSync8,
|
|
89788
|
-
readFileSync as
|
|
90528
|
+
readFileSync as readFileSync42
|
|
89789
90529
|
} from "fs";
|
|
89790
|
-
import { join as
|
|
90530
|
+
import { join as join46 } from "path";
|
|
89791
90531
|
|
|
89792
90532
|
// session-tail.ts
|
|
89793
90533
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -90137,7 +90877,7 @@ function backfillJsonlAgentId(db3, jsonlPath, agentId, log) {
|
|
|
90137
90877
|
const metaPath = jsonlPath.replace(/\.jsonl$/, ".meta.json");
|
|
90138
90878
|
let meta;
|
|
90139
90879
|
try {
|
|
90140
|
-
const raw =
|
|
90880
|
+
const raw = readFileSync42(metaPath, "utf8");
|
|
90141
90881
|
meta = JSON.parse(raw);
|
|
90142
90882
|
} catch {
|
|
90143
90883
|
log?.(`subagent-watcher: backfill skip ${agentId} \u2014 meta.json not readable at ${metaPath}`);
|
|
@@ -90592,7 +91332,7 @@ function startSubagentWatcher(config) {
|
|
|
90592
91332
|
clearTimeout(ref.ref);
|
|
90593
91333
|
});
|
|
90594
91334
|
const fs2 = config.fs ?? {
|
|
90595
|
-
existsSync:
|
|
91335
|
+
existsSync: existsSync41,
|
|
90596
91336
|
readdirSync: readdirSync8,
|
|
90597
91337
|
statSync: statSync13,
|
|
90598
91338
|
openSync: openSync8,
|
|
@@ -91110,8 +91850,8 @@ function startSubagentWatcher(config) {
|
|
|
91110
91850
|
if (stopped)
|
|
91111
91851
|
return;
|
|
91112
91852
|
pruneVanishedDirWatchers();
|
|
91113
|
-
const claudeHome =
|
|
91114
|
-
const projectsRoot =
|
|
91853
|
+
const claudeHome = join46(agentDir, ".claude");
|
|
91854
|
+
const projectsRoot = join46(claudeHome, "projects");
|
|
91115
91855
|
if (!fs2.existsSync(projectsRoot))
|
|
91116
91856
|
return;
|
|
91117
91857
|
let projectDirs;
|
|
@@ -91145,7 +91885,7 @@ function startSubagentWatcher(config) {
|
|
|
91145
91885
|
continue;
|
|
91146
91886
|
}
|
|
91147
91887
|
warnedForeignSlugs.delete(pDir);
|
|
91148
|
-
const projectPath =
|
|
91888
|
+
const projectPath = join46(projectsRoot, pDir);
|
|
91149
91889
|
let sessionDirs;
|
|
91150
91890
|
try {
|
|
91151
91891
|
sessionDirs = fs2.readdirSync(projectPath);
|
|
@@ -91155,7 +91895,7 @@ function startSubagentWatcher(config) {
|
|
|
91155
91895
|
for (const sDir of sessionDirs) {
|
|
91156
91896
|
if (sDir.endsWith(".jsonl"))
|
|
91157
91897
|
continue;
|
|
91158
|
-
const subagentsPath =
|
|
91898
|
+
const subagentsPath = join46(projectPath, sDir, "subagents");
|
|
91159
91899
|
if (!fs2.existsSync(subagentsPath))
|
|
91160
91900
|
continue;
|
|
91161
91901
|
const watchAndScan = (dirPath) => {
|
|
@@ -91164,7 +91904,7 @@ function startSubagentWatcher(config) {
|
|
|
91164
91904
|
const w = fs2.watch(dirPath, (_event, filename) => {
|
|
91165
91905
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
91166
91906
|
return;
|
|
91167
|
-
const filePath =
|
|
91907
|
+
const filePath = join46(dirPath, filename.toString());
|
|
91168
91908
|
if (!knownFiles.has(filePath)) {
|
|
91169
91909
|
scanSubagentsDir(dirPath);
|
|
91170
91910
|
}
|
|
@@ -91178,7 +91918,7 @@ function startSubagentWatcher(config) {
|
|
|
91178
91918
|
scanSubagentsDir(dirPath);
|
|
91179
91919
|
};
|
|
91180
91920
|
watchAndScan(subagentsPath);
|
|
91181
|
-
const workflowsPath =
|
|
91921
|
+
const workflowsPath = join46(subagentsPath, "workflows");
|
|
91182
91922
|
if (fs2.existsSync(workflowsPath)) {
|
|
91183
91923
|
let wfDirs;
|
|
91184
91924
|
try {
|
|
@@ -91188,7 +91928,7 @@ function startSubagentWatcher(config) {
|
|
|
91188
91928
|
}
|
|
91189
91929
|
for (const wfDir of wfDirs) {
|
|
91190
91930
|
try {
|
|
91191
|
-
const wfPath =
|
|
91931
|
+
const wfPath = join46(workflowsPath, wfDir);
|
|
91192
91932
|
if (!fs2.statSync(wfPath).isDirectory())
|
|
91193
91933
|
continue;
|
|
91194
91934
|
watchAndScan(wfPath);
|
|
@@ -91208,7 +91948,7 @@ function startSubagentWatcher(config) {
|
|
|
91208
91948
|
for (const e of entries) {
|
|
91209
91949
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
91210
91950
|
continue;
|
|
91211
|
-
const filePath =
|
|
91951
|
+
const filePath = join46(subagentsPath, e);
|
|
91212
91952
|
if (knownFiles.has(filePath))
|
|
91213
91953
|
continue;
|
|
91214
91954
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -91336,37 +92076,37 @@ function startSubagentWatcher(config) {
|
|
|
91336
92076
|
|
|
91337
92077
|
// ../src/worktree/registry.ts
|
|
91338
92078
|
import {
|
|
91339
|
-
mkdirSync as
|
|
91340
|
-
writeFileSync as
|
|
91341
|
-
readFileSync as
|
|
92079
|
+
mkdirSync as mkdirSync37,
|
|
92080
|
+
writeFileSync as writeFileSync36,
|
|
92081
|
+
readFileSync as readFileSync43,
|
|
91342
92082
|
readdirSync as readdirSync9,
|
|
91343
92083
|
unlinkSync as unlinkSync22,
|
|
91344
|
-
existsSync as
|
|
91345
|
-
renameSync as
|
|
92084
|
+
existsSync as existsSync42,
|
|
92085
|
+
renameSync as renameSync18
|
|
91346
92086
|
} from "node:fs";
|
|
91347
|
-
import { join as
|
|
92087
|
+
import { join as join47, resolve as resolve10 } from "node:path";
|
|
91348
92088
|
import { homedir as homedir16 } from "node:os";
|
|
91349
92089
|
function registryDir() {
|
|
91350
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
92090
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join47(homedir16(), ".switchroom", "worktrees"));
|
|
91351
92091
|
}
|
|
91352
92092
|
function recordPath(id) {
|
|
91353
|
-
return
|
|
92093
|
+
return join47(registryDir(), `${id}.json`);
|
|
91354
92094
|
}
|
|
91355
92095
|
function ensureDir4() {
|
|
91356
|
-
|
|
92096
|
+
mkdirSync37(registryDir(), { recursive: true });
|
|
91357
92097
|
}
|
|
91358
92098
|
function writeRecord(record) {
|
|
91359
92099
|
ensureDir4();
|
|
91360
92100
|
const target = recordPath(record.id);
|
|
91361
92101
|
const tmp = `${target}.tmp${process.pid}`;
|
|
91362
|
-
|
|
92102
|
+
writeFileSync36(tmp, JSON.stringify(record, null, 2) + `
|
|
91363
92103
|
`, { mode: 384 });
|
|
91364
|
-
|
|
92104
|
+
renameSync18(tmp, target);
|
|
91365
92105
|
}
|
|
91366
92106
|
function readRecord(id) {
|
|
91367
92107
|
const path2 = recordPath(id);
|
|
91368
92108
|
try {
|
|
91369
|
-
const raw =
|
|
92109
|
+
const raw = readFileSync43(path2, "utf8");
|
|
91370
92110
|
return JSON.parse(raw);
|
|
91371
92111
|
} catch {
|
|
91372
92112
|
return null;
|
|
@@ -91396,7 +92136,7 @@ function touchHeartbeat(id, onAfterRead) {
|
|
|
91396
92136
|
writeRecord({ ...rec, heartbeatAt: new Date().toISOString() });
|
|
91397
92137
|
}
|
|
91398
92138
|
function recordExists(id) {
|
|
91399
|
-
return
|
|
92139
|
+
return existsSync42(recordPath(id));
|
|
91400
92140
|
}
|
|
91401
92141
|
|
|
91402
92142
|
// worktree-watch-cwds.ts
|
|
@@ -91528,15 +92268,15 @@ function determineRestartReason(opts) {
|
|
|
91528
92268
|
init_boot_card();
|
|
91529
92269
|
|
|
91530
92270
|
// gateway/update-announce.ts
|
|
91531
|
-
import { existsSync as
|
|
91532
|
-
import { join as
|
|
92271
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync41, openSync as openSync9, closeSync as closeSync9, readFileSync as readFileSync50 } from "node:fs";
|
|
92272
|
+
import { join as join52 } from "node:path";
|
|
91533
92273
|
import { homedir as homedir18 } from "node:os";
|
|
91534
92274
|
|
|
91535
92275
|
// ../src/host-control/audit-reader.ts
|
|
91536
92276
|
import { homedir as homedir17 } from "node:os";
|
|
91537
|
-
import { join as
|
|
92277
|
+
import { join as join51 } from "node:path";
|
|
91538
92278
|
function defaultAuditLogPath(home2 = homedir17()) {
|
|
91539
|
-
return
|
|
92279
|
+
return join51(home2, ".switchroom", "host-control-audit.log");
|
|
91540
92280
|
}
|
|
91541
92281
|
function parseAuditLine(line) {
|
|
91542
92282
|
const trimmed = line.trim();
|
|
@@ -91659,8 +92399,8 @@ function readAndFilter(raw, filters, limit) {
|
|
|
91659
92399
|
var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
|
|
91660
92400
|
function readLastTerminalUpdateAudit(opts = {}) {
|
|
91661
92401
|
const path2 = opts.auditLogPath ?? defaultAuditLogPath();
|
|
91662
|
-
const exists = opts.exists ??
|
|
91663
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
92402
|
+
const exists = opts.exists ?? existsSync47;
|
|
92403
|
+
const readFile = opts.readFile ?? ((p) => readFileSync50(p, "utf-8"));
|
|
91664
92404
|
if (!exists(path2))
|
|
91665
92405
|
return null;
|
|
91666
92406
|
let raw;
|
|
@@ -91721,15 +92461,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
91721
92461
|
`);
|
|
91722
92462
|
}
|
|
91723
92463
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
91724
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
91725
|
-
const dir =
|
|
92464
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join52(homedir18(), ".switchroom");
|
|
92465
|
+
const dir = join52(stateDir, "update-announced");
|
|
91726
92466
|
try {
|
|
91727
|
-
|
|
92467
|
+
mkdirSync41(dir, { recursive: true });
|
|
91728
92468
|
} catch {
|
|
91729
92469
|
return false;
|
|
91730
92470
|
}
|
|
91731
92471
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
91732
|
-
const path2 =
|
|
92472
|
+
const path2 = join52(dir, safeId);
|
|
91733
92473
|
try {
|
|
91734
92474
|
const fd = openSync9(path2, "wx");
|
|
91735
92475
|
closeSync9(fd);
|
|
@@ -91749,7 +92489,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
|
|
|
91749
92489
|
|
|
91750
92490
|
// issues-card.ts
|
|
91751
92491
|
init_card_format();
|
|
91752
|
-
import { readFileSync as
|
|
92492
|
+
import { readFileSync as readFileSync51, writeFileSync as writeFileSync41 } from "node:fs";
|
|
91753
92493
|
var SEVERITY_EMOJI = {
|
|
91754
92494
|
info: "\u2139\ufe0f",
|
|
91755
92495
|
warn: "\u26a0\ufe0f",
|
|
@@ -91841,7 +92581,7 @@ function extractRetryAfterSecs2(err) {
|
|
|
91841
92581
|
var COOLDOWN_JITTER_MS2 = 500;
|
|
91842
92582
|
function readPersistedMessageId(path2, log) {
|
|
91843
92583
|
try {
|
|
91844
|
-
const raw =
|
|
92584
|
+
const raw = readFileSync51(path2, "utf8");
|
|
91845
92585
|
const parsed = JSON.parse(raw);
|
|
91846
92586
|
const v = parsed.messageId;
|
|
91847
92587
|
if (typeof v === "number" && Number.isInteger(v) && v > 0)
|
|
@@ -91857,7 +92597,7 @@ function readPersistedMessageId(path2, log) {
|
|
|
91857
92597
|
}
|
|
91858
92598
|
function writePersistedMessageId(path2, messageId, log) {
|
|
91859
92599
|
try {
|
|
91860
|
-
|
|
92600
|
+
writeFileSync41(path2, JSON.stringify({ messageId }) + `
|
|
91861
92601
|
`, { mode: 384 });
|
|
91862
92602
|
} catch (err) {
|
|
91863
92603
|
log(`issues-card: persist write failed (${err.message})`);
|
|
@@ -91950,24 +92690,24 @@ function createIssuesCardHandle(opts) {
|
|
|
91950
92690
|
}
|
|
91951
92691
|
|
|
91952
92692
|
// issues-watcher.ts
|
|
91953
|
-
import { existsSync as
|
|
91954
|
-
import { join as
|
|
92693
|
+
import { existsSync as existsSync49, statSync as statSync16 } from "node:fs";
|
|
92694
|
+
import { join as join54 } from "node:path";
|
|
91955
92695
|
|
|
91956
92696
|
// ../src/issues/store.ts
|
|
91957
92697
|
import {
|
|
91958
92698
|
closeSync as closeSync10,
|
|
91959
|
-
existsSync as
|
|
91960
|
-
mkdirSync as
|
|
92699
|
+
existsSync as existsSync48,
|
|
92700
|
+
mkdirSync as mkdirSync42,
|
|
91961
92701
|
openSync as openSync10,
|
|
91962
92702
|
readdirSync as readdirSync11,
|
|
91963
|
-
readFileSync as
|
|
91964
|
-
renameSync as
|
|
92703
|
+
readFileSync as readFileSync52,
|
|
92704
|
+
renameSync as renameSync21,
|
|
91965
92705
|
statSync as statSync15,
|
|
91966
92706
|
unlinkSync as unlinkSync23,
|
|
91967
|
-
writeFileSync as
|
|
92707
|
+
writeFileSync as writeFileSync42,
|
|
91968
92708
|
writeSync as writeSync6
|
|
91969
92709
|
} from "node:fs";
|
|
91970
|
-
import { join as
|
|
92710
|
+
import { join as join53 } from "node:path";
|
|
91971
92711
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
91972
92712
|
import { execSync } from "node:child_process";
|
|
91973
92713
|
|
|
@@ -91986,12 +92726,12 @@ init_redact();
|
|
|
91986
92726
|
var ISSUES_FILE = "issues.jsonl";
|
|
91987
92727
|
var ISSUES_LOCK = "issues.lock";
|
|
91988
92728
|
function readAll(stateDir) {
|
|
91989
|
-
const path2 =
|
|
91990
|
-
if (!
|
|
92729
|
+
const path2 = join53(stateDir, ISSUES_FILE);
|
|
92730
|
+
if (!existsSync48(path2))
|
|
91991
92731
|
return [];
|
|
91992
92732
|
let raw;
|
|
91993
92733
|
try {
|
|
91994
|
-
raw =
|
|
92734
|
+
raw = readFileSync52(path2, "utf-8");
|
|
91995
92735
|
} catch {
|
|
91996
92736
|
return [];
|
|
91997
92737
|
}
|
|
@@ -92023,7 +92763,7 @@ function list2(stateDir, opts = {}) {
|
|
|
92023
92763
|
});
|
|
92024
92764
|
}
|
|
92025
92765
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
92026
|
-
if (!
|
|
92766
|
+
if (!existsSync48(join53(stateDir, ISSUES_FILE)))
|
|
92027
92767
|
return 0;
|
|
92028
92768
|
return withLock(stateDir, () => {
|
|
92029
92769
|
const all2 = readAll(stateDir);
|
|
@@ -92041,14 +92781,14 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
92041
92781
|
});
|
|
92042
92782
|
}
|
|
92043
92783
|
function writeAll(stateDir, events) {
|
|
92044
|
-
const path2 =
|
|
92784
|
+
const path2 = join53(stateDir, ISSUES_FILE);
|
|
92045
92785
|
sweepOrphanTmpFiles(stateDir);
|
|
92046
92786
|
const tmp = `${path2}.tmp-${process.pid}-${randomBytes8(4).toString("hex")}`;
|
|
92047
92787
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
92048
92788
|
`) + `
|
|
92049
92789
|
`;
|
|
92050
|
-
|
|
92051
|
-
|
|
92790
|
+
writeFileSync42(tmp, body, "utf-8");
|
|
92791
|
+
renameSync21(tmp, path2);
|
|
92052
92792
|
}
|
|
92053
92793
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
92054
92794
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -92063,7 +92803,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
92063
92803
|
for (const entry of entries) {
|
|
92064
92804
|
if (!entry.startsWith(TMP_PREFIX))
|
|
92065
92805
|
continue;
|
|
92066
|
-
const tmpPath2 =
|
|
92806
|
+
const tmpPath2 = join53(stateDir, entry);
|
|
92067
92807
|
try {
|
|
92068
92808
|
const stat = statSync15(tmpPath2);
|
|
92069
92809
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -92075,7 +92815,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
92075
92815
|
var LOCK_RETRY_MS = 25;
|
|
92076
92816
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
92077
92817
|
function withLock(stateDir, fn) {
|
|
92078
|
-
const lockPath =
|
|
92818
|
+
const lockPath = join53(stateDir, ISSUES_LOCK);
|
|
92079
92819
|
const startedAt = Date.now();
|
|
92080
92820
|
let fd = null;
|
|
92081
92821
|
while (fd === null) {
|
|
@@ -92110,7 +92850,7 @@ function withLock(stateDir, fn) {
|
|
|
92110
92850
|
function tryStealStaleLock(lockPath) {
|
|
92111
92851
|
let pidStr;
|
|
92112
92852
|
try {
|
|
92113
|
-
pidStr =
|
|
92853
|
+
pidStr = readFileSync52(lockPath, "utf-8").trim();
|
|
92114
92854
|
} catch {
|
|
92115
92855
|
return true;
|
|
92116
92856
|
}
|
|
@@ -92160,7 +92900,7 @@ function isIssueEvent(v) {
|
|
|
92160
92900
|
// issues-watcher.ts
|
|
92161
92901
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
92162
92902
|
function startIssuesWatcher(opts) {
|
|
92163
|
-
const path2 =
|
|
92903
|
+
const path2 = join54(opts.stateDir, ISSUES_FILE);
|
|
92164
92904
|
const log = opts.log ?? (() => {});
|
|
92165
92905
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
92166
92906
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -92208,7 +92948,7 @@ function startIssuesWatcher(opts) {
|
|
|
92208
92948
|
};
|
|
92209
92949
|
}
|
|
92210
92950
|
function defaultSignatureProvider(path2) {
|
|
92211
|
-
if (!
|
|
92951
|
+
if (!existsSync49(path2))
|
|
92212
92952
|
return null;
|
|
92213
92953
|
try {
|
|
92214
92954
|
const stat = statSync16(path2);
|
|
@@ -92919,8 +93659,8 @@ function readBashCommand(inputPreview) {
|
|
|
92919
93659
|
}
|
|
92920
93660
|
|
|
92921
93661
|
// gateway/scoped-grant-store.ts
|
|
92922
|
-
import { readFileSync as
|
|
92923
|
-
import { join as
|
|
93662
|
+
import { readFileSync as readFileSync53, writeFileSync as writeFileSync43 } from "node:fs";
|
|
93663
|
+
import { join as join55 } from "node:path";
|
|
92924
93664
|
|
|
92925
93665
|
// scoped-approval.ts
|
|
92926
93666
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -92962,11 +93702,11 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
92962
93702
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
92963
93703
|
}
|
|
92964
93704
|
function createScopedGrantStore(stateDir, env = process.env) {
|
|
92965
|
-
const filePath =
|
|
93705
|
+
const filePath = join55(stateDir, "scoped-grants.json");
|
|
92966
93706
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
92967
93707
|
function read() {
|
|
92968
93708
|
try {
|
|
92969
|
-
const raw =
|
|
93709
|
+
const raw = readFileSync53(filePath, "utf-8");
|
|
92970
93710
|
const parsed = JSON.parse(raw);
|
|
92971
93711
|
return Array.isArray(parsed) ? parsed : [];
|
|
92972
93712
|
} catch {
|
|
@@ -92984,7 +93724,7 @@ function createScopedGrantStore(stateDir, env = process.env) {
|
|
|
92984
93724
|
if (!enabled7)
|
|
92985
93725
|
return;
|
|
92986
93726
|
try {
|
|
92987
|
-
|
|
93727
|
+
writeFileSync43(filePath, JSON.stringify(serializeScopedGrants(store2)), {
|
|
92988
93728
|
encoding: "utf-8",
|
|
92989
93729
|
mode: 384
|
|
92990
93730
|
});
|
|
@@ -93335,8 +94075,8 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
93335
94075
|
|
|
93336
94076
|
// credits-watch.ts
|
|
93337
94077
|
init_card_format();
|
|
93338
|
-
import { readFileSync as
|
|
93339
|
-
import { join as
|
|
94078
|
+
import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync50, mkdirSync as mkdirSync43 } from "fs";
|
|
94079
|
+
import { join as join56 } from "path";
|
|
93340
94080
|
var STATE_FILE = "credits-watch.json";
|
|
93341
94081
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
93342
94082
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -93358,12 +94098,12 @@ function emptyCreditState() {
|
|
|
93358
94098
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
93359
94099
|
}
|
|
93360
94100
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
93361
|
-
const path2 =
|
|
93362
|
-
if (!
|
|
94101
|
+
const path2 = join56(claudeConfigDir, ".claude.json");
|
|
94102
|
+
if (!existsSync50(path2))
|
|
93363
94103
|
return null;
|
|
93364
94104
|
let raw;
|
|
93365
94105
|
try {
|
|
93366
|
-
raw =
|
|
94106
|
+
raw = readFileSync54(path2, "utf-8");
|
|
93367
94107
|
} catch {
|
|
93368
94108
|
return null;
|
|
93369
94109
|
}
|
|
@@ -93441,11 +94181,11 @@ function humanizeReason(reason) {
|
|
|
93441
94181
|
}
|
|
93442
94182
|
}
|
|
93443
94183
|
function loadCreditState(stateDir) {
|
|
93444
|
-
const path2 =
|
|
93445
|
-
if (!
|
|
94184
|
+
const path2 = join56(stateDir, STATE_FILE);
|
|
94185
|
+
if (!existsSync50(path2))
|
|
93446
94186
|
return emptyCreditState();
|
|
93447
94187
|
try {
|
|
93448
|
-
const raw =
|
|
94188
|
+
const raw = readFileSync54(path2, "utf-8");
|
|
93449
94189
|
const parsed = JSON.parse(raw);
|
|
93450
94190
|
if (parsed && typeof parsed === "object" && (parsed.lastNotifiedReason === null || typeof parsed.lastNotifiedReason === "string") && typeof parsed.lastNotifiedAt === "number" && Number.isFinite(parsed.lastNotifiedAt)) {
|
|
93451
94191
|
return {
|
|
@@ -93457,17 +94197,17 @@ function loadCreditState(stateDir) {
|
|
|
93457
94197
|
return emptyCreditState();
|
|
93458
94198
|
}
|
|
93459
94199
|
function saveCreditState(stateDir, state7) {
|
|
93460
|
-
|
|
93461
|
-
const path2 =
|
|
93462
|
-
|
|
94200
|
+
mkdirSync43(stateDir, { recursive: true });
|
|
94201
|
+
const path2 = join56(stateDir, STATE_FILE);
|
|
94202
|
+
writeFileSync44(path2, JSON.stringify(state7, null, 2) + `
|
|
93463
94203
|
`, { mode: 384 });
|
|
93464
94204
|
}
|
|
93465
94205
|
|
|
93466
94206
|
// quota-watch.ts
|
|
93467
94207
|
init_auth_snapshot_format();
|
|
93468
94208
|
init_card_format();
|
|
93469
|
-
import { readFileSync as
|
|
93470
|
-
import { join as
|
|
94209
|
+
import { readFileSync as readFileSync55, writeFileSync as writeFileSync45, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
|
|
94210
|
+
import { join as join57 } from "path";
|
|
93471
94211
|
var STATE_FILE2 = "quota-watch.json";
|
|
93472
94212
|
function emptyQuotaWatchState() {
|
|
93473
94213
|
return {};
|
|
@@ -93705,11 +94445,11 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
93705
94445
|
`);
|
|
93706
94446
|
}
|
|
93707
94447
|
function loadQuotaWatchState(stateDir) {
|
|
93708
|
-
const path2 =
|
|
93709
|
-
if (!
|
|
94448
|
+
const path2 = join57(stateDir, STATE_FILE2);
|
|
94449
|
+
if (!existsSync51(path2))
|
|
93710
94450
|
return emptyQuotaWatchState();
|
|
93711
94451
|
try {
|
|
93712
|
-
const raw =
|
|
94452
|
+
const raw = readFileSync55(path2, "utf-8");
|
|
93713
94453
|
const parsed = JSON.parse(raw);
|
|
93714
94454
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
93715
94455
|
return emptyQuotaWatchState();
|
|
@@ -93726,9 +94466,9 @@ function loadQuotaWatchState(stateDir) {
|
|
|
93726
94466
|
}
|
|
93727
94467
|
}
|
|
93728
94468
|
function saveQuotaWatchState(stateDir, state7) {
|
|
93729
|
-
|
|
93730
|
-
const path2 =
|
|
93731
|
-
|
|
94469
|
+
mkdirSync44(stateDir, { recursive: true });
|
|
94470
|
+
const path2 = join57(stateDir, STATE_FILE2);
|
|
94471
|
+
writeFileSync45(path2, JSON.stringify(state7, null, 2) + `
|
|
93732
94472
|
`, { mode: 384 });
|
|
93733
94473
|
}
|
|
93734
94474
|
function patchQuotaWatchState(current, accountLabel, accountState) {
|
|
@@ -93776,27 +94516,27 @@ init_auth_snapshot_format2();
|
|
|
93776
94516
|
// gateway/turn-active-marker.ts
|
|
93777
94517
|
import {
|
|
93778
94518
|
closeSync as closeSync11,
|
|
93779
|
-
existsSync as
|
|
93780
|
-
mkdirSync as
|
|
94519
|
+
existsSync as existsSync52,
|
|
94520
|
+
mkdirSync as mkdirSync45,
|
|
93781
94521
|
openSync as openSync11,
|
|
93782
|
-
readFileSync as
|
|
94522
|
+
readFileSync as readFileSync56,
|
|
93783
94523
|
statSync as statSync17,
|
|
93784
94524
|
unlinkSync as unlinkSync24,
|
|
93785
94525
|
utimesSync as utimesSync2,
|
|
93786
|
-
writeFileSync as
|
|
94526
|
+
writeFileSync as writeFileSync46
|
|
93787
94527
|
} from "node:fs";
|
|
93788
|
-
import { join as
|
|
94528
|
+
import { join as join58 } from "node:path";
|
|
93789
94529
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
93790
94530
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
93791
94531
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
93792
94532
|
function removeTurnActiveMarker2(stateDir) {
|
|
93793
94533
|
try {
|
|
93794
|
-
unlinkSync24(
|
|
94534
|
+
unlinkSync24(join58(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
93795
94535
|
} catch {}
|
|
93796
94536
|
}
|
|
93797
94537
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
93798
|
-
const path2 =
|
|
93799
|
-
if (!
|
|
94538
|
+
const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
94539
|
+
if (!existsSync52(path2))
|
|
93800
94540
|
return false;
|
|
93801
94541
|
const now = opts.now ?? Date.now();
|
|
93802
94542
|
try {
|
|
@@ -93808,7 +94548,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
93808
94548
|
return false;
|
|
93809
94549
|
let payload = null;
|
|
93810
94550
|
try {
|
|
93811
|
-
payload =
|
|
94551
|
+
payload = readFileSync56(path2, "utf8");
|
|
93812
94552
|
} catch {}
|
|
93813
94553
|
unlinkSync24(path2);
|
|
93814
94554
|
if (opts.onRemove) {
|
|
@@ -93826,7 +94566,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
93826
94566
|
}
|
|
93827
94567
|
}
|
|
93828
94568
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
93829
|
-
const path2 =
|
|
94569
|
+
const path2 = join58(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
93830
94570
|
try {
|
|
93831
94571
|
const st = statSync17(path2);
|
|
93832
94572
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -93839,19 +94579,19 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
93839
94579
|
}
|
|
93840
94580
|
|
|
93841
94581
|
// gateway/gateway-heartbeat.ts
|
|
93842
|
-
import { mkdirSync as
|
|
93843
|
-
import { join as
|
|
94582
|
+
import { mkdirSync as mkdirSync46, utimesSync as utimesSync3, writeFileSync as writeFileSync47 } from "node:fs";
|
|
94583
|
+
import { join as join59 } from "node:path";
|
|
93844
94584
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
93845
94585
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
93846
94586
|
function touchGatewayHeartbeat(stateDir) {
|
|
93847
|
-
const path2 =
|
|
94587
|
+
const path2 = join59(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
93848
94588
|
const now = new Date;
|
|
93849
94589
|
try {
|
|
93850
94590
|
utimesSync3(path2, now, now);
|
|
93851
94591
|
} catch {
|
|
93852
94592
|
try {
|
|
93853
|
-
|
|
93854
|
-
|
|
94593
|
+
mkdirSync46(stateDir, { recursive: true });
|
|
94594
|
+
writeFileSync47(path2, `${Date.now()}
|
|
93855
94595
|
`, { mode: 384 });
|
|
93856
94596
|
} catch {}
|
|
93857
94597
|
}
|
|
@@ -93894,11 +94634,23 @@ async function sweepOutbox(deps) {
|
|
|
93894
94634
|
textAlreadyDelivered: resolved != null && deps.textAlreadyDelivered(resolved.chatId, resolved.threadId, record2.text),
|
|
93895
94635
|
routable: resolved != null,
|
|
93896
94636
|
routePrefix,
|
|
93897
|
-
quietMs: deps.quietMs ?? OUTBOX_QUIET_MS
|
|
94637
|
+
quietMs: deps.quietMs ?? OUTBOX_QUIET_MS,
|
|
94638
|
+
shownLedgerHit: isShownBlock(record2.turnNonce, record2.text, deps.stateDir)
|
|
93898
94639
|
});
|
|
93899
94640
|
if (decision.action !== "send" && decision.action !== "send-delayed") {
|
|
93900
94641
|
summary.skipped++;
|
|
93901
|
-
if (decision.action === "skip-
|
|
94642
|
+
if (decision.action === "skip-ephemeral-shown") {
|
|
94643
|
+
appendDelivered({
|
|
94644
|
+
turnNonce: record2.turnNonce,
|
|
94645
|
+
textSha256: record2.textSha256,
|
|
94646
|
+
ts: now,
|
|
94647
|
+
deliverySource: "sweep",
|
|
94648
|
+
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
94649
|
+
}, deps.stateDir);
|
|
94650
|
+
clearOutboxRecord(record2.turnNonce, deps.stateDir);
|
|
94651
|
+
log(`outbox-sweep: suppressed ephemeral-shown nonce=${record2.turnNonce}
|
|
94652
|
+
`);
|
|
94653
|
+
} else if (decision.action === "skip-journaled") {
|
|
93902
94654
|
clearOutboxRecord(record2.turnNonce, deps.stateDir);
|
|
93903
94655
|
} else if (decision.action === "skip-dedup") {
|
|
93904
94656
|
appendDelivered({
|
|
@@ -93949,10 +94701,38 @@ function chatFromTurnKey(turnKey3) {
|
|
|
93949
94701
|
return { chatId, threadId: Number.isFinite(t) ? t : null };
|
|
93950
94702
|
}
|
|
93951
94703
|
var OUTBOX_SWEEP_INTERVAL_MS = 5000;
|
|
94704
|
+
function createOutboxSend(deps) {
|
|
94705
|
+
return async (chatId, threadId, text4) => {
|
|
94706
|
+
const bot = deps.getBot();
|
|
94707
|
+
if (bot == null)
|
|
94708
|
+
throw new Error("outbox-sweep: bot unavailable");
|
|
94709
|
+
if (text4.length === 0)
|
|
94710
|
+
return;
|
|
94711
|
+
const replyMarkup = deps.resolveReplyMarkup?.(chatId, threadId, text4);
|
|
94712
|
+
let lastId;
|
|
94713
|
+
const chunkCount = Math.ceil(text4.length / 4000);
|
|
94714
|
+
for (let i = 0, idx = 0;i < text4.length; i += 4000, idx++) {
|
|
94715
|
+
const chunk2 = text4.slice(i, i + 4000);
|
|
94716
|
+
const isLast = idx === chunkCount - 1;
|
|
94717
|
+
const res = await retryWithThreadFallback(deps.retry, (tid) => {
|
|
94718
|
+
const base = tid != null ? { message_thread_id: tid } : {};
|
|
94719
|
+
const opts = isLast && replyMarkup != null ? { ...base, reply_markup: replyMarkup } : base;
|
|
94720
|
+
return bot.api.sendMessage(chatId, chunk2, opts);
|
|
94721
|
+
}, { threadId: threadId ?? undefined, chat_id: chatId, verb: "outbox-sweep.sendMessage" });
|
|
94722
|
+
lastId = res?.message_id;
|
|
94723
|
+
}
|
|
94724
|
+
return lastId;
|
|
94725
|
+
};
|
|
94726
|
+
}
|
|
93952
94727
|
function startOutboxSweep(deps) {
|
|
93953
94728
|
if (!deps.isGatewayMain || process.env.SWITCHROOM_TG_OUTBOX_DELIVERY === "0")
|
|
93954
94729
|
return;
|
|
93955
94730
|
const retry = createRetryApiCall({ log: deps.log });
|
|
94731
|
+
const send = createOutboxSend({
|
|
94732
|
+
getBot: deps.getBot,
|
|
94733
|
+
retry,
|
|
94734
|
+
...deps.resolveReplyMarkup != null ? { resolveReplyMarkup: deps.resolveReplyMarkup } : {}
|
|
94735
|
+
});
|
|
93956
94736
|
const tick3 = () => {
|
|
93957
94737
|
const bot = deps.getBot();
|
|
93958
94738
|
if (bot == null)
|
|
@@ -93960,15 +94740,7 @@ function startOutboxSweep(deps) {
|
|
|
93960
94740
|
sweepOutbox({
|
|
93961
94741
|
stateDir: deps.stateDir,
|
|
93962
94742
|
log: deps.log,
|
|
93963
|
-
send
|
|
93964
|
-
let lastId;
|
|
93965
|
-
for (let i = 0;i < text4.length; i += 4000) {
|
|
93966
|
-
const chunk2 = text4.slice(i, i + 4000);
|
|
93967
|
-
const res = await retryWithThreadFallback(retry, (tid) => bot.api.sendMessage(chatId, chunk2, tid != null ? { message_thread_id: tid } : {}), { threadId: threadId ?? undefined, chat_id: chatId, verb: "outbox-sweep.sendMessage" });
|
|
93968
|
-
lastId = res?.message_id;
|
|
93969
|
-
}
|
|
93970
|
-
return lastId;
|
|
93971
|
-
},
|
|
94743
|
+
send,
|
|
93972
94744
|
textAlreadyDelivered: (chatId, threadId, text4) => deps.dedupCheck(chatId, threadId ?? undefined, text4),
|
|
93973
94745
|
registryChainLookup: (taskId) => {
|
|
93974
94746
|
const db3 = deps.getTurnsDb();
|
|
@@ -93986,10 +94758,10 @@ function startOutboxSweep(deps) {
|
|
|
93986
94758
|
}
|
|
93987
94759
|
|
|
93988
94760
|
// ../src/build-info.ts
|
|
93989
|
-
var VERSION = "0.19.
|
|
93990
|
-
var COMMIT_SHA = "
|
|
93991
|
-
var COMMIT_DATE = "2026-07-
|
|
93992
|
-
var LATEST_PR =
|
|
94761
|
+
var VERSION = "0.19.16";
|
|
94762
|
+
var COMMIT_SHA = "e905f237";
|
|
94763
|
+
var COMMIT_DATE = "2026-07-24T18:26:03+10:00";
|
|
94764
|
+
var LATEST_PR = null;
|
|
93993
94765
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
93994
94766
|
|
|
93995
94767
|
// gateway/boot-version.ts
|
|
@@ -94067,11 +94839,11 @@ init_peercred();
|
|
|
94067
94839
|
import * as net5 from "node:net";
|
|
94068
94840
|
import * as fs2 from "node:fs";
|
|
94069
94841
|
import { homedir as homedir19 } from "node:os";
|
|
94070
|
-
import { join as
|
|
94842
|
+
import { join as join60 } from "node:path";
|
|
94071
94843
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
94072
94844
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
94073
|
-
var LEGACY_SOCKET_PATH2 =
|
|
94074
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
94845
|
+
var LEGACY_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "vault-broker.sock");
|
|
94846
|
+
var OPERATOR_SOCKET_PATH2 = join60(homedir19(), ".switchroom", "broker-operator", "sock");
|
|
94075
94847
|
function defaultBrokerSocketPath2() {
|
|
94076
94848
|
if (fs2.existsSync(OPERATOR_SOCKET_PATH2))
|
|
94077
94849
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -94953,8 +95725,8 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
94953
95725
|
}
|
|
94954
95726
|
|
|
94955
95727
|
// registry/turns-schema.ts
|
|
94956
|
-
import { chmodSync as chmodSync12, mkdirSync as
|
|
94957
|
-
import { join as
|
|
95728
|
+
import { chmodSync as chmodSync12, mkdirSync as mkdirSync47 } from "fs";
|
|
95729
|
+
import { join as join61 } from "path";
|
|
94958
95730
|
var DatabaseClass3 = null;
|
|
94959
95731
|
function loadDatabaseClass3() {
|
|
94960
95732
|
if (DatabaseClass3 != null)
|
|
@@ -95026,9 +95798,9 @@ function applySchema(db3) {
|
|
|
95026
95798
|
}
|
|
95027
95799
|
function openTurnsDb(agentDir) {
|
|
95028
95800
|
const Database = loadDatabaseClass3();
|
|
95029
|
-
const dir =
|
|
95030
|
-
|
|
95031
|
-
const path2 =
|
|
95801
|
+
const dir = join61(agentDir, "telegram");
|
|
95802
|
+
mkdirSync47(dir, { recursive: true, mode: 448 });
|
|
95803
|
+
const path2 = join61(dir, "registry.db");
|
|
95032
95804
|
const db3 = new Database(path2, { create: true });
|
|
95033
95805
|
applySchema(db3);
|
|
95034
95806
|
try {
|
|
@@ -95372,7 +96144,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
95372
96144
|
}
|
|
95373
96145
|
|
|
95374
96146
|
// gateway/bridge-dead-watchdog.ts
|
|
95375
|
-
import { readFileSync as
|
|
96147
|
+
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync22, unlinkSync as unlinkSync25 } from "node:fs";
|
|
95376
96148
|
|
|
95377
96149
|
// gateway/cron-session.ts
|
|
95378
96150
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -95405,7 +96177,7 @@ function readFreshCrashLogTail(path2, opts = {}) {
|
|
|
95405
96177
|
const nowMs3 = opts.nowMs ?? Date.now();
|
|
95406
96178
|
const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
|
|
95407
96179
|
const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
|
|
95408
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
96180
|
+
const readFile = opts.readFile ?? ((p) => readFileSync58(p, "utf8"));
|
|
95409
96181
|
let raw;
|
|
95410
96182
|
try {
|
|
95411
96183
|
raw = readFile(path2);
|
|
@@ -95426,13 +96198,13 @@ function readFreshCrashLogTail(path2, opts = {}) {
|
|
|
95426
96198
|
}
|
|
95427
96199
|
function writeBridgeDeadEscalationMarker(path2, marker) {
|
|
95428
96200
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
95429
|
-
|
|
95430
|
-
|
|
96201
|
+
writeFileSync48(tmp, JSON.stringify(marker), "utf8");
|
|
96202
|
+
renameSync22(tmp, path2);
|
|
95431
96203
|
}
|
|
95432
96204
|
function consumeBridgeDeadEscalationMarker(path2, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
|
|
95433
96205
|
let marker = null;
|
|
95434
96206
|
try {
|
|
95435
|
-
const parsed = JSON.parse(
|
|
96207
|
+
const parsed = JSON.parse(readFileSync58(path2, "utf8"));
|
|
95436
96208
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
|
|
95437
96209
|
const age = nowMs3 - parsed.ts;
|
|
95438
96210
|
if (age >= 0 && age < maxAgeMs) {
|
|
@@ -95585,7 +96357,7 @@ function createBridgeDeadWatchdog(opts) {
|
|
|
95585
96357
|
}
|
|
95586
96358
|
|
|
95587
96359
|
// gateway/boot-probes.ts
|
|
95588
|
-
import { readFileSync as
|
|
96360
|
+
import { readFileSync as readFileSync59, readdirSync as readdirSync12, existsSync as existsSync54 } from "fs";
|
|
95589
96361
|
init_quota_cache();
|
|
95590
96362
|
init_quota_check();
|
|
95591
96363
|
import { execFile as execFileCb2 } from "child_process";
|
|
@@ -95593,7 +96365,7 @@ import { promisify as promisify2 } from "util";
|
|
|
95593
96365
|
var execFile2 = promisify2(execFileCb2);
|
|
95594
96366
|
var realProcFs2 = {
|
|
95595
96367
|
readdir: (p) => readdirSync12(p),
|
|
95596
|
-
readFile: (p) =>
|
|
96368
|
+
readFile: (p) => readFileSync59(p, "utf-8")
|
|
95597
96369
|
};
|
|
95598
96370
|
function findAgentProcessInContainer2(fs3 = realProcFs2) {
|
|
95599
96371
|
let entries;
|
|
@@ -95843,7 +96615,7 @@ if (isGatewayMain) {
|
|
|
95843
96615
|
shutdownAnalytics();
|
|
95844
96616
|
});
|
|
95845
96617
|
}
|
|
95846
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
96618
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join62(homedir20(), ".claude", "channels", "telegram");
|
|
95847
96619
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
95848
96620
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
95849
96621
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -95882,7 +96654,7 @@ function alwaysAllowDrainDeps() {
|
|
|
95882
96654
|
return {
|
|
95883
96655
|
readConfigText: () => {
|
|
95884
96656
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
95885
|
-
return
|
|
96657
|
+
return readFileSync60(cfgPath, "utf8");
|
|
95886
96658
|
},
|
|
95887
96659
|
resolveAllowList: (_configText, agentName3) => {
|
|
95888
96660
|
const cfg = loadConfig2();
|
|
@@ -95943,11 +96715,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
95943
96715
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
95944
96716
|
timer3.unref?.();
|
|
95945
96717
|
}
|
|
95946
|
-
var ACCESS_FILE =
|
|
95947
|
-
var APPROVED_DIR =
|
|
95948
|
-
var ENV_FILE =
|
|
95949
|
-
var INBOX_DIR =
|
|
95950
|
-
var PEOPLE_FILE =
|
|
96718
|
+
var ACCESS_FILE = join62(STATE_DIR, "access.json");
|
|
96719
|
+
var APPROVED_DIR = join62(STATE_DIR, "approved");
|
|
96720
|
+
var ENV_FILE = join62(STATE_DIR, ".env");
|
|
96721
|
+
var INBOX_DIR = join62(STATE_DIR, "inbox");
|
|
96722
|
+
var PEOPLE_FILE = join62(STATE_DIR, "people.json");
|
|
95951
96723
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
95952
96724
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
95953
96725
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -96012,7 +96784,7 @@ function formatBootVersion() {
|
|
|
96012
96784
|
}
|
|
96013
96785
|
try {
|
|
96014
96786
|
chmodSync14(ENV_FILE, 384);
|
|
96015
|
-
for (const line of
|
|
96787
|
+
for (const line of readFileSync60(ENV_FILE, "utf8").split(`
|
|
96016
96788
|
`)) {
|
|
96017
96789
|
const m = line.match(/^(\w+)=(.*)$/);
|
|
96018
96790
|
if (m && process.env[m[1]] === undefined)
|
|
@@ -96033,7 +96805,7 @@ var bot;
|
|
|
96033
96805
|
var lastGetUpdatesHeartbeatMs = Date.now();
|
|
96034
96806
|
var GRAMMY_VERSION = (() => {
|
|
96035
96807
|
try {
|
|
96036
|
-
const raw =
|
|
96808
|
+
const raw = readFileSync60(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
|
|
96037
96809
|
return JSON.parse(raw).version ?? "unknown";
|
|
96038
96810
|
} catch {
|
|
96039
96811
|
return "unknown";
|
|
@@ -96096,7 +96868,7 @@ function assertSendable(f) {
|
|
|
96096
96868
|
} catch {
|
|
96097
96869
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
96098
96870
|
}
|
|
96099
|
-
const inbox =
|
|
96871
|
+
const inbox = join62(stateReal, "inbox");
|
|
96100
96872
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
96101
96873
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
96102
96874
|
}
|
|
@@ -96115,7 +96887,7 @@ function assertSendable(f) {
|
|
|
96115
96887
|
}
|
|
96116
96888
|
function readAccessFile() {
|
|
96117
96889
|
try {
|
|
96118
|
-
const raw =
|
|
96890
|
+
const raw = readFileSync60(ACCESS_FILE, "utf8");
|
|
96119
96891
|
const parsed = JSON.parse(raw);
|
|
96120
96892
|
const allowFrom = validateStringArray("allowFrom", parsed.allowFrom ?? []);
|
|
96121
96893
|
const groups = {};
|
|
@@ -96155,7 +96927,7 @@ function readAccessFile() {
|
|
|
96155
96927
|
if (err.code === "ENOENT")
|
|
96156
96928
|
return defaultAccess();
|
|
96157
96929
|
try {
|
|
96158
|
-
|
|
96930
|
+
renameSync23(ACCESS_FILE, `${ACCESS_FILE}.corrupt-${Date.now()}`);
|
|
96159
96931
|
} catch {}
|
|
96160
96932
|
process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
|
|
96161
96933
|
`);
|
|
@@ -96177,7 +96949,7 @@ function loadAccess() {
|
|
|
96177
96949
|
}
|
|
96178
96950
|
function readPeopleFile() {
|
|
96179
96951
|
try {
|
|
96180
|
-
const raw =
|
|
96952
|
+
const raw = readFileSync60(PEOPLE_FILE, "utf8");
|
|
96181
96953
|
const parsed = JSON.parse(raw);
|
|
96182
96954
|
if (!Array.isArray(parsed.entries))
|
|
96183
96955
|
return [];
|
|
@@ -96199,11 +96971,11 @@ function assertAllowedChat(chat_id) {
|
|
|
96199
96971
|
function saveAccess(a) {
|
|
96200
96972
|
if (STATIC)
|
|
96201
96973
|
return;
|
|
96202
|
-
|
|
96974
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
96203
96975
|
const tmp = ACCESS_FILE + ".tmp";
|
|
96204
|
-
|
|
96976
|
+
writeFileSync50(tmp, JSON.stringify(a, null, 2) + `
|
|
96205
96977
|
`, { mode: 384 });
|
|
96206
|
-
|
|
96978
|
+
renameSync23(tmp, ACCESS_FILE);
|
|
96207
96979
|
}
|
|
96208
96980
|
function pruneExpired(a) {
|
|
96209
96981
|
const now = Date.now();
|
|
@@ -96221,7 +96993,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
96221
96993
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
96222
96994
|
try {
|
|
96223
96995
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
96224
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
96996
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join62(STATE_DIR, "history.db")}
|
|
96225
96997
|
`);
|
|
96226
96998
|
} catch (err) {
|
|
96227
96999
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -96240,12 +97012,12 @@ if (isGatewayMain)
|
|
|
96240
97012
|
let markerTurnKey = null;
|
|
96241
97013
|
let markerAgeMs = null;
|
|
96242
97014
|
try {
|
|
96243
|
-
const markerPath =
|
|
96244
|
-
if (
|
|
97015
|
+
const markerPath = join62(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
97016
|
+
if (existsSync56(markerPath)) {
|
|
96245
97017
|
const st = statSync20(markerPath);
|
|
96246
97018
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
96247
97019
|
try {
|
|
96248
|
-
const payload = JSON.parse(
|
|
97020
|
+
const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
|
|
96249
97021
|
if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
|
|
96250
97022
|
markerTurnKey = payload.turnKey;
|
|
96251
97023
|
}
|
|
@@ -96265,10 +97037,10 @@ if (isGatewayMain)
|
|
|
96265
97037
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
96266
97038
|
`);
|
|
96267
97039
|
} else {
|
|
96268
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
97040
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join62(agentDir, "telegram", "registry.db")}
|
|
96269
97041
|
`);
|
|
96270
97042
|
}
|
|
96271
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
97043
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join62(STATE_DIR, "bridge-dead-escalation.json"));
|
|
96272
97044
|
if (bridgeDeadMarker != null) {
|
|
96273
97045
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
96274
97046
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -96281,7 +97053,7 @@ if (isGatewayMain)
|
|
|
96281
97053
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
96282
97054
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
96283
97055
|
if (pending2 != null && selfAgent) {
|
|
96284
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
97056
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
|
|
96285
97057
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
96286
97058
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
96287
97059
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -96394,7 +97166,7 @@ if (isGatewayMain)
|
|
|
96394
97166
|
`);
|
|
96395
97167
|
}
|
|
96396
97168
|
}
|
|
96397
|
-
const pendingEnvPath =
|
|
97169
|
+
const pendingEnvPath = join62(agentDir, ".pending-turn.env");
|
|
96398
97170
|
try {
|
|
96399
97171
|
if (pending2 != null) {
|
|
96400
97172
|
const lines = [
|
|
@@ -96408,13 +97180,13 @@ if (isGatewayMain)
|
|
|
96408
97180
|
pending2.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending2.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
|
|
96409
97181
|
];
|
|
96410
97182
|
const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
|
|
96411
|
-
|
|
97183
|
+
writeFileSync50(pendingEnvTmp, lines.join(`
|
|
96412
97184
|
`) + `
|
|
96413
97185
|
`, { mode: 384 });
|
|
96414
|
-
|
|
97186
|
+
renameSync23(pendingEnvTmp, pendingEnvPath);
|
|
96415
97187
|
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
96416
97188
|
`);
|
|
96417
|
-
} else if (
|
|
97189
|
+
} else if (existsSync56(pendingEnvPath)) {
|
|
96418
97190
|
rmSync6(pendingEnvPath, { force: true });
|
|
96419
97191
|
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
96420
97192
|
`);
|
|
@@ -96522,7 +97294,7 @@ function checkApprovals() {
|
|
|
96522
97294
|
return;
|
|
96523
97295
|
}
|
|
96524
97296
|
for (const senderId of files) {
|
|
96525
|
-
const file =
|
|
97297
|
+
const file = join62(APPROVED_DIR, senderId);
|
|
96526
97298
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync6(file, { force: true }), (err) => {
|
|
96527
97299
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
96528
97300
|
`);
|
|
@@ -96695,12 +97467,12 @@ function noteAgentOutputAt(key, ts) {
|
|
|
96695
97467
|
lastAgentOutputAt.delete(oldest);
|
|
96696
97468
|
}
|
|
96697
97469
|
}
|
|
96698
|
-
var OBLIGATION_STORE_PATH =
|
|
97470
|
+
var OBLIGATION_STORE_PATH = join62(STATE_DIR, "obligations.json");
|
|
96699
97471
|
var obligationStoreFs = {
|
|
96700
|
-
readFileSync: (p) =>
|
|
96701
|
-
writeFileSync: (p, d) =>
|
|
96702
|
-
renameSync: (a, b) =>
|
|
96703
|
-
existsSync: (p) =>
|
|
97472
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
97473
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
97474
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
97475
|
+
existsSync: (p) => existsSync56(p)
|
|
96704
97476
|
};
|
|
96705
97477
|
var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX, {
|
|
96706
97478
|
onChange: STATIC || !OBLIGATION_LEDGER_ENABLED ? undefined : (snapshot) => persistObligations(OBLIGATION_STORE_PATH, obligationStoreFs, snapshot)
|
|
@@ -97479,9 +98251,9 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
97479
98251
|
return;
|
|
97480
98252
|
}
|
|
97481
98253
|
},
|
|
97482
|
-
rename: (from, to) =>
|
|
98254
|
+
rename: (from, to) => renameSync23(from, to)
|
|
97483
98255
|
});
|
|
97484
|
-
|
|
98256
|
+
appendFileSync9(turnsPath, rec);
|
|
97485
98257
|
} catch {}
|
|
97486
98258
|
}
|
|
97487
98259
|
function maybeProactiveCompact() {
|
|
@@ -98107,7 +98879,7 @@ function sweepStaleAlwaysAllowCorrelations(now = Date.now()) {
|
|
|
98107
98879
|
var MENTAL_MODEL_CORRELATION_TTL_MS = 720000;
|
|
98108
98880
|
var pendingMentalModelCorrelations = createSweepableStore((entry, now) => now - entry.createdAt > MENTAL_MODEL_CORRELATION_TTL_MS);
|
|
98109
98881
|
function mentalModelCorrelationKey(agentName3, unifiedDiff) {
|
|
98110
|
-
return `${agentName3}::${
|
|
98882
|
+
return `${agentName3}::${createHash6("sha256").update(unifiedDiff).digest("hex")}`;
|
|
98111
98883
|
}
|
|
98112
98884
|
function sweepStaleMentalModelCorrelations(now = Date.now()) {
|
|
98113
98885
|
pendingMentalModelCorrelations.sweep(now);
|
|
@@ -99043,28 +99815,28 @@ var statusPinState = new Map;
|
|
|
99043
99815
|
var statusPinChatIds = new Map;
|
|
99044
99816
|
var statusPinPinnedAt = new Map;
|
|
99045
99817
|
var statusPinRightsCache = new PinRightsCache2;
|
|
99046
|
-
var STATUS_PIN_STORE_PATH =
|
|
99818
|
+
var STATUS_PIN_STORE_PATH = join62(STATE_DIR, "status-pins.json");
|
|
99047
99819
|
var statusPinStoreFs = {
|
|
99048
|
-
readFileSync: (p) =>
|
|
99049
|
-
writeFileSync: (p, d) =>
|
|
99050
|
-
renameSync: (a, b) =>
|
|
99051
|
-
existsSync: (p) =>
|
|
99820
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99821
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99822
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99823
|
+
existsSync: (p) => existsSync56(p)
|
|
99052
99824
|
};
|
|
99053
99825
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
99054
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
99826
|
+
var ACTIVITY_CARD_STORE_PATH = join62(STATE_DIR, "activity-cards-pending.json");
|
|
99055
99827
|
var activityCardStoreFs = {
|
|
99056
|
-
readFileSync: (p) =>
|
|
99057
|
-
writeFileSync: (p, d) =>
|
|
99058
|
-
renameSync: (a, b) =>
|
|
99059
|
-
existsSync: (p) =>
|
|
99828
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99829
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99830
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99831
|
+
existsSync: (p) => existsSync56(p)
|
|
99060
99832
|
};
|
|
99061
99833
|
var activityCardPersistEnabled = !STATIC;
|
|
99062
|
-
var QUEUED_CARD_STORE_PATH =
|
|
99834
|
+
var QUEUED_CARD_STORE_PATH = join62(STATE_DIR, "queued-cards-pending.json");
|
|
99063
99835
|
var queuedCardStoreFs = {
|
|
99064
|
-
readFileSync: (p) =>
|
|
99065
|
-
writeFileSync: (p, d) =>
|
|
99066
|
-
renameSync: (a, b) =>
|
|
99067
|
-
existsSync: (p) =>
|
|
99836
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
99837
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
99838
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
99839
|
+
existsSync: (p) => existsSync56(p)
|
|
99068
99840
|
};
|
|
99069
99841
|
var queuedCardPersistEnabled = !STATIC;
|
|
99070
99842
|
function persistQueuedCard(key, chatId, threadId, messageId) {
|
|
@@ -99437,12 +100209,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
99437
100209
|
var completeProgressCardTurn = null;
|
|
99438
100210
|
var subagentWatcher = null;
|
|
99439
100211
|
var workerActivityFeed = null;
|
|
99440
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
100212
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join62(STATE_DIR, "gateway.sock");
|
|
99441
100213
|
if (isGatewayMain)
|
|
99442
|
-
|
|
99443
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
99444
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
99445
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
100214
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
100215
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join62(STATE_DIR, "gateway.pid.json");
|
|
100216
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join62(STATE_DIR, "gateway-session.json");
|
|
100217
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join62(STATE_DIR, "clean-shutdown.json");
|
|
99446
100218
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
99447
100219
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
99448
100220
|
var activeBootCard = null;
|
|
@@ -99471,7 +100243,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
99471
100243
|
bot: botApi,
|
|
99472
100244
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
99473
100245
|
`),
|
|
99474
|
-
persistPath:
|
|
100246
|
+
persistPath: join62(stateDir, "issues-card.json")
|
|
99475
100247
|
});
|
|
99476
100248
|
activeIssuesWatcher = startIssuesWatcher({
|
|
99477
100249
|
stateDir,
|
|
@@ -99647,7 +100419,7 @@ function runDeliveryConfirmSweep() {
|
|
|
99647
100419
|
}
|
|
99648
100420
|
var _deliveryConfirmSweep = isGatewayMain ? setInterval(runDeliveryConfirmSweep, DELIVERY_CONFIRM_SWEEP_MS) : undefined;
|
|
99649
100421
|
_deliveryConfirmSweep?.unref?.();
|
|
99650
|
-
startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null, log: (l) => process.stderr.write(l) });
|
|
100422
|
+
startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null, resolveReplyMarkup: makeOutboxListenMarkupResolver({ resolveVoiceOutPlan: (t) => resolveVoiceOutPlan(loadAccess().voice_out, t), cachePut: (token, payload) => voiceOnDemandCache.put(token, payload), eagerVoiceEnabled, enqueuePreSynth: (j) => voicePreSynthQueue.enqueue(j) }), log: (l) => process.stderr.write(l) });
|
|
99651
100423
|
if (isGatewayMain)
|
|
99652
100424
|
startTimer2({
|
|
99653
100425
|
editMessage: async (ctx) => {
|
|
@@ -99669,13 +100441,13 @@ if (isGatewayMain)
|
|
|
99669
100441
|
var inboundSpool;
|
|
99670
100442
|
if (isGatewayMain)
|
|
99671
100443
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
99672
|
-
path:
|
|
100444
|
+
path: join62(STATE_DIR, "inbound-spool.jsonl"),
|
|
99673
100445
|
fs: {
|
|
99674
|
-
appendFileSync: (p, d) =>
|
|
99675
|
-
readFileSync: (p) =>
|
|
99676
|
-
writeFileSync: (p, d) =>
|
|
99677
|
-
renameSync: (a, b) =>
|
|
99678
|
-
existsSync: (p) =>
|
|
100446
|
+
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
100447
|
+
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
100448
|
+
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
100449
|
+
renameSync: (a, b) => renameSync23(a, b),
|
|
100450
|
+
existsSync: (p) => existsSync56(p),
|
|
99679
100451
|
statSizeSync: (p) => statSync20(p).size
|
|
99680
100452
|
},
|
|
99681
100453
|
onDegraded: (info) => {
|
|
@@ -99737,13 +100509,13 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
99737
100509
|
let transcriptText;
|
|
99738
100510
|
try {
|
|
99739
100511
|
const projectsDir = getProjectsDirForCwd();
|
|
99740
|
-
const path2 =
|
|
99741
|
-
if (!
|
|
100512
|
+
const path2 = join62(projectsDir, `${sessionId}.jsonl`);
|
|
100513
|
+
if (!existsSync56(path2)) {
|
|
99742
100514
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path2}); skipping
|
|
99743
100515
|
`);
|
|
99744
100516
|
return;
|
|
99745
100517
|
}
|
|
99746
|
-
transcriptText =
|
|
100518
|
+
transcriptText = readFileSync60(path2, "utf8");
|
|
99747
100519
|
} catch (err) {
|
|
99748
100520
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
|
|
99749
100521
|
`);
|
|
@@ -99902,8 +100674,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
99902
100674
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
99903
100675
|
isShuttingDown: () => shuttingDown,
|
|
99904
100676
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
99905
|
-
crashLogPath:
|
|
99906
|
-
markerPath:
|
|
100677
|
+
crashLogPath: join62(STATE_DIR, "bridge-crash.log"),
|
|
100678
|
+
markerPath: join62(STATE_DIR, "bridge-dead-escalation.json"),
|
|
99907
100679
|
log: (line) => process.stderr.write(`${line}
|
|
99908
100680
|
`),
|
|
99909
100681
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -100009,8 +100781,8 @@ if (isGatewayMain)
|
|
|
100009
100781
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
100010
100782
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
100011
100783
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
100012
|
-
configSnapshotPath:
|
|
100013
|
-
bootCardStatePath:
|
|
100784
|
+
configSnapshotPath: join62(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
100785
|
+
bootCardStatePath: join62(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
100014
100786
|
floodStatePath: FLOOD_STATE_PATH,
|
|
100015
100787
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
100016
100788
|
}, ackMsgId).then((handle) => {
|
|
@@ -100120,22 +100892,7 @@ if (isGatewayMain)
|
|
|
100120
100892
|
notifyHaltBoundaryWaiters();
|
|
100121
100893
|
if (currentTurn != null) {
|
|
100122
100894
|
const key = statusKey(currentTurn.sessionChatId, currentTurn.sessionThreadId);
|
|
100123
|
-
|
|
100124
|
-
noteThinking(key, Date.now());
|
|
100125
|
-
} else if (ev.kind === "tool_use") {
|
|
100126
|
-
if (ev.toolUseId != null && ev.toolUseId.length > 0 && !isTelegramSurfaceTool2(ev.toolName)) {
|
|
100127
|
-
const label = toolLabel(ev.toolName, ev.input, undefined, ev.precomputedLabel);
|
|
100128
|
-
noteToolStart(key, ev.toolUseId, ev.toolName, label.length > 0 ? label : null, Date.now());
|
|
100129
|
-
const evInput = ev.input;
|
|
100130
|
-
if (ev.toolName === "Agent" || ev.toolName === "Task" || ev.toolName === "Bash" && evInput?.run_in_background === true) {
|
|
100131
|
-
noteAsyncDispatch(key);
|
|
100132
|
-
}
|
|
100133
|
-
}
|
|
100134
|
-
} else if (ev.kind === "tool_result") {
|
|
100135
|
-
if (ev.toolUseId != null && ev.toolUseId.length > 0) {
|
|
100136
|
-
noteToolEnd(key, ev.toolUseId, Date.now());
|
|
100137
|
-
}
|
|
100138
|
-
}
|
|
100895
|
+
applySilencePokeSessionEvent(exports_silence_poke, exports_pending_work_progress, key, ev);
|
|
100139
100896
|
}
|
|
100140
100897
|
},
|
|
100141
100898
|
onPermissionRequest(_client, msg) {
|
|
@@ -100692,7 +101449,7 @@ if (isGatewayMain)
|
|
|
100692
101449
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
100693
101450
|
if (Number.isInteger(receiverUid))
|
|
100694
101451
|
allowedUids.push(receiverUid);
|
|
100695
|
-
const socketPath =
|
|
101452
|
+
const socketPath = join62(STATE_DIR, "webhook.sock");
|
|
100696
101453
|
const webhookInject = (agentName3, inbound) => {
|
|
100697
101454
|
const msg = inbound;
|
|
100698
101455
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -100920,9 +101677,9 @@ function redactOutboundText(text5, site) {
|
|
|
100920
101677
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
100921
101678
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
100922
101679
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
100923
|
-
persistPath:
|
|
101680
|
+
persistPath: join62(STATE_DIR, "voice-ondemand.json")
|
|
100924
101681
|
});
|
|
100925
|
-
var VOICE_CACHE_DIR =
|
|
101682
|
+
var VOICE_CACHE_DIR = join62(STATE_DIR, "voice-cache");
|
|
100926
101683
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
100927
101684
|
runJob: async (job) => {
|
|
100928
101685
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -101324,11 +102081,11 @@ async function executeSendGif(rawArgs) {
|
|
|
101324
102081
|
};
|
|
101325
102082
|
}
|
|
101326
102083
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
101327
|
-
const accountPath =
|
|
102084
|
+
const accountPath = join62(STATE_DIR, "telegraph-account.json");
|
|
101328
102085
|
let account = null;
|
|
101329
102086
|
try {
|
|
101330
|
-
if (
|
|
101331
|
-
const raw =
|
|
102087
|
+
if (existsSync56(accountPath)) {
|
|
102088
|
+
const raw = readFileSync60(accountPath, "utf-8");
|
|
101332
102089
|
const parsed = JSON.parse(raw);
|
|
101333
102090
|
if (parsed.shortName && parsed.accessToken) {
|
|
101334
102091
|
account = parsed;
|
|
@@ -101347,8 +102104,8 @@ async function publishToTelegraph(text5, shortName, authorName) {
|
|
|
101347
102104
|
}
|
|
101348
102105
|
account = created.value;
|
|
101349
102106
|
try {
|
|
101350
|
-
|
|
101351
|
-
|
|
102107
|
+
mkdirSync49(STATE_DIR, { recursive: true, mode: 448 });
|
|
102108
|
+
writeFileSync50(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
|
|
101352
102109
|
} catch (err) {
|
|
101353
102110
|
process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
|
|
101354
102111
|
`);
|
|
@@ -101464,7 +102221,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
|
|
|
101464
102221
|
}
|
|
101465
102222
|
function readLiveSwitchroomConfigText() {
|
|
101466
102223
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
101467
|
-
return
|
|
102224
|
+
return readFileSync60(cfgPath, "utf8");
|
|
101468
102225
|
}
|
|
101469
102226
|
async function executeReact(args) {
|
|
101470
102227
|
if (!args.chat_id)
|
|
@@ -101503,9 +102260,9 @@ async function executeDownloadAttachment(args) {
|
|
|
101503
102260
|
fileUniqueId: file.file_unique_id,
|
|
101504
102261
|
now: Date.now()
|
|
101505
102262
|
});
|
|
101506
|
-
|
|
102263
|
+
mkdirSync49(INBOX_DIR, { recursive: true, mode: 448 });
|
|
101507
102264
|
assertInsideInbox2(INBOX_DIR, dlPath);
|
|
101508
|
-
|
|
102265
|
+
writeFileSync50(dlPath, buf, { mode: 384 });
|
|
101509
102266
|
return { content: [{ type: "text", text: dlPath }] };
|
|
101510
102267
|
}
|
|
101511
102268
|
async function executeEditMessage(args) {
|
|
@@ -102865,14 +103622,14 @@ function restartMarkerPath() {
|
|
|
102865
103622
|
const agentDir = resolveAgentDirFromEnv();
|
|
102866
103623
|
if (!agentDir)
|
|
102867
103624
|
return null;
|
|
102868
|
-
return
|
|
103625
|
+
return join62(agentDir, "restart-pending.json");
|
|
102869
103626
|
}
|
|
102870
103627
|
function writeRestartMarker(marker) {
|
|
102871
103628
|
const p = restartMarkerPath();
|
|
102872
103629
|
if (!p)
|
|
102873
103630
|
return;
|
|
102874
103631
|
try {
|
|
102875
|
-
|
|
103632
|
+
writeFileSync50(p, JSON.stringify(marker));
|
|
102876
103633
|
lastPlannedRestartAt = Date.now();
|
|
102877
103634
|
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}
|
|
102878
103635
|
`);
|
|
@@ -102891,7 +103648,7 @@ function readRestartMarker() {
|
|
|
102891
103648
|
if (!p)
|
|
102892
103649
|
return null;
|
|
102893
103650
|
try {
|
|
102894
|
-
return JSON.parse(
|
|
103651
|
+
return JSON.parse(readFileSync60(p, "utf8"));
|
|
102895
103652
|
} catch {
|
|
102896
103653
|
return null;
|
|
102897
103654
|
}
|
|
@@ -103040,7 +103797,7 @@ var _dockerReachable;
|
|
|
103040
103797
|
function isDockerReachable() {
|
|
103041
103798
|
if (_dockerReachable !== undefined)
|
|
103042
103799
|
return _dockerReachable;
|
|
103043
|
-
if (!
|
|
103800
|
+
if (!existsSync56("/var/run/docker.sock")) {
|
|
103044
103801
|
_dockerReachable = false;
|
|
103045
103802
|
return _dockerReachable;
|
|
103046
103803
|
}
|
|
@@ -103057,12 +103814,12 @@ function _resetDockerReachableCache() {
|
|
|
103057
103814
|
}
|
|
103058
103815
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
103059
103816
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
103060
|
-
const logPath =
|
|
103817
|
+
const logPath = join62(STATE_DIR, "detached-spawn.log");
|
|
103061
103818
|
let outFd = null;
|
|
103062
103819
|
try {
|
|
103063
|
-
|
|
103820
|
+
mkdirSync49(STATE_DIR, { recursive: true });
|
|
103064
103821
|
outFd = openSync12(logPath, "a");
|
|
103065
|
-
|
|
103822
|
+
writeFileSync50(logPath, `
|
|
103066
103823
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
103067
103824
|
`, { flag: "a" });
|
|
103068
103825
|
} catch {}
|
|
@@ -103088,7 +103845,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
103088
103845
|
return;
|
|
103089
103846
|
let tail = "";
|
|
103090
103847
|
try {
|
|
103091
|
-
const full =
|
|
103848
|
+
const full = readFileSync60(logPath, "utf8");
|
|
103092
103849
|
tail = full.split(`
|
|
103093
103850
|
`).slice(-30).join(`
|
|
103094
103851
|
`).trim();
|
|
@@ -103350,10 +104107,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
103350
104107
|
}
|
|
103351
104108
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
103352
104109
|
try {
|
|
103353
|
-
const auditPath =
|
|
103354
|
-
if (!
|
|
104110
|
+
const auditPath = join62(homedir20(), ".switchroom", "vault-audit.log");
|
|
104111
|
+
if (!existsSync56(auditPath))
|
|
103355
104112
|
return [];
|
|
103356
|
-
const raw =
|
|
104113
|
+
const raw = readFileSync60(auditPath, "utf8");
|
|
103357
104114
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
103358
104115
|
} catch {
|
|
103359
104116
|
return [];
|
|
@@ -103404,7 +104161,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
103404
104161
|
try {
|
|
103405
104162
|
const agentDir = resolveAgentDirFromEnv();
|
|
103406
104163
|
if (agentDir) {
|
|
103407
|
-
const raw =
|
|
104164
|
+
const raw = readFileSync60(join62(agentDir, ".claude", ".claude.json"), "utf8");
|
|
103408
104165
|
claudeJson = JSON.parse(raw);
|
|
103409
104166
|
}
|
|
103410
104167
|
} catch {}
|
|
@@ -103533,7 +104290,7 @@ function buildModelDeps(restartCtx) {
|
|
|
103533
104290
|
try {
|
|
103534
104291
|
const agentDir = resolveAgentDirFromEnv();
|
|
103535
104292
|
if (agentDir) {
|
|
103536
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
104293
|
+
const local = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
|
|
103537
104294
|
if (local.ok)
|
|
103538
104295
|
return formatQuotaLine2(local.data);
|
|
103539
104296
|
}
|
|
@@ -103779,9 +104536,9 @@ function effortMenuReplyMarkup(reply) {
|
|
|
103779
104536
|
function flushAgentHandoff(agentDir) {
|
|
103780
104537
|
let removed = 0;
|
|
103781
104538
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
103782
|
-
const p =
|
|
104539
|
+
const p = join62(agentDir, fname);
|
|
103783
104540
|
try {
|
|
103784
|
-
if (
|
|
104541
|
+
if (existsSync56(p)) {
|
|
103785
104542
|
unlinkSync27(p);
|
|
103786
104543
|
removed++;
|
|
103787
104544
|
}
|
|
@@ -103837,7 +104594,7 @@ async function handleNewCommand(ctx) {
|
|
|
103837
104594
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
103838
104595
|
if (agentDir != null) {
|
|
103839
104596
|
try {
|
|
103840
|
-
|
|
104597
|
+
writeFileSync50(join62(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
103841
104598
|
`, "utf8");
|
|
103842
104599
|
} catch (err) {
|
|
103843
104600
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -103950,16 +104707,16 @@ function buildFolderPickerDeps() {
|
|
|
103950
104707
|
};
|
|
103951
104708
|
}
|
|
103952
104709
|
var lockoutOps = {
|
|
103953
|
-
readFileSync: (p, enc) =>
|
|
103954
|
-
writeFileSync: (p, data, opts) =>
|
|
103955
|
-
existsSync: (p) =>
|
|
103956
|
-
mkdirSync: (p, opts) =>
|
|
103957
|
-
joinPath: (...parts) =>
|
|
104710
|
+
readFileSync: (p, enc) => readFileSync60(p, enc),
|
|
104711
|
+
writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
|
|
104712
|
+
existsSync: (p) => existsSync56(p),
|
|
104713
|
+
mkdirSync: (p, opts) => mkdirSync49(p, opts),
|
|
104714
|
+
joinPath: (...parts) => join62(...parts)
|
|
103958
104715
|
};
|
|
103959
104716
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
103960
104717
|
function isAuthBrokerSocketReachable() {
|
|
103961
104718
|
try {
|
|
103962
|
-
return
|
|
104719
|
+
return existsSync56(resolveAuthBrokerSocketPath2());
|
|
103963
104720
|
} catch {
|
|
103964
104721
|
return false;
|
|
103965
104722
|
}
|
|
@@ -104214,7 +104971,7 @@ async function runCreditWatch() {
|
|
|
104214
104971
|
if (!agentDir)
|
|
104215
104972
|
return;
|
|
104216
104973
|
const agentName3 = getMyAgentName();
|
|
104217
|
-
const claudeConfigDir =
|
|
104974
|
+
const claudeConfigDir = join62(agentDir, ".claude");
|
|
104218
104975
|
const stateDir = STATE_DIR;
|
|
104219
104976
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
104220
104977
|
const prev = loadCreditState(stateDir);
|
|
@@ -105970,7 +106727,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
105970
106727
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
105971
106728
|
return;
|
|
105972
106729
|
}
|
|
105973
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
106730
|
+
const result = await fetchQuota2({ claudeConfigDir: join62(agentDir, ".claude") });
|
|
105974
106731
|
if (!result.ok) {
|
|
105975
106732
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
105976
106733
|
return;
|
|
@@ -106356,7 +107113,7 @@ ${interimLabel}` : interimLabel
|
|
|
106356
107113
|
const unifiedDiff = (() => {
|
|
106357
107114
|
try {
|
|
106358
107115
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
106359
|
-
const raw =
|
|
107116
|
+
const raw = readFileSync60(cfgPath, "utf8");
|
|
106360
107117
|
return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
|
|
106361
107118
|
} catch (err) {
|
|
106362
107119
|
process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
|
|
@@ -106634,6 +107391,7 @@ ${labelWithResume}` : labelWithResume,
|
|
|
106634
107391
|
handleChecklistUpdate(ctx, "checklist_tasks_added", checklistHandlerDeps);
|
|
106635
107392
|
});
|
|
106636
107393
|
bot2.on("message:pinned_message", (ctx) => handlePinnedMessage(ctx, pinnedMessageHandlerDeps));
|
|
107394
|
+
bot2.on("message:rich_message", (ctx) => handleRichMessageMessage(ctx, { ...mediaEnvelopeDeps, handleInbound: handleInboundCoalesced }));
|
|
106637
107395
|
installUnhandledMessageCatchAll(bot2, (ctx, text5) => routeInbound(ctx, text5, undefined, undefined, inboundRouterDeps), (line) => process.stderr.write(line));
|
|
106638
107396
|
bot2.on("message_reaction", (ctx) => {
|
|
106639
107397
|
handleMessageReaction(ctx);
|
|
@@ -107212,7 +107970,7 @@ async function startGateway() {
|
|
|
107212
107970
|
return;
|
|
107213
107971
|
}
|
|
107214
107972
|
})();
|
|
107215
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
107973
|
+
const resolvedAgentDirForBootCard = agentDir ?? join62(homedir20(), ".switchroom", "agents", agentSlug);
|
|
107216
107974
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
107217
107975
|
agentName: agentDisplayName,
|
|
107218
107976
|
agentSlug,
|
|
@@ -107226,8 +107984,8 @@ async function startGateway() {
|
|
|
107226
107984
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
107227
107985
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
107228
107986
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
107229
|
-
configSnapshotPath:
|
|
107230
|
-
bootCardStatePath:
|
|
107987
|
+
configSnapshotPath: join62(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
107988
|
+
bootCardStatePath: join62(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
107231
107989
|
floodStatePath: FLOOD_STATE_PATH,
|
|
107232
107990
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
107233
107991
|
}, ackMsgId);
|
|
@@ -107258,10 +108016,10 @@ async function startGateway() {
|
|
|
107258
108016
|
try {
|
|
107259
108017
|
const smAgentDir = resolveAgentDirFromEnv();
|
|
107260
108018
|
if (smAgentDir) {
|
|
107261
|
-
const activePath =
|
|
107262
|
-
if (
|
|
108019
|
+
const activePath = join62(smAgentDir, ".active-session-model");
|
|
108020
|
+
if (existsSync56(activePath)) {
|
|
107263
108021
|
try {
|
|
107264
|
-
const launched =
|
|
108022
|
+
const launched = readFileSync60(activePath, "utf8").trim();
|
|
107265
108023
|
const configured = (() => {
|
|
107266
108024
|
const d = switchroomExecJson(["agent", "list"]);
|
|
107267
108025
|
const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
|
|
@@ -107294,24 +108052,24 @@ async function startGateway() {
|
|
|
107294
108052
|
deliverModelSwitchBootNotice({
|
|
107295
108053
|
...modelBootCardDeps,
|
|
107296
108054
|
confirmation,
|
|
107297
|
-
hasSessionModelAlert:
|
|
108055
|
+
hasSessionModelAlert: existsSync56(join62(smAgentDir, ".session-model-alert"))
|
|
107298
108056
|
});
|
|
107299
108057
|
}
|
|
107300
108058
|
} catch {}
|
|
107301
108059
|
}
|
|
107302
|
-
const activeEffortPath =
|
|
107303
|
-
if (
|
|
108060
|
+
const activeEffortPath = join62(smAgentDir, ".active-session-effort");
|
|
108061
|
+
if (existsSync56(activeEffortPath)) {
|
|
107304
108062
|
try {
|
|
107305
|
-
const launchedEffort =
|
|
108063
|
+
const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
|
|
107306
108064
|
const configuredEffort = getConfiguredEffortForPersist();
|
|
107307
108065
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
107308
108066
|
} catch {}
|
|
107309
108067
|
}
|
|
107310
|
-
const alertPath =
|
|
107311
|
-
if (
|
|
108068
|
+
const alertPath = join62(smAgentDir, ".session-model-alert");
|
|
108069
|
+
if (existsSync56(alertPath)) {
|
|
107312
108070
|
let alertText = null;
|
|
107313
108071
|
try {
|
|
107314
|
-
alertText =
|
|
108072
|
+
alertText = readFileSync60(alertPath, "utf8").trim();
|
|
107315
108073
|
} catch {
|
|
107316
108074
|
alertText = null;
|
|
107317
108075
|
}
|