switchroom 0.21.9 → 0.21.10
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/dist/gateway/gateway.js +772 -266
- package/telegram-plugin/format.ts +18 -1
- package/telegram-plugin/gateway/outbound-send-path.ts +7 -0
- package/telegram-plugin/gateway/speech-capture.ts +158 -0
- package/telegram-plugin/render/html-fold.ts +354 -0
- package/telegram-plugin/render/parse.ts +570 -29
- package/telegram-plugin/tests/render/html-dialect-content-loss.test.ts +253 -0
- package/telegram-plugin/tests/render/html-dialect.test.ts +283 -0
- package/telegram-plugin/tests/render/parse.test.ts +9 -5
- package/telegram-plugin/tests/send-reply-golden.test.ts +99 -1
- package/telegram-plugin/tests/speech-capture.test.ts +296 -0
- package/telegram-plugin/tests/tts-normalize.test.ts +114 -0
- package/telegram-plugin/tests/voice-normalize-text.test.ts +89 -0
- package/telegram-plugin/tts-normalize.ts +47 -9
- package/telegram-plugin/voice-normalize-text.ts +48 -9
|
@@ -6770,7 +6770,7 @@ function codeSpanSafe(s) {
|
|
|
6770
6770
|
return s.replace(/`/g, "`\u200b");
|
|
6771
6771
|
}
|
|
6772
6772
|
function escapeLinkHref(href) {
|
|
6773
|
-
return href.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
6773
|
+
return href.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)").replace(/[\x00-\x20\x7f]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0")}`);
|
|
6774
6774
|
}
|
|
6775
6775
|
function repairEscapedWhitespace(text) {
|
|
6776
6776
|
if (!/\\[nrt"\\]/.test(text))
|
|
@@ -30173,7 +30173,7 @@ __export(exports_history, {
|
|
|
30173
30173
|
MIN_PREFIX_MATCH_CHARS: () => MIN_PREFIX_MATCH_CHARS2
|
|
30174
30174
|
});
|
|
30175
30175
|
import { chmodSync as chmodSync9, existsSync as existsSync29 } from "fs";
|
|
30176
|
-
import { join as
|
|
30176
|
+
import { join as join38 } from "path";
|
|
30177
30177
|
function loadDatabaseClass2() {
|
|
30178
30178
|
if (DatabaseClass2 != null)
|
|
30179
30179
|
return DatabaseClass2;
|
|
@@ -30231,7 +30231,7 @@ function initHistory2(stateDir, retentionDays = 30) {
|
|
|
30231
30231
|
return;
|
|
30232
30232
|
const Database = loadDatabaseClass2();
|
|
30233
30233
|
mkdirStateSync(stateDir, { recursive: true, mode: 448 });
|
|
30234
|
-
const path2 =
|
|
30234
|
+
const path2 = join38(stateDir, "history.db");
|
|
30235
30235
|
dbPath2 = path2;
|
|
30236
30236
|
db2 = new Database(path2, { create: true });
|
|
30237
30237
|
db2.exec("PRAGMA journal_mode = WAL");
|
|
@@ -30685,7 +30685,7 @@ var init_turn_flush_suppression = () => {};
|
|
|
30685
30685
|
// ../src/agents/generation-stamp.ts
|
|
30686
30686
|
import { createHash as createHash6 } from "node:crypto";
|
|
30687
30687
|
import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "node:fs";
|
|
30688
|
-
import { join as
|
|
30688
|
+
import { join as join45 } from "node:path";
|
|
30689
30689
|
function sha256Text(s) {
|
|
30690
30690
|
return createHash6("sha256").update(s, "utf-8").digest("hex");
|
|
30691
30691
|
}
|
|
@@ -30695,7 +30695,7 @@ function hashManagedClaudeMd(content3) {
|
|
|
30695
30695
|
return sha256Text(managed);
|
|
30696
30696
|
}
|
|
30697
30697
|
function hashStampedFileOnDisk(agentDir, rel) {
|
|
30698
|
-
const p =
|
|
30698
|
+
const p = join45(agentDir, rel);
|
|
30699
30699
|
if (!existsSync36(p))
|
|
30700
30700
|
return null;
|
|
30701
30701
|
let content3;
|
|
@@ -30707,7 +30707,7 @@ function hashStampedFileOnDisk(agentDir, rel) {
|
|
|
30707
30707
|
return rel === "CLAUDE.md" ? hashManagedClaudeMd(content3) : sha256Text(content3);
|
|
30708
30708
|
}
|
|
30709
30709
|
function readGenerationStamp(agentDir) {
|
|
30710
|
-
const p =
|
|
30710
|
+
const p = join45(agentDir, GENERATION_STAMP_FILE);
|
|
30711
30711
|
if (!existsSync36(p))
|
|
30712
30712
|
return null;
|
|
30713
30713
|
try {
|
|
@@ -33711,7 +33711,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
33711
33711
|
return path2;
|
|
33712
33712
|
}
|
|
33713
33713
|
exports2.normalize = normalize;
|
|
33714
|
-
function
|
|
33714
|
+
function join47(aRoot, aPath) {
|
|
33715
33715
|
if (aRoot === "") {
|
|
33716
33716
|
aRoot = ".";
|
|
33717
33717
|
}
|
|
@@ -33743,7 +33743,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
33743
33743
|
}
|
|
33744
33744
|
return joined;
|
|
33745
33745
|
}
|
|
33746
|
-
exports2.join =
|
|
33746
|
+
exports2.join = join47;
|
|
33747
33747
|
exports2.isAbsolute = function(aPath) {
|
|
33748
33748
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
33749
33749
|
};
|
|
@@ -33916,7 +33916,7 @@ var require_util = __commonJS((exports2) => {
|
|
|
33916
33916
|
parsed.path = parsed.path.substring(0, index2 + 1);
|
|
33917
33917
|
}
|
|
33918
33918
|
}
|
|
33919
|
-
sourceURL =
|
|
33919
|
+
sourceURL = join47(urlGenerate(parsed), sourceURL);
|
|
33920
33920
|
}
|
|
33921
33921
|
return normalize(sourceURL);
|
|
33922
33922
|
}
|
|
@@ -36522,9 +36522,9 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
|
|
|
36522
36522
|
|
|
36523
36523
|
// gateway/quota-cache.ts
|
|
36524
36524
|
import { existsSync as existsSync49, readFileSync as readFileSync49, writeFileSync as writeFileSync41, mkdirSync as mkdirSync42 } from "fs";
|
|
36525
|
-
import { join as
|
|
36525
|
+
import { join as join60, dirname as dirname25 } from "path";
|
|
36526
36526
|
function defaultCachePath() {
|
|
36527
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
36527
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join60(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
36528
36528
|
}
|
|
36529
36529
|
function readQuotaCache(opts = {}) {
|
|
36530
36530
|
const path3 = opts.path ?? defaultCachePath();
|
|
@@ -36571,7 +36571,7 @@ var init_quota_cache = __esm(() => {
|
|
|
36571
36571
|
|
|
36572
36572
|
// gateway/boot-probes.ts
|
|
36573
36573
|
import { readFileSync as readFileSync50, readdirSync as readdirSync14, existsSync as existsSync50 } from "fs";
|
|
36574
|
-
import { join as
|
|
36574
|
+
import { join as join61 } from "path";
|
|
36575
36575
|
import { execFile as execFileCb } from "child_process";
|
|
36576
36576
|
import { promisify } from "util";
|
|
36577
36577
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -36613,8 +36613,8 @@ function mapPlan(billingType, hasExtra) {
|
|
|
36613
36613
|
}
|
|
36614
36614
|
async function probeAccount(agentDir) {
|
|
36615
36615
|
return withTimeout("Account", (async () => {
|
|
36616
|
-
const claudeDir =
|
|
36617
|
-
const claudeJsonPath =
|
|
36616
|
+
const claudeDir = join61(agentDir, ".claude");
|
|
36617
|
+
const claudeJsonPath = join61(claudeDir, ".claude.json");
|
|
36618
36618
|
let cfg = {};
|
|
36619
36619
|
try {
|
|
36620
36620
|
const raw = readFileSync50(claudeJsonPath, "utf8");
|
|
@@ -36635,8 +36635,8 @@ async function probeAccount(agentDir) {
|
|
|
36635
36635
|
let tokenStr = "";
|
|
36636
36636
|
let status = "ok";
|
|
36637
36637
|
for (const candidate of [
|
|
36638
|
-
|
|
36639
|
-
|
|
36638
|
+
join61(claudeDir, ".oauth-token.meta.json"),
|
|
36639
|
+
join61(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
36640
36640
|
]) {
|
|
36641
36641
|
if (existsSync50(candidate)) {
|
|
36642
36642
|
try {
|
|
@@ -37022,9 +37022,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
37022
37022
|
let claudeDirForProbe = null;
|
|
37023
37023
|
for (const candidate of [
|
|
37024
37024
|
claudeConfigDir,
|
|
37025
|
-
|
|
37025
|
+
join61(claudeConfigDir, "accounts", "default")
|
|
37026
37026
|
]) {
|
|
37027
|
-
if (existsSync50(
|
|
37027
|
+
if (existsSync50(join61(candidate, ".oauth-token"))) {
|
|
37028
37028
|
claudeDirForProbe = candidate;
|
|
37029
37029
|
break;
|
|
37030
37030
|
}
|
|
@@ -37259,7 +37259,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
37259
37259
|
return withTimeout("Skills", (async () => {
|
|
37260
37260
|
const fs3 = opts.fs ?? realSkillsFs;
|
|
37261
37261
|
const max = opts.maxNamesShown ?? 3;
|
|
37262
|
-
const skillsDir =
|
|
37262
|
+
const skillsDir = join61(agentDir, ".claude", "skills");
|
|
37263
37263
|
if (!fs3.exists(skillsDir)) {
|
|
37264
37264
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
37265
37265
|
}
|
|
@@ -37274,17 +37274,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
37274
37274
|
}
|
|
37275
37275
|
const dangling = [];
|
|
37276
37276
|
for (const name of entries) {
|
|
37277
|
-
const skillPath =
|
|
37277
|
+
const skillPath = join61(skillsDir, name);
|
|
37278
37278
|
if (!fs3.exists(skillPath)) {
|
|
37279
37279
|
dangling.push(name);
|
|
37280
37280
|
continue;
|
|
37281
37281
|
}
|
|
37282
|
-
const skillMd =
|
|
37282
|
+
const skillMd = join61(skillPath, "SKILL.md");
|
|
37283
37283
|
if (!fs3.exists(skillMd) && !fs3.exists(skillPath + ".md")) {
|
|
37284
37284
|
continue;
|
|
37285
37285
|
}
|
|
37286
37286
|
}
|
|
37287
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
37287
|
+
const overlayDir = opts.overlaySkillsDir ?? join61(agentDir, "skills.d");
|
|
37288
37288
|
const overlaySlugs = new Set;
|
|
37289
37289
|
if (fs3.exists(overlayDir)) {
|
|
37290
37290
|
let overlayEntries = [];
|
|
@@ -37326,7 +37326,7 @@ function renderBucketedSkills(switchroom, agent) {
|
|
|
37326
37326
|
}
|
|
37327
37327
|
async function probeConnections(agentDir, opts = {}) {
|
|
37328
37328
|
return withTimeout("Connections", (async () => {
|
|
37329
|
-
const path3 =
|
|
37329
|
+
const path3 = join61(agentDir, ".claude", "connection-health.json");
|
|
37330
37330
|
const read = opts.readFileImpl ?? ((p) => readFileSync50(p, "utf8"));
|
|
37331
37331
|
let issues = [];
|
|
37332
37332
|
try {
|
|
@@ -37367,7 +37367,7 @@ async function probeDrift(agentDir, opts = {}) {
|
|
|
37367
37367
|
}
|
|
37368
37368
|
} catch {}
|
|
37369
37369
|
try {
|
|
37370
|
-
const raw = readFileSync50(
|
|
37370
|
+
const raw = readFileSync50(join61(agentDir, ".switchroom-drift.json"), "utf8");
|
|
37371
37371
|
const report = JSON.parse(raw);
|
|
37372
37372
|
if (report?.version === 1 && Array.isArray(report.findings)) {
|
|
37373
37373
|
const gen = report.generatedAt ? Date.parse(report.generatedAt) : NaN;
|
|
@@ -37727,7 +37727,7 @@ __export(exports_boot_card, {
|
|
|
37727
37727
|
readRoutingMode: () => readRoutingMode,
|
|
37728
37728
|
containerBootStartMs: () => containerBootStartMs
|
|
37729
37729
|
});
|
|
37730
|
-
import { join as
|
|
37730
|
+
import { join as join62 } from "path";
|
|
37731
37731
|
import { readFileSync as readFileSync54, statSync as statSync19 } from "fs";
|
|
37732
37732
|
function resolvePersonaName(slug, loadConfig3) {
|
|
37733
37733
|
try {
|
|
@@ -37772,7 +37772,7 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync54 }) {
|
|
|
37772
37772
|
}
|
|
37773
37773
|
}
|
|
37774
37774
|
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync54, statSync: statSync19 }) {
|
|
37775
|
-
const path3 =
|
|
37775
|
+
const path3 = join62(agentDir, ".routing-mode");
|
|
37776
37776
|
try {
|
|
37777
37777
|
const raw = fsImpl.readFileSync(path3, "utf-8");
|
|
37778
37778
|
const line = raw.split(`
|
|
@@ -37879,7 +37879,7 @@ function renderBootCard(opts) {
|
|
|
37879
37879
|
return stackCardLines(flatLines);
|
|
37880
37880
|
}
|
|
37881
37881
|
async function runAllProbes(opts) {
|
|
37882
|
-
const claudeDir =
|
|
37882
|
+
const claudeDir = join62(opts.agentDir, ".claude");
|
|
37883
37883
|
const probes = {};
|
|
37884
37884
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
37885
37885
|
await Promise.allSettled([
|
|
@@ -39870,7 +39870,7 @@ import {
|
|
|
39870
39870
|
closeSync as closeSync18,
|
|
39871
39871
|
existsSync as existsSync65,
|
|
39872
39872
|
unlinkSync as unlinkSync33,
|
|
39873
|
-
appendFileSync as
|
|
39873
|
+
appendFileSync as appendFileSync12
|
|
39874
39874
|
} from "fs";
|
|
39875
39875
|
|
|
39876
39876
|
// ../src/util/atomic.ts
|
|
@@ -39887,7 +39887,7 @@ function fsyncPathSync(path) {
|
|
|
39887
39887
|
|
|
39888
39888
|
// gateway/gateway.ts
|
|
39889
39889
|
import { homedir as homedir22 } from "os";
|
|
39890
|
-
import { join as
|
|
39890
|
+
import { join as join78, sep as sep6, basename as basename19 } from "path";
|
|
39891
39891
|
|
|
39892
39892
|
// plugin-logger.ts
|
|
39893
39893
|
import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
|
|
@@ -41632,7 +41632,7 @@ function normalizeForSpeech(input) {
|
|
|
41632
41632
|
const w = numberToWords(Number(n) * 1000);
|
|
41633
41633
|
return w ? w : m;
|
|
41634
41634
|
});
|
|
41635
|
-
|
|
41635
|
+
const unitReplacer = (m, num, unitRaw) => {
|
|
41636
41636
|
const unit = UNIT_MAP[unitRaw.toLowerCase()];
|
|
41637
41637
|
if (!unit)
|
|
41638
41638
|
return m;
|
|
@@ -41641,7 +41641,9 @@ function normalizeForSpeech(input) {
|
|
|
41641
41641
|
if (!w)
|
|
41642
41642
|
return m;
|
|
41643
41643
|
return `${w} ${n === 1 ? unit.s : unit.p}`;
|
|
41644
|
-
}
|
|
41644
|
+
};
|
|
41645
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})(ms|sec|min|kb|mb|gb|tb|hr)(?![a-zA-Z])/gi, unitReplacer);
|
|
41646
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})(s|m|h|d)(?![a-zA-Z])/g, unitReplacer);
|
|
41645
41647
|
s = s.replace(/(\S)\s*\+\s*(\S)/g, "$1 plus $2");
|
|
41646
41648
|
s = s.replace(/\s=\s/g, " equals ");
|
|
41647
41649
|
s = s.replace(/(\s)&(\s)/g, "$1and$2");
|
|
@@ -42003,7 +42005,7 @@ table omitted.`);
|
|
|
42003
42005
|
const w = ordinalToWords(num);
|
|
42004
42006
|
return w ?? m;
|
|
42005
42007
|
});
|
|
42006
|
-
|
|
42008
|
+
const unitReplacer = (m, num, unitRaw) => {
|
|
42007
42009
|
const unit = UNIT_MAP2[unitRaw.toLowerCase()];
|
|
42008
42010
|
if (!unit)
|
|
42009
42011
|
return m;
|
|
@@ -42012,7 +42014,9 @@ table omitted.`);
|
|
|
42012
42014
|
if (!w)
|
|
42013
42015
|
return m;
|
|
42014
42016
|
return `${w} ${n === 1 ? unit.s : unit.p}`;
|
|
42015
|
-
}
|
|
42017
|
+
};
|
|
42018
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})\s?(ms|sec|min|km|cm|mm|kg|kb|mb|gb|tb|ghz|mhz|hr|mi)(?![a-zA-Z])/gi, unitReplacer);
|
|
42019
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})\s?(s|m|h|d|g)(?![a-zA-Z])/g, unitReplacer);
|
|
42016
42020
|
s = s.replace(/(\s)&(\s)/g, "$1and$2");
|
|
42017
42021
|
s = s.replace(/(\w)&(\w)/g, "$1 and $2");
|
|
42018
42022
|
s = s.replace(/(^|\s)@(\w)/g, "$1at $2");
|
|
@@ -48111,7 +48115,7 @@ table omitted.`);
|
|
|
48111
48115
|
const w = ordinalToWords2(num);
|
|
48112
48116
|
return w ?? m;
|
|
48113
48117
|
});
|
|
48114
|
-
|
|
48118
|
+
const unitReplacer = (m, num, unitRaw) => {
|
|
48115
48119
|
const unit = UNIT_MAP3[unitRaw.toLowerCase()];
|
|
48116
48120
|
if (!unit)
|
|
48117
48121
|
return m;
|
|
@@ -48120,7 +48124,9 @@ table omitted.`);
|
|
|
48120
48124
|
if (!w)
|
|
48121
48125
|
return m;
|
|
48122
48126
|
return `${w} ${n === 1 ? unit.s : unit.p}`;
|
|
48123
|
-
}
|
|
48127
|
+
};
|
|
48128
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})\s?(ms|sec|min|km|cm|mm|kg|kb|mb|gb|tb|ghz|mhz|hr|mi)(?![a-zA-Z])/gi, unitReplacer);
|
|
48129
|
+
s = s.replace(/(?<![\d.,])\b(\d{1,9})\s?(s|m|h|d|g)(?![a-zA-Z])/g, unitReplacer);
|
|
48124
48130
|
s = s.replace(/(\s)&(\s)/g, "$1and$2");
|
|
48125
48131
|
s = s.replace(/(\w)&(\w)/g, "$1 and $2");
|
|
48126
48132
|
s = s.replace(/(^|\s)@(\w)/g, "$1at $2");
|
|
@@ -65005,6 +65011,176 @@ function gfmFromMarkdown() {
|
|
|
65005
65011
|
gfmTaskListItemFromMarkdown()
|
|
65006
65012
|
];
|
|
65007
65013
|
}
|
|
65014
|
+
// render/html-fold.ts
|
|
65015
|
+
var HTML_FOLD_TAGS = {
|
|
65016
|
+
b: "bold",
|
|
65017
|
+
strong: "bold",
|
|
65018
|
+
i: "italic",
|
|
65019
|
+
em: "italic",
|
|
65020
|
+
s: "strike",
|
|
65021
|
+
del: "strike",
|
|
65022
|
+
strike: "strike",
|
|
65023
|
+
code: "code",
|
|
65024
|
+
a: "link",
|
|
65025
|
+
br: "break",
|
|
65026
|
+
pre: "pre"
|
|
65027
|
+
};
|
|
65028
|
+
var HTML_VOID_TAGS = new Set([
|
|
65029
|
+
"area",
|
|
65030
|
+
"base",
|
|
65031
|
+
"col",
|
|
65032
|
+
"embed",
|
|
65033
|
+
"hr",
|
|
65034
|
+
"img",
|
|
65035
|
+
"input",
|
|
65036
|
+
"link",
|
|
65037
|
+
"meta",
|
|
65038
|
+
"param",
|
|
65039
|
+
"source",
|
|
65040
|
+
"track",
|
|
65041
|
+
"wbr"
|
|
65042
|
+
]);
|
|
65043
|
+
var HTML_BLOCK_LEVEL_TAGS = new Set([
|
|
65044
|
+
"address",
|
|
65045
|
+
"article",
|
|
65046
|
+
"blockquote",
|
|
65047
|
+
"center",
|
|
65048
|
+
"dd",
|
|
65049
|
+
"div",
|
|
65050
|
+
"dl",
|
|
65051
|
+
"dt",
|
|
65052
|
+
"fieldset",
|
|
65053
|
+
"figcaption",
|
|
65054
|
+
"figure",
|
|
65055
|
+
"footer",
|
|
65056
|
+
"form",
|
|
65057
|
+
"h1",
|
|
65058
|
+
"h2",
|
|
65059
|
+
"h3",
|
|
65060
|
+
"h4",
|
|
65061
|
+
"h5",
|
|
65062
|
+
"h6",
|
|
65063
|
+
"header",
|
|
65064
|
+
"hr",
|
|
65065
|
+
"li",
|
|
65066
|
+
"main",
|
|
65067
|
+
"nav",
|
|
65068
|
+
"ol",
|
|
65069
|
+
"p",
|
|
65070
|
+
"section",
|
|
65071
|
+
"table",
|
|
65072
|
+
"tbody",
|
|
65073
|
+
"td",
|
|
65074
|
+
"tfoot",
|
|
65075
|
+
"th",
|
|
65076
|
+
"thead",
|
|
65077
|
+
"tr",
|
|
65078
|
+
"ul"
|
|
65079
|
+
]);
|
|
65080
|
+
function isBlockLevelTag(name) {
|
|
65081
|
+
return HTML_BLOCK_LEVEL_TAGS.has(name);
|
|
65082
|
+
}
|
|
65083
|
+
function isVoidTag(name) {
|
|
65084
|
+
return HTML_VOID_TAGS.has(name);
|
|
65085
|
+
}
|
|
65086
|
+
function escapeHtmlLiteral(text4) {
|
|
65087
|
+
return text4.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
65088
|
+
}
|
|
65089
|
+
var LANGUAGE_CLASS_RE = /(?:^|\s)class\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+))/i;
|
|
65090
|
+
function languageOf(tag) {
|
|
65091
|
+
const m = LANGUAGE_CLASS_RE.exec(tag.attrs);
|
|
65092
|
+
if (m == null)
|
|
65093
|
+
return null;
|
|
65094
|
+
const cls = m[1] ?? m[2] ?? m[3] ?? "";
|
|
65095
|
+
const lang = cls.split(/\s+/).map((c) => /^language-(.+)$/.exec(c)?.[1]).find((c) => c != null && c.length > 0);
|
|
65096
|
+
return lang != null && !lang.includes("`") ? lang : null;
|
|
65097
|
+
}
|
|
65098
|
+
var HTML_PASSTHROUGH_TAGS = new Set([
|
|
65099
|
+
"u",
|
|
65100
|
+
"sub",
|
|
65101
|
+
"sup",
|
|
65102
|
+
"details",
|
|
65103
|
+
"summary",
|
|
65104
|
+
"aside",
|
|
65105
|
+
"cite"
|
|
65106
|
+
]);
|
|
65107
|
+
var HTML_TOKEN_RE = /<!--[\s\S]*?-->|<\/?[A-Za-z][A-Za-z0-9-]*(?:\s[^<>]*?)?\/?>/g;
|
|
65108
|
+
var TAG_RE = /^<(\/?)([A-Za-z][A-Za-z0-9-]*)((?:\s[^<>]*?)?)(\/?)>$/;
|
|
65109
|
+
var HREF_RE = /(?:^|\s)href\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'>]+))/i;
|
|
65110
|
+
function classifyHtmlTag(raw) {
|
|
65111
|
+
if (raw.startsWith("<!--"))
|
|
65112
|
+
return { kind: "comment", name: "", raw, attrs: "" };
|
|
65113
|
+
const m = TAG_RE.exec(raw);
|
|
65114
|
+
if (m == null)
|
|
65115
|
+
return { kind: "other", name: "", raw, attrs: "" };
|
|
65116
|
+
const [, slash, name, attrs, selfClose] = m;
|
|
65117
|
+
const kind = slash === "/" ? "close" : selfClose === "/" ? "selfclose" : "open";
|
|
65118
|
+
return { kind, name: name.toLowerCase(), raw, attrs: attrs ?? "" };
|
|
65119
|
+
}
|
|
65120
|
+
function hrefOf(tag) {
|
|
65121
|
+
const m = HREF_RE.exec(tag.attrs);
|
|
65122
|
+
if (m == null)
|
|
65123
|
+
return null;
|
|
65124
|
+
const value = m[1] ?? m[2] ?? m[3] ?? "";
|
|
65125
|
+
return value.length > 0 ? value : null;
|
|
65126
|
+
}
|
|
65127
|
+
function isPassthroughTag(tag) {
|
|
65128
|
+
return tag.name.length > 0 && HTML_PASSTHROUGH_TAGS.has(tag.name);
|
|
65129
|
+
}
|
|
65130
|
+
function matchedTagOffsets(tokens) {
|
|
65131
|
+
const matched = new Set;
|
|
65132
|
+
const stack = [];
|
|
65133
|
+
for (const { tag, start } of tokens) {
|
|
65134
|
+
if (tag.kind === "open" && !isVoidTag(tag.name)) {
|
|
65135
|
+
stack.push({ name: tag.name, start });
|
|
65136
|
+
continue;
|
|
65137
|
+
}
|
|
65138
|
+
if (tag.kind !== "close")
|
|
65139
|
+
continue;
|
|
65140
|
+
for (let i = stack.length - 1;i >= 0; i--) {
|
|
65141
|
+
if (stack[i].name !== tag.name)
|
|
65142
|
+
continue;
|
|
65143
|
+
matched.add(stack[i].start);
|
|
65144
|
+
matched.add(start);
|
|
65145
|
+
stack.length = i;
|
|
65146
|
+
break;
|
|
65147
|
+
}
|
|
65148
|
+
}
|
|
65149
|
+
return matched;
|
|
65150
|
+
}
|
|
65151
|
+
function tokenizeHtml(raw, base) {
|
|
65152
|
+
const pieces = [];
|
|
65153
|
+
const re = new RegExp(HTML_TOKEN_RE.source, "g");
|
|
65154
|
+
let last = 0;
|
|
65155
|
+
let m;
|
|
65156
|
+
while ((m = re.exec(raw)) != null) {
|
|
65157
|
+
if (m.index > last) {
|
|
65158
|
+
pieces.push({
|
|
65159
|
+
kind: "text",
|
|
65160
|
+
text: raw.slice(last, m.index),
|
|
65161
|
+
start: base + last,
|
|
65162
|
+
end: base + m.index
|
|
65163
|
+
});
|
|
65164
|
+
}
|
|
65165
|
+
pieces.push({
|
|
65166
|
+
kind: "tag",
|
|
65167
|
+
tag: classifyHtmlTag(m[0]),
|
|
65168
|
+
start: base + m.index,
|
|
65169
|
+
end: base + m.index + m[0].length
|
|
65170
|
+
});
|
|
65171
|
+
last = m.index + m[0].length;
|
|
65172
|
+
}
|
|
65173
|
+
if (last < raw.length) {
|
|
65174
|
+
pieces.push({
|
|
65175
|
+
kind: "text",
|
|
65176
|
+
text: raw.slice(last),
|
|
65177
|
+
start: base + last,
|
|
65178
|
+
end: base + raw.length
|
|
65179
|
+
});
|
|
65180
|
+
}
|
|
65181
|
+
return pieces;
|
|
65182
|
+
}
|
|
65183
|
+
|
|
65008
65184
|
// render/parse.ts
|
|
65009
65185
|
function pos(node2) {
|
|
65010
65186
|
const p = node2.position;
|
|
@@ -65023,11 +65199,32 @@ function isTgInlineEntityHref(href) {
|
|
|
65023
65199
|
const h = href.toLowerCase();
|
|
65024
65200
|
return TG_INLINE_ENTITY_HREFS.some((base) => h === base || h.startsWith(`${base}?`));
|
|
65025
65201
|
}
|
|
65202
|
+
var FENCE_DELIM_RE = /^ {0,3}(`{3,}|~{3,})/;
|
|
65026
65203
|
function markExpandableQuotes(markdown) {
|
|
65027
65204
|
const expandableLineStarts = new Set;
|
|
65028
65205
|
let out = "";
|
|
65029
65206
|
let offset = 0;
|
|
65207
|
+
let openFence = null;
|
|
65030
65208
|
for (const line of markdown.split(/(?<=\n)/)) {
|
|
65209
|
+
const body = line.replace(/\r?\n$/, "");
|
|
65210
|
+
const fence = FENCE_DELIM_RE.exec(body)?.[1] ?? null;
|
|
65211
|
+
if (openFence !== null) {
|
|
65212
|
+
out += line;
|
|
65213
|
+
if (fence !== null && fence[0] === openFence[0] && fence.length >= openFence.length && body.slice(body.indexOf(fence) + fence.length).trim() === "") {
|
|
65214
|
+
openFence = null;
|
|
65215
|
+
}
|
|
65216
|
+
offset += line.length;
|
|
65217
|
+
continue;
|
|
65218
|
+
}
|
|
65219
|
+
if (fence !== null) {
|
|
65220
|
+
const rest = body.slice(body.indexOf(fence) + fence.length);
|
|
65221
|
+
if (!(fence[0] === "`" && rest.includes("`"))) {
|
|
65222
|
+
openFence = fence;
|
|
65223
|
+
out += line;
|
|
65224
|
+
offset += line.length;
|
|
65225
|
+
continue;
|
|
65226
|
+
}
|
|
65227
|
+
}
|
|
65031
65228
|
if (EXPANDABLE_MARKER_RE.test(line)) {
|
|
65032
65229
|
expandableLineStarts.add(offset);
|
|
65033
65230
|
out += " " + line.slice(2);
|
|
@@ -65048,7 +65245,7 @@ function lineStart(source, offset) {
|
|
|
65048
65245
|
function foldAlign(a) {
|
|
65049
65246
|
return a ?? null;
|
|
65050
65247
|
}
|
|
65051
|
-
function foldInline(node2, source) {
|
|
65248
|
+
function foldInline(node2, source, ctx) {
|
|
65052
65249
|
switch (node2.type) {
|
|
65053
65250
|
case "text":
|
|
65054
65251
|
return { type: "plain", text: node2.value, ...pos(node2) };
|
|
@@ -65057,21 +65254,21 @@ function foldInline(node2, source) {
|
|
|
65057
65254
|
const underline = source.slice(p.start, p.start + 2) === "__";
|
|
65058
65255
|
return {
|
|
65059
65256
|
type: underline ? "underline" : "bold",
|
|
65060
|
-
children: foldInlineChildren(node2, source),
|
|
65257
|
+
children: foldInlineChildren(node2, source, ctx),
|
|
65061
65258
|
...p
|
|
65062
65259
|
};
|
|
65063
65260
|
}
|
|
65064
65261
|
case "emphasis":
|
|
65065
|
-
return { type: "italic", children: foldInlineChildren(node2, source), ...pos(node2) };
|
|
65262
|
+
return { type: "italic", children: foldInlineChildren(node2, source, ctx), ...pos(node2) };
|
|
65066
65263
|
case "delete":
|
|
65067
|
-
return { type: "strike", children: foldInlineChildren(node2, source), ...pos(node2) };
|
|
65264
|
+
return { type: "strike", children: foldInlineChildren(node2, source, ctx), ...pos(node2) };
|
|
65068
65265
|
case "inlineCode":
|
|
65069
65266
|
return { type: "code", text: node2.value, ...pos(node2) };
|
|
65070
65267
|
case "link":
|
|
65071
65268
|
return {
|
|
65072
65269
|
type: "link",
|
|
65073
65270
|
href: node2.url,
|
|
65074
|
-
children: foldInlineChildren(node2, source),
|
|
65271
|
+
children: foldInlineChildren(node2, source, ctx),
|
|
65075
65272
|
...pos(node2)
|
|
65076
65273
|
};
|
|
65077
65274
|
case "image": {
|
|
@@ -65127,28 +65324,250 @@ function expandPlainNode(node2, source) {
|
|
|
65127
65324
|
}
|
|
65128
65325
|
return out;
|
|
65129
65326
|
}
|
|
65130
|
-
function
|
|
65131
|
-
|
|
65327
|
+
function findClosingTag(items, from, name) {
|
|
65328
|
+
let depth = 0;
|
|
65329
|
+
for (let i = from;i < items.length; i++) {
|
|
65330
|
+
const it = items[i];
|
|
65331
|
+
if (it.kind !== "tag" || it.tag.name !== name)
|
|
65332
|
+
continue;
|
|
65333
|
+
if (it.tag.kind === "open")
|
|
65334
|
+
depth++;
|
|
65335
|
+
else if (it.tag.kind === "close") {
|
|
65336
|
+
if (depth === 0)
|
|
65337
|
+
return i;
|
|
65338
|
+
depth--;
|
|
65339
|
+
}
|
|
65340
|
+
}
|
|
65341
|
+
return -1;
|
|
65342
|
+
}
|
|
65343
|
+
function inlineLiteralText(nodes) {
|
|
65344
|
+
let out = "";
|
|
65345
|
+
for (const n of nodes) {
|
|
65346
|
+
if (n.type !== "plain")
|
|
65347
|
+
return null;
|
|
65348
|
+
out += n.text;
|
|
65349
|
+
}
|
|
65350
|
+
return out;
|
|
65351
|
+
}
|
|
65352
|
+
var structuralSeparators = new WeakSet;
|
|
65353
|
+
function mkSeparator(ctx, start, end) {
|
|
65354
|
+
const node2 = {
|
|
65355
|
+
type: "raw",
|
|
65356
|
+
text: ctx.noBreaks === true ? " " : `
|
|
65357
|
+
`,
|
|
65358
|
+
start,
|
|
65359
|
+
end
|
|
65360
|
+
};
|
|
65361
|
+
structuralSeparators.add(node2);
|
|
65362
|
+
return node2;
|
|
65363
|
+
}
|
|
65364
|
+
function normalizeSeparators(nodes) {
|
|
65365
|
+
const out = [];
|
|
65366
|
+
for (const node2 of nodes) {
|
|
65367
|
+
if (!structuralSeparators.has(node2)) {
|
|
65368
|
+
out.push(node2);
|
|
65369
|
+
continue;
|
|
65370
|
+
}
|
|
65371
|
+
if (out.length === 0)
|
|
65372
|
+
continue;
|
|
65373
|
+
if (structuralSeparators.has(out[out.length - 1]))
|
|
65374
|
+
continue;
|
|
65375
|
+
out.push(node2);
|
|
65376
|
+
}
|
|
65377
|
+
while (out.length > 0 && structuralSeparators.has(out[out.length - 1]))
|
|
65378
|
+
out.pop();
|
|
65379
|
+
return out;
|
|
65380
|
+
}
|
|
65381
|
+
function literalTag(tag, start, end) {
|
|
65382
|
+
return { type: "plain", text: escapeHtmlLiteral(tag.raw), start, end };
|
|
65383
|
+
}
|
|
65384
|
+
function foldHtmlItems(items, active, ctx) {
|
|
65385
|
+
const out = [];
|
|
65386
|
+
let i = 0;
|
|
65387
|
+
while (i < items.length) {
|
|
65388
|
+
const it = items[i];
|
|
65389
|
+
if (it.kind === "inline") {
|
|
65390
|
+
out.push(it.node);
|
|
65391
|
+
i++;
|
|
65392
|
+
continue;
|
|
65393
|
+
}
|
|
65394
|
+
const tag = it.tag;
|
|
65395
|
+
if (tag.kind === "comment") {
|
|
65396
|
+
i++;
|
|
65397
|
+
continue;
|
|
65398
|
+
}
|
|
65399
|
+
if (HTML_FOLD_TAGS[tag.name] === "break" && tag.kind !== "close") {
|
|
65400
|
+
out.push(ctx.noBreaks === true ? { type: "raw", text: " ", start: it.start, end: it.end } : { type: "raw", text: `
|
|
65401
|
+
`, start: it.start, end: it.end });
|
|
65402
|
+
i++;
|
|
65403
|
+
continue;
|
|
65404
|
+
}
|
|
65405
|
+
if (tag.kind === "selfclose" || tag.kind === "open" && isVoidTag(tag.name)) {
|
|
65406
|
+
if (isPassthroughTag(tag)) {
|
|
65407
|
+
out.push({ type: "raw", text: tag.raw, start: it.start, end: it.end });
|
|
65408
|
+
} else if (isBlockLevelTag(tag.name)) {
|
|
65409
|
+
out.push(mkSeparator(ctx, it.start, it.end));
|
|
65410
|
+
}
|
|
65411
|
+
i++;
|
|
65412
|
+
continue;
|
|
65413
|
+
}
|
|
65414
|
+
if (isPassthroughTag(tag) && (tag.kind === "open" || tag.kind === "close")) {
|
|
65415
|
+
out.push(ctx.matched.has(it.start) ? { type: "raw", text: tag.raw, start: it.start, end: it.end } : literalTag(tag, it.start, it.end));
|
|
65416
|
+
i++;
|
|
65417
|
+
continue;
|
|
65418
|
+
}
|
|
65419
|
+
if (tag.kind === "open") {
|
|
65420
|
+
const close = findClosingTag(items, i + 1, tag.name);
|
|
65421
|
+
const closeItem = close >= 0 ? items[close] : undefined;
|
|
65422
|
+
if (closeItem !== undefined && closeItem.kind === "tag") {
|
|
65423
|
+
out.push(...foldMatchedTag(tag, closeItem, items.slice(i + 1, close), active, ctx, {
|
|
65424
|
+
start: it.start,
|
|
65425
|
+
end: closeItem.end
|
|
65426
|
+
}));
|
|
65427
|
+
i = close + 1;
|
|
65428
|
+
continue;
|
|
65429
|
+
}
|
|
65430
|
+
}
|
|
65431
|
+
if (ctx.matched.has(it.start) && tag.kind !== "other") {
|
|
65432
|
+
if (isBlockLevelTag(tag.name))
|
|
65433
|
+
out.push(mkSeparator(ctx, it.start, it.end));
|
|
65434
|
+
i++;
|
|
65435
|
+
continue;
|
|
65436
|
+
}
|
|
65437
|
+
out.push(literalTag(tag, it.start, it.end));
|
|
65438
|
+
i++;
|
|
65439
|
+
}
|
|
65440
|
+
return normalizeSeparators(out);
|
|
65441
|
+
}
|
|
65442
|
+
function foldMatchedTag(tag, closeTag, innerItems, active, ctx, span) {
|
|
65443
|
+
const target = HTML_FOLD_TAGS[tag.name];
|
|
65444
|
+
if (target === "pre") {
|
|
65445
|
+
const folded = buildPreBlock(innerItems, ctx, span);
|
|
65446
|
+
if (folded !== null)
|
|
65447
|
+
return folded;
|
|
65448
|
+
}
|
|
65449
|
+
if (target !== undefined && target !== "break" && target !== "pre") {
|
|
65450
|
+
const nested = new Set(active);
|
|
65451
|
+
nested.add(target);
|
|
65452
|
+
const inner2 = foldHtmlItems(innerItems, nested, ctx);
|
|
65453
|
+
if (active.has(target)) {
|
|
65454
|
+
return target === "link" ? [
|
|
65455
|
+
literalTag(tag, span.start, span.start + tag.raw.length),
|
|
65456
|
+
...inner2,
|
|
65457
|
+
literalTag(closeTag.tag, closeTag.start, closeTag.end)
|
|
65458
|
+
] : inner2;
|
|
65459
|
+
}
|
|
65460
|
+
const folded = buildFoldedTag(target, tag, inner2, span.start, span.end);
|
|
65461
|
+
return folded !== null ? [folded] : inner2;
|
|
65462
|
+
}
|
|
65463
|
+
const inner = foldHtmlItems(innerItems, active, ctx);
|
|
65464
|
+
if (!isBlockLevelTag(tag.name))
|
|
65465
|
+
return inner;
|
|
65466
|
+
return [
|
|
65467
|
+
mkSeparator(ctx, span.start, span.start + tag.raw.length),
|
|
65468
|
+
...inner,
|
|
65469
|
+
mkSeparator(ctx, closeTag.start, closeTag.end)
|
|
65470
|
+
];
|
|
65471
|
+
}
|
|
65472
|
+
function buildPreBlock(innerItems, ctx, span) {
|
|
65473
|
+
let body = innerItems;
|
|
65474
|
+
let language = null;
|
|
65475
|
+
const first = body[0];
|
|
65476
|
+
const last = body[body.length - 1];
|
|
65477
|
+
if (body.length >= 2 && first?.kind === "tag" && first.tag.kind === "open" && first.tag.name === "code" && last?.kind === "tag" && last.tag.kind === "close" && last.tag.name === "code") {
|
|
65478
|
+
language = languageOf(first.tag);
|
|
65479
|
+
body = body.slice(1, -1);
|
|
65480
|
+
}
|
|
65481
|
+
let text4 = "";
|
|
65482
|
+
for (const item of body) {
|
|
65483
|
+
if (item.kind !== "inline" || item.node.type !== "plain")
|
|
65484
|
+
return null;
|
|
65485
|
+
text4 += item.node.text;
|
|
65486
|
+
}
|
|
65487
|
+
text4 = text4.replace(/^\r?\n/, "").replace(/[ \t]*\r?\n[ \t]*$/, "");
|
|
65488
|
+
if (ctx.noBreaks === true) {
|
|
65489
|
+
return [{ type: "code", text: text4.replace(/\s*\r?\n\s*/g, " "), ...span }];
|
|
65490
|
+
}
|
|
65491
|
+
const fence = "```";
|
|
65492
|
+
return [
|
|
65493
|
+
mkSeparator(ctx, span.start, span.start),
|
|
65494
|
+
{
|
|
65495
|
+
type: "raw",
|
|
65496
|
+
text: `${fence}${language ?? ""}
|
|
65497
|
+
${text4}
|
|
65498
|
+
${fence}`,
|
|
65499
|
+
...span
|
|
65500
|
+
},
|
|
65501
|
+
mkSeparator(ctx, span.end, span.end)
|
|
65502
|
+
];
|
|
65132
65503
|
}
|
|
65133
|
-
function
|
|
65134
|
-
|
|
65504
|
+
function buildFoldedTag(target, tag, children, start, end) {
|
|
65505
|
+
switch (target) {
|
|
65506
|
+
case "bold":
|
|
65507
|
+
case "italic":
|
|
65508
|
+
case "strike":
|
|
65509
|
+
if (children.length === 1 && children[0].type === target)
|
|
65510
|
+
return children[0];
|
|
65511
|
+
return { type: target, children, start, end };
|
|
65512
|
+
case "code": {
|
|
65513
|
+
const text4 = inlineLiteralText(children);
|
|
65514
|
+
return text4 === null ? null : { type: "code", text: text4, start, end };
|
|
65515
|
+
}
|
|
65516
|
+
case "link": {
|
|
65517
|
+
const href = hrefOf(tag);
|
|
65518
|
+
return href === null ? null : { type: "link", href, children, start, end };
|
|
65519
|
+
}
|
|
65520
|
+
default:
|
|
65521
|
+
return null;
|
|
65522
|
+
}
|
|
65523
|
+
}
|
|
65524
|
+
function htmlStringToItems(raw, base, source) {
|
|
65525
|
+
return tokenizeHtml(raw, base).flatMap((piece) => piece.kind === "tag" ? [{ kind: "tag", tag: piece.tag, start: piece.start, end: piece.end }] : expandPlainNode(mkPlain(piece.text, piece.start, piece.end), source).map((node2) => ({ kind: "inline", node: node2 })));
|
|
65526
|
+
}
|
|
65527
|
+
function buildInlines(children, source, ctx) {
|
|
65528
|
+
const items = [];
|
|
65529
|
+
let sawHtml = false;
|
|
65530
|
+
for (const child of children) {
|
|
65531
|
+
if (child.type === "html") {
|
|
65532
|
+
sawHtml = true;
|
|
65533
|
+
const p = pos(child);
|
|
65534
|
+
items.push(...htmlStringToItems(slice(source, child), p.start, source));
|
|
65535
|
+
continue;
|
|
65536
|
+
}
|
|
65537
|
+
const folded = foldInline(child, source, ctx);
|
|
65538
|
+
const expanded = folded.type === "plain" ? expandPlainNode(folded, source) : [folded];
|
|
65539
|
+
for (const node2 of expanded)
|
|
65540
|
+
items.push({ kind: "inline", node: node2 });
|
|
65541
|
+
}
|
|
65542
|
+
if (!sawHtml)
|
|
65543
|
+
return items.map((it) => it.node);
|
|
65544
|
+
return foldHtmlItems(items, new Set, ctx);
|
|
65135
65545
|
}
|
|
65136
|
-
function
|
|
65546
|
+
function foldInlineChildren(node2, source, ctx) {
|
|
65547
|
+
return buildInlines(node2.children, source, ctx);
|
|
65548
|
+
}
|
|
65549
|
+
function foldTableRow(row, source, ctx) {
|
|
65137
65550
|
const cells = row.children.map((cell) => ({
|
|
65138
|
-
children: buildInlines(cell.children, source),
|
|
65551
|
+
children: buildInlines(cell.children, source, { ...ctx, noBreaks: true }),
|
|
65139
65552
|
...pos(cell)
|
|
65140
65553
|
}));
|
|
65141
65554
|
return { cells, ...pos(row) };
|
|
65142
65555
|
}
|
|
65143
|
-
function
|
|
65556
|
+
function isEmptyBlock(block) {
|
|
65557
|
+
return block.type === "paragraph" && block.children.length === 0;
|
|
65558
|
+
}
|
|
65559
|
+
function foldBlocks(nodes, source, expandableLineStarts, ctx) {
|
|
65560
|
+
return nodes.map((n) => foldBlock(n, source, expandableLineStarts, ctx)).filter((b) => !isEmptyBlock(b));
|
|
65561
|
+
}
|
|
65562
|
+
function foldBlock(node2, source, expandableLineStarts, ctx) {
|
|
65144
65563
|
switch (node2.type) {
|
|
65145
65564
|
case "paragraph":
|
|
65146
|
-
return { type: "paragraph", children: foldInlineChildren(node2, source), ...pos(node2) };
|
|
65565
|
+
return { type: "paragraph", children: foldInlineChildren(node2, source, ctx), ...pos(node2) };
|
|
65147
65566
|
case "heading":
|
|
65148
65567
|
return {
|
|
65149
65568
|
type: "heading",
|
|
65150
65569
|
level: node2.depth,
|
|
65151
|
-
children: foldInlineChildren(node2, source),
|
|
65570
|
+
children: foldInlineChildren(node2, source, { ...ctx, noBreaks: true }),
|
|
65152
65571
|
...pos(node2)
|
|
65153
65572
|
};
|
|
65154
65573
|
case "blockquote": {
|
|
@@ -65156,7 +65575,7 @@ function foldBlock(node2, source, expandableLineStarts) {
|
|
|
65156
65575
|
const expandable = expandableLineStarts.has(lineStart(source, p.start));
|
|
65157
65576
|
return {
|
|
65158
65577
|
type: "blockquote",
|
|
65159
|
-
children: node2.children
|
|
65578
|
+
children: foldBlocks(node2.children, source, expandableLineStarts, ctx),
|
|
65160
65579
|
expandable,
|
|
65161
65580
|
...p
|
|
65162
65581
|
};
|
|
@@ -65170,7 +65589,7 @@ function foldBlock(node2, source, expandableLineStarts) {
|
|
|
65170
65589
|
};
|
|
65171
65590
|
case "list": {
|
|
65172
65591
|
const items = node2.children.map((li) => ({
|
|
65173
|
-
children: li.children
|
|
65592
|
+
children: foldBlocks(li.children, source, expandableLineStarts, ctx),
|
|
65174
65593
|
checked: li.checked ?? null,
|
|
65175
65594
|
spread: li.spread ?? false,
|
|
65176
65595
|
...pos(li)
|
|
@@ -65191,8 +65610,8 @@ function foldBlock(node2, source, expandableLineStarts) {
|
|
|
65191
65610
|
const [headerRow2, ...bodyRows] = rows;
|
|
65192
65611
|
return {
|
|
65193
65612
|
type: "table",
|
|
65194
|
-
header: foldTableRow(headerRow2, source),
|
|
65195
|
-
rows: bodyRows.map((r) => foldTableRow(r, source)),
|
|
65613
|
+
header: foldTableRow(headerRow2, source, ctx),
|
|
65614
|
+
rows: bodyRows.map((r) => foldTableRow(r, source, ctx)),
|
|
65196
65615
|
align: (node2.align ?? []).map(foldAlign),
|
|
65197
65616
|
...pos(node2)
|
|
65198
65617
|
};
|
|
@@ -65203,6 +65622,14 @@ function foldBlock(node2, source, expandableLineStarts) {
|
|
|
65203
65622
|
children: [{ type: "raw", text: slice(source, node2), ...pos(node2) }],
|
|
65204
65623
|
...pos(node2)
|
|
65205
65624
|
};
|
|
65625
|
+
case "html": {
|
|
65626
|
+
const p = pos(node2);
|
|
65627
|
+
return {
|
|
65628
|
+
type: "paragraph",
|
|
65629
|
+
children: foldHtmlItems(htmlStringToItems(slice(source, node2), p.start, source), new Set, ctx),
|
|
65630
|
+
...p
|
|
65631
|
+
};
|
|
65632
|
+
}
|
|
65206
65633
|
default:
|
|
65207
65634
|
return {
|
|
65208
65635
|
type: "paragraph",
|
|
@@ -65218,8 +65645,30 @@ function parse2(markdown) {
|
|
|
65218
65645
|
mdastExtensions: [gfmFromMarkdown()]
|
|
65219
65646
|
});
|
|
65220
65647
|
return {
|
|
65221
|
-
blocks: tree.children
|
|
65648
|
+
blocks: foldBlocks(tree.children, markdown, expandableLineStarts, {
|
|
65649
|
+
matched: matchedTagOffsets(collectHtmlTokens(tree.children, markdown))
|
|
65650
|
+
})
|
|
65651
|
+
};
|
|
65652
|
+
}
|
|
65653
|
+
function collectHtmlTokens(nodes, source) {
|
|
65654
|
+
const out = [];
|
|
65655
|
+
const walk = (list2) => {
|
|
65656
|
+
for (const node2 of list2) {
|
|
65657
|
+
if (node2.type === "html") {
|
|
65658
|
+
const p = pos(node2);
|
|
65659
|
+
for (const piece of tokenizeHtml(slice(source, node2), p.start)) {
|
|
65660
|
+
if (piece.kind === "tag")
|
|
65661
|
+
out.push({ tag: piece.tag, start: piece.start });
|
|
65662
|
+
}
|
|
65663
|
+
continue;
|
|
65664
|
+
}
|
|
65665
|
+
const children = node2.children;
|
|
65666
|
+
if (Array.isArray(children))
|
|
65667
|
+
walk(children);
|
|
65668
|
+
}
|
|
65222
65669
|
};
|
|
65670
|
+
walk(nodes);
|
|
65671
|
+
return out;
|
|
65223
65672
|
}
|
|
65224
65673
|
|
|
65225
65674
|
// render/render.ts
|
|
@@ -79880,6 +80329,62 @@ function normalizeTemporal(text4, tz, nowMs2) {
|
|
|
79880
80329
|
return normalizeRelativeDays(normalizeUtcDatetimes(text4, tz, nowMs2), tz, nowMs2);
|
|
79881
80330
|
}
|
|
79882
80331
|
|
|
80332
|
+
// gateway/speech-capture.ts
|
|
80333
|
+
import { appendFileSync as appendFileSync5 } from "node:fs";
|
|
80334
|
+
import { join as join34 } from "node:path";
|
|
80335
|
+
var SPEECH_CAPTURE_FILE_NAME = "speech-capture.jsonl";
|
|
80336
|
+
var SPEECH_CAPTURE_FILE_MODE = 384;
|
|
80337
|
+
function envFlagEnabled() {
|
|
80338
|
+
const v = process.env.SWITCHROOM_SPEECH_CAPTURE;
|
|
80339
|
+
return v === "1" || v === "true";
|
|
80340
|
+
}
|
|
80341
|
+
function isCaptureEnabled(override) {
|
|
80342
|
+
if (override !== undefined)
|
|
80343
|
+
return override;
|
|
80344
|
+
return envFlagEnabled();
|
|
80345
|
+
}
|
|
80346
|
+
var loggedEnabledOnce = false;
|
|
80347
|
+
var lastWriteErrorLoggedAt = null;
|
|
80348
|
+
var WRITE_ERROR_LOG_INTERVAL_MS = 5 * 60000;
|
|
80349
|
+
function logEnabledOnce() {
|
|
80350
|
+
if (loggedEnabledOnce)
|
|
80351
|
+
return;
|
|
80352
|
+
loggedEnabledOnce = true;
|
|
80353
|
+
try {
|
|
80354
|
+
process.stderr.write(`telegram gateway: speech-capture: enabled \u2014 writing $TELEGRAM_STATE_DIR/${SPEECH_CAPTURE_FILE_NAME}
|
|
80355
|
+
`);
|
|
80356
|
+
} catch {}
|
|
80357
|
+
}
|
|
80358
|
+
function logWriteErrorRateLimited(err, nowMs2) {
|
|
80359
|
+
if (lastWriteErrorLoggedAt !== null && nowMs2 - lastWriteErrorLoggedAt < WRITE_ERROR_LOG_INTERVAL_MS)
|
|
80360
|
+
return;
|
|
80361
|
+
lastWriteErrorLoggedAt = nowMs2;
|
|
80362
|
+
try {
|
|
80363
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
80364
|
+
process.stderr.write(`telegram gateway: speech-capture: write failed (further failures rate-limited ` + `${Math.round(WRITE_ERROR_LOG_INTERVAL_MS / 60000)}m) err=${msg}
|
|
80365
|
+
`);
|
|
80366
|
+
} catch {}
|
|
80367
|
+
}
|
|
80368
|
+
function captureSpeechText(text4, opts = {}) {
|
|
80369
|
+
if (!isCaptureEnabled(opts.enabled))
|
|
80370
|
+
return;
|
|
80371
|
+
logEnabledOnce();
|
|
80372
|
+
try {
|
|
80373
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR;
|
|
80374
|
+
if (stateDir == null || stateDir.length === 0)
|
|
80375
|
+
return;
|
|
80376
|
+
const now = opts.now ?? Date.now;
|
|
80377
|
+
const line = `${JSON.stringify({ ts: now(), text: text4 })}
|
|
80378
|
+
`;
|
|
80379
|
+
appendFileSync5(join34(stateDir, SPEECH_CAPTURE_FILE_NAME), line, {
|
|
80380
|
+
encoding: "utf8",
|
|
80381
|
+
mode: SPEECH_CAPTURE_FILE_MODE
|
|
80382
|
+
});
|
|
80383
|
+
} catch (err) {
|
|
80384
|
+
logWriteErrorRateLimited(err, Date.now());
|
|
80385
|
+
}
|
|
80386
|
+
}
|
|
80387
|
+
|
|
79883
80388
|
// gateway/outbound-send-path.ts
|
|
79884
80389
|
var import_grammy11 = __toESM(require_mod2(), 1);
|
|
79885
80390
|
import { statSync as statSync12 } from "fs";
|
|
@@ -80024,9 +80529,9 @@ import {
|
|
|
80024
80529
|
statSync as statSync11,
|
|
80025
80530
|
unlinkSync as unlinkSync14,
|
|
80026
80531
|
writeFileSync as writeFileSync25,
|
|
80027
|
-
appendFileSync as
|
|
80532
|
+
appendFileSync as appendFileSync6
|
|
80028
80533
|
} from "node:fs";
|
|
80029
|
-
import { join as
|
|
80534
|
+
import { join as join35 } from "node:path";
|
|
80030
80535
|
import { homedir as homedir9 } from "node:os";
|
|
80031
80536
|
|
|
80032
80537
|
// hooks/audience-classify.mjs
|
|
@@ -80110,10 +80615,10 @@ function resolveStateDir2(explicit) {
|
|
|
80110
80615
|
if (env != null && env !== "")
|
|
80111
80616
|
return env;
|
|
80112
80617
|
const home2 = process.env.HOME ?? homedir9();
|
|
80113
|
-
return
|
|
80618
|
+
return join35(home2, ".claude", "channels", "telegram");
|
|
80114
80619
|
}
|
|
80115
80620
|
function resolveOutboxDir(stateDir) {
|
|
80116
|
-
return
|
|
80621
|
+
return join35(resolveStateDir2(stateDir), "outbox");
|
|
80117
80622
|
}
|
|
80118
80623
|
var JOURNAL_FILE = "delivered.jsonl";
|
|
80119
80624
|
var OUTBOX_MAX_AGE_MS = 30 * 60000;
|
|
@@ -80123,10 +80628,10 @@ function writeOutboxRecordAtomic(record, stateDir) {
|
|
|
80123
80628
|
const dir = resolveOutboxDir(stateDir);
|
|
80124
80629
|
try {
|
|
80125
80630
|
mkdirSync29(dir, { recursive: true });
|
|
80126
|
-
const finalPath =
|
|
80631
|
+
const finalPath = join35(dir, `${record.turnNonce}.json`);
|
|
80127
80632
|
if (existsSync26(finalPath))
|
|
80128
80633
|
return true;
|
|
80129
|
-
const tmpPath =
|
|
80634
|
+
const tmpPath = join35(dir, `.${record.turnNonce}.${process.pid}.tmp`);
|
|
80130
80635
|
writeFileSync25(tmpPath, JSON.stringify(record), { mode: 384 });
|
|
80131
80636
|
renameSync14(tmpPath, finalPath);
|
|
80132
80637
|
return true;
|
|
@@ -80144,7 +80649,7 @@ function listPendingRecords(stateDir) {
|
|
|
80144
80649
|
}
|
|
80145
80650
|
function readOutboxRecord(fileName, stateDir) {
|
|
80146
80651
|
try {
|
|
80147
|
-
const raw = readFileSync26(
|
|
80652
|
+
const raw = readFileSync26(join35(resolveOutboxDir(stateDir), fileName), "utf8");
|
|
80148
80653
|
return JSON.parse(raw);
|
|
80149
80654
|
} catch {
|
|
80150
80655
|
return null;
|
|
@@ -80152,8 +80657,8 @@ function readOutboxRecord(fileName, stateDir) {
|
|
|
80152
80657
|
}
|
|
80153
80658
|
function claimRecord(nonce, stateDir) {
|
|
80154
80659
|
const dir = resolveOutboxDir(stateDir);
|
|
80155
|
-
const from =
|
|
80156
|
-
const to =
|
|
80660
|
+
const from = join35(dir, `${nonce}.json`);
|
|
80661
|
+
const to = join35(dir, `${nonce}.sending`);
|
|
80157
80662
|
try {
|
|
80158
80663
|
renameSync14(from, to);
|
|
80159
80664
|
return to;
|
|
@@ -80164,12 +80669,12 @@ function claimRecord(nonce, stateDir) {
|
|
|
80164
80669
|
function releaseClaim(nonce, stateDir) {
|
|
80165
80670
|
const dir = resolveOutboxDir(stateDir);
|
|
80166
80671
|
try {
|
|
80167
|
-
renameSync14(
|
|
80672
|
+
renameSync14(join35(dir, `${nonce}.sending`), join35(dir, `${nonce}.json`));
|
|
80168
80673
|
} catch {}
|
|
80169
80674
|
}
|
|
80170
80675
|
function removeClaimed(nonce, stateDir) {
|
|
80171
80676
|
try {
|
|
80172
|
-
unlinkSync14(
|
|
80677
|
+
unlinkSync14(join35(resolveOutboxDir(stateDir), `${nonce}.sending`));
|
|
80173
80678
|
} catch {}
|
|
80174
80679
|
}
|
|
80175
80680
|
function reclaimStaleSending(stateDir, now = Date.now()) {
|
|
@@ -80182,16 +80687,16 @@ function reclaimStaleSending(stateDir, now = Date.now()) {
|
|
|
80182
80687
|
}
|
|
80183
80688
|
for (const f of files) {
|
|
80184
80689
|
try {
|
|
80185
|
-
const st = statSync11(
|
|
80690
|
+
const st = statSync11(join35(dir, f));
|
|
80186
80691
|
if (now - st.mtimeMs > OUTBOX_SENDING_TIMEOUT_MS) {
|
|
80187
|
-
renameSync14(
|
|
80692
|
+
renameSync14(join35(dir, f), join35(dir, f.replace(/\.sending$/, ".json")));
|
|
80188
80693
|
}
|
|
80189
80694
|
} catch {}
|
|
80190
80695
|
}
|
|
80191
80696
|
}
|
|
80192
80697
|
function readDeliveredNonces(stateDir) {
|
|
80193
80698
|
const set = new Set;
|
|
80194
|
-
const path2 =
|
|
80699
|
+
const path2 = join35(resolveOutboxDir(stateDir), JOURNAL_FILE);
|
|
80195
80700
|
if (!existsSync26(path2))
|
|
80196
80701
|
return set;
|
|
80197
80702
|
try {
|
|
@@ -80218,7 +80723,7 @@ function isBackstopDeliveredEntry(e) {
|
|
|
80218
80723
|
function backstopAlreadyDelivered(nonce, stateDir) {
|
|
80219
80724
|
if (nonce == null || nonce === "")
|
|
80220
80725
|
return false;
|
|
80221
|
-
const path2 =
|
|
80726
|
+
const path2 = join35(resolveOutboxDir(stateDir), JOURNAL_FILE);
|
|
80222
80727
|
if (!existsSync26(path2))
|
|
80223
80728
|
return false;
|
|
80224
80729
|
try {
|
|
@@ -80239,10 +80744,10 @@ var JOURNAL_KEEP = 2000;
|
|
|
80239
80744
|
var JOURNAL_ROTATE_AT = 4000;
|
|
80240
80745
|
function appendDelivered(entry, stateDir) {
|
|
80241
80746
|
const dir = resolveOutboxDir(stateDir);
|
|
80242
|
-
const path2 =
|
|
80747
|
+
const path2 = join35(dir, JOURNAL_FILE);
|
|
80243
80748
|
try {
|
|
80244
80749
|
mkdirSync29(dir, { recursive: true });
|
|
80245
|
-
|
|
80750
|
+
appendFileSync6(path2, JSON.stringify(entry) + `
|
|
80246
80751
|
`, { mode: 384 });
|
|
80247
80752
|
compactJournalIfLarge(path2);
|
|
80248
80753
|
} catch {}
|
|
@@ -80265,7 +80770,7 @@ function clearOutboxRecord(nonce, stateDir) {
|
|
|
80265
80770
|
const dir = resolveOutboxDir(stateDir);
|
|
80266
80771
|
for (const suffix of [".json", ".sending"]) {
|
|
80267
80772
|
try {
|
|
80268
|
-
unlinkSync14(
|
|
80773
|
+
unlinkSync14(join35(dir, `${nonce}${suffix}`));
|
|
80269
80774
|
} catch {}
|
|
80270
80775
|
}
|
|
80271
80776
|
}
|
|
@@ -80335,9 +80840,9 @@ import {
|
|
|
80335
80840
|
readFileSync as readFileSync27,
|
|
80336
80841
|
renameSync as renameSync15,
|
|
80337
80842
|
writeFileSync as writeFileSync26,
|
|
80338
|
-
appendFileSync as
|
|
80843
|
+
appendFileSync as appendFileSync7
|
|
80339
80844
|
} from "node:fs";
|
|
80340
|
-
import { join as
|
|
80845
|
+
import { join as join36 } from "node:path";
|
|
80341
80846
|
|
|
80342
80847
|
// hooks/narration-classify.mjs
|
|
80343
80848
|
import { createHash as createHash5 } from "node:crypto";
|
|
@@ -80408,7 +80913,7 @@ var SHOWN_LEDGER_FILE = "shown-ledger.jsonl";
|
|
|
80408
80913
|
var SHOWN_LEDGER_KEEP = 2000;
|
|
80409
80914
|
var SHOWN_LEDGER_ROTATE_AT = 4000;
|
|
80410
80915
|
function shownLedgerPath(stateDir) {
|
|
80411
|
-
return
|
|
80916
|
+
return join36(resolveOutboxDir(stateDir), SHOWN_LEDGER_FILE);
|
|
80412
80917
|
}
|
|
80413
80918
|
function appendShownBlock(turnNonce, text4, stateDir, now = Date.now()) {
|
|
80414
80919
|
if (turnNonce == null || turnNonce === "")
|
|
@@ -80421,7 +80926,7 @@ function appendShownBlock(turnNonce, text4, stateDir, now = Date.now()) {
|
|
|
80421
80926
|
try {
|
|
80422
80927
|
mkdirSync30(dir, { recursive: true });
|
|
80423
80928
|
const entry = { turnNonce, hash: ledgerHashHex(trimmed), ts: now };
|
|
80424
|
-
|
|
80929
|
+
appendFileSync7(path2, JSON.stringify(entry) + `
|
|
80425
80930
|
`, { mode: 384 });
|
|
80426
80931
|
compactIfLarge(path2);
|
|
80427
80932
|
} catch {}
|
|
@@ -81229,7 +81734,7 @@ function monotonicNowMs2() {
|
|
|
81229
81734
|
|
|
81230
81735
|
// silent-end.ts
|
|
81231
81736
|
import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync27, unlinkSync as unlinkSync15, mkdirSync as mkdirSync31 } from "node:fs";
|
|
81232
|
-
import { dirname as dirname17, join as
|
|
81737
|
+
import { dirname as dirname17, join as join37 } from "node:path";
|
|
81233
81738
|
import { homedir as homedir10 } from "node:os";
|
|
81234
81739
|
var SILENT_END_MAX_RETRIES2 = 2;
|
|
81235
81740
|
var SILENT_END_STALE_RECORD_MAX_AGE_MS2 = 30 * 60000;
|
|
@@ -81244,10 +81749,10 @@ function resolveStateDir3(deps) {
|
|
|
81244
81749
|
if (env != null && env !== "")
|
|
81245
81750
|
return env;
|
|
81246
81751
|
const home2 = process.env.HOME ?? homedir10();
|
|
81247
|
-
return
|
|
81752
|
+
return join37(home2, ".claude", "channels", "telegram");
|
|
81248
81753
|
}
|
|
81249
81754
|
function resolveStatePath3(deps) {
|
|
81250
|
-
return
|
|
81755
|
+
return join37(resolveStateDir3(deps), "silent-end-pending.json");
|
|
81251
81756
|
}
|
|
81252
81757
|
function emitLog2(deps, line) {
|
|
81253
81758
|
if (deps?.log != null)
|
|
@@ -81775,6 +82280,7 @@ async function sendReply(deps, req) {
|
|
|
81775
82280
|
const protectContent = args.protect_content === true;
|
|
81776
82281
|
const quoteText = args.quote_text;
|
|
81777
82282
|
const access = loadAccess();
|
|
82283
|
+
captureSpeechText(text4);
|
|
81778
82284
|
const voiceOutPlan = resolveVoiceOutPlan(access.voice_out, text4);
|
|
81779
82285
|
const configParseMode = access.parseMode ?? "html";
|
|
81780
82286
|
const format = args.format ?? configParseMode;
|
|
@@ -83102,20 +83608,20 @@ var INTERRUPTED_VIA = new Set([
|
|
|
83102
83608
|
init_rich_send();
|
|
83103
83609
|
|
|
83104
83610
|
// runtime-metrics.ts
|
|
83105
|
-
import { mkdirSync as mkdirSync32, appendFileSync as
|
|
83106
|
-
import { dirname as dirname18, join as
|
|
83611
|
+
import { mkdirSync as mkdirSync32, appendFileSync as appendFileSync8 } from "node:fs";
|
|
83612
|
+
import { dirname as dirname18, join as join39 } from "node:path";
|
|
83107
83613
|
function resolveJsonlPath2() {
|
|
83108
83614
|
const override = process.env.SWITCHROOM_RUNTIME_METRICS_PATH;
|
|
83109
83615
|
if (override && override.trim() !== "")
|
|
83110
83616
|
return override.trim();
|
|
83111
83617
|
const base = process.env.SWITCHROOM_RUNTIME_STATE_DIR ?? "/state/agent";
|
|
83112
|
-
return
|
|
83618
|
+
return join39(base, "runtime-metrics.jsonl");
|
|
83113
83619
|
}
|
|
83114
83620
|
function appendJsonl2(line) {
|
|
83115
83621
|
const path2 = resolveJsonlPath2();
|
|
83116
83622
|
try {
|
|
83117
83623
|
mkdirSync32(dirname18(path2), { recursive: true });
|
|
83118
|
-
|
|
83624
|
+
appendFileSync8(path2, line + `
|
|
83119
83625
|
`, "utf-8");
|
|
83120
83626
|
} catch (err) {
|
|
83121
83627
|
process.stderr.write(`runtime-metrics: jsonl write failed: ${err.message}
|
|
@@ -83659,18 +84165,18 @@ import {
|
|
|
83659
84165
|
unlinkSync as unlinkSync16,
|
|
83660
84166
|
utimesSync
|
|
83661
84167
|
} from "node:fs";
|
|
83662
|
-
import { join as
|
|
84168
|
+
import { join as join40 } from "node:path";
|
|
83663
84169
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
83664
84170
|
var TURN_ACTIVE_HARD_TTL_MS = 10 * 60000;
|
|
83665
84171
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
83666
84172
|
try {
|
|
83667
84173
|
mkdirStateSync(stateDir, { recursive: true });
|
|
83668
|
-
writeStateFileSync(
|
|
84174
|
+
writeStateFileSync(join40(stateDir, TURN_ACTIVE_MARKER_FILE), JSON.stringify(marker, null, 2) + `
|
|
83669
84175
|
`, { mode: 384 });
|
|
83670
84176
|
} catch {}
|
|
83671
84177
|
}
|
|
83672
84178
|
function touchTurnActiveMarker(stateDir) {
|
|
83673
|
-
const path2 =
|
|
84179
|
+
const path2 = join40(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
83674
84180
|
if (!existsSync31(path2))
|
|
83675
84181
|
return;
|
|
83676
84182
|
const now = new Date;
|
|
@@ -83685,11 +84191,11 @@ function touchTurnActiveMarker(stateDir) {
|
|
|
83685
84191
|
}
|
|
83686
84192
|
function removeTurnActiveMarker(stateDir) {
|
|
83687
84193
|
try {
|
|
83688
|
-
unlinkSync16(
|
|
84194
|
+
unlinkSync16(join40(stateDir, TURN_ACTIVE_MARKER_FILE));
|
|
83689
84195
|
} catch {}
|
|
83690
84196
|
}
|
|
83691
84197
|
function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
83692
|
-
const path2 =
|
|
84198
|
+
const path2 = join40(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
83693
84199
|
try {
|
|
83694
84200
|
const st = statSync13(path2);
|
|
83695
84201
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -86011,10 +86517,10 @@ function resolveAgentDirFromEnv() {
|
|
|
86011
86517
|
|
|
86012
86518
|
// active-reactions.ts
|
|
86013
86519
|
import { readFileSync as readFileSync30, writeFileSync as writeFileSync28, renameSync as renameSync16, existsSync as existsSync32, unlinkSync as unlinkSync17 } from "node:fs";
|
|
86014
|
-
import { join as
|
|
86520
|
+
import { join as join41 } from "node:path";
|
|
86015
86521
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
86016
86522
|
function reactionsPath(agentDir) {
|
|
86017
|
-
return
|
|
86523
|
+
return join41(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
86018
86524
|
}
|
|
86019
86525
|
function readActiveReactions(agentDir) {
|
|
86020
86526
|
const p = reactionsPath(agentDir);
|
|
@@ -86079,10 +86585,10 @@ function clearActiveReactions(agentDir) {
|
|
|
86079
86585
|
|
|
86080
86586
|
// active-reactions.ts
|
|
86081
86587
|
import { readFileSync as readFileSync31, writeFileSync as writeFileSync29, renameSync as renameSync17, existsSync as existsSync33, unlinkSync as unlinkSync18 } from "node:fs";
|
|
86082
|
-
import { join as
|
|
86588
|
+
import { join as join42 } from "node:path";
|
|
86083
86589
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
86084
86590
|
function reactionsPath2(agentDir) {
|
|
86085
|
-
return
|
|
86591
|
+
return join42(agentDir, ACTIVE_REACTIONS_FILENAME2);
|
|
86086
86592
|
}
|
|
86087
86593
|
function readActiveReactions2(agentDir) {
|
|
86088
86594
|
const p = reactionsPath2(agentDir);
|
|
@@ -86962,12 +87468,12 @@ async function approvalRecord(args, opts) {
|
|
|
86962
87468
|
|
|
86963
87469
|
// quota-check.ts
|
|
86964
87470
|
import { readFileSync as readFileSync32, existsSync as existsSync34 } from "fs";
|
|
86965
|
-
import { join as
|
|
87471
|
+
import { join as join43 } from "path";
|
|
86966
87472
|
var OAUTH_BETA2 = "oauth-2025-04-20";
|
|
86967
87473
|
var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
|
|
86968
87474
|
var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
|
|
86969
87475
|
function readOauthToken2(claudeConfigDir) {
|
|
86970
|
-
const tokenFile =
|
|
87476
|
+
const tokenFile = join43(claudeConfigDir, ".oauth-token");
|
|
86971
87477
|
if (!existsSync34(tokenFile))
|
|
86972
87478
|
return null;
|
|
86973
87479
|
try {
|
|
@@ -88357,7 +88863,7 @@ async function menuWithBannerStatic(deps, banner) {
|
|
|
88357
88863
|
|
|
88358
88864
|
// gateway/session-model-file.ts
|
|
88359
88865
|
import { readFileSync as readFileSync33, writeFileSync as writeFileSync30, renameSync as renameSync18, rmSync as rmSync7 } from "node:fs";
|
|
88360
|
-
import { join as
|
|
88866
|
+
import { join as join44 } from "node:path";
|
|
88361
88867
|
var SESSION_MODEL_FILE = ".session-model";
|
|
88362
88868
|
var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
|
|
88363
88869
|
var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
|
|
@@ -88379,28 +88885,28 @@ function writeSessionModelFile(agentDir, model, configuredDefaultAtWrite) {
|
|
|
88379
88885
|
throw new Error(`refusing to persist non-canonical session model token: ${JSON.stringify(model)}`);
|
|
88380
88886
|
}
|
|
88381
88887
|
try {
|
|
88382
|
-
rmSync7(
|
|
88888
|
+
rmSync7(join44(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
88383
88889
|
} catch {}
|
|
88384
|
-
atomicWrite(
|
|
88890
|
+
atomicWrite(join44(agentDir, SESSION_MODEL_FILE), serializeSessionModel({ model, configuredDefaultAtWrite, ts: Date.now() }));
|
|
88385
88891
|
}
|
|
88386
88892
|
function readSessionModelFileRaw(agentDir) {
|
|
88387
88893
|
try {
|
|
88388
|
-
return readFileSync33(
|
|
88894
|
+
return readFileSync33(join44(agentDir, SESSION_MODEL_FILE), "utf8");
|
|
88389
88895
|
} catch {
|
|
88390
88896
|
return null;
|
|
88391
88897
|
}
|
|
88392
88898
|
}
|
|
88393
88899
|
function clearSessionModelFile(agentDir) {
|
|
88394
88900
|
try {
|
|
88395
|
-
rmSync7(
|
|
88901
|
+
rmSync7(join44(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
88396
88902
|
} catch {}
|
|
88397
88903
|
}
|
|
88398
88904
|
function consumeSessionModelCarrierOnHealthyBoot(agentDir) {
|
|
88399
88905
|
try {
|
|
88400
|
-
rmSync7(
|
|
88906
|
+
rmSync7(join44(agentDir, SESSION_MODEL_FILE), { force: true });
|
|
88401
88907
|
} catch {}
|
|
88402
88908
|
try {
|
|
88403
|
-
rmSync7(
|
|
88909
|
+
rmSync7(join44(agentDir, SESSION_MODEL_BOOT_ATTEMPTS_FILE), { force: true });
|
|
88404
88910
|
} catch {}
|
|
88405
88911
|
}
|
|
88406
88912
|
function restoreSessionModelFileRaw(agentDir, raw) {
|
|
@@ -88409,12 +88915,12 @@ function restoreSessionModelFileRaw(agentDir, raw) {
|
|
|
88409
88915
|
return;
|
|
88410
88916
|
}
|
|
88411
88917
|
try {
|
|
88412
|
-
atomicWrite(
|
|
88918
|
+
atomicWrite(join44(agentDir, SESSION_MODEL_FILE), raw);
|
|
88413
88919
|
} catch {}
|
|
88414
88920
|
}
|
|
88415
88921
|
function readConfiguredDefaultModel(agentDir) {
|
|
88416
88922
|
try {
|
|
88417
|
-
const v = readFileSync33(
|
|
88923
|
+
const v = readFileSync33(join44(agentDir, CONFIGURED_DEFAULT_MODEL_FILE), "utf8").trim();
|
|
88418
88924
|
return v.length > 0 ? v : null;
|
|
88419
88925
|
} catch {
|
|
88420
88926
|
return null;
|
|
@@ -88426,12 +88932,12 @@ function writeSessionEffortFile(agentDir, level, configuredDefaultAtWrite) {
|
|
|
88426
88932
|
if (!EFFORT_LEVEL_RE.test(level)) {
|
|
88427
88933
|
throw new Error(`refusing to persist non-allowlisted effort level: ${JSON.stringify(level)}`);
|
|
88428
88934
|
}
|
|
88429
|
-
atomicWrite(
|
|
88935
|
+
atomicWrite(join44(agentDir, SESSION_EFFORT_FILE), `${JSON.stringify({ level, configuredDefaultAtWrite: configuredDefaultAtWrite ?? "", ts: Date.now() })}
|
|
88430
88936
|
`);
|
|
88431
88937
|
}
|
|
88432
88938
|
function clearSessionEffortFile(agentDir) {
|
|
88433
88939
|
try {
|
|
88434
|
-
rmSync7(
|
|
88940
|
+
rmSync7(join44(agentDir, SESSION_EFFORT_FILE), { force: true });
|
|
88435
88941
|
} catch {}
|
|
88436
88942
|
}
|
|
88437
88943
|
var PREMIUM_RECOVERY_FILE = ".premium-recovery";
|
|
@@ -88454,13 +88960,13 @@ function writePremiumRecoveryFile(agentDir, premiumModel, chats) {
|
|
|
88454
88960
|
if (clean.length === 0) {
|
|
88455
88961
|
throw new Error("refusing to persist premium-recovery marker with no chats to notify");
|
|
88456
88962
|
}
|
|
88457
|
-
atomicWrite(
|
|
88963
|
+
atomicWrite(join44(agentDir, PREMIUM_RECOVERY_FILE), `${JSON.stringify({ premiumModel, chats: clean, ts: Date.now() })}
|
|
88458
88964
|
`);
|
|
88459
88965
|
}
|
|
88460
88966
|
function readPremiumRecoveryFile(agentDir) {
|
|
88461
88967
|
let raw;
|
|
88462
88968
|
try {
|
|
88463
|
-
raw = readFileSync33(
|
|
88969
|
+
raw = readFileSync33(join44(agentDir, PREMIUM_RECOVERY_FILE), "utf8");
|
|
88464
88970
|
} catch {
|
|
88465
88971
|
return null;
|
|
88466
88972
|
}
|
|
@@ -88473,7 +88979,7 @@ function readPremiumRecoveryFile(agentDir) {
|
|
|
88473
88979
|
}
|
|
88474
88980
|
function clearPremiumRecoveryFile(agentDir) {
|
|
88475
88981
|
try {
|
|
88476
|
-
rmSync7(
|
|
88982
|
+
rmSync7(join44(agentDir, PREMIUM_RECOVERY_FILE), { force: true });
|
|
88477
88983
|
} catch {}
|
|
88478
88984
|
}
|
|
88479
88985
|
|
|
@@ -88867,7 +89373,7 @@ init_merge();
|
|
|
88867
89373
|
init_timezone();
|
|
88868
89374
|
|
|
88869
89375
|
// ../src/cli/agent-config.ts
|
|
88870
|
-
import { join as
|
|
89376
|
+
import { join as join46 } from "node:path";
|
|
88871
89377
|
import { homedir as homedir11 } from "node:os";
|
|
88872
89378
|
|
|
88873
89379
|
// ../src/cli/helpers.ts
|
|
@@ -88888,12 +89394,12 @@ var WEBKITE_VAULT_KEYS = new Set([
|
|
|
88888
89394
|
init_overlay_loader();
|
|
88889
89395
|
|
|
88890
89396
|
// ../src/cli/agent-config.ts
|
|
88891
|
-
var AUDIT_ROOT =
|
|
89397
|
+
var AUDIT_ROOT = join46(homedir11(), ".switchroom", "audit");
|
|
88892
89398
|
|
|
88893
89399
|
// ../src/agents/profiles.ts
|
|
88894
89400
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
88895
89401
|
import { readFileSync as readFileSync36, writeFileSync as writeFileSync32, existsSync as existsSync37, readdirSync as readdirSync9, statSync as statSync14, copyFileSync, mkdirSync as mkdirSync33, realpathSync as realpathSync4 } from "node:fs";
|
|
88896
|
-
import { resolve as resolve8, join as
|
|
89402
|
+
import { resolve as resolve8, join as join47, sep as pathSep } from "node:path";
|
|
88897
89403
|
function resolveProfilesRootDetailed() {
|
|
88898
89404
|
return resolveShippedAsset(PROFILES_ASSET, {
|
|
88899
89405
|
bundleDir: import.meta.dirname,
|
|
@@ -88912,7 +89418,7 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
|
|
|
88912
89418
|
var SHARED_FRAGMENTS_DIR = resolve8(PROFILES_ROOT, "_shared");
|
|
88913
89419
|
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol", "local-time"];
|
|
88914
89420
|
for (const name of SHARED_FRAGMENTS) {
|
|
88915
|
-
const fragPath =
|
|
89421
|
+
const fragPath = join47(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
88916
89422
|
if (existsSync37(fragPath)) {
|
|
88917
89423
|
import_handlebars.default.registerPartial(name, readFileSync36(fragPath, "utf-8"));
|
|
88918
89424
|
}
|
|
@@ -90864,7 +91370,7 @@ function numField(obj, key) {
|
|
|
90864
91370
|
|
|
90865
91371
|
// gateway/context-occupancy.ts
|
|
90866
91372
|
import { mkdirSync as mkdirSync34, writeFileSync as writeFileSync33 } from "node:fs";
|
|
90867
|
-
import { join as
|
|
91373
|
+
import { join as join48 } from "node:path";
|
|
90868
91374
|
var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
|
|
90869
91375
|
var TIGHT_FRACTION = 0.8;
|
|
90870
91376
|
function buildContextOccupancy(occupancy, cap, now) {
|
|
@@ -90887,7 +91393,7 @@ function buildContextOccupancy(occupancy, cap, now) {
|
|
|
90887
91393
|
}
|
|
90888
91394
|
function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
|
|
90889
91395
|
try {
|
|
90890
|
-
const path2 =
|
|
91396
|
+
const path2 = join48(stateDir, CONTEXT_OCCUPANCY_FILENAME);
|
|
90891
91397
|
(deps?.mkdir ?? ((p, o) => mkdirSync34(p, o)))(stateDir, { recursive: true });
|
|
90892
91398
|
(deps?.writeFile ?? ((p, d) => writeFileSync33(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
|
|
90893
91399
|
`);
|
|
@@ -91025,17 +91531,17 @@ function idleDurationToMs(raw) {
|
|
|
91025
91531
|
init_state_owner();
|
|
91026
91532
|
import { readFileSync as readFileSync39, mkdirSync as mkdirSync35 } from "node:fs";
|
|
91027
91533
|
import { homedir as homedir13 } from "node:os";
|
|
91028
|
-
import { join as
|
|
91534
|
+
import { join as join49 } from "node:path";
|
|
91029
91535
|
function emptyPrivacyState() {
|
|
91030
91536
|
return { version: 1, intervals: [] };
|
|
91031
91537
|
}
|
|
91032
91538
|
var PRIVATE_ON_REPLY = "\uD83D\uDD12 Private mode ON \u2014 memory writing paused. Nothing said until /public is stored.";
|
|
91033
91539
|
var PUBLIC_REPLY = "\uD83D\uDD13 Public mode \u2014 memory writing resumed. The private stretch was excluded from memory.";
|
|
91034
91540
|
function resolvePrivacyStateDir() {
|
|
91035
|
-
return process.env.TELEGRAM_STATE_DIR ??
|
|
91541
|
+
return process.env.TELEGRAM_STATE_DIR ?? join49(homedir13(), ".claude", "channels", "telegram");
|
|
91036
91542
|
}
|
|
91037
91543
|
function privacyStatePath(stateDir = resolvePrivacyStateDir()) {
|
|
91038
|
-
return
|
|
91544
|
+
return join49(stateDir, "privacy-state.json");
|
|
91039
91545
|
}
|
|
91040
91546
|
function isInterval(v) {
|
|
91041
91547
|
if (v === null || typeof v !== "object")
|
|
@@ -91091,22 +91597,22 @@ function closePrivateInterval(now = new Date, stateDir = resolvePrivacyStateDir(
|
|
|
91091
91597
|
|
|
91092
91598
|
// gateway/privacy-reset.ts
|
|
91093
91599
|
import { existsSync as existsSync40 } from "node:fs";
|
|
91094
|
-
import { join as
|
|
91600
|
+
import { join as join51 } from "node:path";
|
|
91095
91601
|
|
|
91096
91602
|
// gateway/privacy-state.ts
|
|
91097
91603
|
init_state_owner();
|
|
91098
91604
|
import { readFileSync as readFileSync40, mkdirSync as mkdirSync36 } from "node:fs";
|
|
91099
91605
|
import { homedir as homedir14 } from "node:os";
|
|
91100
|
-
import { join as
|
|
91606
|
+
import { join as join50 } from "node:path";
|
|
91101
91607
|
function emptyPrivacyState2() {
|
|
91102
91608
|
return { version: 1, intervals: [] };
|
|
91103
91609
|
}
|
|
91104
91610
|
var SESSION_RESET_ALERT = "\uD83D\uDD13 New session \u2014 memory writing is ON by default. Private mode from the previous session was reset.";
|
|
91105
91611
|
function resolvePrivacyStateDir2() {
|
|
91106
|
-
return process.env.TELEGRAM_STATE_DIR ??
|
|
91612
|
+
return process.env.TELEGRAM_STATE_DIR ?? join50(homedir14(), ".claude", "channels", "telegram");
|
|
91107
91613
|
}
|
|
91108
91614
|
function privacyStatePath2(stateDir = resolvePrivacyStateDir2()) {
|
|
91109
|
-
return
|
|
91615
|
+
return join50(stateDir, "privacy-state.json");
|
|
91110
91616
|
}
|
|
91111
91617
|
function isInterval2(v) {
|
|
91112
91618
|
if (v === null || typeof v !== "object")
|
|
@@ -91170,7 +91676,7 @@ function bootRestoresTranscript(opts) {
|
|
|
91170
91676
|
return opts.resumeMode === "continue" || opts.resumeMode === "auto";
|
|
91171
91677
|
}
|
|
91172
91678
|
function isContinueRestoreBoot(agentDir) {
|
|
91173
|
-
const forceFresh = process.env.SWITCHROOM_FORCE_FRESH === "1" || agentDir != null && existsSync40(
|
|
91679
|
+
const forceFresh = process.env.SWITCHROOM_FORCE_FRESH === "1" || agentDir != null && existsSync40(join51(agentDir, ".force-fresh-session"));
|
|
91174
91680
|
return bootRestoresTranscript({
|
|
91175
91681
|
resumeMode: process.env.SWITCHROOM_RESUME_MODE,
|
|
91176
91682
|
forceFresh
|
|
@@ -92261,7 +92767,7 @@ function reseedSweepLedger(path2, fs2, log = (l) => process.stderr.write(l)) {
|
|
|
92261
92767
|
// ../src/util/state-owner.ts
|
|
92262
92768
|
init_atomic();
|
|
92263
92769
|
import {
|
|
92264
|
-
appendFileSync as
|
|
92770
|
+
appendFileSync as appendFileSync9,
|
|
92265
92771
|
closeSync as closeSync11,
|
|
92266
92772
|
constants as constants5,
|
|
92267
92773
|
existsSync as existsSync42,
|
|
@@ -92273,7 +92779,7 @@ import {
|
|
|
92273
92779
|
statSync as statSync15,
|
|
92274
92780
|
writeFileSync as writeFileSync34
|
|
92275
92781
|
} from "node:fs";
|
|
92276
|
-
import { dirname as dirname21, join as
|
|
92782
|
+
import { dirname as dirname21, join as join52, relative as relative2, sep as sep5 } from "node:path";
|
|
92277
92783
|
var NOFOLLOW2 = constants5.O_NOFOLLOW ?? 0;
|
|
92278
92784
|
var ownerCache2 = new Map;
|
|
92279
92785
|
var loggedFailure2 = false;
|
|
@@ -92347,7 +92853,7 @@ function mkdirStateSync2(path2, options = { recursive: true }, log = defaultLog3
|
|
|
92347
92853
|
for (const part of tail.split(sep5)) {
|
|
92348
92854
|
if (part === "")
|
|
92349
92855
|
continue;
|
|
92350
|
-
current =
|
|
92856
|
+
current = join52(current, part);
|
|
92351
92857
|
adoptStateOwnership2(current, owner, log);
|
|
92352
92858
|
}
|
|
92353
92859
|
}
|
|
@@ -92389,11 +92895,11 @@ function writeStateFileSync2(path2, data, options, log = defaultLog3) {
|
|
|
92389
92895
|
function appendStateFileSync(path2, data, options, log = defaultLog3) {
|
|
92390
92896
|
const owner = resolveStateOwner2(dirname21(path2));
|
|
92391
92897
|
if (!owner) {
|
|
92392
|
-
|
|
92898
|
+
appendFileSync9(path2, data, options);
|
|
92393
92899
|
return;
|
|
92394
92900
|
}
|
|
92395
92901
|
const existed = existsSync42(path2);
|
|
92396
|
-
|
|
92902
|
+
appendFileSync9(path2, data, options);
|
|
92397
92903
|
if (!existed)
|
|
92398
92904
|
adoptStateOwnership2(path2, owner, log);
|
|
92399
92905
|
}
|
|
@@ -92449,7 +92955,7 @@ function reconcileStateDirOwnership(dir, opts = {}) {
|
|
|
92449
92955
|
result.symlinksSkipped++;
|
|
92450
92956
|
continue;
|
|
92451
92957
|
}
|
|
92452
|
-
const child =
|
|
92958
|
+
const child = join52(current, entry.name);
|
|
92453
92959
|
result.scanned++;
|
|
92454
92960
|
if (adoptAndReport(child, owner, log))
|
|
92455
92961
|
result.adopted++;
|
|
@@ -92614,13 +93120,13 @@ function startWebhookIngestServer(opts) {
|
|
|
92614
93120
|
}
|
|
92615
93121
|
|
|
92616
93122
|
// ../src/web/webhook-gateway-record.ts
|
|
92617
|
-
import { appendFileSync as
|
|
92618
|
-
import { join as
|
|
93123
|
+
import { appendFileSync as appendFileSync11, mkdirSync as mkdirSync40 } from "fs";
|
|
93124
|
+
import { join as join56 } from "path";
|
|
92619
93125
|
import { homedir as homedir16 } from "os";
|
|
92620
93126
|
|
|
92621
93127
|
// ../src/web/webhook-handler.ts
|
|
92622
|
-
import { appendFileSync as
|
|
92623
|
-
import { join as
|
|
93128
|
+
import { appendFileSync as appendFileSync10, existsSync as existsSync45, mkdirSync as mkdirSync38, readFileSync as readFileSync41, writeFileSync as writeFileSync35 } from "fs";
|
|
93129
|
+
import { join as join54 } from "path";
|
|
92624
93130
|
|
|
92625
93131
|
// ../src/util/log-rotation.ts
|
|
92626
93132
|
import * as fs2 from "node:fs";
|
|
@@ -92982,8 +93488,8 @@ var agentDedupCache = new Map;
|
|
|
92982
93488
|
function createFileDedupStore(resolveAgentDir) {
|
|
92983
93489
|
return {
|
|
92984
93490
|
check(agent, deliveryId, now) {
|
|
92985
|
-
const telegramDir =
|
|
92986
|
-
const filePath =
|
|
93491
|
+
const telegramDir = join54(resolveAgentDir(agent), "telegram");
|
|
93492
|
+
const filePath = join54(telegramDir, "webhook-dedup.json");
|
|
92987
93493
|
if (!agentDedupCache.has(agent)) {
|
|
92988
93494
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
92989
93495
|
}
|
|
@@ -93005,7 +93511,7 @@ var throttleIssueWindow = new Map;
|
|
|
93005
93511
|
|
|
93006
93512
|
// ../src/web/webhook-dispatch.ts
|
|
93007
93513
|
import { existsSync as existsSync46, mkdirSync as mkdirSync39, readFileSync as readFileSync42, writeFileSync as writeFileSync36 } from "fs";
|
|
93008
|
-
import { join as
|
|
93514
|
+
import { join as join55 } from "path";
|
|
93009
93515
|
import { homedir as homedir15 } from "os";
|
|
93010
93516
|
|
|
93011
93517
|
// ../src/agent-scheduler/ipc-client.ts
|
|
@@ -93325,8 +93831,8 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
93325
93831
|
isCoolingDown(agent, key, cooldownMs, now) {
|
|
93326
93832
|
if (cooldownMs <= 0)
|
|
93327
93833
|
return false;
|
|
93328
|
-
const telegramDir =
|
|
93329
|
-
const filePath =
|
|
93834
|
+
const telegramDir = join55(resolveAgentDir(agent), "telegram");
|
|
93835
|
+
const filePath = join55(telegramDir, "webhook-cooldown.json");
|
|
93330
93836
|
if (!cache.has(agent)) {
|
|
93331
93837
|
cache.set(agent, loadCooldownFile(filePath));
|
|
93332
93838
|
}
|
|
@@ -93383,9 +93889,9 @@ async function defaultInject(socketPath, agentName3, inbound) {
|
|
|
93383
93889
|
}
|
|
93384
93890
|
function injectWebhookInbound(agent, prompt, ctx, deps = {}) {
|
|
93385
93891
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
93386
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
93892
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join55(homedir15(), ".switchroom", "agents", a));
|
|
93387
93893
|
const now = (deps.now ?? Date.now)();
|
|
93388
|
-
const socketPath =
|
|
93894
|
+
const socketPath = join55(resolveAgentDir(agent), "telegram", "gateway.sock");
|
|
93389
93895
|
const inbound = {
|
|
93390
93896
|
type: "inbound",
|
|
93391
93897
|
chatId: ctx.chatId,
|
|
@@ -93457,7 +93963,7 @@ function evaluateDispatch(args, deps = {}) {
|
|
|
93457
93963
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
93458
93964
|
const now = (deps.now ?? Date.now)();
|
|
93459
93965
|
const nowDate = deps.nowDate ?? (() => new Date(now));
|
|
93460
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
93966
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join55(homedir15(), ".switchroom", "agents", a));
|
|
93461
93967
|
const cooldownStore = deps.cooldownStore ?? createFileCooldownStore(resolveAgentDir);
|
|
93462
93968
|
if (!DISPATCH_SOURCES.includes(args.source))
|
|
93463
93969
|
return 0;
|
|
@@ -93535,10 +94041,10 @@ var CONSOLIDATION_COMPLETED_EVENT = "consolidation.completed";
|
|
|
93535
94041
|
function recordWebhookEvent(rec, deps = {}) {
|
|
93536
94042
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
93537
94043
|
const now = rec.ts || (deps.now ?? Date.now)();
|
|
93538
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
94044
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join56(homedir16(), ".switchroom", "agents", a));
|
|
93539
94045
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
93540
94046
|
const agent = rec.agent;
|
|
93541
|
-
const telegramDir =
|
|
94047
|
+
const telegramDir = join56(resolveAgentDir(agent), "telegram");
|
|
93542
94048
|
if (rec.source === "github" && rec.delivery_id) {
|
|
93543
94049
|
const originalTs = dedupStore.check(agent, rec.delivery_id, now);
|
|
93544
94050
|
if (originalTs !== undefined) {
|
|
@@ -93547,7 +94053,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
93547
94053
|
return { status: "deduped", ts: originalTs };
|
|
93548
94054
|
}
|
|
93549
94055
|
}
|
|
93550
|
-
const logPath =
|
|
94056
|
+
const logPath = join56(telegramDir, "webhook-events.jsonl");
|
|
93551
94057
|
try {
|
|
93552
94058
|
mkdirSync40(telegramDir, { recursive: true });
|
|
93553
94059
|
rotateWebhookLogIfNeeded(logPath);
|
|
@@ -93558,7 +94064,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
93558
94064
|
rendered_text: rec.rendered_text,
|
|
93559
94065
|
payload: rec.payload
|
|
93560
94066
|
};
|
|
93561
|
-
|
|
94067
|
+
appendFileSync11(logPath, JSON.stringify(record) + `
|
|
93562
94068
|
`, { mode: 384 });
|
|
93563
94069
|
} catch (err) {
|
|
93564
94070
|
log(`webhook-gateway: agent='${agent}' source='${rec.source}' write failed: ${err.message}
|
|
@@ -98213,14 +98719,14 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
|
|
|
98213
98719
|
// gateway/compaction-marker.ts
|
|
98214
98720
|
import { statSync as statSync17, unlinkSync as unlinkSync22 } from "node:fs";
|
|
98215
98721
|
import { homedir as homedir17 } from "node:os";
|
|
98216
|
-
import { join as
|
|
98722
|
+
import { join as join57 } from "node:path";
|
|
98217
98723
|
var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
|
|
98218
98724
|
function resolveTelegramStateDir() {
|
|
98219
|
-
return process.env.TELEGRAM_STATE_DIR ??
|
|
98725
|
+
return process.env.TELEGRAM_STATE_DIR ?? join57(homedir17(), ".claude", "channels", "telegram");
|
|
98220
98726
|
}
|
|
98221
98727
|
function readCompactionMarkerAgeMs(stateDir, now) {
|
|
98222
98728
|
try {
|
|
98223
|
-
const st = statSync17(
|
|
98729
|
+
const st = statSync17(join57(stateDir, COMPACTION_MARKER_FILE));
|
|
98224
98730
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
98225
98731
|
} catch {
|
|
98226
98732
|
return null;
|
|
@@ -98228,7 +98734,7 @@ function readCompactionMarkerAgeMs(stateDir, now) {
|
|
|
98228
98734
|
}
|
|
98229
98735
|
function removeCompactionMarker(stateDir) {
|
|
98230
98736
|
try {
|
|
98231
|
-
unlinkSync22(
|
|
98737
|
+
unlinkSync22(join57(stateDir, COMPACTION_MARKER_FILE));
|
|
98232
98738
|
} catch {}
|
|
98233
98739
|
}
|
|
98234
98740
|
|
|
@@ -100293,7 +100799,7 @@ import {
|
|
|
100293
100799
|
readdirSync as readdirSync12,
|
|
100294
100800
|
readFileSync as readFileSync47
|
|
100295
100801
|
} from "fs";
|
|
100296
|
-
import { join as
|
|
100802
|
+
import { join as join58 } from "path";
|
|
100297
100803
|
|
|
100298
100804
|
// session-tail.ts
|
|
100299
100805
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -101616,8 +102122,8 @@ function startSubagentWatcher(config) {
|
|
|
101616
102122
|
if (stopped)
|
|
101617
102123
|
return;
|
|
101618
102124
|
pruneVanishedDirWatchers();
|
|
101619
|
-
const claudeHome =
|
|
101620
|
-
const projectsRoot =
|
|
102125
|
+
const claudeHome = join58(agentDir, ".claude");
|
|
102126
|
+
const projectsRoot = join58(claudeHome, "projects");
|
|
101621
102127
|
if (!fs3.existsSync(projectsRoot))
|
|
101622
102128
|
return;
|
|
101623
102129
|
let projectDirs;
|
|
@@ -101651,7 +102157,7 @@ function startSubagentWatcher(config) {
|
|
|
101651
102157
|
continue;
|
|
101652
102158
|
}
|
|
101653
102159
|
warnedForeignSlugs.delete(pDir);
|
|
101654
|
-
const projectPath =
|
|
102160
|
+
const projectPath = join58(projectsRoot, pDir);
|
|
101655
102161
|
let sessionDirs;
|
|
101656
102162
|
try {
|
|
101657
102163
|
sessionDirs = fs3.readdirSync(projectPath);
|
|
@@ -101661,7 +102167,7 @@ function startSubagentWatcher(config) {
|
|
|
101661
102167
|
for (const sDir of sessionDirs) {
|
|
101662
102168
|
if (sDir.endsWith(".jsonl"))
|
|
101663
102169
|
continue;
|
|
101664
|
-
const subagentsPath =
|
|
102170
|
+
const subagentsPath = join58(projectPath, sDir, "subagents");
|
|
101665
102171
|
if (!fs3.existsSync(subagentsPath))
|
|
101666
102172
|
continue;
|
|
101667
102173
|
const watchAndScan = (dirPath) => {
|
|
@@ -101670,7 +102176,7 @@ function startSubagentWatcher(config) {
|
|
|
101670
102176
|
const w = fs3.watch(dirPath, (_event, filename) => {
|
|
101671
102177
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
101672
102178
|
return;
|
|
101673
|
-
const filePath =
|
|
102179
|
+
const filePath = join58(dirPath, filename.toString());
|
|
101674
102180
|
if (!knownFiles.has(filePath)) {
|
|
101675
102181
|
scanSubagentsDir(dirPath);
|
|
101676
102182
|
}
|
|
@@ -101684,7 +102190,7 @@ function startSubagentWatcher(config) {
|
|
|
101684
102190
|
scanSubagentsDir(dirPath);
|
|
101685
102191
|
};
|
|
101686
102192
|
watchAndScan(subagentsPath);
|
|
101687
|
-
const workflowsPath =
|
|
102193
|
+
const workflowsPath = join58(subagentsPath, "workflows");
|
|
101688
102194
|
if (fs3.existsSync(workflowsPath)) {
|
|
101689
102195
|
let wfDirs;
|
|
101690
102196
|
try {
|
|
@@ -101694,7 +102200,7 @@ function startSubagentWatcher(config) {
|
|
|
101694
102200
|
}
|
|
101695
102201
|
for (const wfDir of wfDirs) {
|
|
101696
102202
|
try {
|
|
101697
|
-
const wfPath =
|
|
102203
|
+
const wfPath = join58(workflowsPath, wfDir);
|
|
101698
102204
|
if (!fs3.statSync(wfPath).isDirectory())
|
|
101699
102205
|
continue;
|
|
101700
102206
|
watchAndScan(wfPath);
|
|
@@ -101714,7 +102220,7 @@ function startSubagentWatcher(config) {
|
|
|
101714
102220
|
for (const e of entries) {
|
|
101715
102221
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
101716
102222
|
continue;
|
|
101717
|
-
const filePath =
|
|
102223
|
+
const filePath = join58(subagentsPath, e);
|
|
101718
102224
|
if (knownFiles.has(filePath))
|
|
101719
102225
|
continue;
|
|
101720
102226
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -101850,13 +102356,13 @@ import {
|
|
|
101850
102356
|
existsSync as existsSync48,
|
|
101851
102357
|
renameSync as renameSync24
|
|
101852
102358
|
} from "node:fs";
|
|
101853
|
-
import { join as
|
|
102359
|
+
import { join as join59, resolve as resolve10 } from "node:path";
|
|
101854
102360
|
import { homedir as homedir18 } from "node:os";
|
|
101855
102361
|
function registryDir2() {
|
|
101856
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
102362
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join59(homedir18(), ".switchroom", "worktrees"));
|
|
101857
102363
|
}
|
|
101858
102364
|
function recordPath(id) {
|
|
101859
|
-
return
|
|
102365
|
+
return join59(registryDir2(), `${id}.json`);
|
|
101860
102366
|
}
|
|
101861
102367
|
function ensureDir4() {
|
|
101862
102368
|
mkdirSync41(registryDir2(), { recursive: true });
|
|
@@ -102040,19 +102546,19 @@ function determineBridgeReconnectReason(opts) {
|
|
|
102040
102546
|
|
|
102041
102547
|
// gateway/update-announce.ts
|
|
102042
102548
|
import { existsSync as existsSync53, mkdirSync as mkdirSync45, openSync as openSync14, closeSync as closeSync14, readFileSync as readFileSync55 } from "node:fs";
|
|
102043
|
-
import { join as
|
|
102549
|
+
import { join as join64 } from "node:path";
|
|
102044
102550
|
import { homedir as homedir20 } from "node:os";
|
|
102045
102551
|
|
|
102046
102552
|
// ../src/host-control/audit-reader.ts
|
|
102047
102553
|
import { homedir as homedir19 } from "node:os";
|
|
102048
|
-
import { join as
|
|
102554
|
+
import { join as join63 } from "node:path";
|
|
102049
102555
|
|
|
102050
102556
|
// ../src/host-control/audit-rotation-config.ts
|
|
102051
102557
|
var DEFAULT_HOSTD_AUDIT_MAX_BYTES = 32 * 1024 * 1024;
|
|
102052
102558
|
|
|
102053
102559
|
// ../src/host-control/audit-reader.ts
|
|
102054
102560
|
function defaultAuditLogPath(home2 = homedir19()) {
|
|
102055
|
-
return
|
|
102561
|
+
return join63(home2, ".switchroom", "host-control-audit.log");
|
|
102056
102562
|
}
|
|
102057
102563
|
var AUDIT_READ_WINDOW_BYTES = 4 * 1024 * 1024;
|
|
102058
102564
|
function parseAuditLine(line) {
|
|
@@ -102251,15 +102757,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
102251
102757
|
`);
|
|
102252
102758
|
}
|
|
102253
102759
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
102254
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
102255
|
-
const dir =
|
|
102760
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join64(homedir20(), ".switchroom");
|
|
102761
|
+
const dir = join64(stateDir, "update-announced");
|
|
102256
102762
|
try {
|
|
102257
102763
|
mkdirSync45(dir, { recursive: true });
|
|
102258
102764
|
} catch {
|
|
102259
102765
|
return false;
|
|
102260
102766
|
}
|
|
102261
102767
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
102262
|
-
const path3 =
|
|
102768
|
+
const path3 = join64(dir, safeId);
|
|
102263
102769
|
try {
|
|
102264
102770
|
const fd = openSync14(path3, "wx");
|
|
102265
102771
|
closeSync14(fd);
|
|
@@ -102481,7 +102987,7 @@ function createIssuesCardHandle(opts) {
|
|
|
102481
102987
|
|
|
102482
102988
|
// issues-watcher.ts
|
|
102483
102989
|
import { existsSync as existsSync55, statSync as statSync21 } from "node:fs";
|
|
102484
|
-
import { join as
|
|
102990
|
+
import { join as join66 } from "node:path";
|
|
102485
102991
|
|
|
102486
102992
|
// ../src/issues/store.ts
|
|
102487
102993
|
import {
|
|
@@ -102497,7 +103003,7 @@ import {
|
|
|
102497
103003
|
writeFileSync as writeFileSync46,
|
|
102498
103004
|
writeSync as writeSync8
|
|
102499
103005
|
} from "node:fs";
|
|
102500
|
-
import { join as
|
|
103006
|
+
import { join as join65 } from "node:path";
|
|
102501
103007
|
import { randomBytes as randomBytes10 } from "node:crypto";
|
|
102502
103008
|
import { execSync } from "node:child_process";
|
|
102503
103009
|
|
|
@@ -102516,7 +103022,7 @@ init_redact();
|
|
|
102516
103022
|
var ISSUES_FILE = "issues.jsonl";
|
|
102517
103023
|
var ISSUES_LOCK = "issues.lock";
|
|
102518
103024
|
function readAll(stateDir) {
|
|
102519
|
-
const path3 =
|
|
103025
|
+
const path3 = join65(stateDir, ISSUES_FILE);
|
|
102520
103026
|
if (!existsSync54(path3))
|
|
102521
103027
|
return [];
|
|
102522
103028
|
let raw;
|
|
@@ -102553,7 +103059,7 @@ function list2(stateDir, opts = {}) {
|
|
|
102553
103059
|
});
|
|
102554
103060
|
}
|
|
102555
103061
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
102556
|
-
if (!existsSync54(
|
|
103062
|
+
if (!existsSync54(join65(stateDir, ISSUES_FILE)))
|
|
102557
103063
|
return 0;
|
|
102558
103064
|
return withLock(stateDir, () => {
|
|
102559
103065
|
const all2 = readAll(stateDir);
|
|
@@ -102571,7 +103077,7 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
102571
103077
|
});
|
|
102572
103078
|
}
|
|
102573
103079
|
function writeAll(stateDir, events) {
|
|
102574
|
-
const path3 =
|
|
103080
|
+
const path3 = join65(stateDir, ISSUES_FILE);
|
|
102575
103081
|
sweepOrphanTmpFiles(stateDir);
|
|
102576
103082
|
const tmp = `${path3}.tmp-${process.pid}-${randomBytes10(4).toString("hex")}`;
|
|
102577
103083
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -102593,7 +103099,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
102593
103099
|
for (const entry of entries) {
|
|
102594
103100
|
if (!entry.startsWith(TMP_PREFIX))
|
|
102595
103101
|
continue;
|
|
102596
|
-
const tmpPath2 =
|
|
103102
|
+
const tmpPath2 = join65(stateDir, entry);
|
|
102597
103103
|
try {
|
|
102598
103104
|
const stat = statSync20(tmpPath2);
|
|
102599
103105
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -102605,7 +103111,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
102605
103111
|
var LOCK_RETRY_MS = 25;
|
|
102606
103112
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
102607
103113
|
function withLock(stateDir, fn) {
|
|
102608
|
-
const lockPath =
|
|
103114
|
+
const lockPath = join65(stateDir, ISSUES_LOCK);
|
|
102609
103115
|
const startedAt = Date.now();
|
|
102610
103116
|
let fd = null;
|
|
102611
103117
|
while (fd === null) {
|
|
@@ -102690,7 +103196,7 @@ function isIssueEvent(v) {
|
|
|
102690
103196
|
// issues-watcher.ts
|
|
102691
103197
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
102692
103198
|
function startIssuesWatcher(opts) {
|
|
102693
|
-
const path3 =
|
|
103199
|
+
const path3 = join66(opts.stateDir, ISSUES_FILE);
|
|
102694
103200
|
const log = opts.log ?? (() => {});
|
|
102695
103201
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
102696
103202
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -103450,7 +103956,7 @@ function readBashCommand(inputPreview) {
|
|
|
103450
103956
|
|
|
103451
103957
|
// gateway/scoped-grant-store.ts
|
|
103452
103958
|
init_state_owner();
|
|
103453
|
-
import { join as
|
|
103959
|
+
import { join as join67 } from "node:path";
|
|
103454
103960
|
|
|
103455
103961
|
// scoped-approval.ts
|
|
103456
103962
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -103492,7 +103998,7 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
103492
103998
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
103493
103999
|
}
|
|
103494
104000
|
function createScopedGrantStore(stateDir, env = process.env, log = (l) => process.stderr.write(l)) {
|
|
103495
|
-
const filePath =
|
|
104001
|
+
const filePath = join67(stateDir, "scoped-grants.json");
|
|
103496
104002
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
103497
104003
|
let unreadable = false;
|
|
103498
104004
|
function read() {
|
|
@@ -103871,7 +104377,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
103871
104377
|
// credits-watch.ts
|
|
103872
104378
|
init_card_format();
|
|
103873
104379
|
import { readFileSync as readFileSync58, writeFileSync as writeFileSync47, existsSync as existsSync56, mkdirSync as mkdirSync47 } from "fs";
|
|
103874
|
-
import { join as
|
|
104380
|
+
import { join as join68 } from "path";
|
|
103875
104381
|
var STATE_FILE = "credits-watch.json";
|
|
103876
104382
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
103877
104383
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -103893,7 +104399,7 @@ function emptyCreditState() {
|
|
|
103893
104399
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
103894
104400
|
}
|
|
103895
104401
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
103896
|
-
const path3 =
|
|
104402
|
+
const path3 = join68(claudeConfigDir, ".claude.json");
|
|
103897
104403
|
if (!existsSync56(path3))
|
|
103898
104404
|
return null;
|
|
103899
104405
|
let raw;
|
|
@@ -103976,7 +104482,7 @@ function humanizeReason(reason) {
|
|
|
103976
104482
|
}
|
|
103977
104483
|
}
|
|
103978
104484
|
function loadCreditState(stateDir) {
|
|
103979
|
-
const path3 =
|
|
104485
|
+
const path3 = join68(stateDir, STATE_FILE);
|
|
103980
104486
|
if (!existsSync56(path3))
|
|
103981
104487
|
return emptyCreditState();
|
|
103982
104488
|
try {
|
|
@@ -103993,7 +104499,7 @@ function loadCreditState(stateDir) {
|
|
|
103993
104499
|
}
|
|
103994
104500
|
function saveCreditState(stateDir, state7) {
|
|
103995
104501
|
mkdirSync47(stateDir, { recursive: true });
|
|
103996
|
-
const path3 =
|
|
104502
|
+
const path3 = join68(stateDir, STATE_FILE);
|
|
103997
104503
|
writeFileSync47(path3, JSON.stringify(state7, null, 2) + `
|
|
103998
104504
|
`, { mode: 384 });
|
|
103999
104505
|
}
|
|
@@ -104002,7 +104508,7 @@ function saveCreditState(stateDir, state7) {
|
|
|
104002
104508
|
init_auth_snapshot_format();
|
|
104003
104509
|
init_card_format();
|
|
104004
104510
|
import { readFileSync as readFileSync59, writeFileSync as writeFileSync48, existsSync as existsSync57, mkdirSync as mkdirSync48 } from "fs";
|
|
104005
|
-
import { join as
|
|
104511
|
+
import { join as join69 } from "path";
|
|
104006
104512
|
var STATE_FILE2 = "quota-watch.json";
|
|
104007
104513
|
function emptyQuotaWatchState() {
|
|
104008
104514
|
return {};
|
|
@@ -104240,7 +104746,7 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
104240
104746
|
`);
|
|
104241
104747
|
}
|
|
104242
104748
|
function loadQuotaWatchState(stateDir) {
|
|
104243
|
-
const path3 =
|
|
104749
|
+
const path3 = join69(stateDir, STATE_FILE2);
|
|
104244
104750
|
if (!existsSync57(path3))
|
|
104245
104751
|
return emptyQuotaWatchState();
|
|
104246
104752
|
try {
|
|
@@ -104262,7 +104768,7 @@ function loadQuotaWatchState(stateDir) {
|
|
|
104262
104768
|
}
|
|
104263
104769
|
function saveQuotaWatchState(stateDir, state7) {
|
|
104264
104770
|
mkdirSync48(stateDir, { recursive: true });
|
|
104265
|
-
const path3 =
|
|
104771
|
+
const path3 = join69(stateDir, STATE_FILE2);
|
|
104266
104772
|
writeFileSync48(path3, JSON.stringify(state7, null, 2) + `
|
|
104267
104773
|
`, { mode: 384 });
|
|
104268
104774
|
}
|
|
@@ -104319,17 +104825,17 @@ import {
|
|
|
104319
104825
|
unlinkSync as unlinkSync28,
|
|
104320
104826
|
utimesSync as utimesSync2
|
|
104321
104827
|
} from "node:fs";
|
|
104322
|
-
import { join as
|
|
104828
|
+
import { join as join70 } from "node:path";
|
|
104323
104829
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
104324
104830
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
104325
104831
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
104326
104832
|
function removeTurnActiveMarker2(stateDir) {
|
|
104327
104833
|
try {
|
|
104328
|
-
unlinkSync28(
|
|
104834
|
+
unlinkSync28(join70(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
104329
104835
|
} catch {}
|
|
104330
104836
|
}
|
|
104331
104837
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
104332
|
-
const path3 =
|
|
104838
|
+
const path3 = join70(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
104333
104839
|
if (!existsSync58(path3))
|
|
104334
104840
|
return false;
|
|
104335
104841
|
const now = opts.now ?? Date.now();
|
|
@@ -104360,7 +104866,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
104360
104866
|
}
|
|
104361
104867
|
}
|
|
104362
104868
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
104363
|
-
const path3 =
|
|
104869
|
+
const path3 = join70(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
104364
104870
|
try {
|
|
104365
104871
|
const st = statSync22(path3);
|
|
104366
104872
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -104375,11 +104881,11 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
104375
104881
|
// gateway/gateway-heartbeat.ts
|
|
104376
104882
|
init_state_owner();
|
|
104377
104883
|
import { utimesSync as utimesSync3 } from "node:fs";
|
|
104378
|
-
import { join as
|
|
104884
|
+
import { join as join71 } from "node:path";
|
|
104379
104885
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
104380
104886
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
104381
104887
|
function touchGatewayHeartbeat(stateDir) {
|
|
104382
|
-
const path3 =
|
|
104888
|
+
const path3 = join71(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
104383
104889
|
const now = new Date;
|
|
104384
104890
|
try {
|
|
104385
104891
|
utimesSync3(path3, now, now);
|
|
@@ -104410,7 +104916,7 @@ import {
|
|
|
104410
104916
|
unlinkSync as unlinkSync29,
|
|
104411
104917
|
writeFileSync as writeFileSync49
|
|
104412
104918
|
} from "node:fs";
|
|
104413
|
-
import { join as
|
|
104919
|
+
import { join as join72 } from "node:path";
|
|
104414
104920
|
var BOOT_BEACON_FILE = "gateway-beacon.json";
|
|
104415
104921
|
var HOST_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
|
|
104416
104922
|
var CGROUP_MEMORY_EVENTS_PATH = "/sys/fs/cgroup/memory.events";
|
|
@@ -104509,7 +105015,7 @@ function sampleBeaconHost(paths = {}) {
|
|
|
104509
105015
|
return sample3;
|
|
104510
105016
|
}
|
|
104511
105017
|
function writeBootBeaconFile(stateDir, beacon) {
|
|
104512
|
-
const path3 =
|
|
105018
|
+
const path3 = join72(stateDir, BOOT_BEACON_FILE);
|
|
104513
105019
|
const tmp = `${path3}.tmp-${process.pid}`;
|
|
104514
105020
|
let fd;
|
|
104515
105021
|
try {
|
|
@@ -104901,10 +105407,10 @@ function startOutboxSweep(deps) {
|
|
|
104901
105407
|
}
|
|
104902
105408
|
|
|
104903
105409
|
// ../src/build-info.ts
|
|
104904
|
-
var VERSION2 = "0.21.
|
|
104905
|
-
var COMMIT_SHA = "
|
|
104906
|
-
var COMMIT_DATE = "2026-08-
|
|
104907
|
-
var LATEST_PR =
|
|
105410
|
+
var VERSION2 = "0.21.10";
|
|
105411
|
+
var COMMIT_SHA = "fd1650e7";
|
|
105412
|
+
var COMMIT_DATE = "2026-08-14T03:50:00Z";
|
|
105413
|
+
var LATEST_PR = 4698;
|
|
104908
105414
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
104909
105415
|
|
|
104910
105416
|
// gateway/boot-version.ts
|
|
@@ -104982,11 +105488,11 @@ init_peercred();
|
|
|
104982
105488
|
import * as net5 from "node:net";
|
|
104983
105489
|
import * as fs3 from "node:fs";
|
|
104984
105490
|
import { homedir as homedir21 } from "node:os";
|
|
104985
|
-
import { join as
|
|
105491
|
+
import { join as join73 } from "node:path";
|
|
104986
105492
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
104987
105493
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
104988
|
-
var LEGACY_SOCKET_PATH2 =
|
|
104989
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
105494
|
+
var LEGACY_SOCKET_PATH2 = join73(homedir21(), ".switchroom", "vault-broker.sock");
|
|
105495
|
+
var OPERATOR_SOCKET_PATH2 = join73(homedir21(), ".switchroom", "broker-operator", "sock");
|
|
104990
105496
|
function defaultBrokerSocketPath2() {
|
|
104991
105497
|
if (fs3.existsSync(OPERATOR_SOCKET_PATH2))
|
|
104992
105498
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -105870,7 +106376,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
105870
106376
|
// registry/turns-schema.ts
|
|
105871
106377
|
init_state_owner();
|
|
105872
106378
|
import { chmodSync as chmodSync12 } from "fs";
|
|
105873
|
-
import { join as
|
|
106379
|
+
import { join as join74 } from "path";
|
|
105874
106380
|
var DatabaseClass3 = null;
|
|
105875
106381
|
function loadDatabaseClass3() {
|
|
105876
106382
|
if (DatabaseClass3 != null)
|
|
@@ -105942,9 +106448,9 @@ function applySchema(db3) {
|
|
|
105942
106448
|
}
|
|
105943
106449
|
function openTurnsDb(agentDir) {
|
|
105944
106450
|
const Database = loadDatabaseClass3();
|
|
105945
|
-
const dir =
|
|
106451
|
+
const dir = join74(agentDir, "telegram");
|
|
105946
106452
|
mkdirStateSync(dir, { recursive: true, mode: 448 });
|
|
105947
|
-
const path3 =
|
|
106453
|
+
const path3 = join74(dir, "registry.db");
|
|
105948
106454
|
const db3 = new Database(path3, { create: true });
|
|
105949
106455
|
applySchema(db3);
|
|
105950
106456
|
try {
|
|
@@ -106287,7 +106793,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
106287
106793
|
|
|
106288
106794
|
// gateway/boot-briefing-wiring.ts
|
|
106289
106795
|
import { existsSync as existsSync60, readFileSync as readFileSync63, writeFileSync as writeFileSync50 } from "node:fs";
|
|
106290
|
-
import { join as
|
|
106796
|
+
import { join as join75 } from "node:path";
|
|
106291
106797
|
init_history();
|
|
106292
106798
|
|
|
106293
106799
|
// gateway/resume-inbound-builder.ts
|
|
@@ -106594,8 +107100,8 @@ function readDailyMemory(agentDir, env, nowMs3, readFile = (p) => readFileSync63
|
|
|
106594
107100
|
const date = agentLocalDate(nowMs3, env.SWITCHROOM_TIMEZONE || env.TZ || undefined);
|
|
106595
107101
|
if (!date)
|
|
106596
107102
|
return null;
|
|
106597
|
-
const workspaceDir = env.WORKSPACE_DIR && env.WORKSPACE_DIR.trim() ? env.WORKSPACE_DIR :
|
|
106598
|
-
const file =
|
|
107103
|
+
const workspaceDir = env.WORKSPACE_DIR && env.WORKSPACE_DIR.trim() ? env.WORKSPACE_DIR : join75(agentDir, "workspace");
|
|
107104
|
+
const file = join75(workspaceDir, "memory", `${date}.md`);
|
|
106599
107105
|
try {
|
|
106600
107106
|
const content3 = readFile(file);
|
|
106601
107107
|
if (!content3 || !content3.trim())
|
|
@@ -106624,7 +107130,7 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106624
107130
|
try {
|
|
106625
107131
|
const agentDir = opts.stateDir.endsWith("/telegram") ? opts.stateDir.slice(0, -"/telegram".length) : opts.stateDir;
|
|
106626
107132
|
const bootId = opts.env.SWITCHROOM_GATEWAY_BOOT_ID;
|
|
106627
|
-
const genMarkerPath =
|
|
107133
|
+
const genMarkerPath = join75(agentDir, ".boot-briefing-generation");
|
|
106628
107134
|
if (bootId) {
|
|
106629
107135
|
let prevGen = null;
|
|
106630
107136
|
try {
|
|
@@ -106646,7 +107152,7 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106646
107152
|
`);
|
|
106647
107153
|
} catch {}
|
|
106648
107154
|
};
|
|
106649
|
-
const forceFresh = opts.env.SWITCHROOM_FORCE_FRESH === "1" || existsSync60(
|
|
107155
|
+
const forceFresh = opts.env.SWITCHROOM_FORCE_FRESH === "1" || existsSync60(join75(agentDir, ".force-fresh-session"));
|
|
106650
107156
|
const decision = decideBootBriefing({
|
|
106651
107157
|
briefingMode: opts.env.SWITCHROOM_SESSION_BRIEFING,
|
|
106652
107158
|
resumeMode: opts.env.SWITCHROOM_RESUME_MODE,
|
|
@@ -106680,7 +107186,7 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106680
107186
|
return null;
|
|
106681
107187
|
}
|
|
106682
107188
|
const restartReason = readRestartBreadcrumb({
|
|
106683
|
-
restartReasonPath:
|
|
107189
|
+
restartReasonPath: join75(agentDir, ".restart-reason"),
|
|
106684
107190
|
env: opts.env,
|
|
106685
107191
|
readFile: (p) => readFileSync63(p, "utf8")
|
|
106686
107192
|
});
|
|
@@ -106717,9 +107223,9 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106717
107223
|
|
|
106718
107224
|
// gateway/pending-turn-env.ts
|
|
106719
107225
|
import { existsSync as existsSync61, renameSync as renameSync29, rmSync as rmSync8, writeFileSync as writeFileSync51 } from "node:fs";
|
|
106720
|
-
import { join as
|
|
107226
|
+
import { join as join76 } from "node:path";
|
|
106721
107227
|
function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.write(l)) {
|
|
106722
|
-
const pendingEnvPath =
|
|
107228
|
+
const pendingEnvPath = join76(agentDir, ".pending-turn.env");
|
|
106723
107229
|
try {
|
|
106724
107230
|
if (pending != null) {
|
|
106725
107231
|
const lines = [
|
|
@@ -106752,7 +107258,7 @@ function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.writ
|
|
|
106752
107258
|
|
|
106753
107259
|
// gateway/agent-process-liveness.ts
|
|
106754
107260
|
import { existsSync as existsSync62, readFileSync as readFileSync64, writeFileSync as writeFileSync52, renameSync as renameSync30, unlinkSync as unlinkSync30, readdirSync as readdirSync16 } from "node:fs";
|
|
106755
|
-
import { join as
|
|
107261
|
+
import { join as join77, dirname as dirname28, basename as basename18 } from "node:path";
|
|
106756
107262
|
var AGENT_PROCESS_RECORD_FILE = "agent-process.json";
|
|
106757
107263
|
var BOOT_RESUME_DONE_FILE = ".boot-resume-done";
|
|
106758
107264
|
function parseProcStat(raw) {
|
|
@@ -106775,7 +107281,7 @@ function readProcIdentity(pid, procRoot = "/proc") {
|
|
|
106775
107281
|
return null;
|
|
106776
107282
|
let identity;
|
|
106777
107283
|
try {
|
|
106778
|
-
identity = parseProcStat(readFileSync64(
|
|
107284
|
+
identity = parseProcStat(readFileSync64(join77(procRoot, String(pid), "stat"), "utf8"));
|
|
106779
107285
|
} catch {
|
|
106780
107286
|
return null;
|
|
106781
107287
|
}
|
|
@@ -106807,7 +107313,7 @@ function readAgentProcessRecord(path3) {
|
|
|
106807
107313
|
return rec;
|
|
106808
107314
|
}
|
|
106809
107315
|
function bootResumeDonePath(stateDir) {
|
|
106810
|
-
return
|
|
107316
|
+
return join77(stateDir, BOOT_RESUME_DONE_FILE);
|
|
106811
107317
|
}
|
|
106812
107318
|
function containerBootIdentity(procRoot = "/proc") {
|
|
106813
107319
|
return readProcIdentity(1, procRoot)?.starttime ?? null;
|
|
@@ -106840,7 +107346,7 @@ function sweepStrayTmps(path3) {
|
|
|
106840
107346
|
if (!name.startsWith(prefix))
|
|
106841
107347
|
continue;
|
|
106842
107348
|
try {
|
|
106843
|
-
unlinkSync30(
|
|
107349
|
+
unlinkSync30(join77(dirname28(path3), name));
|
|
106844
107350
|
} catch {}
|
|
106845
107351
|
}
|
|
106846
107352
|
} catch {}
|
|
@@ -106892,7 +107398,7 @@ function detectGatewayOnlyRespawn(opts) {
|
|
|
106892
107398
|
return { gatewayOnly: false, reason: "guard-disabled", pid: null };
|
|
106893
107399
|
const procRoot = opts.procRoot ?? "/proc";
|
|
106894
107400
|
const sentinel = readBootResumeSentinel(opts.sentinelPath ?? bootResumeDonePath(opts.stateDir), { procRoot });
|
|
106895
|
-
const recordPath2 = opts.recordPath ??
|
|
107401
|
+
const recordPath2 = opts.recordPath ?? join77(opts.stateDir, AGENT_PROCESS_RECORD_FILE);
|
|
106896
107402
|
const record2 = readAgentProcessRecord(recordPath2);
|
|
106897
107403
|
const live = record2 == null ? null : readProcIdentity(record2.pid, procRoot);
|
|
106898
107404
|
return decideGatewayOnlyRespawn({
|
|
@@ -107450,7 +107956,7 @@ if (isGatewayMain) {
|
|
|
107450
107956
|
shutdownAnalytics();
|
|
107451
107957
|
});
|
|
107452
107958
|
}
|
|
107453
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
107959
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join78(homedir22(), ".claude", "channels", "telegram");
|
|
107454
107960
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
107455
107961
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
107456
107962
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -107550,11 +108056,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
107550
108056
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
107551
108057
|
timer3.unref?.();
|
|
107552
108058
|
}
|
|
107553
|
-
var ACCESS_FILE =
|
|
107554
|
-
var APPROVED_DIR =
|
|
107555
|
-
var ENV_FILE =
|
|
107556
|
-
var INBOX_DIR =
|
|
107557
|
-
var PEOPLE_FILE =
|
|
108059
|
+
var ACCESS_FILE = join78(STATE_DIR, "access.json");
|
|
108060
|
+
var APPROVED_DIR = join78(STATE_DIR, "approved");
|
|
108061
|
+
var ENV_FILE = join78(STATE_DIR, ".env");
|
|
108062
|
+
var INBOX_DIR = join78(STATE_DIR, "inbox");
|
|
108063
|
+
var PEOPLE_FILE = join78(STATE_DIR, "people.json");
|
|
107558
108064
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
107559
108065
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
107560
108066
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -107681,7 +108187,7 @@ function assertSendable(f) {
|
|
|
107681
108187
|
} catch {
|
|
107682
108188
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
107683
108189
|
}
|
|
107684
|
-
const inbox =
|
|
108190
|
+
const inbox = join78(stateReal, "inbox");
|
|
107685
108191
|
if (real.startsWith(stateReal + sep6) && !real.startsWith(inbox + sep6)) {
|
|
107686
108192
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
107687
108193
|
}
|
|
@@ -107710,7 +108216,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
107710
108216
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
107711
108217
|
try {
|
|
107712
108218
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
107713
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
108219
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join78(STATE_DIR, "history.db")}
|
|
107714
108220
|
`);
|
|
107715
108221
|
} catch (err) {
|
|
107716
108222
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -107733,7 +108239,7 @@ bootResumeInit:
|
|
|
107733
108239
|
let markerTurnKey = null;
|
|
107734
108240
|
let markerAgeMs = null;
|
|
107735
108241
|
try {
|
|
107736
|
-
const markerPath =
|
|
108242
|
+
const markerPath = join78(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
107737
108243
|
if (existsSync65(markerPath)) {
|
|
107738
108244
|
const st = statSync25(markerPath);
|
|
107739
108245
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
@@ -107758,10 +108264,10 @@ bootResumeInit:
|
|
|
107758
108264
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
107759
108265
|
`);
|
|
107760
108266
|
} else {
|
|
107761
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
108267
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join78(agentDir, "telegram", "registry.db")}
|
|
107762
108268
|
`);
|
|
107763
108269
|
}
|
|
107764
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
108270
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join78(STATE_DIR, "bridge-dead-escalation.json"));
|
|
107765
108271
|
if (bridgeDeadMarker != null) {
|
|
107766
108272
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
107767
108273
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -107774,7 +108280,7 @@ bootResumeInit:
|
|
|
107774
108280
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
107775
108281
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
107776
108282
|
if (pending2 != null && selfAgent) {
|
|
107777
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
108283
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join78(STATE_DIR, "clean-shutdown.json");
|
|
107778
108284
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
107779
108285
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
107780
108286
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -107981,7 +108487,7 @@ function checkApprovals() {
|
|
|
107981
108487
|
return;
|
|
107982
108488
|
}
|
|
107983
108489
|
for (const senderId of files) {
|
|
107984
|
-
const file =
|
|
108490
|
+
const file = join78(APPROVED_DIR, senderId);
|
|
107985
108491
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync9(file, { force: true }), (err) => {
|
|
107986
108492
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
107987
108493
|
`);
|
|
@@ -108159,7 +108665,7 @@ function noteAgentOutputAt(key, ts) {
|
|
|
108159
108665
|
lastAgentOutputAt.delete(oldest);
|
|
108160
108666
|
}
|
|
108161
108667
|
}
|
|
108162
|
-
var OBLIGATION_STORE_PATH =
|
|
108668
|
+
var OBLIGATION_STORE_PATH = join78(STATE_DIR, "obligations.json");
|
|
108163
108669
|
var obligationStoreFs = {
|
|
108164
108670
|
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
108165
108671
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
@@ -108928,7 +109434,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
108928
109434
|
},
|
|
108929
109435
|
rename: (from, to) => renameSync32(from, to)
|
|
108930
109436
|
});
|
|
108931
|
-
|
|
109437
|
+
appendFileSync12(turnsPath, rec);
|
|
108932
109438
|
} catch {}
|
|
108933
109439
|
}
|
|
108934
109440
|
function maybeProactiveCompact() {
|
|
@@ -110497,7 +111003,7 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
110497
111003
|
})();
|
|
110498
111004
|
var statusPinClaims = new Map;
|
|
110499
111005
|
var statusPinRightsCache = new PinRightsCache2;
|
|
110500
|
-
var STATUS_PIN_STORE_PATH =
|
|
111006
|
+
var STATUS_PIN_STORE_PATH = join78(STATE_DIR, "status-pins.json");
|
|
110501
111007
|
var statusPinStoreFs = {
|
|
110502
111008
|
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
110503
111009
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
@@ -110505,7 +111011,7 @@ var statusPinStoreFs = {
|
|
|
110505
111011
|
existsSync: (p) => existsSync65(p)
|
|
110506
111012
|
};
|
|
110507
111013
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
110508
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
111014
|
+
var ACTIVITY_CARD_STORE_PATH = join78(STATE_DIR, "activity-cards-pending.json");
|
|
110509
111015
|
var activityCardStoreFs = {
|
|
110510
111016
|
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
110511
111017
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
@@ -110513,7 +111019,7 @@ var activityCardStoreFs = {
|
|
|
110513
111019
|
existsSync: (p) => existsSync65(p)
|
|
110514
111020
|
};
|
|
110515
111021
|
var activityCardPersistEnabled = !STATIC;
|
|
110516
|
-
var QUEUED_CARD_STORE_PATH =
|
|
111022
|
+
var QUEUED_CARD_STORE_PATH = join78(STATE_DIR, "queued-cards-pending.json");
|
|
110517
111023
|
var queuedCardStoreFs = {
|
|
110518
111024
|
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
110519
111025
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
@@ -110801,7 +111307,7 @@ async function unpinAllStatusPins() {
|
|
|
110801
111307
|
}
|
|
110802
111308
|
}
|
|
110803
111309
|
var stalePinSweepEligible = false;
|
|
110804
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
111310
|
+
var STALE_PIN_SWEEP_STORE_PATH = join78(STATE_DIR, "stale-pin-sweep.json");
|
|
110805
111311
|
var sweepStoreFs = {
|
|
110806
111312
|
readFileSync: (p) => readFileSync67(p, "utf-8"),
|
|
110807
111313
|
writeFileSync: (p, data) => atomicWriteStateFileSync2(p, data, 384),
|
|
@@ -110842,12 +111348,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
110842
111348
|
var completeProgressCardTurn = null;
|
|
110843
111349
|
var subagentWatcher = null;
|
|
110844
111350
|
var workerActivityFeed = null;
|
|
110845
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
111351
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join78(STATE_DIR, "gateway.sock");
|
|
110846
111352
|
if (isGatewayMain)
|
|
110847
111353
|
mkdirStateSync2(STATE_DIR, { recursive: true, mode: 448 });
|
|
110848
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
110849
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
110850
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
111354
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join78(STATE_DIR, "gateway.pid.json");
|
|
111355
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join78(STATE_DIR, "gateway-session.json");
|
|
111356
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join78(STATE_DIR, "clean-shutdown.json");
|
|
110851
111357
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
110852
111358
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
110853
111359
|
var activeBootCard = null;
|
|
@@ -110877,7 +111383,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
110877
111383
|
bot: botApi,
|
|
110878
111384
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
110879
111385
|
`),
|
|
110880
|
-
persistPath:
|
|
111386
|
+
persistPath: join78(stateDir, "issues-card.json")
|
|
110881
111387
|
});
|
|
110882
111388
|
activeIssuesWatcher = startIssuesWatcher({
|
|
110883
111389
|
stateDir,
|
|
@@ -111082,7 +111588,7 @@ if (isGatewayMain)
|
|
|
111082
111588
|
var inboundSpool;
|
|
111083
111589
|
if (isGatewayMain)
|
|
111084
111590
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
111085
|
-
path:
|
|
111591
|
+
path: join78(STATE_DIR, "inbound-spool.jsonl"),
|
|
111086
111592
|
fs: {
|
|
111087
111593
|
appendFileSync: (p, d) => appendStateFileSync(p, d),
|
|
111088
111594
|
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
@@ -111153,7 +111659,7 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
111153
111659
|
let transcriptText;
|
|
111154
111660
|
try {
|
|
111155
111661
|
const projectsDir = getProjectsDirForCwd();
|
|
111156
|
-
const path3 =
|
|
111662
|
+
const path3 = join78(projectsDir, `${sessionId}.jsonl`);
|
|
111157
111663
|
if (!existsSync65(path3)) {
|
|
111158
111664
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
111159
111665
|
`);
|
|
@@ -111328,8 +111834,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
111328
111834
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
111329
111835
|
isShuttingDown: () => shuttingDown,
|
|
111330
111836
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
111331
|
-
crashLogPath:
|
|
111332
|
-
markerPath:
|
|
111837
|
+
crashLogPath: join78(STATE_DIR, "bridge-crash.log"),
|
|
111838
|
+
markerPath: join78(STATE_DIR, "bridge-dead-escalation.json"),
|
|
111333
111839
|
log: (line) => process.stderr.write(`${line}
|
|
111334
111840
|
`),
|
|
111335
111841
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -111436,8 +111942,8 @@ if (isGatewayMain)
|
|
|
111436
111942
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
111437
111943
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
111438
111944
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
111439
|
-
configSnapshotPath:
|
|
111440
|
-
bootCardStatePath:
|
|
111945
|
+
configSnapshotPath: join78(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
111946
|
+
bootCardStatePath: join78(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
111441
111947
|
floodStatePath: FLOOD_STATE_PATH,
|
|
111442
111948
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
111443
111949
|
}, ackMsgId).then((handle) => {
|
|
@@ -112071,7 +112577,7 @@ if (isGatewayMain)
|
|
|
112071
112577
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
112072
112578
|
if (Number.isInteger(receiverUid))
|
|
112073
112579
|
allowedUids.push(receiverUid);
|
|
112074
|
-
const socketPath =
|
|
112580
|
+
const socketPath = join78(STATE_DIR, "webhook.sock");
|
|
112075
112581
|
const webhookInject = (agentName3, inbound) => {
|
|
112076
112582
|
const msg = inbound;
|
|
112077
112583
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -112323,9 +112829,9 @@ function redactOutboundText(text5, site) {
|
|
|
112323
112829
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
112324
112830
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
112325
112831
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
112326
|
-
persistPath:
|
|
112832
|
+
persistPath: join78(STATE_DIR, "voice-ondemand.json")
|
|
112327
112833
|
});
|
|
112328
|
-
var VOICE_CACHE_DIR =
|
|
112834
|
+
var VOICE_CACHE_DIR = join78(STATE_DIR, "voice-cache");
|
|
112329
112835
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
112330
112836
|
runJob: async (job) => {
|
|
112331
112837
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -112733,7 +113239,7 @@ async function executeSendGif(rawArgs) {
|
|
|
112733
113239
|
};
|
|
112734
113240
|
}
|
|
112735
113241
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
112736
|
-
const accountPath =
|
|
113242
|
+
const accountPath = join78(STATE_DIR, "telegraph-account.json");
|
|
112737
113243
|
let account = null;
|
|
112738
113244
|
try {
|
|
112739
113245
|
if (existsSync65(accountPath)) {
|
|
@@ -114283,7 +114789,7 @@ function restartMarkerPath() {
|
|
|
114283
114789
|
const agentDir = resolveAgentDirFromEnv();
|
|
114284
114790
|
if (!agentDir)
|
|
114285
114791
|
return null;
|
|
114286
|
-
return
|
|
114792
|
+
return join78(agentDir, "restart-pending.json");
|
|
114287
114793
|
}
|
|
114288
114794
|
function writeRestartMarker(marker) {
|
|
114289
114795
|
const p = restartMarkerPath();
|
|
@@ -114475,7 +114981,7 @@ function _resetDockerReachableCache() {
|
|
|
114475
114981
|
}
|
|
114476
114982
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
114477
114983
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
114478
|
-
const logPath =
|
|
114984
|
+
const logPath = join78(STATE_DIR, "detached-spawn.log");
|
|
114479
114985
|
let outFd = null;
|
|
114480
114986
|
try {
|
|
114481
114987
|
mkdirStateSync2(STATE_DIR, { recursive: true });
|
|
@@ -114768,7 +115274,7 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
114768
115274
|
}
|
|
114769
115275
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
114770
115276
|
try {
|
|
114771
|
-
const auditPath =
|
|
115277
|
+
const auditPath = join78(homedir22(), ".switchroom", "vault-audit.log");
|
|
114772
115278
|
if (!existsSync65(auditPath))
|
|
114773
115279
|
return [];
|
|
114774
115280
|
const raw = readFileSync67(auditPath, "utf8");
|
|
@@ -114822,7 +115328,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
114822
115328
|
try {
|
|
114823
115329
|
const agentDir = resolveAgentDirFromEnv();
|
|
114824
115330
|
if (agentDir) {
|
|
114825
|
-
const raw = readFileSync67(
|
|
115331
|
+
const raw = readFileSync67(join78(agentDir, ".claude", ".claude.json"), "utf8");
|
|
114826
115332
|
claudeJson = JSON.parse(raw);
|
|
114827
115333
|
}
|
|
114828
115334
|
} catch {}
|
|
@@ -114951,7 +115457,7 @@ function buildModelDeps(restartCtx) {
|
|
|
114951
115457
|
try {
|
|
114952
115458
|
const agentDir = resolveAgentDirFromEnv();
|
|
114953
115459
|
if (agentDir) {
|
|
114954
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
115460
|
+
const local = await fetchQuota2({ claudeConfigDir: join78(agentDir, ".claude") });
|
|
114955
115461
|
if (local.ok)
|
|
114956
115462
|
return formatQuotaLine2(local.data);
|
|
114957
115463
|
}
|
|
@@ -115198,7 +115704,7 @@ function effortMenuReplyMarkup(reply) {
|
|
|
115198
115704
|
function flushAgentHandoff(agentDir) {
|
|
115199
115705
|
let removed = 0;
|
|
115200
115706
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
115201
|
-
const p =
|
|
115707
|
+
const p = join78(agentDir, fname);
|
|
115202
115708
|
try {
|
|
115203
115709
|
if (existsSync65(p)) {
|
|
115204
115710
|
unlinkSync33(p);
|
|
@@ -115256,7 +115762,7 @@ async function handleNewCommand(ctx) {
|
|
|
115256
115762
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
115257
115763
|
if (agentDir != null) {
|
|
115258
115764
|
try {
|
|
115259
|
-
writeFileSync55(
|
|
115765
|
+
writeFileSync55(join78(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
115260
115766
|
`, "utf8");
|
|
115261
115767
|
} catch (err) {
|
|
115262
115768
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -115373,7 +115879,7 @@ var lockoutOps = {
|
|
|
115373
115879
|
writeFileSync: (p, data, opts) => writeStateFileSync2(p, data, opts),
|
|
115374
115880
|
existsSync: (p) => existsSync65(p),
|
|
115375
115881
|
mkdirSync: (p, opts) => mkdirStateSync2(p, opts),
|
|
115376
|
-
joinPath: (...parts) =>
|
|
115882
|
+
joinPath: (...parts) => join78(...parts)
|
|
115377
115883
|
};
|
|
115378
115884
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
115379
115885
|
function isAuthBrokerSocketReachable() {
|
|
@@ -115634,7 +116140,7 @@ async function runCreditWatch() {
|
|
|
115634
116140
|
if (!agentDir)
|
|
115635
116141
|
return;
|
|
115636
116142
|
const agentName3 = getMyAgentName();
|
|
115637
|
-
const claudeConfigDir =
|
|
116143
|
+
const claudeConfigDir = join78(agentDir, ".claude");
|
|
115638
116144
|
const stateDir = STATE_DIR;
|
|
115639
116145
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
115640
116146
|
const prev = loadCreditState(stateDir);
|
|
@@ -117404,7 +117910,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
117404
117910
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
117405
117911
|
return;
|
|
117406
117912
|
}
|
|
117407
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
117913
|
+
const result = await fetchQuota2({ claudeConfigDir: join78(agentDir, ".claude") });
|
|
117408
117914
|
if (!result.ok) {
|
|
117409
117915
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
117410
117916
|
return;
|
|
@@ -118670,7 +119176,7 @@ async function startGateway() {
|
|
|
118670
119176
|
return;
|
|
118671
119177
|
}
|
|
118672
119178
|
})();
|
|
118673
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
119179
|
+
const resolvedAgentDirForBootCard = agentDir ?? join78(homedir22(), ".switchroom", "agents", agentSlug);
|
|
118674
119180
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
118675
119181
|
agentName: agentDisplayName,
|
|
118676
119182
|
agentSlug,
|
|
@@ -118684,8 +119190,8 @@ async function startGateway() {
|
|
|
118684
119190
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
118685
119191
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
118686
119192
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
118687
|
-
configSnapshotPath:
|
|
118688
|
-
bootCardStatePath:
|
|
119193
|
+
configSnapshotPath: join78(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
119194
|
+
bootCardStatePath: join78(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
118689
119195
|
floodStatePath: FLOOD_STATE_PATH,
|
|
118690
119196
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
118691
119197
|
}, ackMsgId);
|
|
@@ -118718,7 +119224,7 @@ async function startGateway() {
|
|
|
118718
119224
|
if (smAgentDir) {
|
|
118719
119225
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
118720
119226
|
const resolved = await waitForSessionModelResolution({
|
|
118721
|
-
barrierExists: () => existsSync65(
|
|
119227
|
+
barrierExists: () => existsSync65(join78(smAgentDir, ".session-model-resolved")),
|
|
118722
119228
|
timeoutMs: resolutionTimeoutMs
|
|
118723
119229
|
});
|
|
118724
119230
|
if (!resolved) {
|
|
@@ -118726,7 +119232,7 @@ async function startGateway() {
|
|
|
118726
119232
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
118727
119233
|
`);
|
|
118728
119234
|
} else {
|
|
118729
|
-
const activePath =
|
|
119235
|
+
const activePath = join78(smAgentDir, ".active-session-model");
|
|
118730
119236
|
if (existsSync65(activePath)) {
|
|
118731
119237
|
try {
|
|
118732
119238
|
const launched = readFileSync67(activePath, "utf8").trim();
|
|
@@ -118762,12 +119268,12 @@ async function startGateway() {
|
|
|
118762
119268
|
deliverModelSwitchBootNotice({
|
|
118763
119269
|
...modelBootCardDeps,
|
|
118764
119270
|
confirmation,
|
|
118765
|
-
hasSessionModelAlert: existsSync65(
|
|
119271
|
+
hasSessionModelAlert: existsSync65(join78(smAgentDir, ".session-model-alert"))
|
|
118766
119272
|
});
|
|
118767
119273
|
}
|
|
118768
119274
|
} catch {}
|
|
118769
119275
|
}
|
|
118770
|
-
const activeEffortPath =
|
|
119276
|
+
const activeEffortPath = join78(smAgentDir, ".active-session-effort");
|
|
118771
119277
|
if (existsSync65(activeEffortPath)) {
|
|
118772
119278
|
try {
|
|
118773
119279
|
const launchedEffort = readFileSync67(activeEffortPath, "utf8").trim();
|
|
@@ -118775,7 +119281,7 @@ async function startGateway() {
|
|
|
118775
119281
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
118776
119282
|
} catch {}
|
|
118777
119283
|
}
|
|
118778
|
-
const alertPath =
|
|
119284
|
+
const alertPath = join78(smAgentDir, ".session-model-alert");
|
|
118779
119285
|
if (existsSync65(alertPath)) {
|
|
118780
119286
|
let alertText = null;
|
|
118781
119287
|
try {
|