switchroom 0.13.57 → 0.13.59
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 +451 -343
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +611 -759
- package/telegram-plugin/gateway/gateway.ts +191 -92
- package/telegram-plugin/tests/tool-activity-summary.test.ts +191 -0
- package/telegram-plugin/tool-activity-summary.ts +164 -0
- package/telegram-plugin/tests/tool-intent-surface.test.ts +0 -128
- package/telegram-plugin/tool-intent-surface.ts +0 -155
|
@@ -16334,10 +16334,10 @@ __export(exports_client, {
|
|
|
16334
16334
|
AuthBrokerClient: () => AuthBrokerClient
|
|
16335
16335
|
});
|
|
16336
16336
|
import * as net from "node:net";
|
|
16337
|
-
import { existsSync as
|
|
16337
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
16338
16338
|
import { homedir as homedir3 } from "node:os";
|
|
16339
16339
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
16340
|
-
import { join as
|
|
16340
|
+
import { join as join8 } from "node:path";
|
|
16341
16341
|
function reviveDate(v) {
|
|
16342
16342
|
if (v == null)
|
|
16343
16343
|
return null;
|
|
@@ -16347,7 +16347,7 @@ function reviveDate(v) {
|
|
|
16347
16347
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
16348
16348
|
}
|
|
16349
16349
|
function operatorSocketPath(home = homedir3()) {
|
|
16350
|
-
return
|
|
16350
|
+
return join8(home, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
16351
16351
|
}
|
|
16352
16352
|
function resolveAuthBrokerSocketPath(opts) {
|
|
16353
16353
|
if (opts?.socket)
|
|
@@ -16617,7 +16617,7 @@ async function withAuthBrokerClient(fn, opts) {
|
|
|
16617
16617
|
}
|
|
16618
16618
|
}
|
|
16619
16619
|
function authBrokerSocketExists(opts) {
|
|
16620
|
-
return
|
|
16620
|
+
return existsSync6(resolveAuthBrokerSocketPath(opts));
|
|
16621
16621
|
}
|
|
16622
16622
|
var DEFAULT_TIMEOUT_MS = 5000, AuthBrokerError, AuthBrokerUnreachableError;
|
|
16623
16623
|
var init_client = __esm(() => {
|
|
@@ -24109,7 +24109,7 @@ var init_schema = __esm(() => {
|
|
|
24109
24109
|
});
|
|
24110
24110
|
|
|
24111
24111
|
// ../src/config/paths.ts
|
|
24112
|
-
import { existsSync as
|
|
24112
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
24113
24113
|
import { resolve as resolve2 } from "node:path";
|
|
24114
24114
|
function home() {
|
|
24115
24115
|
return process.env.HOME ?? "/root";
|
|
@@ -24128,9 +24128,9 @@ function resolveDualPath(pathStr) {
|
|
|
24128
24128
|
const absolute = resolve2(h, rest);
|
|
24129
24129
|
if (rest.startsWith(`${DEFAULT_STATE_DIR}/`)) {
|
|
24130
24130
|
const frag = rest.slice(DEFAULT_STATE_DIR.length + 1);
|
|
24131
|
-
if (!
|
|
24131
|
+
if (!existsSync7(absolute)) {
|
|
24132
24132
|
const legacy = resolve2(h, LEGACY_STATE_DIR, frag);
|
|
24133
|
-
if (
|
|
24133
|
+
if (existsSync7(legacy)) {
|
|
24134
24134
|
warnLegacyStateOnce(legacy);
|
|
24135
24135
|
return legacy;
|
|
24136
24136
|
}
|
|
@@ -24155,14 +24155,14 @@ var init_overlay_schema = __esm(() => {
|
|
|
24155
24155
|
});
|
|
24156
24156
|
|
|
24157
24157
|
// ../src/config/overlay-loader.ts
|
|
24158
|
-
import { existsSync as
|
|
24158
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4, readdirSync, statSync as statSync2 } from "node:fs";
|
|
24159
24159
|
import { resolve as resolve3 } from "node:path";
|
|
24160
24160
|
function overlayDirFor(agentName3, subdir) {
|
|
24161
24161
|
const base = resolveDualPath(`~/.switchroom/agents/${agentName3}/${subdir}`);
|
|
24162
24162
|
return resolve3(base);
|
|
24163
24163
|
}
|
|
24164
24164
|
function listYamlFiles(dir) {
|
|
24165
|
-
if (!
|
|
24165
|
+
if (!existsSync8(dir))
|
|
24166
24166
|
return [];
|
|
24167
24167
|
let entries;
|
|
24168
24168
|
try {
|
|
@@ -24619,7 +24619,7 @@ function validateNotionWorkspaceConfig(config) {
|
|
|
24619
24619
|
}
|
|
24620
24620
|
|
|
24621
24621
|
// ../src/config/loader.ts
|
|
24622
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
24622
|
+
import { readFileSync as readFileSync5, existsSync as existsSync9 } from "node:fs";
|
|
24623
24623
|
import { homedir as homedir5 } from "node:os";
|
|
24624
24624
|
import { resolve as resolve4 } from "node:path";
|
|
24625
24625
|
function formatZodErrors(error) {
|
|
@@ -24686,7 +24686,7 @@ function findConfigFile(startDir) {
|
|
|
24686
24686
|
resolve4(userDir, "clerk.yml")
|
|
24687
24687
|
].filter(Boolean);
|
|
24688
24688
|
for (const path of searchPaths) {
|
|
24689
|
-
if (
|
|
24689
|
+
if (existsSync9(path)) {
|
|
24690
24690
|
return path;
|
|
24691
24691
|
}
|
|
24692
24692
|
}
|
|
@@ -24694,7 +24694,7 @@ function findConfigFile(startDir) {
|
|
|
24694
24694
|
}
|
|
24695
24695
|
function loadConfig(configPath) {
|
|
24696
24696
|
const filePath = configPath ?? findConfigFile();
|
|
24697
|
-
if (!
|
|
24697
|
+
if (!existsSync9(filePath)) {
|
|
24698
24698
|
throw new ConfigError(`Config file not found: ${filePath}`);
|
|
24699
24699
|
}
|
|
24700
24700
|
let raw;
|
|
@@ -24802,7 +24802,7 @@ __export(exports_history, {
|
|
|
24802
24802
|
_resetForTests: () => _resetForTests
|
|
24803
24803
|
});
|
|
24804
24804
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
24805
|
-
import { join as
|
|
24805
|
+
import { join as join11 } from "path";
|
|
24806
24806
|
function loadDatabaseClass() {
|
|
24807
24807
|
if (DatabaseClass != null)
|
|
24808
24808
|
return DatabaseClass;
|
|
@@ -24825,7 +24825,7 @@ function initHistory(stateDir, retentionDays = 30) {
|
|
|
24825
24825
|
return;
|
|
24826
24826
|
const Database = loadDatabaseClass();
|
|
24827
24827
|
mkdirSync9(stateDir, { recursive: true, mode: 448 });
|
|
24828
|
-
const path =
|
|
24828
|
+
const path = join11(stateDir, "history.db");
|
|
24829
24829
|
db = new Database(path, { create: true });
|
|
24830
24830
|
db.exec("PRAGMA journal_mode = WAL");
|
|
24831
24831
|
db.exec("PRAGMA synchronous = NORMAL");
|
|
@@ -25015,11 +25015,11 @@ var DatabaseClass = null, DEFAULT_LIMIT = 10, MAX_LIMIT = 50, db = null;
|
|
|
25015
25015
|
var init_history = () => {};
|
|
25016
25016
|
|
|
25017
25017
|
// quota-check.ts
|
|
25018
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
25019
|
-
import { join as
|
|
25018
|
+
import { readFileSync as readFileSync8, existsSync as existsSync12 } from "fs";
|
|
25019
|
+
import { join as join12 } from "path";
|
|
25020
25020
|
function readOauthToken(claudeConfigDir) {
|
|
25021
|
-
const tokenFile =
|
|
25022
|
-
if (!
|
|
25021
|
+
const tokenFile = join12(claudeConfigDir, ".oauth-token");
|
|
25022
|
+
if (!existsSync12(tokenFile))
|
|
25023
25023
|
return null;
|
|
25024
25024
|
try {
|
|
25025
25025
|
const raw = readFileSync8(tokenFile, "utf-8").trim();
|
|
@@ -25501,7 +25501,7 @@ function isDockerRuntime() {
|
|
|
25501
25501
|
import * as net3 from "node:net";
|
|
25502
25502
|
import * as fs from "node:fs";
|
|
25503
25503
|
import { homedir as homedir7 } from "node:os";
|
|
25504
|
-
import { join as
|
|
25504
|
+
import { join as join16 } from "node:path";
|
|
25505
25505
|
function defaultBrokerSocketPath() {
|
|
25506
25506
|
if (fs.existsSync(OPERATOR_SOCKET_PATH))
|
|
25507
25507
|
return OPERATOR_SOCKET_PATH;
|
|
@@ -25510,7 +25510,7 @@ function defaultBrokerSocketPath() {
|
|
|
25510
25510
|
return LEGACY_SOCKET_PATH;
|
|
25511
25511
|
}
|
|
25512
25512
|
function vaultTokenFilePath(agentSlug) {
|
|
25513
|
-
return
|
|
25513
|
+
return join16(homedir7(), ".switchroom", "agents", agentSlug, ".vault-token");
|
|
25514
25514
|
}
|
|
25515
25515
|
function readVaultTokenFile(agentSlug) {
|
|
25516
25516
|
const filePath = vaultTokenFilePath(agentSlug);
|
|
@@ -25665,8 +25665,8 @@ var DEFAULT_TIMEOUT_MS3 = 2000, LEGACY_SOCKET_PATH, OPERATOR_SOCKET_PATH;
|
|
|
25665
25665
|
var init_client2 = __esm(() => {
|
|
25666
25666
|
init_protocol2();
|
|
25667
25667
|
init_peercred();
|
|
25668
|
-
LEGACY_SOCKET_PATH =
|
|
25669
|
-
OPERATOR_SOCKET_PATH =
|
|
25668
|
+
LEGACY_SOCKET_PATH = join16(homedir7(), ".switchroom", "vault-broker.sock");
|
|
25669
|
+
OPERATOR_SOCKET_PATH = join16(homedir7(), ".switchroom", "broker-operator", "sock");
|
|
25670
25670
|
});
|
|
25671
25671
|
|
|
25672
25672
|
// ../src/drive/deep-links.ts
|
|
@@ -27779,15 +27779,15 @@ var init_secretlint_source = __esm(() => {
|
|
|
27779
27779
|
});
|
|
27780
27780
|
|
|
27781
27781
|
// card-format.ts
|
|
27782
|
-
function
|
|
27782
|
+
function escapeHtml8(s) {
|
|
27783
27783
|
return s.replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" })[c]);
|
|
27784
27784
|
}
|
|
27785
|
-
function
|
|
27785
|
+
function truncate5(s, n) {
|
|
27786
27786
|
return s.length > n ? s.slice(0, n - 1) + "\u2026" : s;
|
|
27787
27787
|
}
|
|
27788
27788
|
|
|
27789
27789
|
// gateway/auth-line.ts
|
|
27790
|
-
function
|
|
27790
|
+
function escapeHtml9(s) {
|
|
27791
27791
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
27792
27792
|
}
|
|
27793
27793
|
function formatRelativeMs2(ms) {
|
|
@@ -27847,7 +27847,7 @@ function renderAuthLine(state4, agentName3, now = Date.now()) {
|
|
|
27847
27847
|
if (!acc)
|
|
27848
27848
|
continue;
|
|
27849
27849
|
const marker = label === activeLabel ? "\u25b6" : "\u21b3";
|
|
27850
|
-
const labelHtml = `<code>${
|
|
27850
|
+
const labelHtml = `<code>${escapeHtml9(acc.label)}</code>`;
|
|
27851
27851
|
const quotaLine = formatAuthQuotaLine(acc, now);
|
|
27852
27852
|
rows.push(quotaLine ? `${marker} ${labelHtml} ${quotaLine}` : `${marker} ${labelHtml}`);
|
|
27853
27853
|
}
|
|
@@ -27855,15 +27855,15 @@ function renderAuthLine(state4, agentName3, now = Date.now()) {
|
|
|
27855
27855
|
}
|
|
27856
27856
|
|
|
27857
27857
|
// gateway/quota-cache.ts
|
|
27858
|
-
import { existsSync as
|
|
27859
|
-
import { join as
|
|
27858
|
+
import { existsSync as existsSync23, readFileSync as readFileSync22, writeFileSync as writeFileSync13, mkdirSync as mkdirSync11 } from "fs";
|
|
27859
|
+
import { join as join20, dirname as dirname8 } from "path";
|
|
27860
27860
|
function defaultCachePath() {
|
|
27861
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
27861
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join20(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
27862
27862
|
}
|
|
27863
27863
|
function readQuotaCache(opts = {}) {
|
|
27864
27864
|
const path = opts.path ?? defaultCachePath();
|
|
27865
27865
|
const now = opts.now ?? Date.now();
|
|
27866
|
-
if (!
|
|
27866
|
+
if (!existsSync23(path))
|
|
27867
27867
|
return null;
|
|
27868
27868
|
let entry;
|
|
27869
27869
|
try {
|
|
@@ -27904,8 +27904,8 @@ var init_quota_cache = __esm(() => {
|
|
|
27904
27904
|
});
|
|
27905
27905
|
|
|
27906
27906
|
// gateway/boot-probes.ts
|
|
27907
|
-
import { readFileSync as readFileSync23, readdirSync as readdirSync4, existsSync as
|
|
27908
|
-
import { join as
|
|
27907
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync4, existsSync as existsSync24 } from "fs";
|
|
27908
|
+
import { join as join21 } from "path";
|
|
27909
27909
|
import { execFile as execFileCb } from "child_process";
|
|
27910
27910
|
import { promisify as promisify3 } from "util";
|
|
27911
27911
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -27947,8 +27947,8 @@ function mapPlan(billingType, hasExtra) {
|
|
|
27947
27947
|
}
|
|
27948
27948
|
async function probeAccount(agentDir) {
|
|
27949
27949
|
return withTimeout("Account", (async () => {
|
|
27950
|
-
const claudeDir =
|
|
27951
|
-
const claudeJsonPath =
|
|
27950
|
+
const claudeDir = join21(agentDir, ".claude");
|
|
27951
|
+
const claudeJsonPath = join21(claudeDir, ".claude.json");
|
|
27952
27952
|
let cfg = {};
|
|
27953
27953
|
try {
|
|
27954
27954
|
const raw = readFileSync23(claudeJsonPath, "utf8");
|
|
@@ -27969,10 +27969,10 @@ async function probeAccount(agentDir) {
|
|
|
27969
27969
|
let tokenStr = "";
|
|
27970
27970
|
let status = "ok";
|
|
27971
27971
|
for (const candidate of [
|
|
27972
|
-
|
|
27973
|
-
|
|
27972
|
+
join21(claudeDir, ".oauth-token.meta.json"),
|
|
27973
|
+
join21(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
27974
27974
|
]) {
|
|
27975
|
-
if (
|
|
27975
|
+
if (existsSync24(candidate)) {
|
|
27976
27976
|
try {
|
|
27977
27977
|
const meta = JSON.parse(readFileSync23(candidate, "utf8"));
|
|
27978
27978
|
if (meta.expiresAt) {
|
|
@@ -28149,7 +28149,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
28149
28149
|
if (!cgroup)
|
|
28150
28150
|
return null;
|
|
28151
28151
|
const procsPath = `/sys/fs/cgroup${cgroup}/cgroup.procs`;
|
|
28152
|
-
if (!
|
|
28152
|
+
if (!existsSync24(procsPath))
|
|
28153
28153
|
return null;
|
|
28154
28154
|
const pidsRaw = readFileSync23(procsPath, "utf-8");
|
|
28155
28155
|
const pids = pidsRaw.split(`
|
|
@@ -28356,9 +28356,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
28356
28356
|
let claudeDirForProbe = null;
|
|
28357
28357
|
for (const candidate of [
|
|
28358
28358
|
claudeConfigDir,
|
|
28359
|
-
|
|
28359
|
+
join21(claudeConfigDir, "accounts", "default")
|
|
28360
28360
|
]) {
|
|
28361
|
-
if (
|
|
28361
|
+
if (existsSync24(join21(candidate, ".oauth-token"))) {
|
|
28362
28362
|
claudeDirForProbe = candidate;
|
|
28363
28363
|
break;
|
|
28364
28364
|
}
|
|
@@ -28529,7 +28529,7 @@ async function probeUds(label, socketPath, opts = {}) {
|
|
|
28529
28529
|
}
|
|
28530
28530
|
return withTimeout(label, (async () => {
|
|
28531
28531
|
if (!opts.connectImpl) {
|
|
28532
|
-
if (!
|
|
28532
|
+
if (!existsSync24(socketPath)) {
|
|
28533
28533
|
return {
|
|
28534
28534
|
status: "fail",
|
|
28535
28535
|
label,
|
|
@@ -28593,7 +28593,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
28593
28593
|
return withTimeout("Skills", (async () => {
|
|
28594
28594
|
const fs2 = opts.fs ?? realSkillsFs;
|
|
28595
28595
|
const max = opts.maxNamesShown ?? 3;
|
|
28596
|
-
const skillsDir =
|
|
28596
|
+
const skillsDir = join21(agentDir, ".claude", "skills");
|
|
28597
28597
|
if (!fs2.exists(skillsDir)) {
|
|
28598
28598
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
28599
28599
|
}
|
|
@@ -28608,17 +28608,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
28608
28608
|
}
|
|
28609
28609
|
const dangling = [];
|
|
28610
28610
|
for (const name of entries) {
|
|
28611
|
-
const skillPath =
|
|
28611
|
+
const skillPath = join21(skillsDir, name);
|
|
28612
28612
|
if (!fs2.exists(skillPath)) {
|
|
28613
28613
|
dangling.push(name);
|
|
28614
28614
|
continue;
|
|
28615
28615
|
}
|
|
28616
|
-
const skillMd =
|
|
28616
|
+
const skillMd = join21(skillPath, "SKILL.md");
|
|
28617
28617
|
if (!fs2.exists(skillMd) && !fs2.exists(skillPath + ".md")) {
|
|
28618
28618
|
continue;
|
|
28619
28619
|
}
|
|
28620
28620
|
}
|
|
28621
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
28621
|
+
const overlayDir = opts.overlaySkillsDir ?? join21(agentDir, "skills.d");
|
|
28622
28622
|
const overlaySlugs = new Set;
|
|
28623
28623
|
if (fs2.exists(overlayDir)) {
|
|
28624
28624
|
let overlayEntries = [];
|
|
@@ -28673,16 +28673,16 @@ var init_boot_probes = __esm(() => {
|
|
|
28673
28673
|
const { statSync: statSync7 } = __require("fs");
|
|
28674
28674
|
return statSync7(p).mtimeMs;
|
|
28675
28675
|
},
|
|
28676
|
-
exists: (p) =>
|
|
28676
|
+
exists: (p) => existsSync24(p)
|
|
28677
28677
|
};
|
|
28678
28678
|
realSkillsFs = {
|
|
28679
28679
|
readdir: (p) => readdirSync4(p),
|
|
28680
|
-
exists: (p) =>
|
|
28680
|
+
exists: (p) => existsSync24(p)
|
|
28681
28681
|
};
|
|
28682
28682
|
});
|
|
28683
28683
|
|
|
28684
28684
|
// gateway/boot-issue-cache.ts
|
|
28685
|
-
import { existsSync as
|
|
28685
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync12, renameSync as renameSync9 } from "fs";
|
|
28686
28686
|
import { dirname as dirname9 } from "path";
|
|
28687
28687
|
function fingerprintProbe(key, r) {
|
|
28688
28688
|
if (r.status === "ok")
|
|
@@ -28762,7 +28762,7 @@ function diffProbes(probes, cache, opts = {}) {
|
|
|
28762
28762
|
return out;
|
|
28763
28763
|
}
|
|
28764
28764
|
function loadCache(path, now = Date.now) {
|
|
28765
|
-
if (!
|
|
28765
|
+
if (!existsSync25(path))
|
|
28766
28766
|
return { ...EMPTY_CACHE, probes: {} };
|
|
28767
28767
|
let raw;
|
|
28768
28768
|
try {
|
|
@@ -28833,7 +28833,7 @@ __export(exports_boot_card, {
|
|
|
28833
28833
|
renderBootCard: () => renderBootCard,
|
|
28834
28834
|
renderAccountRows: () => renderAuthLine
|
|
28835
28835
|
});
|
|
28836
|
-
import { join as
|
|
28836
|
+
import { join as join22 } from "path";
|
|
28837
28837
|
function resolvePersonaName(slug, loadConfig3) {
|
|
28838
28838
|
try {
|
|
28839
28839
|
const config = loadConfig3 ? loadConfig3() : loadConfig();
|
|
@@ -28858,14 +28858,14 @@ function shouldSkipDuplicateBootCard(gate, site) {
|
|
|
28858
28858
|
function renderNextStep(text) {
|
|
28859
28859
|
const parts = text.split("`");
|
|
28860
28860
|
if (parts.length % 2 === 0)
|
|
28861
|
-
return
|
|
28862
|
-
return parts.map((p, i) => i % 2 === 0 ?
|
|
28861
|
+
return escapeHtml8(text);
|
|
28862
|
+
return parts.map((p, i) => i % 2 === 0 ? escapeHtml8(p) : `<code>${escapeHtml8(p)}</code>`).join("");
|
|
28863
28863
|
}
|
|
28864
28864
|
function renderBootCard(opts) {
|
|
28865
28865
|
const { agentName: agentName3, version: version2, probes, restartReason, restartAgeMs } = opts;
|
|
28866
28866
|
const agentSlug = opts.agentSlug ?? agentName3;
|
|
28867
28867
|
const ackEmoji = restartReason ? REASON_EMOJI[restartReason] : "\u2705";
|
|
28868
|
-
const ack = `${ackEmoji} <b>${
|
|
28868
|
+
const ack = `${ackEmoji} <b>${escapeHtml8(agentName3)}</b> back up \u00b7 ${escapeHtml8(version2)}`;
|
|
28869
28869
|
const degradedRows = [];
|
|
28870
28870
|
const snoozeSet = new Set(opts.snoozeRows ?? []);
|
|
28871
28871
|
if (opts.resolvedRows && opts.resolvedRows.length > 0) {
|
|
@@ -28873,13 +28873,13 @@ function renderBootCard(opts) {
|
|
|
28873
28873
|
const lbl = PROBE_LABELS[key];
|
|
28874
28874
|
if (!lbl)
|
|
28875
28875
|
continue;
|
|
28876
|
-
degradedRows.push(`\u2705 <b>${
|
|
28876
|
+
degradedRows.push(`\u2705 <b>${escapeHtml8(lbl)}</b> resolved`);
|
|
28877
28877
|
}
|
|
28878
28878
|
}
|
|
28879
28879
|
if (restartReason === "crash") {
|
|
28880
28880
|
const ageStr = restartAgeMs != null && restartAgeMs > 0 ? ` \u00b7 ${(restartAgeMs / 1000).toFixed(1)}s ago` : "";
|
|
28881
|
-
degradedRows.push(`\u26a0\ufe0f <b>Restart</b> ${
|
|
28882
|
-
const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${
|
|
28881
|
+
degradedRows.push(`\u26a0\ufe0f <b>Restart</b> ${escapeHtml8(REASON_LABEL.crash)}${ageStr}`);
|
|
28882
|
+
const tailCmd = process.env.SWITCHROOM_RUNTIME === "docker" ? `docker logs --tail 100 switchroom-${escapeHtml8(agentSlug)}` : `journalctl --user -u switchroom-${escapeHtml8(agentSlug)} -n 100`;
|
|
28883
28883
|
degradedRows.push(` \u21b3 Tail logs: <code>${tailCmd}</code>`);
|
|
28884
28884
|
}
|
|
28885
28885
|
if (probes) {
|
|
@@ -28892,7 +28892,7 @@ function renderBootCard(opts) {
|
|
|
28892
28892
|
if (snoozeSet.has(key))
|
|
28893
28893
|
continue;
|
|
28894
28894
|
const dot = DOT[r.status] ?? DOT.fail;
|
|
28895
|
-
degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${
|
|
28895
|
+
degradedRows.push(`${dot} <b>${PROBE_LABELS[key]}</b> ${escapeHtml8(r.detail)}`);
|
|
28896
28896
|
if (r.nextStep) {
|
|
28897
28897
|
degradedRows.push(` \u21b3 ${renderNextStep(r.nextStep)}`);
|
|
28898
28898
|
}
|
|
@@ -28914,7 +28914,7 @@ function renderBootCard(opts) {
|
|
|
28914
28914
|
`);
|
|
28915
28915
|
}
|
|
28916
28916
|
async function runAllProbes(opts) {
|
|
28917
|
-
const claudeDir =
|
|
28917
|
+
const claudeDir = join22(opts.agentDir, ".claude");
|
|
28918
28918
|
const probes = {};
|
|
28919
28919
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
28920
28920
|
await Promise.allSettled([
|
|
@@ -29158,10 +29158,10 @@ import { randomBytes as randomBytes5, scryptSync, createCipheriv, createDecipher
|
|
|
29158
29158
|
import {
|
|
29159
29159
|
readFileSync as readFileSync31,
|
|
29160
29160
|
writeFileSync as writeFileSync19,
|
|
29161
|
-
existsSync as
|
|
29161
|
+
existsSync as existsSync32,
|
|
29162
29162
|
renameSync as renameSync11,
|
|
29163
29163
|
mkdirSync as mkdirSync18,
|
|
29164
|
-
unlinkSync as
|
|
29164
|
+
unlinkSync as unlinkSync12,
|
|
29165
29165
|
lstatSync,
|
|
29166
29166
|
realpathSync
|
|
29167
29167
|
} from "node:fs";
|
|
@@ -29196,7 +29196,7 @@ function normalizeSecrets(raw) {
|
|
|
29196
29196
|
return out;
|
|
29197
29197
|
}
|
|
29198
29198
|
function openVault(passphrase, vaultPath) {
|
|
29199
|
-
if (!
|
|
29199
|
+
if (!existsSync32(vaultPath)) {
|
|
29200
29200
|
throw new VaultError(`Vault file not found: ${vaultPath}`);
|
|
29201
29201
|
}
|
|
29202
29202
|
let vaultFile;
|
|
@@ -29247,15 +29247,15 @@ var init_vault = __esm(() => {
|
|
|
29247
29247
|
// ../src/vault/resolver.ts
|
|
29248
29248
|
import {
|
|
29249
29249
|
chmodSync as chmodSync4,
|
|
29250
|
-
closeSync as
|
|
29250
|
+
closeSync as closeSync7,
|
|
29251
29251
|
mkdirSync as mkdirSync19,
|
|
29252
29252
|
mkdtempSync as mkdtempSync2,
|
|
29253
|
-
openSync as
|
|
29253
|
+
openSync as openSync7,
|
|
29254
29254
|
rmSync as rmSync3,
|
|
29255
29255
|
statSync as statSync11,
|
|
29256
29256
|
writeSync as writeSync2
|
|
29257
29257
|
} from "node:fs";
|
|
29258
|
-
import { join as
|
|
29258
|
+
import { join as join31 } from "node:path";
|
|
29259
29259
|
import { tmpdir } from "node:os";
|
|
29260
29260
|
import { constants as fsConstants } from "node:fs";
|
|
29261
29261
|
function isVaultReference(value) {
|
|
@@ -29307,26 +29307,26 @@ function materializationRoot() {
|
|
|
29307
29307
|
return cachedRoot;
|
|
29308
29308
|
const xdg = process.env.XDG_RUNTIME_DIR;
|
|
29309
29309
|
if (xdg) {
|
|
29310
|
-
const base =
|
|
29310
|
+
const base = join31(xdg, "switchroom", "vault");
|
|
29311
29311
|
mkdirSync19(base, { recursive: true, mode: 448 });
|
|
29312
|
-
cachedRoot = mkdtempSync2(
|
|
29312
|
+
cachedRoot = mkdtempSync2(join31(base, "run-"));
|
|
29313
29313
|
} else {
|
|
29314
|
-
cachedRoot = mkdtempSync2(
|
|
29314
|
+
cachedRoot = mkdtempSync2(join31(tmpdir(), "switchroom-vault-"));
|
|
29315
29315
|
}
|
|
29316
29316
|
chmodSync4(cachedRoot, 448);
|
|
29317
29317
|
return cachedRoot;
|
|
29318
29318
|
}
|
|
29319
29319
|
function writeFileExclusive(filePath, content) {
|
|
29320
29320
|
const buf = typeof content === "string" ? Buffer.from(content, "utf8") : content;
|
|
29321
|
-
const fd =
|
|
29321
|
+
const fd = openSync7(filePath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 384);
|
|
29322
29322
|
try {
|
|
29323
29323
|
writeSync2(fd, buf);
|
|
29324
29324
|
} finally {
|
|
29325
|
-
|
|
29325
|
+
closeSync7(fd);
|
|
29326
29326
|
}
|
|
29327
29327
|
}
|
|
29328
29328
|
function materializeFilesEntry(key, files) {
|
|
29329
|
-
const dir =
|
|
29329
|
+
const dir = join31(materializationRoot(), key);
|
|
29330
29330
|
if (materializedDirs.has(dir)) {
|
|
29331
29331
|
try {
|
|
29332
29332
|
rmSync3(dir, { recursive: true, force: true });
|
|
@@ -29342,7 +29342,7 @@ function materializeFilesEntry(key, files) {
|
|
|
29342
29342
|
if (filename.includes("/") || filename.includes("\\") || filename === ".." || filename === "." || filename.includes("\x00")) {
|
|
29343
29343
|
throw new Error(`Refusing to materialize vault file with unsafe name: ${filename}`);
|
|
29344
29344
|
}
|
|
29345
|
-
const filePath =
|
|
29345
|
+
const filePath = join31(dir, filename);
|
|
29346
29346
|
const content = encoding === "base64" ? Buffer.from(value, "base64") : value;
|
|
29347
29347
|
writeFileExclusive(filePath, content);
|
|
29348
29348
|
}
|
|
@@ -29475,7 +29475,7 @@ __export(exports_materialize_bot_token, {
|
|
|
29475
29475
|
materializeBotToken: () => materializeBotToken,
|
|
29476
29476
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
29477
29477
|
});
|
|
29478
|
-
import { existsSync as
|
|
29478
|
+
import { existsSync as existsSync33 } from "node:fs";
|
|
29479
29479
|
function pickConfiguredToken(config, agentName3) {
|
|
29480
29480
|
if (agentName3) {
|
|
29481
29481
|
const agent = config.agents?.[agentName3];
|
|
@@ -29489,7 +29489,7 @@ function tryDirectVaultRead(ref, config, passphrase) {
|
|
|
29489
29489
|
if (!passphrase)
|
|
29490
29490
|
return null;
|
|
29491
29491
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
29492
|
-
if (!
|
|
29492
|
+
if (!existsSync33(vaultPath))
|
|
29493
29493
|
return null;
|
|
29494
29494
|
try {
|
|
29495
29495
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -29607,7 +29607,7 @@ function truncateDiffForCard(unifiedDiff, maxLines = 50, maxChars = 3000) {
|
|
|
29607
29607
|
}
|
|
29608
29608
|
return out === unifiedDiff ? out : out + sentinel;
|
|
29609
29609
|
}
|
|
29610
|
-
function
|
|
29610
|
+
function escapeHtml11(s) {
|
|
29611
29611
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
29612
29612
|
}
|
|
29613
29613
|
function clipReason(reason) {
|
|
@@ -29618,10 +29618,10 @@ function clipReason(reason) {
|
|
|
29618
29618
|
function buildConfigApprovalCardBody(args) {
|
|
29619
29619
|
const safeReason = clipReason(args.reason);
|
|
29620
29620
|
const render = (diff) => `\uD83D\uDEE0 <b>Config edit proposed</b>
|
|
29621
|
-
` + `Agent: <code>${
|
|
29622
|
-
` + `Reason: ${
|
|
29621
|
+
` + `Agent: <code>${escapeHtml11(args.agentName)}</code>
|
|
29622
|
+
` + `Reason: ${escapeHtml11(safeReason)}
|
|
29623
29623
|
|
|
29624
|
-
` + `<pre>${
|
|
29624
|
+
` + `<pre>${escapeHtml11(diff)}</pre>`;
|
|
29625
29625
|
return truncateRawToFit({
|
|
29626
29626
|
raw: args.unifiedDiff,
|
|
29627
29627
|
render,
|
|
@@ -29728,8 +29728,8 @@ async function handleRequestConfigFinalize(_client, msg, deps) {
|
|
|
29728
29728
|
}
|
|
29729
29729
|
pending.delete(msg.requestId);
|
|
29730
29730
|
const body = msg.outcome === "applied" ? `\u2705 <b>Applied</b>${msg.detail ? `
|
|
29731
|
-
${
|
|
29732
|
-
${
|
|
29731
|
+
${escapeHtml11(msg.detail)}` : ""}` : `\u26a0\ufe0f <b>Reconcile failed; rolled back</b>${msg.detail ? `
|
|
29732
|
+
${escapeHtml11(msg.detail)}` : ""}`;
|
|
29733
29733
|
try {
|
|
29734
29734
|
await deps.editCard({
|
|
29735
29735
|
chatId: entry.chatId,
|
|
@@ -29794,7 +29794,7 @@ __export(exports_tmux, {
|
|
|
29794
29794
|
captureAgentPane: () => captureAgentPane
|
|
29795
29795
|
});
|
|
29796
29796
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
29797
|
-
import { mkdirSync as mkdirSync20, readdirSync as readdirSync6, statSync as statSync12, unlinkSync as
|
|
29797
|
+
import { mkdirSync as mkdirSync20, readdirSync as readdirSync6, statSync as statSync12, unlinkSync as unlinkSync13, writeFileSync as writeFileSync20 } from "node:fs";
|
|
29798
29798
|
import { resolve as resolve7 } from "node:path";
|
|
29799
29799
|
function captureAgentPane(opts) {
|
|
29800
29800
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -29908,7 +29908,7 @@ function pruneOldReports(dir, retain) {
|
|
|
29908
29908
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
29909
29909
|
for (const stale of files.slice(retain)) {
|
|
29910
29910
|
try {
|
|
29911
|
-
|
|
29911
|
+
unlinkSync13(stale.full);
|
|
29912
29912
|
} catch {}
|
|
29913
29913
|
}
|
|
29914
29914
|
}
|
|
@@ -29999,17 +29999,17 @@ function registerApprovalsCommands(bot, opts) {
|
|
|
29999
29999
|
return;
|
|
30000
30000
|
}
|
|
30001
30001
|
if (decisions.length === 0) {
|
|
30002
|
-
await ctx.reply(agentFilter ? `No active approvals for <code>${
|
|
30002
|
+
await ctx.reply(agentFilter ? `No active approvals for <code>${escapeHtml12(agentFilter)}</code>.` : "No active approvals.", { parse_mode: "HTML" });
|
|
30003
30003
|
return;
|
|
30004
30004
|
}
|
|
30005
30005
|
const byAgent = new Map;
|
|
30006
30006
|
for (const d of decisions)
|
|
30007
30007
|
byAgent.set(d.agent_unit, (byAgent.get(d.agent_unit) ?? 0) + 1);
|
|
30008
|
-
const summary = Array.from(byAgent.entries()).map(([a, n]) => `\u2022 <b>${
|
|
30008
|
+
const summary = Array.from(byAgent.entries()).map(([a, n]) => `\u2022 <b>${escapeHtml12(a)}</b>: ${n}`).join(`
|
|
30009
30009
|
`);
|
|
30010
30010
|
const detail = decisions.slice(0, 20).map((d) => {
|
|
30011
30011
|
const ttl = d.ttl_expires_at === null ? "always" : `until ${new Date(d.ttl_expires_at).toISOString().slice(0, 16).replace("T", " ")}`;
|
|
30012
|
-
return `<code>${
|
|
30012
|
+
return `<code>${escapeHtml12(d.id.slice(0, 8))}</code> ` + `${escapeHtml12(d.agent_unit)} \u2192 ` + `<code>${escapeHtml12(d.scope)}</code> ` + `(${escapeHtml12(d.action)}, ${ttl}) ` + `\u00b7 /approvals revoke ${escapeHtml12(d.id)}`;
|
|
30013
30013
|
}).join(`
|
|
30014
30014
|
`);
|
|
30015
30015
|
await ctx.reply(`<b>Active approvals</b>
|
|
@@ -30035,13 +30035,13 @@ ${detail}`, {
|
|
|
30035
30035
|
await ctx.reply("Approval kernel unreachable.");
|
|
30036
30036
|
return;
|
|
30037
30037
|
}
|
|
30038
|
-
await ctx.reply(ok ? `Revoked <code>${
|
|
30038
|
+
await ctx.reply(ok ? `Revoked <code>${escapeHtml12(id)}</code>.` : `No such active decision <code>${escapeHtml12(id)}</code>.`, { parse_mode: "HTML" });
|
|
30039
30039
|
return;
|
|
30040
30040
|
}
|
|
30041
|
-
await ctx.reply(`Unknown subcommand <code>${
|
|
30041
|
+
await ctx.reply(`Unknown subcommand <code>${escapeHtml12(sub)}</code>. ` + `Use <code>/approvals list</code> or <code>/approvals revoke <id></code>. ` + `(<code>add</code> and <code>stats</code> are coming in a follow-up.)`, { parse_mode: "HTML" });
|
|
30042
30042
|
});
|
|
30043
30043
|
}
|
|
30044
|
-
function
|
|
30044
|
+
function escapeHtml12(s) {
|
|
30045
30045
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
30046
30046
|
}
|
|
30047
30047
|
var init_approvals_commands = __esm(() => {
|
|
@@ -30123,16 +30123,16 @@ function renderAccountRow2(snap, opts) {
|
|
|
30123
30123
|
const lines = [];
|
|
30124
30124
|
const marker = snap.isActive ? "\u25cf " : "";
|
|
30125
30125
|
if (!snap.quota) {
|
|
30126
|
-
lines.push(`${marker}<code>${
|
|
30126
|
+
lines.push(`${marker}<code>${escapeHtml13(snap.label)}</code> <i>quota probe failed</i>`);
|
|
30127
30127
|
if (snap.quotaError) {
|
|
30128
|
-
lines.push(` <i>${
|
|
30128
|
+
lines.push(` <i>${escapeHtml13(snap.quotaError)}</i>`);
|
|
30129
30129
|
}
|
|
30130
30130
|
return lines;
|
|
30131
30131
|
}
|
|
30132
30132
|
const q = snap.quota;
|
|
30133
30133
|
const fiveStr = fmtPct2(q.fiveHourUtilizationPct);
|
|
30134
30134
|
const sevenStr = fmtPct2(q.sevenDayUtilizationPct);
|
|
30135
|
-
lines.push(`${marker}<code>${
|
|
30135
|
+
lines.push(`${marker}<code>${escapeHtml13(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
|
|
30136
30136
|
const health = classifyHealth2(snap);
|
|
30137
30137
|
if (health === "blocked") {
|
|
30138
30138
|
const win = bindingWindow2(q);
|
|
@@ -30238,13 +30238,13 @@ function renderFallbackAnnouncement2(input) {
|
|
|
30238
30238
|
const limitWord = input.oldQuota ? limitWordFor2(input.oldQuota) : "quota";
|
|
30239
30239
|
const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
30240
30240
|
if (!input.newLabel) {
|
|
30241
|
-
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${
|
|
30241
|
+
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
|
|
30242
30242
|
lines.push("");
|
|
30243
|
-
lines.push(`Triggered by: agent <b>${
|
|
30243
|
+
lines.push(`Triggered by: agent <b>${escapeHtml13(input.triggerAgent)}</b>`);
|
|
30244
30244
|
if (input.oldQuota) {
|
|
30245
30245
|
const recovery = recoveryAtFor2(input.oldQuota);
|
|
30246
30246
|
if (recovery) {
|
|
30247
|
-
lines.push(`${
|
|
30247
|
+
lines.push(`${escapeHtml13(input.oldLabel)} recovers ${formatAbsolute2(recovery, tz)} ` + `(in ${formatRelative2(recovery, now)})`);
|
|
30248
30248
|
}
|
|
30249
30249
|
}
|
|
30250
30250
|
lines.push("");
|
|
@@ -30252,15 +30252,15 @@ function renderFallbackAnnouncement2(input) {
|
|
|
30252
30252
|
return lines.join(`
|
|
30253
30253
|
`);
|
|
30254
30254
|
}
|
|
30255
|
-
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${
|
|
30255
|
+
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml13(input.oldLabel)}</b>`);
|
|
30256
30256
|
lines.push("");
|
|
30257
|
-
lines.push(`<code>${
|
|
30258
|
-
lines.push(`Triggered by: agent <b>${
|
|
30257
|
+
lines.push(`<code>${escapeHtml13(input.oldLabel)}</code> \u2192 <code>${escapeHtml13(input.newLabel)}</code>`);
|
|
30258
|
+
lines.push(`Triggered by: agent <b>${escapeHtml13(input.triggerAgent)}</b>`);
|
|
30259
30259
|
lines.push("");
|
|
30260
30260
|
if (input.oldQuota) {
|
|
30261
30261
|
const recovery = recoveryAtFor2(input.oldQuota);
|
|
30262
30262
|
if (recovery) {
|
|
30263
|
-
lines.push(`<code>${
|
|
30263
|
+
lines.push(`<code>${escapeHtml13(input.oldLabel)}</code> recovers ` + `${formatAbsolute2(recovery, tz)} (in ${formatRelative2(recovery, now)})`);
|
|
30264
30264
|
}
|
|
30265
30265
|
}
|
|
30266
30266
|
if (input.newQuota) {
|
|
@@ -30268,7 +30268,7 @@ function renderFallbackAnnouncement2(input) {
|
|
|
30268
30268
|
const sevenStr = fmtPct2(input.newQuota.sevenDayUtilizationPct);
|
|
30269
30269
|
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT2 && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT2;
|
|
30270
30270
|
const headroomStr = hasHeadroom ? "<i>(plenty of headroom)</i>" : "<i>(near limit \u2014 watch this)</i>";
|
|
30271
|
-
lines.push(`<code>${
|
|
30271
|
+
lines.push(`<code>${escapeHtml13(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
30272
30272
|
} else {
|
|
30273
30273
|
lines.push(`<i>(quota probe for new account is pending \u2014 will reflect on next /auth)</i>`);
|
|
30274
30274
|
}
|
|
@@ -30327,7 +30327,7 @@ function switchPriority2(s) {
|
|
|
30327
30327
|
return 2;
|
|
30328
30328
|
return 3;
|
|
30329
30329
|
}
|
|
30330
|
-
function
|
|
30330
|
+
function escapeHtml13(s) {
|
|
30331
30331
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
30332
30332
|
}
|
|
30333
30333
|
function buildSnapshotsFromState2(state4, quotas) {
|
|
@@ -30504,14 +30504,14 @@ import {
|
|
|
30504
30504
|
renameSync as renameSync12,
|
|
30505
30505
|
realpathSync as realpathSync2,
|
|
30506
30506
|
chmodSync as chmodSync5,
|
|
30507
|
-
openSync as
|
|
30508
|
-
closeSync as
|
|
30509
|
-
existsSync as
|
|
30510
|
-
unlinkSync as
|
|
30507
|
+
openSync as openSync8,
|
|
30508
|
+
closeSync as closeSync8,
|
|
30509
|
+
existsSync as existsSync34,
|
|
30510
|
+
unlinkSync as unlinkSync14,
|
|
30511
30511
|
appendFileSync as appendFileSync3
|
|
30512
30512
|
} from "fs";
|
|
30513
30513
|
import { homedir as homedir12 } from "os";
|
|
30514
|
-
import { join as
|
|
30514
|
+
import { join as join32, extname, sep as sep3, basename as basename7 } from "path";
|
|
30515
30515
|
|
|
30516
30516
|
// plugin-logger.ts
|
|
30517
30517
|
import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
|
|
@@ -31559,6 +31559,109 @@ function isTelegramSurfaceTool(toolName) {
|
|
|
31559
31559
|
return suffix === "reply" || suffix === "stream_reply" || suffix === "edit_message" || suffix === "react";
|
|
31560
31560
|
}
|
|
31561
31561
|
|
|
31562
|
+
// draft-transport.ts
|
|
31563
|
+
var DRAFT_STREAM_STATE_KEY = Symbol.for("switchroom.draftStreamState");
|
|
31564
|
+
function getDraftStreamState() {
|
|
31565
|
+
const g = globalThis;
|
|
31566
|
+
let state = g[DRAFT_STREAM_STATE_KEY];
|
|
31567
|
+
if (!state) {
|
|
31568
|
+
state = { nextDraftId: 0 };
|
|
31569
|
+
g[DRAFT_STREAM_STATE_KEY] = state;
|
|
31570
|
+
}
|
|
31571
|
+
return state;
|
|
31572
|
+
}
|
|
31573
|
+
function allocateDraftId() {
|
|
31574
|
+
const state = getDraftStreamState();
|
|
31575
|
+
state.nextDraftId = state.nextDraftId >= 2147483647 ? 1 : state.nextDraftId + 1;
|
|
31576
|
+
return state.nextDraftId;
|
|
31577
|
+
}
|
|
31578
|
+
|
|
31579
|
+
// tool-activity-summary.ts
|
|
31580
|
+
var READ_VERBS = new Set(["read"]);
|
|
31581
|
+
var WRITE_VERBS = new Set(["wrote", "created", "edited"]);
|
|
31582
|
+
function makeEmptyActivityState() {
|
|
31583
|
+
return { counts: {}, order: [], firstToolName: null };
|
|
31584
|
+
}
|
|
31585
|
+
function verbForTool(toolName) {
|
|
31586
|
+
if (!toolName)
|
|
31587
|
+
return null;
|
|
31588
|
+
const mcpMatch = /^mcp__([^_]+)__(.+)$/.exec(toolName);
|
|
31589
|
+
if (mcpMatch && mcpMatch[1] === "switchroom-telegram")
|
|
31590
|
+
return null;
|
|
31591
|
+
const suffix = (mcpMatch ? mcpMatch[2] : toolName).toLowerCase();
|
|
31592
|
+
switch (suffix) {
|
|
31593
|
+
case "read":
|
|
31594
|
+
return "read";
|
|
31595
|
+
case "write":
|
|
31596
|
+
return "created";
|
|
31597
|
+
case "edit":
|
|
31598
|
+
case "multiedit":
|
|
31599
|
+
case "notebookedit":
|
|
31600
|
+
return "edited";
|
|
31601
|
+
case "bash":
|
|
31602
|
+
case "bashoutput":
|
|
31603
|
+
case "killshell":
|
|
31604
|
+
return "ran";
|
|
31605
|
+
case "websearch":
|
|
31606
|
+
case "grep":
|
|
31607
|
+
case "glob":
|
|
31608
|
+
return "searched";
|
|
31609
|
+
case "webfetch":
|
|
31610
|
+
return "fetched";
|
|
31611
|
+
case "task":
|
|
31612
|
+
case "agent":
|
|
31613
|
+
return "dispatched";
|
|
31614
|
+
case "todowrite":
|
|
31615
|
+
case "todoread":
|
|
31616
|
+
return "noted";
|
|
31617
|
+
default:
|
|
31618
|
+
return "used";
|
|
31619
|
+
}
|
|
31620
|
+
}
|
|
31621
|
+
function register(state, toolName) {
|
|
31622
|
+
const verb = verbForTool(toolName);
|
|
31623
|
+
if (!verb)
|
|
31624
|
+
return false;
|
|
31625
|
+
if (state.firstToolName == null)
|
|
31626
|
+
state.firstToolName = toolName;
|
|
31627
|
+
const prior = state.counts[verb] ?? 0;
|
|
31628
|
+
if (prior === 0)
|
|
31629
|
+
state.order.push(verb);
|
|
31630
|
+
state.counts[verb] = prior + 1;
|
|
31631
|
+
return true;
|
|
31632
|
+
}
|
|
31633
|
+
var VERB_PHRASE = {
|
|
31634
|
+
read: { singular: "read a file", plural: "read $N files" },
|
|
31635
|
+
edited: { singular: "edited a file", plural: "edited $N files" },
|
|
31636
|
+
created: { singular: "created a file", plural: "created $N files" },
|
|
31637
|
+
ran: { singular: "ran a command", plural: "ran $N commands" },
|
|
31638
|
+
searched: { singular: "ran a search", plural: "ran $N searches" },
|
|
31639
|
+
fetched: { singular: "fetched a URL", plural: "fetched $N URLs" },
|
|
31640
|
+
dispatched: { singular: "dispatched a sub-agent", plural: "dispatched $N sub-agents" },
|
|
31641
|
+
noted: { singular: "updated the todo list", plural: "updated the todo list ($N edits)" },
|
|
31642
|
+
used: { singular: "used a tool", plural: "used $N tools" }
|
|
31643
|
+
};
|
|
31644
|
+
function formatSummary(state) {
|
|
31645
|
+
const phrases = [];
|
|
31646
|
+
for (const verb of state.order) {
|
|
31647
|
+
const n = state.counts[verb] ?? 0;
|
|
31648
|
+
if (n <= 0)
|
|
31649
|
+
continue;
|
|
31650
|
+
const p = VERB_PHRASE[verb];
|
|
31651
|
+
phrases.push(n === 1 ? p.singular : p.plural.replace("$N", String(n)));
|
|
31652
|
+
}
|
|
31653
|
+
if (phrases.length === 0)
|
|
31654
|
+
return null;
|
|
31655
|
+
const sentence = phrases.join(", ");
|
|
31656
|
+
return sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
|
31657
|
+
}
|
|
31658
|
+
function registerAndRender(state, toolName) {
|
|
31659
|
+
const changed = register(state, toolName);
|
|
31660
|
+
if (!changed)
|
|
31661
|
+
return null;
|
|
31662
|
+
return formatSummary(state);
|
|
31663
|
+
}
|
|
31664
|
+
|
|
31562
31665
|
// tool-labels.ts
|
|
31563
31666
|
var MAX_LABEL_CHARS = 60;
|
|
31564
31667
|
var MAX_BASH_CHARS = 40;
|
|
@@ -31755,264 +31858,6 @@ function prettifyServer(name) {
|
|
|
31755
31858
|
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
31756
31859
|
}
|
|
31757
31860
|
|
|
31758
|
-
// tool-intent-surface.ts
|
|
31759
|
-
var MAX_LABEL_LEN = 140;
|
|
31760
|
-
function frameworkVerbFor(toolName) {
|
|
31761
|
-
const m = /^mcp__[^_]+__(.+)$/.exec(toolName);
|
|
31762
|
-
const suffix = (m ? m[1] : toolName).toLowerCase();
|
|
31763
|
-
switch (suffix) {
|
|
31764
|
-
case "bash":
|
|
31765
|
-
case "bashoutput":
|
|
31766
|
-
case "killshell":
|
|
31767
|
-
return "running";
|
|
31768
|
-
case "websearch":
|
|
31769
|
-
case "grep":
|
|
31770
|
-
case "glob":
|
|
31771
|
-
return "searching";
|
|
31772
|
-
case "webfetch":
|
|
31773
|
-
return "fetching";
|
|
31774
|
-
case "read":
|
|
31775
|
-
return "reading";
|
|
31776
|
-
case "write":
|
|
31777
|
-
return "writing";
|
|
31778
|
-
case "edit":
|
|
31779
|
-
case "multiedit":
|
|
31780
|
-
case "notebookedit":
|
|
31781
|
-
return "editing";
|
|
31782
|
-
case "todowrite":
|
|
31783
|
-
case "todoread":
|
|
31784
|
-
return "noting";
|
|
31785
|
-
case "task":
|
|
31786
|
-
case "agent":
|
|
31787
|
-
return "dispatching";
|
|
31788
|
-
case "toolsearch":
|
|
31789
|
-
return "loading tools";
|
|
31790
|
-
default:
|
|
31791
|
-
if (m)
|
|
31792
|
-
return `using ${m[1].replace(/_/g, " ")}`;
|
|
31793
|
-
return `using ${toolName}`;
|
|
31794
|
-
}
|
|
31795
|
-
}
|
|
31796
|
-
function isUserFacingTool(toolName) {
|
|
31797
|
-
const m = /^mcp__switchroom-telegram__(.+)$/.exec(toolName);
|
|
31798
|
-
const suffix = m ? m[1] : toolName;
|
|
31799
|
-
return suffix === "reply" || suffix === "stream_reply" || suffix === "edit_message" || suffix === "react" || suffix === "send_typing" || suffix === "pin_message" || suffix === "delete_message" || suffix === "forward_message" || suffix === "download_attachment" || suffix === "get_recent_messages" || suffix === "progress_update";
|
|
31800
|
-
}
|
|
31801
|
-
function deriveIntentSurface(toolName, toolInput, precomputedLabel) {
|
|
31802
|
-
if (!toolName)
|
|
31803
|
-
return { text: null };
|
|
31804
|
-
if (isUserFacingTool(toolName))
|
|
31805
|
-
return { text: null };
|
|
31806
|
-
const label = toolLabel(toolName, toolInput, undefined, precomputedLabel);
|
|
31807
|
-
if (!label || !label.trim()) {
|
|
31808
|
-
return {
|
|
31809
|
-
text: `<i>${escapeHtml(frameworkVerbFor(toolName))}</i>`
|
|
31810
|
-
};
|
|
31811
|
-
}
|
|
31812
|
-
const verb = frameworkVerbFor(toolName);
|
|
31813
|
-
const safeLabel = escapeHtml(label).slice(0, MAX_LABEL_LEN);
|
|
31814
|
-
return { text: `<i>${escapeHtml(verb)}:</i> ${safeLabel}` };
|
|
31815
|
-
}
|
|
31816
|
-
function escapeHtml(s) {
|
|
31817
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
31818
|
-
}
|
|
31819
|
-
|
|
31820
|
-
// tool-labels.ts
|
|
31821
|
-
var MAX_LABEL_CHARS2 = 60;
|
|
31822
|
-
var MAX_BASH_CHARS2 = 40;
|
|
31823
|
-
var MAX_DESCRIPTION_CHARS2 = 160;
|
|
31824
|
-
function basename2(p) {
|
|
31825
|
-
if (!p)
|
|
31826
|
-
return "";
|
|
31827
|
-
const parts = p.split("/").filter(Boolean);
|
|
31828
|
-
return parts.length > 0 ? parts[parts.length - 1] : p;
|
|
31829
|
-
}
|
|
31830
|
-
function shortenGrepPath2(p) {
|
|
31831
|
-
if (!p)
|
|
31832
|
-
return "repo";
|
|
31833
|
-
const hadTrailingSlash = /\/+$/.test(p);
|
|
31834
|
-
const trimmed = p.replace(/\/+$/, "");
|
|
31835
|
-
const parts = trimmed.split("/").filter(Boolean);
|
|
31836
|
-
if (parts.length === 0)
|
|
31837
|
-
return "repo";
|
|
31838
|
-
const last = parts[parts.length - 1];
|
|
31839
|
-
if (hadTrailingSlash)
|
|
31840
|
-
return `${last}/`;
|
|
31841
|
-
if (last.startsWith(".") && !last.slice(1).includes("."))
|
|
31842
|
-
return last;
|
|
31843
|
-
if (!last.includes("."))
|
|
31844
|
-
return `${last}/`;
|
|
31845
|
-
return last;
|
|
31846
|
-
}
|
|
31847
|
-
function hostFromUrl2(u) {
|
|
31848
|
-
if (!u)
|
|
31849
|
-
return "";
|
|
31850
|
-
try {
|
|
31851
|
-
return new URL(u).host;
|
|
31852
|
-
} catch {
|
|
31853
|
-
return truncate2(u);
|
|
31854
|
-
}
|
|
31855
|
-
}
|
|
31856
|
-
function truncate2(s, n = MAX_LABEL_CHARS2) {
|
|
31857
|
-
if (s.length <= n)
|
|
31858
|
-
return s;
|
|
31859
|
-
return s.slice(0, n - 1) + "\u2026";
|
|
31860
|
-
}
|
|
31861
|
-
function stripHtml2(s) {
|
|
31862
|
-
return s.replace(/<\/?[a-zA-Z][^>]*>/g, "");
|
|
31863
|
-
}
|
|
31864
|
-
function firstLine2(s) {
|
|
31865
|
-
const idx = s.indexOf(`
|
|
31866
|
-
`);
|
|
31867
|
-
return idx === -1 ? s : s.slice(0, idx);
|
|
31868
|
-
}
|
|
31869
|
-
function toolLabel2(tool, input, preamble, precomputedLabel) {
|
|
31870
|
-
if (precomputedLabel && precomputedLabel.trim().length > 0) {
|
|
31871
|
-
return truncate2(firstLine2(precomputedLabel.trim()), MAX_DESCRIPTION_CHARS2);
|
|
31872
|
-
}
|
|
31873
|
-
if (!input || typeof input !== "object")
|
|
31874
|
-
return "";
|
|
31875
|
-
const str = (k) => typeof input[k] === "string" ? input[k] : undefined;
|
|
31876
|
-
const preambleLabel = () => {
|
|
31877
|
-
if (!preamble)
|
|
31878
|
-
return null;
|
|
31879
|
-
if (preamble.includes(`
|
|
31880
|
-
`))
|
|
31881
|
-
return null;
|
|
31882
|
-
const trimmed = preamble.trim();
|
|
31883
|
-
if (!trimmed)
|
|
31884
|
-
return null;
|
|
31885
|
-
if (trimmed.length > MAX_DESCRIPTION_CHARS2)
|
|
31886
|
-
return null;
|
|
31887
|
-
return trimmed;
|
|
31888
|
-
};
|
|
31889
|
-
switch (tool) {
|
|
31890
|
-
case "Read":
|
|
31891
|
-
case "Write":
|
|
31892
|
-
case "NotebookEdit":
|
|
31893
|
-
case "Edit": {
|
|
31894
|
-
const pre = preambleLabel();
|
|
31895
|
-
if (pre)
|
|
31896
|
-
return pre;
|
|
31897
|
-
return truncate2(basename2(str("file_path") ?? ""));
|
|
31898
|
-
}
|
|
31899
|
-
case "Bash":
|
|
31900
|
-
case "BashOutput": {
|
|
31901
|
-
const description = str("description");
|
|
31902
|
-
if (description)
|
|
31903
|
-
return truncate2(firstLine2(description), MAX_DESCRIPTION_CHARS2);
|
|
31904
|
-
const pre = preambleLabel();
|
|
31905
|
-
if (pre)
|
|
31906
|
-
return pre;
|
|
31907
|
-
const cmd = str("command") ?? str("bash_id") ?? "";
|
|
31908
|
-
return truncate2(firstLine2(cmd), MAX_BASH_CHARS2);
|
|
31909
|
-
}
|
|
31910
|
-
case "KillShell":
|
|
31911
|
-
return truncate2(str("shell_id") ?? "");
|
|
31912
|
-
case "Glob": {
|
|
31913
|
-
const pre = preambleLabel();
|
|
31914
|
-
if (pre)
|
|
31915
|
-
return pre;
|
|
31916
|
-
return truncate2(str("pattern") ?? "");
|
|
31917
|
-
}
|
|
31918
|
-
case "Grep": {
|
|
31919
|
-
const pre = preambleLabel();
|
|
31920
|
-
if (pre)
|
|
31921
|
-
return pre;
|
|
31922
|
-
const pat = str("pattern") ?? "";
|
|
31923
|
-
if (!pat)
|
|
31924
|
-
return "";
|
|
31925
|
-
const path = str("path");
|
|
31926
|
-
const where = shortenGrepPath2(path ?? "");
|
|
31927
|
-
return truncate2(`"${pat}" (in ${where})`);
|
|
31928
|
-
}
|
|
31929
|
-
case "WebFetch":
|
|
31930
|
-
return truncate2(hostFromUrl2(str("url") ?? ""));
|
|
31931
|
-
case "WebSearch": {
|
|
31932
|
-
const q = str("query") ?? "";
|
|
31933
|
-
return q ? truncate2(`"${q}"`) : "";
|
|
31934
|
-
}
|
|
31935
|
-
case "Task":
|
|
31936
|
-
case "Agent": {
|
|
31937
|
-
const desc = str("description") ?? str("subagent_type") ?? "";
|
|
31938
|
-
return truncate2(desc);
|
|
31939
|
-
}
|
|
31940
|
-
case "TodoWrite":
|
|
31941
|
-
case "TaskCreate":
|
|
31942
|
-
case "TaskUpdate":
|
|
31943
|
-
case "TaskList":
|
|
31944
|
-
case "TaskGet":
|
|
31945
|
-
case "TaskStop":
|
|
31946
|
-
case "TaskOutput":
|
|
31947
|
-
return "";
|
|
31948
|
-
case "Skill":
|
|
31949
|
-
return truncate2(str("skill") ?? "");
|
|
31950
|
-
case "SlashCommand":
|
|
31951
|
-
return truncate2(str("command") ?? "");
|
|
31952
|
-
case "ToolSearch": {
|
|
31953
|
-
const q = str("query") ?? "";
|
|
31954
|
-
if (!q)
|
|
31955
|
-
return "";
|
|
31956
|
-
const selectMatch = q.match(/^\s*select\s*:\s*(.+)$/i);
|
|
31957
|
-
if (selectMatch) {
|
|
31958
|
-
const names = selectMatch[1].split(",").map((n) => n.trim()).filter((n) => n.length > 0).join(", ");
|
|
31959
|
-
return truncate2(`Loading schema: ${names}`);
|
|
31960
|
-
}
|
|
31961
|
-
return truncate2(`Searching tools: ${q}`);
|
|
31962
|
-
}
|
|
31963
|
-
default:
|
|
31964
|
-
if (tool.startsWith("mcp__")) {
|
|
31965
|
-
const description = str("description");
|
|
31966
|
-
if (description)
|
|
31967
|
-
return truncate2(firstLine2(stripHtml2(description)), MAX_DESCRIPTION_CHARS2);
|
|
31968
|
-
const label = mcpBaseLabel2(tool);
|
|
31969
|
-
const query = str("query") ?? str("text") ?? str("name");
|
|
31970
|
-
if (label && query) {
|
|
31971
|
-
const budget = Math.max(8, MAX_LABEL_CHARS2 - label.length - 4);
|
|
31972
|
-
const preview = truncate2(firstLine2(stripHtml2(query)), budget);
|
|
31973
|
-
return `${label} (${preview})`;
|
|
31974
|
-
}
|
|
31975
|
-
if (label)
|
|
31976
|
-
return truncate2(label);
|
|
31977
|
-
}
|
|
31978
|
-
for (const k of ["description", "file_path", "path", "url", "query", "pattern", "command"]) {
|
|
31979
|
-
const v = str(k);
|
|
31980
|
-
if (v != null && v.length > 0) {
|
|
31981
|
-
if (k === "file_path" || k === "path")
|
|
31982
|
-
return truncate2(basename2(v));
|
|
31983
|
-
if (k === "url")
|
|
31984
|
-
return truncate2(hostFromUrl2(v));
|
|
31985
|
-
if (k === "description")
|
|
31986
|
-
return truncate2(firstLine2(v), MAX_DESCRIPTION_CHARS2);
|
|
31987
|
-
return truncate2(firstLine2(v));
|
|
31988
|
-
}
|
|
31989
|
-
}
|
|
31990
|
-
return "";
|
|
31991
|
-
}
|
|
31992
|
-
}
|
|
31993
|
-
function mcpBaseLabel2(tool) {
|
|
31994
|
-
if (!tool.startsWith("mcp__"))
|
|
31995
|
-
return "";
|
|
31996
|
-
const parts = tool.slice("mcp__".length).split("__");
|
|
31997
|
-
if (parts.length < 2)
|
|
31998
|
-
return "";
|
|
31999
|
-
const rawServer = parts[0];
|
|
32000
|
-
const action = parts.slice(1).join("__");
|
|
32001
|
-
if (!rawServer || !action)
|
|
32002
|
-
return "";
|
|
32003
|
-
return `${prettifyServer2(rawServer)}: ${action}`;
|
|
32004
|
-
}
|
|
32005
|
-
function prettifyServer2(name) {
|
|
32006
|
-
const LABELS = {
|
|
32007
|
-
"switchroom-telegram": "Telegram"
|
|
32008
|
-
};
|
|
32009
|
-
if (LABELS[name])
|
|
32010
|
-
return LABELS[name];
|
|
32011
|
-
if (!name)
|
|
32012
|
-
return name;
|
|
32013
|
-
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
32014
|
-
}
|
|
32015
|
-
|
|
32016
31861
|
// gateway/chat-key.ts
|
|
32017
31862
|
function chatKey(chatId, threadId) {
|
|
32018
31863
|
const t = threadId == null || threadId === 0 ? "_" : String(threadId);
|
|
@@ -32121,18 +31966,18 @@ function isDraft429(err) {
|
|
|
32121
31966
|
const text = typeof err === "string" ? err : err instanceof Error ? err.message : typeof err === "object" && err != null && ("description" in err) ? typeof err.description === "string" ? err.description : "" : "";
|
|
32122
31967
|
return /sendMessageDraft/i.test(text);
|
|
32123
31968
|
}
|
|
32124
|
-
var
|
|
32125
|
-
function
|
|
31969
|
+
var DRAFT_STREAM_STATE_KEY2 = Symbol.for("switchroom.draftStreamState");
|
|
31970
|
+
function getDraftStreamState2() {
|
|
32126
31971
|
const g = globalThis;
|
|
32127
|
-
let state = g[
|
|
31972
|
+
let state = g[DRAFT_STREAM_STATE_KEY2];
|
|
32128
31973
|
if (!state) {
|
|
32129
31974
|
state = { nextDraftId: 0 };
|
|
32130
|
-
g[
|
|
31975
|
+
g[DRAFT_STREAM_STATE_KEY2] = state;
|
|
32131
31976
|
}
|
|
32132
31977
|
return state;
|
|
32133
31978
|
}
|
|
32134
|
-
function
|
|
32135
|
-
const state =
|
|
31979
|
+
function allocateDraftId2() {
|
|
31980
|
+
const state = getDraftStreamState2();
|
|
32136
31981
|
state.nextDraftId = state.nextDraftId >= 2147483647 ? 1 : state.nextDraftId + 1;
|
|
32137
31982
|
return state.nextDraftId;
|
|
32138
31983
|
}
|
|
@@ -32162,7 +32007,7 @@ function createDraftStream(send, edit, config = {}) {
|
|
|
32162
32007
|
warn?.('draft-stream: previewTransport="auto" with sendMessageDraft but isPrivateChat undefined \u2014 defaulting to message transport');
|
|
32163
32008
|
}
|
|
32164
32009
|
let usesDraftTransport = prefersDraft && draftApi != null;
|
|
32165
|
-
let draftId = usesDraftTransport ?
|
|
32010
|
+
let draftId = usesDraftTransport ? allocateDraftId2() : undefined;
|
|
32166
32011
|
if (prefersDraft && !usesDraftTransport) {
|
|
32167
32012
|
warn?.("draft-stream: sendMessageDraft unavailable; falling back to sendMessage/editMessageText");
|
|
32168
32013
|
}
|
|
@@ -32270,7 +32115,7 @@ function createDraftStream(send, edit, config = {}) {
|
|
|
32270
32115
|
const newMsgId = await send(chunk);
|
|
32271
32116
|
messageId = newMsgId;
|
|
32272
32117
|
persistedTextLen = textToSend.length;
|
|
32273
|
-
draftId =
|
|
32118
|
+
draftId = allocateDraftId2();
|
|
32274
32119
|
currentChunkStartedAt = null;
|
|
32275
32120
|
persistChainFires++;
|
|
32276
32121
|
sendFires++;
|
|
@@ -33145,7 +32990,7 @@ function installTgPostLogger(bot) {
|
|
|
33145
32990
|
}
|
|
33146
32991
|
|
|
33147
32992
|
// attachment-path.ts
|
|
33148
|
-
import { join as join2, basename as
|
|
32993
|
+
import { join as join2, basename as basename2, resolve, sep } from "node:path";
|
|
33149
32994
|
function sanitizeExtension(ext) {
|
|
33150
32995
|
if (ext == null)
|
|
33151
32996
|
return "bin";
|
|
@@ -33174,7 +33019,7 @@ function assertInsideInbox(inboxDir, candidatePath) {
|
|
|
33174
33019
|
const inboxReal = resolve(inboxDir);
|
|
33175
33020
|
const candidateReal = resolve(candidatePath);
|
|
33176
33021
|
if (candidateReal !== inboxReal && !candidateReal.startsWith(inboxReal + sep)) {
|
|
33177
|
-
throw new Error(`attachment path escape: ${
|
|
33022
|
+
throw new Error(`attachment path escape: ${basename2(candidatePath)} resolved outside ${inboxDir}`);
|
|
33178
33023
|
}
|
|
33179
33024
|
}
|
|
33180
33025
|
|
|
@@ -38514,45 +38359,6 @@ function recordSilentTurnEnd(args, deps) {
|
|
|
38514
38359
|
}
|
|
38515
38360
|
var recordUndeliveredTurnEnd = recordSilentTurnEnd;
|
|
38516
38361
|
|
|
38517
|
-
// ack-flag.ts
|
|
38518
|
-
import { closeSync, existsSync as existsSync6, openSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
38519
|
-
import { join as join7 } from "node:path";
|
|
38520
|
-
var ACK_SENT_MARKER = "ack-sent.flag";
|
|
38521
|
-
function markerPath() {
|
|
38522
|
-
const dir = process.env.TELEGRAM_STATE_DIR;
|
|
38523
|
-
if (!dir)
|
|
38524
|
-
return null;
|
|
38525
|
-
return join7(dir, ACK_SENT_MARKER);
|
|
38526
|
-
}
|
|
38527
|
-
function markAckSent() {
|
|
38528
|
-
const path = markerPath();
|
|
38529
|
-
if (path == null)
|
|
38530
|
-
return;
|
|
38531
|
-
if (existsSync6(path))
|
|
38532
|
-
return;
|
|
38533
|
-
try {
|
|
38534
|
-
const fd = openSync(path, "w");
|
|
38535
|
-
closeSync(fd);
|
|
38536
|
-
} catch (err) {
|
|
38537
|
-
process.stderr.write(`ack-flag: markAckSent failed path=${path}: ${err}
|
|
38538
|
-
`);
|
|
38539
|
-
}
|
|
38540
|
-
}
|
|
38541
|
-
function clearAckSent() {
|
|
38542
|
-
const path = markerPath();
|
|
38543
|
-
if (path == null)
|
|
38544
|
-
return;
|
|
38545
|
-
try {
|
|
38546
|
-
unlinkSync2(path);
|
|
38547
|
-
} catch (err) {
|
|
38548
|
-
const code = err?.code;
|
|
38549
|
-
if (code === "ENOENT")
|
|
38550
|
-
return;
|
|
38551
|
-
process.stderr.write(`ack-flag: clearAckSent failed path=${path}: ${err}
|
|
38552
|
-
`);
|
|
38553
|
-
}
|
|
38554
|
-
}
|
|
38555
|
-
|
|
38556
38362
|
// final-answer-detect.ts
|
|
38557
38363
|
var FINAL_ANSWER_MIN_CHARS = 200;
|
|
38558
38364
|
function isFinalAnswerReply(input) {
|
|
@@ -38586,7 +38392,7 @@ function isSilentFlushMarker(text) {
|
|
|
38586
38392
|
var MIN_INITIAL_CHARS = 50;
|
|
38587
38393
|
var DEFAULT_THROTTLE_MS = 1000;
|
|
38588
38394
|
var TELEGRAM_MAX_CHARS2 = 4096;
|
|
38589
|
-
var
|
|
38395
|
+
var allocateDraftId3 = allocateDraftId2;
|
|
38590
38396
|
function createAnswerStream(config) {
|
|
38591
38397
|
const {
|
|
38592
38398
|
chatId,
|
|
@@ -38609,7 +38415,7 @@ function createAnswerStream(config) {
|
|
|
38609
38415
|
const effectiveThrottle = Math.max(250, throttleMs);
|
|
38610
38416
|
const preferDraft = isPrivateChat && draftApi != null;
|
|
38611
38417
|
let usesDraftTransport = preferDraft;
|
|
38612
|
-
let draftId = preferDraft ?
|
|
38418
|
+
let draftId = preferDraft ? allocateDraftId3() : undefined;
|
|
38613
38419
|
let streamMsgId;
|
|
38614
38420
|
let pendingText = null;
|
|
38615
38421
|
let lastSentText = "";
|
|
@@ -38858,7 +38664,7 @@ function createAnswerStream(config) {
|
|
|
38858
38664
|
if (staleDraftId != null) {
|
|
38859
38665
|
clearDraftBestEffort(staleDraftId);
|
|
38860
38666
|
}
|
|
38861
|
-
draftId =
|
|
38667
|
+
draftId = allocateDraftId3();
|
|
38862
38668
|
}
|
|
38863
38669
|
log?.(`answer-stream: forceNewMessage (gen=${generation})`);
|
|
38864
38670
|
},
|
|
@@ -38976,7 +38782,7 @@ async function gatewayStartupRetry(fn, opts = {}) {
|
|
|
38976
38782
|
|
|
38977
38783
|
// gateway/quarantine.ts
|
|
38978
38784
|
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
38979
|
-
import { join as
|
|
38785
|
+
import { join as join7 } from "node:path";
|
|
38980
38786
|
var QUARANTINE_FILENAME = "quarantine.json";
|
|
38981
38787
|
function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.now) {
|
|
38982
38788
|
mkdirSync6(telegramStateDir, { recursive: true, mode: 448 });
|
|
@@ -38986,7 +38792,7 @@ function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.no
|
|
|
38986
38792
|
ts: nowFn(),
|
|
38987
38793
|
detail
|
|
38988
38794
|
};
|
|
38989
|
-
writeFileSync4(
|
|
38795
|
+
writeFileSync4(join7(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
|
|
38990
38796
|
`, "utf-8");
|
|
38991
38797
|
}
|
|
38992
38798
|
|
|
@@ -39064,16 +38870,16 @@ function renderAccountRow(snap, opts) {
|
|
|
39064
38870
|
const lines = [];
|
|
39065
38871
|
const marker = snap.isActive ? "\u25cf " : "";
|
|
39066
38872
|
if (!snap.quota) {
|
|
39067
|
-
lines.push(`${marker}<code>${
|
|
38873
|
+
lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> <i>quota probe failed</i>`);
|
|
39068
38874
|
if (snap.quotaError) {
|
|
39069
|
-
lines.push(` <i>${
|
|
38875
|
+
lines.push(` <i>${escapeHtml(snap.quotaError)}</i>`);
|
|
39070
38876
|
}
|
|
39071
38877
|
return lines;
|
|
39072
38878
|
}
|
|
39073
38879
|
const q = snap.quota;
|
|
39074
38880
|
const fiveStr = fmtPct(q.fiveHourUtilizationPct);
|
|
39075
38881
|
const sevenStr = fmtPct(q.sevenDayUtilizationPct);
|
|
39076
|
-
lines.push(`${marker}<code>${
|
|
38882
|
+
lines.push(`${marker}<code>${escapeHtml(snap.label)}</code> ${fiveStr} / ${sevenStr}`);
|
|
39077
38883
|
const health = classifyHealth(snap);
|
|
39078
38884
|
if (health === "blocked") {
|
|
39079
38885
|
const win = bindingWindow(q);
|
|
@@ -39179,13 +38985,13 @@ function renderFallbackAnnouncement(input) {
|
|
|
39179
38985
|
const limitWord = input.oldQuota ? limitWordFor(input.oldQuota) : "quota";
|
|
39180
38986
|
const headerLimit = limitWord === "quota" ? "quota cap" : `${limitWord} limit`;
|
|
39181
38987
|
if (!input.newLabel) {
|
|
39182
|
-
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${
|
|
38988
|
+
lines.push(`\uD83D\uDD34 <b>All accounts blocked \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
|
|
39183
38989
|
lines.push("");
|
|
39184
|
-
lines.push(`Triggered by: agent <b>${
|
|
38990
|
+
lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
|
|
39185
38991
|
if (input.oldQuota) {
|
|
39186
38992
|
const recovery = recoveryAtFor(input.oldQuota);
|
|
39187
38993
|
if (recovery) {
|
|
39188
|
-
lines.push(`${
|
|
38994
|
+
lines.push(`${escapeHtml(input.oldLabel)} recovers ${formatAbsolute(recovery, tz)} ` + `(in ${formatRelative(recovery, now)})`);
|
|
39189
38995
|
}
|
|
39190
38996
|
}
|
|
39191
38997
|
lines.push("");
|
|
@@ -39193,15 +38999,15 @@ function renderFallbackAnnouncement(input) {
|
|
|
39193
38999
|
return lines.join(`
|
|
39194
39000
|
`);
|
|
39195
39001
|
}
|
|
39196
|
-
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${
|
|
39002
|
+
lines.push(`\u2713 <b>Switched fleet \u00b7 ${headerLimit} on ${escapeHtml(input.oldLabel)}</b>`);
|
|
39197
39003
|
lines.push("");
|
|
39198
|
-
lines.push(`<code>${
|
|
39199
|
-
lines.push(`Triggered by: agent <b>${
|
|
39004
|
+
lines.push(`<code>${escapeHtml(input.oldLabel)}</code> \u2192 <code>${escapeHtml(input.newLabel)}</code>`);
|
|
39005
|
+
lines.push(`Triggered by: agent <b>${escapeHtml(input.triggerAgent)}</b>`);
|
|
39200
39006
|
lines.push("");
|
|
39201
39007
|
if (input.oldQuota) {
|
|
39202
39008
|
const recovery = recoveryAtFor(input.oldQuota);
|
|
39203
39009
|
if (recovery) {
|
|
39204
|
-
lines.push(`<code>${
|
|
39010
|
+
lines.push(`<code>${escapeHtml(input.oldLabel)}</code> recovers ` + `${formatAbsolute(recovery, tz)} (in ${formatRelative(recovery, now)})`);
|
|
39205
39011
|
}
|
|
39206
39012
|
}
|
|
39207
39013
|
if (input.newQuota) {
|
|
@@ -39209,7 +39015,7 @@ function renderFallbackAnnouncement(input) {
|
|
|
39209
39015
|
const sevenStr = fmtPct(input.newQuota.sevenDayUtilizationPct);
|
|
39210
39016
|
const hasHeadroom = input.newQuota.fiveHourUtilizationPct < THROTTLING_THRESHOLD_PCT && input.newQuota.sevenDayUtilizationPct < THROTTLING_THRESHOLD_PCT;
|
|
39211
39017
|
const headroomStr = hasHeadroom ? "<i>(plenty of headroom)</i>" : "<i>(near limit \u2014 watch this)</i>";
|
|
39212
|
-
lines.push(`<code>${
|
|
39018
|
+
lines.push(`<code>${escapeHtml(input.newLabel)}</code> now: ${fiveStr} of 5h \u00b7 ${sevenStr} of 7d ${headroomStr}`);
|
|
39213
39019
|
} else {
|
|
39214
39020
|
lines.push(`<i>(quota probe for new account is pending \u2014 will reflect on next /auth)</i>`);
|
|
39215
39021
|
}
|
|
@@ -39268,7 +39074,7 @@ function switchPriority(s) {
|
|
|
39268
39074
|
return 2;
|
|
39269
39075
|
return 3;
|
|
39270
39076
|
}
|
|
39271
|
-
function
|
|
39077
|
+
function escapeHtml(s) {
|
|
39272
39078
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
39273
39079
|
}
|
|
39274
39080
|
function buildSnapshotsFromState(state3, quotas) {
|
|
@@ -39361,7 +39167,7 @@ function parseAuthCommand(text) {
|
|
|
39361
39167
|
if (tail.length > 0) {
|
|
39362
39168
|
return {
|
|
39363
39169
|
kind: "help",
|
|
39364
|
-
reason: `Unknown <code>rm</code> modifier: <code>${
|
|
39170
|
+
reason: `Unknown <code>rm</code> modifier: <code>${escapeHtml2(tail)}</code>. Use <code>/auth rm <label> confirm</code> to confirm.`
|
|
39365
39171
|
};
|
|
39366
39172
|
}
|
|
39367
39173
|
return { kind: "rm-prompt", label };
|
|
@@ -39381,7 +39187,7 @@ function parseAuthCommand(text) {
|
|
|
39381
39187
|
if (sub !== "override") {
|
|
39382
39188
|
return {
|
|
39383
39189
|
kind: "help",
|
|
39384
|
-
reason: `Unknown <code>agent</code> subcommand: <code>${
|
|
39190
|
+
reason: `Unknown <code>agent</code> subcommand: <code>${escapeHtml2(sub || "(none)")}</code>. Try <code>/auth agent override <agent> <label|clear></code>.`
|
|
39385
39191
|
};
|
|
39386
39192
|
}
|
|
39387
39193
|
const agent = parts[2];
|
|
@@ -39403,7 +39209,7 @@ function parseAuthCommand(text) {
|
|
|
39403
39209
|
case "help":
|
|
39404
39210
|
return { kind: "help" };
|
|
39405
39211
|
default:
|
|
39406
|
-
return { kind: "help", reason: `Unknown verb: <code>${
|
|
39212
|
+
return { kind: "help", reason: `Unknown verb: <code>${escapeHtml2(verb)}</code>` };
|
|
39407
39213
|
}
|
|
39408
39214
|
}
|
|
39409
39215
|
async function handleAuthCommand(parsed, ctx) {
|
|
@@ -39457,7 +39263,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39457
39263
|
};
|
|
39458
39264
|
} catch (err) {
|
|
39459
39265
|
return {
|
|
39460
|
-
text: `<b>/auth show failed:</b> ${
|
|
39266
|
+
text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39461
39267
|
html: true
|
|
39462
39268
|
};
|
|
39463
39269
|
}
|
|
@@ -39469,7 +39275,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39469
39275
|
const agent = state3.agents.find((a) => a.name === agentName3);
|
|
39470
39276
|
if (!agent) {
|
|
39471
39277
|
return {
|
|
39472
|
-
text: `<b>/auth show:</b> no agent named <code>${
|
|
39278
|
+
text: `<b>/auth show:</b> no agent named <code>${escapeHtml2(agentName3)}</code> in broker view.
|
|
39473
39279
|
` + `Run <code>/auth show</code> for the fleet snapshot.`,
|
|
39474
39280
|
html: true
|
|
39475
39281
|
};
|
|
@@ -39477,7 +39283,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39477
39283
|
return { text: renderAgentDetail(state3, agent), html: true };
|
|
39478
39284
|
} catch (err) {
|
|
39479
39285
|
return {
|
|
39480
|
-
text: `<b>/auth show failed:</b> ${
|
|
39286
|
+
text: `<b>/auth show failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39481
39287
|
html: true
|
|
39482
39288
|
};
|
|
39483
39289
|
}
|
|
@@ -39499,13 +39305,13 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39499
39305
|
try {
|
|
39500
39306
|
const result = await ctx.client.setActive(parsed.label);
|
|
39501
39307
|
return {
|
|
39502
|
-
text: `<b>Active account \u2192</b> <code>${
|
|
39308
|
+
text: `<b>Active account \u2192</b> <code>${escapeHtml2(result.active)}</code>
|
|
39503
39309
|
` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
|
|
39504
39310
|
html: true
|
|
39505
39311
|
};
|
|
39506
39312
|
} catch (err) {
|
|
39507
39313
|
return {
|
|
39508
|
-
text: `<b>/auth use failed:</b> ${
|
|
39314
|
+
text: `<b>/auth use failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39509
39315
|
html: true
|
|
39510
39316
|
};
|
|
39511
39317
|
}
|
|
@@ -39523,13 +39329,13 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39523
39329
|
}
|
|
39524
39330
|
const result = await ctx.client.setActive(nextLabel);
|
|
39525
39331
|
return {
|
|
39526
|
-
text: `<b>Rotated:</b> active \u2192 <code>${
|
|
39332
|
+
text: `<b>Rotated:</b> active \u2192 <code>${escapeHtml2(result.active)}</code>
|
|
39527
39333
|
` + `Re-mirrored credentials for ${result.fanned.length} agent${result.fanned.length === 1 ? "" : "s"}.`,
|
|
39528
39334
|
html: true
|
|
39529
39335
|
};
|
|
39530
39336
|
} catch (err) {
|
|
39531
39337
|
return {
|
|
39532
|
-
text: `<b>/auth rotate failed:</b> ${
|
|
39338
|
+
text: `<b>/auth rotate failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39533
39339
|
html: true
|
|
39534
39340
|
};
|
|
39535
39341
|
}
|
|
@@ -39540,20 +39346,20 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39540
39346
|
state3 = await ctx.client.listState();
|
|
39541
39347
|
} catch (err) {
|
|
39542
39348
|
return {
|
|
39543
|
-
text: `<b>/auth rm failed:</b> ${
|
|
39349
|
+
text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39544
39350
|
html: true
|
|
39545
39351
|
};
|
|
39546
39352
|
}
|
|
39547
39353
|
const exists = state3.accounts.some((a) => a.label === parsed.label);
|
|
39548
39354
|
if (!exists) {
|
|
39549
39355
|
return {
|
|
39550
|
-
text: `<b>/auth rm:</b> no account named <code>${
|
|
39356
|
+
text: `<b>/auth rm:</b> no account named <code>${escapeHtml2(parsed.label)}</code>. ` + `Run <code>/auth show</code> for the current list.`,
|
|
39551
39357
|
html: true
|
|
39552
39358
|
};
|
|
39553
39359
|
}
|
|
39554
39360
|
if (state3.active === parsed.label) {
|
|
39555
39361
|
return {
|
|
39556
|
-
text: `<b>/auth rm refused.</b> <code>${
|
|
39362
|
+
text: `<b>/auth rm refused.</b> <code>${escapeHtml2(parsed.label)}</code> is the fleet active. ` + `Switch with <code>/auth use <other></code> or <code>/auth rotate</code> first.`,
|
|
39557
39363
|
html: true
|
|
39558
39364
|
};
|
|
39559
39365
|
}
|
|
@@ -39564,10 +39370,10 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39564
39370
|
});
|
|
39565
39371
|
}
|
|
39566
39372
|
return {
|
|
39567
|
-
text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${
|
|
39568
|
-
` + `The fleet active is unchanged. Any agent override pointing at <code>${
|
|
39373
|
+
text: `<b>\u26a0 /auth rm</b> \u2014 about to remove <code>${escapeHtml2(parsed.label)}</code> from the broker.
|
|
39374
|
+
` + `The fleet active is unchanged. Any agent override pointing at <code>${escapeHtml2(parsed.label)}</code> will stop working.
|
|
39569
39375
|
|
|
39570
|
-
` + `Send <code>/auth rm ${
|
|
39376
|
+
` + `Send <code>/auth rm ${escapeHtml2(parsed.label)} confirm</code> within ${Math.round(AUTH_RM_CONFIRM_TTL_MS / 1000)}s to proceed.`,
|
|
39571
39377
|
html: true
|
|
39572
39378
|
};
|
|
39573
39379
|
}
|
|
@@ -39579,7 +39385,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39579
39385
|
pendingAuthRmFlows.delete(ctx.chatId);
|
|
39580
39386
|
}
|
|
39581
39387
|
return {
|
|
39582
|
-
text: `<b>/auth rm:</b> no pending confirm for <code>${
|
|
39388
|
+
text: `<b>/auth rm:</b> no pending confirm for <code>${escapeHtml2(parsed.label)}</code> (expired or not started). ` + `Send <code>/auth rm ${escapeHtml2(parsed.label)}</code> first.`,
|
|
39583
39389
|
html: true
|
|
39584
39390
|
};
|
|
39585
39391
|
}
|
|
@@ -39588,12 +39394,12 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39588
39394
|
try {
|
|
39589
39395
|
const data = await ctx.client.rmAccount(parsed.label);
|
|
39590
39396
|
return {
|
|
39591
|
-
text: `<b>Removed</b> <code>${
|
|
39397
|
+
text: `<b>Removed</b> <code>${escapeHtml2(data.label)}</code> from the broker.`,
|
|
39592
39398
|
html: true
|
|
39593
39399
|
};
|
|
39594
39400
|
} catch (err) {
|
|
39595
39401
|
return {
|
|
39596
|
-
text: `<b>/auth rm failed:</b> ${
|
|
39402
|
+
text: `<b>/auth rm failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39597
39403
|
html: true
|
|
39598
39404
|
};
|
|
39599
39405
|
}
|
|
@@ -39604,7 +39410,7 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39604
39410
|
const targets = parsed.label ? state3.accounts.filter((a) => a.label === parsed.label).map((a) => a.label) : state3.accounts.map((a) => a.label);
|
|
39605
39411
|
if (parsed.label && targets.length === 0) {
|
|
39606
39412
|
return {
|
|
39607
|
-
text: `<b>/auth refresh:</b> no account named <code>${
|
|
39413
|
+
text: `<b>/auth refresh:</b> no account named <code>${escapeHtml2(parsed.label)}</code>.`,
|
|
39608
39414
|
html: true
|
|
39609
39415
|
};
|
|
39610
39416
|
}
|
|
@@ -39623,10 +39429,10 @@ async function handleAuthCommand(parsed, ctx) {
|
|
|
39623
39429
|
formatExpiryAbs(data.expiresAt)
|
|
39624
39430
|
]);
|
|
39625
39431
|
} catch (err) {
|
|
39626
|
-
failures.push(`${label}: ${
|
|
39432
|
+
failures.push(`${label}: ${escapeHtml2(err?.message ?? String(err))}`);
|
|
39627
39433
|
}
|
|
39628
39434
|
}
|
|
39629
|
-
const head = targets.length === 1 ? `<b>Refreshed</b> <code>${
|
|
39435
|
+
const head = targets.length === 1 ? `<b>Refreshed</b> <code>${escapeHtml2(targets[0])}</code>` : `<b>Refreshed</b> ${rows.length - 1}/${targets.length} account${targets.length === 1 ? "" : "s"}`;
|
|
39630
39436
|
const table = rows.length > 1 ? `
|
|
39631
39437
|
<pre>${alignTable(rows)}</pre>` : "";
|
|
39632
39438
|
const failBlock = failures.length > 0 ? `
|
|
@@ -39636,7 +39442,7 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39636
39442
|
return { text: head + table + failBlock, html: true };
|
|
39637
39443
|
} catch (err) {
|
|
39638
39444
|
return {
|
|
39639
|
-
text: `<b>/auth refresh failed:</b> ${
|
|
39445
|
+
text: `<b>/auth refresh failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39640
39446
|
html: true
|
|
39641
39447
|
};
|
|
39642
39448
|
}
|
|
@@ -39645,12 +39451,12 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39645
39451
|
try {
|
|
39646
39452
|
const data = await ctx.client.setOverride(parsed.agent, parsed.label);
|
|
39647
39453
|
return {
|
|
39648
|
-
text: `<b>Override set.</b> <code>${
|
|
39454
|
+
text: `<b>Override set.</b> <code>${escapeHtml2(data.agent)}</code> is now pinned to ` + `<code>${escapeHtml2(data.account ?? parsed.label)}</code>.`,
|
|
39649
39455
|
html: true
|
|
39650
39456
|
};
|
|
39651
39457
|
} catch (err) {
|
|
39652
39458
|
return {
|
|
39653
|
-
text: `<b>/auth agent override failed:</b> ${
|
|
39459
|
+
text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39654
39460
|
html: true
|
|
39655
39461
|
};
|
|
39656
39462
|
}
|
|
@@ -39659,12 +39465,12 @@ ${failures.map((f) => ` ${f}`).join(`
|
|
|
39659
39465
|
try {
|
|
39660
39466
|
const data = await ctx.client.setOverride(parsed.agent, null);
|
|
39661
39467
|
return {
|
|
39662
|
-
text: `<b>Override cleared</b> on <code>${
|
|
39468
|
+
text: `<b>Override cleared</b> on <code>${escapeHtml2(data.agent)}</code> ` + `\u2014 back to fleet active.`,
|
|
39663
39469
|
html: true
|
|
39664
39470
|
};
|
|
39665
39471
|
} catch (err) {
|
|
39666
39472
|
return {
|
|
39667
|
-
text: `<b>/auth agent override failed:</b> ${
|
|
39473
|
+
text: `<b>/auth agent override failed:</b> ${escapeHtml2(err?.message ?? String(err))}`,
|
|
39668
39474
|
html: true
|
|
39669
39475
|
};
|
|
39670
39476
|
}
|
|
@@ -39743,7 +39549,7 @@ function formatAccountsTable(state3, now) {
|
|
|
39743
39549
|
const status = isActive ? "active" : acc.exhausted ? "exhausted" : "available";
|
|
39744
39550
|
const expires = acc.expiresAt != null ? formatRelativeMs(acc.expiresAt - now) : "\u2014";
|
|
39745
39551
|
const quotaReset = acc.exhausted && acc.exhausted_until != null && acc.exhausted_until > now ? formatRelativeMs(acc.exhausted_until - now) : "\u2014";
|
|
39746
|
-
rows.push([`${marker} ${
|
|
39552
|
+
rows.push([`${marker} ${escapeHtml2(acc.label)}`, status, expires, quotaReset]);
|
|
39747
39553
|
}
|
|
39748
39554
|
return alignTable(rows);
|
|
39749
39555
|
}
|
|
@@ -39751,15 +39557,15 @@ function formatAgentsTable(state3) {
|
|
|
39751
39557
|
const rows = [["AGENT", "ACTIVE", "SOURCE"]];
|
|
39752
39558
|
for (const a of state3.agents) {
|
|
39753
39559
|
const source = a.override ? "override" : a.account === state3.active ? "fleet-active" : "pinned";
|
|
39754
|
-
rows.push([
|
|
39560
|
+
rows.push([escapeHtml2(a.name), escapeHtml2(a.account), source]);
|
|
39755
39561
|
}
|
|
39756
39562
|
return alignTable(rows);
|
|
39757
39563
|
}
|
|
39758
39564
|
function renderAgentDetail(state3, agent, now = Date.now()) {
|
|
39759
39565
|
const lines = [];
|
|
39760
|
-
lines.push(`<b>${
|
|
39566
|
+
lines.push(`<b>${escapeHtml2(agent.name)}</b>`);
|
|
39761
39567
|
const source = agent.override ? "override" : "fleet-active";
|
|
39762
|
-
lines.push(`Active account: <code>${
|
|
39568
|
+
lines.push(`Active account: <code>${escapeHtml2(agent.account)}</code> (${source})`);
|
|
39763
39569
|
const acct = state3.accounts.find((a) => a.label === agent.account);
|
|
39764
39570
|
if (acct) {
|
|
39765
39571
|
const expRel = acct.expiresAt != null ? formatRelativeMs(acct.expiresAt - now) : "\u2014";
|
|
@@ -39782,11 +39588,11 @@ function formatConsumersTable(state3, now) {
|
|
|
39782
39588
|
const rows = [["CONSUMER", "ACTIVE", "STATUS"]];
|
|
39783
39589
|
for (const c of state3.consumers) {
|
|
39784
39590
|
const status = c.last_seen_at == null ? "socket bound" : `socket bound (last seen ${formatRelativeMs(now - c.last_seen_at)} ago)`;
|
|
39785
|
-
rows.push([
|
|
39591
|
+
rows.push([escapeHtml2(c.name), escapeHtml2(c.account), status]);
|
|
39786
39592
|
}
|
|
39787
39593
|
return alignTable(rows);
|
|
39788
39594
|
}
|
|
39789
|
-
function
|
|
39595
|
+
function escapeHtml2(s) {
|
|
39790
39596
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
39791
39597
|
}
|
|
39792
39598
|
function formatRelativeMs(ms) {
|
|
@@ -39871,7 +39677,7 @@ import * as net2 from "node:net";
|
|
|
39871
39677
|
init_protocol();
|
|
39872
39678
|
import { homedir as homedir4 } from "node:os";
|
|
39873
39679
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
39874
|
-
import { join as
|
|
39680
|
+
import { join as join9 } from "node:path";
|
|
39875
39681
|
var DEFAULT_TIMEOUT_MS2 = 5000;
|
|
39876
39682
|
function reviveDate2(v) {
|
|
39877
39683
|
if (v == null)
|
|
@@ -39882,7 +39688,7 @@ function reviveDate2(v) {
|
|
|
39882
39688
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
39883
39689
|
}
|
|
39884
39690
|
function operatorSocketPath2(home = homedir4()) {
|
|
39885
|
-
return
|
|
39691
|
+
return join9(home, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
39886
39692
|
}
|
|
39887
39693
|
function resolveAuthBrokerSocketPath2(opts) {
|
|
39888
39694
|
if (opts?.socket)
|
|
@@ -40214,16 +40020,16 @@ function createFleetFallbackGate(opts) {
|
|
|
40214
40020
|
|
|
40215
40021
|
// gateway/auth-add-flow.ts
|
|
40216
40022
|
import { spawn } from "node:child_process";
|
|
40217
|
-
import { existsSync as
|
|
40023
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2 } from "node:fs";
|
|
40218
40024
|
import { homedir as homedir6 } from "node:os";
|
|
40219
|
-
import { join as
|
|
40025
|
+
import { join as join10 } from "node:path";
|
|
40220
40026
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
40221
40027
|
|
|
40222
40028
|
// ../src/auth/manager.ts
|
|
40223
40029
|
import {
|
|
40224
40030
|
readFileSync as readFileSync6,
|
|
40225
40031
|
readdirSync as readdirSync2,
|
|
40226
|
-
existsSync as
|
|
40032
|
+
existsSync as existsSync10,
|
|
40227
40033
|
writeFileSync as writeFileSync5,
|
|
40228
40034
|
mkdirSync as mkdirSync7,
|
|
40229
40035
|
mkdtempSync,
|
|
@@ -40250,7 +40056,7 @@ function parseSetupTokenUrl(output) {
|
|
|
40250
40056
|
}
|
|
40251
40057
|
function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
40252
40058
|
try {
|
|
40253
|
-
if (!
|
|
40059
|
+
if (!existsSync10(credentialsFilePath))
|
|
40254
40060
|
return null;
|
|
40255
40061
|
const raw = readFileSync6(credentialsFilePath, "utf-8");
|
|
40256
40062
|
const parsed = JSON.parse(raw);
|
|
@@ -40269,7 +40075,7 @@ function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
|
40269
40075
|
var pendingAuthAddFlows = new Map;
|
|
40270
40076
|
function pickScratchDir(label, home2 = homedir6()) {
|
|
40271
40077
|
const suffix = randomBytes2(8).toString("hex");
|
|
40272
|
-
return
|
|
40078
|
+
return join10(home2, ".switchroom", "accounts", ".in-progress", `${label}-${suffix}`);
|
|
40273
40079
|
}
|
|
40274
40080
|
function cleanScratchDir(scratchDir) {
|
|
40275
40081
|
try {
|
|
@@ -40330,7 +40136,7 @@ async function startAccountAuthSession(label, opts = {}) {
|
|
|
40330
40136
|
async function submitAccountAuthCode(flow, code, opts = {}) {
|
|
40331
40137
|
const pollIntervalMs = opts.pollIntervalMs ?? 250;
|
|
40332
40138
|
const pollTimeoutMs = opts.pollTimeoutMs ?? 120000;
|
|
40333
|
-
const credentialsPath =
|
|
40139
|
+
const credentialsPath = join10(flow.scratchDir, ".credentials.json");
|
|
40334
40140
|
if (!flow.child.stdin || flow.child.stdin.destroyed) {
|
|
40335
40141
|
cleanScratchDir(flow.scratchDir);
|
|
40336
40142
|
throw new Error("claude setup-token process stdin is not writable (child may have exited)");
|
|
@@ -40340,7 +40146,7 @@ async function submitAccountAuthCode(flow, code, opts = {}) {
|
|
|
40340
40146
|
const deadline = Date.now() + pollTimeoutMs;
|
|
40341
40147
|
while (Date.now() < deadline) {
|
|
40342
40148
|
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
40343
|
-
if (
|
|
40149
|
+
if (existsSync11(credentialsPath)) {
|
|
40344
40150
|
const token = readTokenFromCredentialsFile(credentialsPath);
|
|
40345
40151
|
if (token) {
|
|
40346
40152
|
try {
|
|
@@ -41101,11 +40907,11 @@ function renderTable(headers, rows) {
|
|
|
41101
40907
|
if (colCount <= 3 && rowCount <= 6) {
|
|
41102
40908
|
const bullets = rows.map((row) => {
|
|
41103
40909
|
const cells = headers.map((_, i) => (row[i] ?? "").trim());
|
|
41104
|
-
const key =
|
|
41105
|
-
const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${
|
|
40910
|
+
const key = escapeHtml4(cells[0] || "\u2014");
|
|
40911
|
+
const rest = cells.slice(1).filter((v) => v !== "").map((v) => ` \u2014 ${escapeHtml4(v)}`).join("");
|
|
41106
40912
|
return `\u2022 <b>${key}</b>${rest}`;
|
|
41107
40913
|
});
|
|
41108
|
-
const headerLine = colCount >= 2 ? `<b>${headers.map((h) =>
|
|
40914
|
+
const headerLine = colCount >= 2 ? `<b>${headers.map((h) => escapeHtml4(h)).join(" / ")}</b>
|
|
41109
40915
|
` : "";
|
|
41110
40916
|
return headerLine + bullets.join(`
|
|
41111
40917
|
`);
|
|
@@ -41120,7 +40926,7 @@ function renderTable(headers, rows) {
|
|
|
41120
40926
|
sepLine,
|
|
41121
40927
|
...rows.map((r) => formatRow(r))
|
|
41122
40928
|
];
|
|
41123
|
-
return `<pre>${
|
|
40929
|
+
return `<pre>${escapeHtml4(lines.join(`
|
|
41124
40930
|
`))}</pre>`;
|
|
41125
40931
|
}
|
|
41126
40932
|
function extractMarkdownTables(text, store2, placeholderPrefix) {
|
|
@@ -41168,7 +40974,7 @@ function markdownToHtml(text) {
|
|
|
41168
40974
|
const INLINE_PH = "\x00CODEINLINE";
|
|
41169
40975
|
const TABLE_PH = "\x00TABLEBLOCK";
|
|
41170
40976
|
let result = text.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, lang, code) => {
|
|
41171
|
-
const escaped =
|
|
40977
|
+
const escaped = escapeHtml4(code.replace(/\n$/, ""));
|
|
41172
40978
|
const cls = lang ? ` class="language-${lang}"` : "";
|
|
41173
40979
|
const idx = codeBlocks.length;
|
|
41174
40980
|
codeBlocks.push(`<pre><code${cls}>${escaped}</code></pre>`);
|
|
@@ -41181,7 +40987,7 @@ function markdownToHtml(text) {
|
|
|
41181
40987
|
const inlineCodes = [];
|
|
41182
40988
|
result = result.replace(/`([^`\n]+)`/g, (_m, code) => {
|
|
41183
40989
|
const idx = inlineCodes.length;
|
|
41184
|
-
inlineCodes.push(`<code>${
|
|
40990
|
+
inlineCodes.push(`<code>${escapeHtml4(code)}</code>`);
|
|
41185
40991
|
return `${INLINE_PH}${idx}\x00`;
|
|
41186
40992
|
});
|
|
41187
40993
|
const htmlTags = [];
|
|
@@ -41193,24 +40999,24 @@ function markdownToHtml(text) {
|
|
|
41193
40999
|
htmlTags.push(match);
|
|
41194
41000
|
return `${HTMLTAG_PH}${idx}\x00`;
|
|
41195
41001
|
});
|
|
41196
|
-
result =
|
|
41002
|
+
result = escapeHtml4(result);
|
|
41197
41003
|
result = result.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
|
|
41198
41004
|
result = result.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<i>$1</i>");
|
|
41199
41005
|
result = result.replace(/(?<![\w_])_(?!_)([^_\n]+?)_(?![\w_])/g, "<i>$1</i>");
|
|
41200
41006
|
result = result.replace(/~~(.+?)~~/g, "<s>$1</s>");
|
|
41201
|
-
result = result.replace(new RegExp(`${
|
|
41202
|
-
result = result.replace(new RegExp(`${
|
|
41203
|
-
result = result.replace(new RegExp(`${
|
|
41007
|
+
result = result.replace(new RegExp(`${escapeHtml4(BLOCK_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
|
|
41008
|
+
result = result.replace(new RegExp(`${escapeHtml4(TABLE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => codeBlocks[Number(idx)]);
|
|
41009
|
+
result = result.replace(new RegExp(`${escapeHtml4(INLINE_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => inlineCodes[Number(idx)]);
|
|
41204
41010
|
const ALLOWED_LINK_SCHEMES = /^(?:https?|mailto|tel|tg):/i;
|
|
41205
41011
|
result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, linkText, url) => {
|
|
41206
41012
|
const safe = ALLOWED_LINK_SCHEMES.test(url.trim()) ? url.trim() : "#";
|
|
41207
|
-
return `<a href="${
|
|
41013
|
+
return `<a href="${escapeHtml4(safe)}">${linkText}</a>`;
|
|
41208
41014
|
});
|
|
41209
41015
|
result = result.replace(/(?<![<\/\w>])(\b[\w][\w.-]*\.(?:ts|js|py|rs|go|json|yaml|yml|toml|md|txt|sh|bash|zsh|css|html|xml|sql|env|cfg|conf|ini|log|csv|tsx|jsx|vue|svelte|rb|java|kt|swift|c|cpp|h|hpp|zig|asm|wasm|lock|mod|sum)\b)(?![^<]*>)/g, "<code>$1</code>");
|
|
41210
|
-
result = result.replace(new RegExp(`${
|
|
41016
|
+
result = result.replace(new RegExp(`${escapeHtml4(HTMLTAG_PH)}(\\d+)${escapeHtml4("\x00")}`, "g"), (_m, idx) => htmlTags[Number(idx)]);
|
|
41211
41017
|
return result;
|
|
41212
41018
|
}
|
|
41213
|
-
function
|
|
41019
|
+
function escapeHtml4(text) {
|
|
41214
41020
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
41215
41021
|
}
|
|
41216
41022
|
function telegramHtmlToPlainText(html) {
|
|
@@ -41611,7 +41417,7 @@ async function finalizeCallback(ctx, opts) {
|
|
|
41611
41417
|
}
|
|
41612
41418
|
|
|
41613
41419
|
// welcome-text.ts
|
|
41614
|
-
function
|
|
41420
|
+
function escapeHtml5(text) {
|
|
41615
41421
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
41616
41422
|
}
|
|
41617
41423
|
function formatAuthLine(auth) {
|
|
@@ -41623,13 +41429,13 @@ function formatAuthLine(auth) {
|
|
|
41623
41429
|
return "\u2717 not authenticated";
|
|
41624
41430
|
}
|
|
41625
41431
|
const sub = auth.subscription_type ?? "subscription";
|
|
41626
|
-
const expires = auth.expires_in ? ` \u00b7 expires ${
|
|
41627
|
-
return `\u2713 ${
|
|
41432
|
+
const expires = auth.expires_in ? ` \u00b7 expires ${escapeHtml5(auth.expires_in)}` : "";
|
|
41433
|
+
return `\u2713 ${escapeHtml5(sub)}${expires}`;
|
|
41628
41434
|
}
|
|
41629
41435
|
function formatAgentLine(meta) {
|
|
41630
41436
|
const m = meta.model && meta.model.length > 0 ? meta.model : "default";
|
|
41631
|
-
const topic = meta.topicName ? ` \u00b7 topic: ${
|
|
41632
|
-
return `<b>${
|
|
41437
|
+
const topic = meta.topicName ? ` \u00b7 topic: ${escapeHtml5([meta.topicEmoji, meta.topicName].filter(Boolean).join(" "))}` : "";
|
|
41438
|
+
return `<b>${escapeHtml5(meta.agentName)}</b> \u00b7 model: <code>${escapeHtml5(m)}</code>${topic}`;
|
|
41633
41439
|
}
|
|
41634
41440
|
function startText(agentName3, dmDisabled) {
|
|
41635
41441
|
if (dmDisabled)
|
|
@@ -41637,7 +41443,7 @@ function startText(agentName3, dmDisabled) {
|
|
|
41637
41443
|
return [
|
|
41638
41444
|
`<b>Switchroom</b> \u2014 Telegram on your Claude Pro or Max subscription.`,
|
|
41639
41445
|
``,
|
|
41640
|
-
`This bot is the <b>${
|
|
41446
|
+
`This bot is the <b>${escapeHtml5(agentName3)}</b> agent. Pair first, then send messages here and they reach the agent; replies and reactions come back.`,
|
|
41641
41447
|
``,
|
|
41642
41448
|
`<b>To pair:</b>`,
|
|
41643
41449
|
`1. DM me anything \u2014 you'll get a 6-char code`,
|
|
@@ -41651,7 +41457,7 @@ function helpText(agentName3) {
|
|
|
41651
41457
|
return [
|
|
41652
41458
|
`<b>Switchroom</b> \u2014 your Pro/Max subscription, wired to Telegram.`,
|
|
41653
41459
|
``,
|
|
41654
|
-
`This bot is the <b>${
|
|
41460
|
+
`This bot is the <b>${escapeHtml5(agentName3)}</b> agent. Text and photos route through to it; replies, reactions and progress cards come back.`,
|
|
41655
41461
|
``,
|
|
41656
41462
|
`Tool approvals surface as inline buttons (\u2705 / \u274c) or via <code>/approve</code>, <code>/deny</code>, <code>/pending</code>. Start a fresh session with <code>/new</code> or <code>/reset</code>.`,
|
|
41657
41463
|
``,
|
|
@@ -41670,40 +41476,40 @@ var STATUS_DOT = {
|
|
|
41670
41476
|
function statusPairedText(params) {
|
|
41671
41477
|
const { user, meta } = params;
|
|
41672
41478
|
const lines = [
|
|
41673
|
-
`Paired as ${
|
|
41479
|
+
`Paired as ${escapeHtml5(user)}.`,
|
|
41674
41480
|
``,
|
|
41675
41481
|
`Agent: ${formatAgentLine(meta)}`,
|
|
41676
41482
|
`Auth: ${formatAuthLine(meta.auth)}`
|
|
41677
41483
|
];
|
|
41678
41484
|
if (meta.status)
|
|
41679
|
-
lines.push(`Status: <code>${
|
|
41485
|
+
lines.push(`Status: <code>${escapeHtml5(meta.status)}</code>${meta.uptime ? ` \u00b7 up ${escapeHtml5(meta.uptime)}` : ""}`);
|
|
41680
41486
|
if (meta.live && meta.live.length > 0) {
|
|
41681
41487
|
lines.push("");
|
|
41682
41488
|
lines.push("<b>Health</b>");
|
|
41683
41489
|
for (const row of meta.live) {
|
|
41684
41490
|
const dot = STATUS_DOT[row.status] ?? STATUS_DOT.fail;
|
|
41685
|
-
lines.push(`${dot} <b>${
|
|
41491
|
+
lines.push(`${dot} <b>${escapeHtml5(row.label)}</b> ${escapeHtml5(row.detail)}`);
|
|
41686
41492
|
}
|
|
41687
41493
|
}
|
|
41688
41494
|
const audit = meta.audit;
|
|
41689
41495
|
if (audit) {
|
|
41690
41496
|
lines.push("");
|
|
41691
41497
|
if (audit.version)
|
|
41692
|
-
lines.push(`<b>Version</b> ${
|
|
41498
|
+
lines.push(`<b>Version</b> ${escapeHtml5(audit.version)}`);
|
|
41693
41499
|
if (meta.extendsProfile)
|
|
41694
|
-
lines.push(`<b>Profile</b> ${
|
|
41500
|
+
lines.push(`<b>Profile</b> ${escapeHtml5(meta.extendsProfile)}`);
|
|
41695
41501
|
if (audit.tools)
|
|
41696
|
-
lines.push(`<b>Tools</b> ${
|
|
41502
|
+
lines.push(`<b>Tools</b> ${escapeHtml5(audit.tools)}`);
|
|
41697
41503
|
if (audit.toolsDeny)
|
|
41698
|
-
lines.push(`<b>Deny</b> ${
|
|
41504
|
+
lines.push(`<b>Deny</b> ${escapeHtml5(audit.toolsDeny)}`);
|
|
41699
41505
|
if (audit.skills)
|
|
41700
|
-
lines.push(`<b>Skills</b> ${
|
|
41506
|
+
lines.push(`<b>Skills</b> ${escapeHtml5(audit.skills)}`);
|
|
41701
41507
|
if (audit.limits)
|
|
41702
|
-
lines.push(`<b>Limits</b> ${
|
|
41508
|
+
lines.push(`<b>Limits</b> ${escapeHtml5(audit.limits)}`);
|
|
41703
41509
|
if (audit.channel)
|
|
41704
|
-
lines.push(`<b>Channel</b> ${
|
|
41510
|
+
lines.push(`<b>Channel</b> ${escapeHtml5(audit.channel)}`);
|
|
41705
41511
|
if (audit.memoryBank)
|
|
41706
|
-
lines.push(`<b>Memory</b> ${
|
|
41512
|
+
lines.push(`<b>Memory</b> ${escapeHtml5(audit.memoryBank)}`);
|
|
41707
41513
|
}
|
|
41708
41514
|
return lines.join(`
|
|
41709
41515
|
`);
|
|
@@ -41711,7 +41517,7 @@ function statusPairedText(params) {
|
|
|
41711
41517
|
function statusPendingText(code) {
|
|
41712
41518
|
return `Pending pairing \u2014 run in Claude Code:
|
|
41713
41519
|
|
|
41714
|
-
<code>/telegram:access pair ${
|
|
41520
|
+
<code>/telegram:access pair ${escapeHtml5(code)}</code>`;
|
|
41715
41521
|
}
|
|
41716
41522
|
function statusUnpairedText() {
|
|
41717
41523
|
return "Not paired. Send me a message to get a pairing code.";
|
|
@@ -41740,7 +41546,7 @@ var TELEGRAM_BASE_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(0, 3);
|
|
|
41740
41546
|
var TELEGRAM_SWITCHROOM_COMMANDS = TELEGRAM_MENU_COMMANDS.slice(3);
|
|
41741
41547
|
function switchroomHelpText(agentName3) {
|
|
41742
41548
|
return [
|
|
41743
|
-
`<b>Switchroom bot</b> \u2014 commands for the <b>${
|
|
41549
|
+
`<b>Switchroom bot</b> \u2014 commands for the <b>${escapeHtml5(agentName3)}</b> agent.`,
|
|
41744
41550
|
``,
|
|
41745
41551
|
`<b>Session & approvals</b>`,
|
|
41746
41552
|
`<code>/new</code> \u2014 fresh session (flush handoff, restart)`,
|
|
@@ -41788,15 +41594,15 @@ function switchroomHelpText(agentName3) {
|
|
|
41788
41594
|
`);
|
|
41789
41595
|
}
|
|
41790
41596
|
function restartAckText(agentName3) {
|
|
41791
|
-
return `\uD83D\uDD04 Restarting <b>${
|
|
41597
|
+
return `\uD83D\uDD04 Restarting <b>${escapeHtml5(agentName3)}</b>\u2026`;
|
|
41792
41598
|
}
|
|
41793
41599
|
function newSessionAckText(agentName3, flushedHandoff) {
|
|
41794
41600
|
const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
|
|
41795
|
-
return `\uD83C\uDD95 Started fresh session for <b>${
|
|
41601
|
+
return `\uD83C\uDD95 Started fresh session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
|
|
41796
41602
|
}
|
|
41797
41603
|
function resetSessionAckText(agentName3, flushedHandoff) {
|
|
41798
41604
|
const tail = flushedHandoff ? " \u00b7 flushed handoff" : "";
|
|
41799
|
-
return `\uD83D\uDD04 Reset session for <b>${
|
|
41605
|
+
return `\uD83D\uDD04 Reset session for <b>${escapeHtml5(agentName3)}</b>${tail} \u00b7 restarting\u2026`;
|
|
41800
41606
|
}
|
|
41801
41607
|
|
|
41802
41608
|
// gateway/auth-status-adapter.ts
|
|
@@ -41900,8 +41706,8 @@ function isTurnFlushSafetyEnabled(env = process.env) {
|
|
|
41900
41706
|
}
|
|
41901
41707
|
|
|
41902
41708
|
// handoff-continuity.ts
|
|
41903
|
-
import { readFileSync as readFileSync9, unlinkSync as
|
|
41904
|
-
import { dirname as dirname7, join as
|
|
41709
|
+
import { readFileSync as readFileSync9, unlinkSync as unlinkSync2, existsSync as existsSync13, writeFileSync as writeFileSync6, renameSync as renameSync2 } from "node:fs";
|
|
41710
|
+
import { dirname as dirname7, join as join13 } from "node:path";
|
|
41905
41711
|
var TOPIC_DISPLAY_MAX = 117;
|
|
41906
41712
|
var HANDOFF_TOPIC_FILENAME = ".handoff-topic";
|
|
41907
41713
|
var LAST_TURN_SUMMARY_FILENAME = ".last-turn-summary";
|
|
@@ -41912,8 +41718,8 @@ function resolveAgentDirFromEnv() {
|
|
|
41912
41718
|
return dirname7(state3);
|
|
41913
41719
|
}
|
|
41914
41720
|
function readHandoffTopic(agentDir) {
|
|
41915
|
-
const p =
|
|
41916
|
-
if (!
|
|
41721
|
+
const p = join13(agentDir, HANDOFF_TOPIC_FILENAME);
|
|
41722
|
+
if (!existsSync13(p))
|
|
41917
41723
|
return null;
|
|
41918
41724
|
let raw;
|
|
41919
41725
|
try {
|
|
@@ -41931,8 +41737,8 @@ function readHandoffTopic(agentDir) {
|
|
|
41931
41737
|
return topic;
|
|
41932
41738
|
}
|
|
41933
41739
|
function readLastTurnSummary(agentDir) {
|
|
41934
|
-
const p =
|
|
41935
|
-
if (!
|
|
41740
|
+
const p = join13(agentDir, LAST_TURN_SUMMARY_FILENAME);
|
|
41741
|
+
if (!existsSync13(p))
|
|
41936
41742
|
return null;
|
|
41937
41743
|
let raw;
|
|
41938
41744
|
try {
|
|
@@ -41951,16 +41757,16 @@ function readLastTurnSummary(agentDir) {
|
|
|
41951
41757
|
}
|
|
41952
41758
|
function consumeHandoffTopic(agentDir) {
|
|
41953
41759
|
const primary = readHandoffTopic(agentDir);
|
|
41954
|
-
const primaryPath =
|
|
41955
|
-
const fallbackPath =
|
|
41760
|
+
const primaryPath = join13(agentDir, HANDOFF_TOPIC_FILENAME);
|
|
41761
|
+
const fallbackPath = join13(agentDir, LAST_TURN_SUMMARY_FILENAME);
|
|
41956
41762
|
const removeFallback = () => {
|
|
41957
41763
|
try {
|
|
41958
|
-
|
|
41764
|
+
unlinkSync2(fallbackPath);
|
|
41959
41765
|
} catch {}
|
|
41960
41766
|
};
|
|
41961
41767
|
if (primary !== null) {
|
|
41962
41768
|
try {
|
|
41963
|
-
|
|
41769
|
+
unlinkSync2(primaryPath);
|
|
41964
41770
|
} catch {}
|
|
41965
41771
|
removeFallback();
|
|
41966
41772
|
return primary;
|
|
@@ -41981,7 +41787,7 @@ function shouldShowHandoffLine() {
|
|
|
41981
41787
|
function formatHandoffLine(topic, format) {
|
|
41982
41788
|
const prefix = "\u21a9\ufe0f Picked up where we left off, ";
|
|
41983
41789
|
if (format === "html") {
|
|
41984
|
-
return `<i>${prefix}${
|
|
41790
|
+
return `<i>${prefix}${escapeHtml6(topic)}</i>
|
|
41985
41791
|
|
|
41986
41792
|
`;
|
|
41987
41793
|
}
|
|
@@ -41996,7 +41802,7 @@ function formatHandoffLine(topic, format) {
|
|
|
41996
41802
|
|
|
41997
41803
|
`;
|
|
41998
41804
|
}
|
|
41999
|
-
function
|
|
41805
|
+
function escapeHtml6(s) {
|
|
42000
41806
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
42001
41807
|
}
|
|
42002
41808
|
var MDV2_SPECIALS = /[_*\[\]()~`>#+\-=|{}.!\\]/g;
|
|
@@ -42005,15 +41811,15 @@ function escapeMarkdownV2(s) {
|
|
|
42005
41811
|
}
|
|
42006
41812
|
|
|
42007
41813
|
// active-reactions.ts
|
|
42008
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, renameSync as renameSync3, existsSync as
|
|
42009
|
-
import { join as
|
|
41814
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, renameSync as renameSync3, existsSync as existsSync14, unlinkSync as unlinkSync3 } from "node:fs";
|
|
41815
|
+
import { join as join14 } from "node:path";
|
|
42010
41816
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
42011
41817
|
function reactionsPath(agentDir) {
|
|
42012
|
-
return
|
|
41818
|
+
return join14(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
42013
41819
|
}
|
|
42014
41820
|
function readActiveReactions(agentDir) {
|
|
42015
41821
|
const p = reactionsPath(agentDir);
|
|
42016
|
-
if (!
|
|
41822
|
+
if (!existsSync14(p))
|
|
42017
41823
|
return [];
|
|
42018
41824
|
let raw;
|
|
42019
41825
|
try {
|
|
@@ -42043,7 +41849,7 @@ function writeActiveReactions(agentDir, reactions) {
|
|
|
42043
41849
|
const p = reactionsPath(agentDir);
|
|
42044
41850
|
if (reactions.length === 0) {
|
|
42045
41851
|
try {
|
|
42046
|
-
|
|
41852
|
+
unlinkSync3(p);
|
|
42047
41853
|
} catch {}
|
|
42048
41854
|
return;
|
|
42049
41855
|
}
|
|
@@ -42068,20 +41874,20 @@ function removeActiveReaction(agentDir, chatId, messageId) {
|
|
|
42068
41874
|
}
|
|
42069
41875
|
function clearActiveReactions(agentDir) {
|
|
42070
41876
|
try {
|
|
42071
|
-
|
|
41877
|
+
unlinkSync3(reactionsPath(agentDir));
|
|
42072
41878
|
} catch {}
|
|
42073
41879
|
}
|
|
42074
41880
|
|
|
42075
41881
|
// active-reactions.ts
|
|
42076
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync4, existsSync as
|
|
42077
|
-
import { join as
|
|
41882
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync4, existsSync as existsSync15, unlinkSync as unlinkSync4 } from "node:fs";
|
|
41883
|
+
import { join as join15 } from "node:path";
|
|
42078
41884
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
42079
41885
|
function reactionsPath2(agentDir) {
|
|
42080
|
-
return
|
|
41886
|
+
return join15(agentDir, ACTIVE_REACTIONS_FILENAME2);
|
|
42081
41887
|
}
|
|
42082
41888
|
function readActiveReactions2(agentDir) {
|
|
42083
41889
|
const p = reactionsPath2(agentDir);
|
|
42084
|
-
if (!
|
|
41890
|
+
if (!existsSync15(p))
|
|
42085
41891
|
return [];
|
|
42086
41892
|
let raw;
|
|
42087
41893
|
try {
|
|
@@ -42109,7 +41915,7 @@ function readActiveReactions2(agentDir) {
|
|
|
42109
41915
|
}
|
|
42110
41916
|
function clearActiveReactions2(agentDir) {
|
|
42111
41917
|
try {
|
|
42112
|
-
|
|
41918
|
+
unlinkSync4(reactionsPath2(agentDir));
|
|
42113
41919
|
} catch {}
|
|
42114
41920
|
}
|
|
42115
41921
|
|
|
@@ -42962,14 +42768,14 @@ async function approvalRecord(args, opts) {
|
|
|
42962
42768
|
}
|
|
42963
42769
|
|
|
42964
42770
|
// quota-check.ts
|
|
42965
|
-
import { readFileSync as readFileSync13, existsSync as
|
|
42966
|
-
import { join as
|
|
42771
|
+
import { readFileSync as readFileSync13, existsSync as existsSync17 } from "fs";
|
|
42772
|
+
import { join as join17 } from "path";
|
|
42967
42773
|
var OAUTH_BETA2 = "oauth-2025-04-20";
|
|
42968
42774
|
var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
|
|
42969
42775
|
var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
|
|
42970
42776
|
function readOauthToken2(claudeConfigDir) {
|
|
42971
|
-
const tokenFile =
|
|
42972
|
-
if (!
|
|
42777
|
+
const tokenFile = join17(claudeConfigDir, ".oauth-token");
|
|
42778
|
+
if (!existsSync17(tokenFile))
|
|
42973
42779
|
return null;
|
|
42974
42780
|
try {
|
|
42975
42781
|
const raw = readFileSync13(tokenFile, "utf-8").trim();
|
|
@@ -43568,7 +43374,7 @@ init_schema();
|
|
|
43568
43374
|
init_paths();
|
|
43569
43375
|
init_overlay_loader();
|
|
43570
43376
|
init_merge();
|
|
43571
|
-
import { readFileSync as readFileSync14, existsSync as
|
|
43377
|
+
import { readFileSync as readFileSync14, existsSync as existsSync18 } from "node:fs";
|
|
43572
43378
|
import { homedir as homedir8 } from "node:os";
|
|
43573
43379
|
import { resolve as resolve5 } from "node:path";
|
|
43574
43380
|
|
|
@@ -43644,7 +43450,7 @@ function findConfigFile2(startDir) {
|
|
|
43644
43450
|
resolve5(userDir, "clerk.yml")
|
|
43645
43451
|
].filter(Boolean);
|
|
43646
43452
|
for (const path of searchPaths) {
|
|
43647
|
-
if (
|
|
43453
|
+
if (existsSync18(path)) {
|
|
43648
43454
|
return path;
|
|
43649
43455
|
}
|
|
43650
43456
|
}
|
|
@@ -43652,7 +43458,7 @@ function findConfigFile2(startDir) {
|
|
|
43652
43458
|
}
|
|
43653
43459
|
function loadConfig2(configPath) {
|
|
43654
43460
|
const filePath = configPath ?? findConfigFile2();
|
|
43655
|
-
if (!
|
|
43461
|
+
if (!existsSync18(filePath)) {
|
|
43656
43462
|
throw new ConfigError2(`Config file not found: ${filePath}`);
|
|
43657
43463
|
}
|
|
43658
43464
|
let raw;
|
|
@@ -44085,9 +43891,9 @@ function resolveOutboundTopic(config, event) {
|
|
|
44085
43891
|
}
|
|
44086
43892
|
|
|
44087
43893
|
// ../src/agents/perf.ts
|
|
44088
|
-
import { existsSync as
|
|
43894
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
|
|
44089
43895
|
function readTurnUsages(jsonlPath, lastN) {
|
|
44090
|
-
if (!
|
|
43896
|
+
if (!existsSync19(jsonlPath))
|
|
44091
43897
|
return [];
|
|
44092
43898
|
if (lastN <= 0)
|
|
44093
43899
|
return [];
|
|
@@ -44231,7 +44037,7 @@ function nextCompactNotify(state3, ev) {
|
|
|
44231
44037
|
}
|
|
44232
44038
|
|
|
44233
44039
|
// gateway/hostd-dispatch.ts
|
|
44234
|
-
import { existsSync as
|
|
44040
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
44235
44041
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
44236
44042
|
|
|
44237
44043
|
// ../src/host-control/client.ts
|
|
@@ -44522,13 +44328,13 @@ function hostdSocketPath(agentName3) {
|
|
|
44522
44328
|
function hostdWillBeUsed(agentName3) {
|
|
44523
44329
|
if (!isHostdEnabled())
|
|
44524
44330
|
return false;
|
|
44525
|
-
return
|
|
44331
|
+
return existsSync20(hostdSocketPath(agentName3));
|
|
44526
44332
|
}
|
|
44527
44333
|
async function tryHostdDispatch(agentName3, req) {
|
|
44528
44334
|
if (!isHostdEnabled())
|
|
44529
44335
|
return "not-configured";
|
|
44530
44336
|
const sockPath = hostdSocketPath(agentName3);
|
|
44531
|
-
if (!
|
|
44337
|
+
if (!existsSync20(sockPath))
|
|
44532
44338
|
return "not-configured";
|
|
44533
44339
|
try {
|
|
44534
44340
|
return await hostdRequest({ socketPath: sockPath, timeoutMs: 5000 }, req);
|
|
@@ -44552,7 +44358,7 @@ async function hostdGetStatusOnce(agentName3, targetRequestId) {
|
|
|
44552
44358
|
if (!isHostdEnabled())
|
|
44553
44359
|
return "not-configured";
|
|
44554
44360
|
const sockPath = hostdSocketPath(agentName3);
|
|
44555
|
-
if (!
|
|
44361
|
+
if (!existsSync20(sockPath))
|
|
44556
44362
|
return "not-configured";
|
|
44557
44363
|
try {
|
|
44558
44364
|
const resp = await hostdRequest({ socketPath: sockPath, timeoutMs: 3000 }, {
|
|
@@ -44573,7 +44379,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
|
|
|
44573
44379
|
if (!isHostdEnabled())
|
|
44574
44380
|
return "not-configured";
|
|
44575
44381
|
const sockPath = hostdSocketPath(agentName3);
|
|
44576
|
-
if (!
|
|
44382
|
+
if (!existsSync20(sockPath))
|
|
44577
44383
|
return "not-configured";
|
|
44578
44384
|
const now = opts.now ?? Date.now;
|
|
44579
44385
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -44651,7 +44457,7 @@ function shouldSweepChatAtBoot(chatId) {
|
|
|
44651
44457
|
}
|
|
44652
44458
|
|
|
44653
44459
|
// gateway/ipc-server.ts
|
|
44654
|
-
import { renameSync as renameSync5, unlinkSync as
|
|
44460
|
+
import { renameSync as renameSync5, unlinkSync as unlinkSync5 } from "fs";
|
|
44655
44461
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
44656
44462
|
var VALID_OPERATOR_KINDS = new Set([
|
|
44657
44463
|
"credentials-expired",
|
|
@@ -44769,7 +44575,7 @@ function createIpcServer(options) {
|
|
|
44769
44575
|
renameSync5(socketPath, socketPath + ".bak");
|
|
44770
44576
|
} catch {}
|
|
44771
44577
|
try {
|
|
44772
|
-
|
|
44578
|
+
unlinkSync5(socketPath + ".bak");
|
|
44773
44579
|
} catch {}
|
|
44774
44580
|
const clients = new Set;
|
|
44775
44581
|
const agentIndex = new Map;
|
|
@@ -45375,13 +45181,13 @@ function buildMs365CardText(p) {
|
|
|
45375
45181
|
const lines = [];
|
|
45376
45182
|
lines.push(`\uD83D\uDCC4 Microsoft 365 write approval`);
|
|
45377
45183
|
lines.push("");
|
|
45378
|
-
lines.push(`Agent: ${
|
|
45379
|
-
lines.push(`Tool: ${
|
|
45380
|
-
lines.push(`Item: ${
|
|
45184
|
+
lines.push(`Agent: ${truncate2(p.agentName, 64)}`);
|
|
45185
|
+
lines.push(`Tool: ${truncate2(p.toolName.replace(/^mcp__/, ""), 96)}`);
|
|
45186
|
+
lines.push(`Item: ${truncate2(p.itemDisplayName, 256)}`);
|
|
45381
45187
|
if (p.itemId !== "(new)") {
|
|
45382
|
-
lines.push(`ID: ${
|
|
45188
|
+
lines.push(`ID: ${truncate2(p.itemId, 96)}`);
|
|
45383
45189
|
}
|
|
45384
|
-
lines.push(`Account: ${
|
|
45190
|
+
lines.push(`Account: ${truncate2(p.accountEmail, 96)}`);
|
|
45385
45191
|
if (typeof p.sizeBytesBefore === "number" || typeof p.sizeBytesAfter === "number") {
|
|
45386
45192
|
const before = p.sizeBytesBefore ?? 0;
|
|
45387
45193
|
const after = p.sizeBytesAfter ?? 0;
|
|
@@ -45390,18 +45196,18 @@ function buildMs365CardText(p) {
|
|
|
45390
45196
|
lines.push(`Size: ${humanBytes(before)} \u2192 ${humanBytes(after)} (${sign}${humanBytes(delta)})`);
|
|
45391
45197
|
}
|
|
45392
45198
|
if (p.deepLink) {
|
|
45393
|
-
lines.push(`Link: ${
|
|
45199
|
+
lines.push(`Link: ${truncate2(p.deepLink, 256)}`);
|
|
45394
45200
|
}
|
|
45395
45201
|
if (p.agentRationale) {
|
|
45396
45202
|
lines.push("");
|
|
45397
|
-
lines.push(`\uD83D\uDCAC ${
|
|
45203
|
+
lines.push(`\uD83D\uDCAC ${truncate2(p.agentRationale, 512)}`);
|
|
45398
45204
|
}
|
|
45399
45205
|
lines.push("");
|
|
45400
45206
|
lines.push("\u26a0\ufe0f Weak attestation (RFC \u00a78 v1): operator should click through to verify the actual change before approving. Structural diff coming v1.5.");
|
|
45401
45207
|
return lines.join(`
|
|
45402
45208
|
`);
|
|
45403
45209
|
}
|
|
45404
|
-
function
|
|
45210
|
+
function truncate2(s, n) {
|
|
45405
45211
|
if (s.length <= n)
|
|
45406
45212
|
return s;
|
|
45407
45213
|
return s.slice(0, n - 1) + "\u2026";
|
|
@@ -45517,9 +45323,9 @@ function buildDiffPreviewCard(input) {
|
|
|
45517
45323
|
}
|
|
45518
45324
|
const preview = input.preview;
|
|
45519
45325
|
const bodyLines = [];
|
|
45520
|
-
bodyLines.push(`<b>${
|
|
45326
|
+
bodyLines.push(`<b>${escapeHtml7(preview.title)}</b>`);
|
|
45521
45327
|
for (const line of preview.lines) {
|
|
45522
|
-
bodyLines.push(
|
|
45328
|
+
bodyLines.push(escapeHtml7(line.text));
|
|
45523
45329
|
}
|
|
45524
45330
|
const text = bodyLines.join(`
|
|
45525
45331
|
`);
|
|
@@ -45572,7 +45378,7 @@ function buildDiffPreviewCard(input) {
|
|
|
45572
45378
|
}
|
|
45573
45379
|
return { text, reply_markup: kb };
|
|
45574
45380
|
}
|
|
45575
|
-
function
|
|
45381
|
+
function escapeHtml7(s) {
|
|
45576
45382
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
45577
45383
|
}
|
|
45578
45384
|
|
|
@@ -46418,14 +46224,14 @@ function buildVaultSaveDiscardedInbound(opts) {
|
|
|
46418
46224
|
// gateway/subagent-handback-inbound-builder.ts
|
|
46419
46225
|
var HANDBACK_RESULT_MAX = 3000;
|
|
46420
46226
|
var HANDBACK_DESC_MAX = 200;
|
|
46421
|
-
function
|
|
46227
|
+
function truncate3(s, max) {
|
|
46422
46228
|
const t = s.trim();
|
|
46423
46229
|
return t.length > max ? t.slice(0, max) + "\u2026" : t;
|
|
46424
46230
|
}
|
|
46425
46231
|
function buildSubagentHandbackInbound(opts) {
|
|
46426
46232
|
const ts = opts.nowMs ?? Date.now();
|
|
46427
|
-
const desc =
|
|
46428
|
-
const result =
|
|
46233
|
+
const desc = truncate3(opts.ctx.taskDescription, HANDBACK_DESC_MAX) || "(no description)";
|
|
46234
|
+
const result = truncate3(opts.ctx.resultText, HANDBACK_RESULT_MAX);
|
|
46429
46235
|
const text = opts.ctx.outcome === "failed" ? `\uD83E\uDD1D A background worker you dispatched has FAILED.
|
|
46430
46236
|
|
|
46431
46237
|
` + `Task: ${desc}
|
|
@@ -46489,7 +46295,7 @@ function decideSubagentHandback(input) {
|
|
|
46489
46295
|
var PROGRESS_RESULT_MAX = 800;
|
|
46490
46296
|
var PROGRESS_DESC_MAX = 200;
|
|
46491
46297
|
var DEFAULT_PROGRESS_INTERVAL_MS = 5 * 60 * 1000;
|
|
46492
|
-
function
|
|
46298
|
+
function truncate4(s, max) {
|
|
46493
46299
|
const t = s.trim();
|
|
46494
46300
|
return t.length > max ? t.slice(0, max) + "\u2026" : t;
|
|
46495
46301
|
}
|
|
@@ -46503,8 +46309,8 @@ function formatElapsed(ms) {
|
|
|
46503
46309
|
}
|
|
46504
46310
|
function buildSubagentProgressInbound(opts) {
|
|
46505
46311
|
const ts = opts.nowMs ?? Date.now();
|
|
46506
|
-
const desc =
|
|
46507
|
-
const summary =
|
|
46312
|
+
const desc = truncate4(opts.ctx.taskDescription, PROGRESS_DESC_MAX) || "(no description)";
|
|
46313
|
+
const summary = truncate4(opts.ctx.latestSummary, PROGRESS_RESULT_MAX);
|
|
46508
46314
|
const elapsed = formatElapsed(opts.ctx.elapsedMs);
|
|
46509
46315
|
const expiresAt = ts + 2 * opts.ctx.progressIntervalMs;
|
|
46510
46316
|
const text = `\uD83D\uDD04 A background worker you dispatched is still running.
|
|
@@ -46832,7 +46638,7 @@ function escapeBody(s) {
|
|
|
46832
46638
|
}
|
|
46833
46639
|
|
|
46834
46640
|
// gateway/pid-file.ts
|
|
46835
|
-
import { writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as
|
|
46641
|
+
import { writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync6, renameSync as renameSync6 } from "node:fs";
|
|
46836
46642
|
function writePidFile(path, record) {
|
|
46837
46643
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
46838
46644
|
writeFileSync9(tmp, JSON.stringify(record), "utf-8");
|
|
@@ -46840,7 +46646,7 @@ function writePidFile(path, record) {
|
|
|
46840
46646
|
}
|
|
46841
46647
|
function clearPidFile(path) {
|
|
46842
46648
|
try {
|
|
46843
|
-
|
|
46649
|
+
unlinkSync6(path);
|
|
46844
46650
|
} catch {}
|
|
46845
46651
|
}
|
|
46846
46652
|
|
|
@@ -47057,7 +46863,7 @@ function safeCount(fn) {
|
|
|
47057
46863
|
}
|
|
47058
46864
|
|
|
47059
46865
|
// gateway/session-marker.ts
|
|
47060
|
-
import { writeFileSync as writeFileSync10, readFileSync as readFileSync18, renameSync as renameSync7, unlinkSync as
|
|
46866
|
+
import { writeFileSync as writeFileSync10, readFileSync as readFileSync18, renameSync as renameSync7, unlinkSync as unlinkSync7 } from "node:fs";
|
|
47061
46867
|
function writeSessionMarker(path, marker) {
|
|
47062
46868
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
47063
46869
|
writeFileSync10(tmp, JSON.stringify(marker), "utf-8");
|
|
@@ -47087,7 +46893,7 @@ function shouldFireRestartBanner(input) {
|
|
|
47087
46893
|
}
|
|
47088
46894
|
|
|
47089
46895
|
// gateway/clean-shutdown-marker.ts
|
|
47090
|
-
import { writeFileSync as writeFileSync11, readFileSync as readFileSync19, renameSync as renameSync8, unlinkSync as
|
|
46896
|
+
import { writeFileSync as writeFileSync11, readFileSync as readFileSync19, renameSync as renameSync8, unlinkSync as unlinkSync8 } from "node:fs";
|
|
47091
46897
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
47092
46898
|
function writeCleanShutdownMarker(path, marker) {
|
|
47093
46899
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -47111,7 +46917,7 @@ function readCleanShutdownMarker(path) {
|
|
|
47111
46917
|
}
|
|
47112
46918
|
function clearCleanShutdownMarker(path) {
|
|
47113
46919
|
try {
|
|
47114
|
-
|
|
46920
|
+
unlinkSync8(path);
|
|
47115
46921
|
} catch {}
|
|
47116
46922
|
}
|
|
47117
46923
|
function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
@@ -47891,16 +47697,16 @@ function classifyAdminGate(text, myAgentName) {
|
|
|
47891
47697
|
|
|
47892
47698
|
// subagent-watcher.ts
|
|
47893
47699
|
import {
|
|
47894
|
-
existsSync as
|
|
47895
|
-
openSync as
|
|
47700
|
+
existsSync as existsSync22,
|
|
47701
|
+
openSync as openSync2,
|
|
47896
47702
|
readSync,
|
|
47897
47703
|
statSync as statSync6,
|
|
47898
|
-
closeSync as
|
|
47704
|
+
closeSync as closeSync2,
|
|
47899
47705
|
watch,
|
|
47900
47706
|
readdirSync as readdirSync3,
|
|
47901
47707
|
readFileSync as readFileSync21
|
|
47902
47708
|
} from "fs";
|
|
47903
|
-
import { join as
|
|
47709
|
+
import { join as join19 } from "path";
|
|
47904
47710
|
|
|
47905
47711
|
// operator-events.ts
|
|
47906
47712
|
var DEFAULT_OPERATOR_EVENT_COOLDOWN_MS2 = 5 * 60000;
|
|
@@ -48024,7 +47830,7 @@ function sanitiseToolArg(name, raw) {
|
|
|
48024
47830
|
case "NotebookEdit": {
|
|
48025
47831
|
const fp = raw.file_path;
|
|
48026
47832
|
if (typeof fp === "string" && fp.length > 0)
|
|
48027
|
-
out =
|
|
47833
|
+
out = basename3(fp);
|
|
48028
47834
|
break;
|
|
48029
47835
|
}
|
|
48030
47836
|
case "Bash": {
|
|
@@ -48060,7 +47866,7 @@ function sanitiseToolArg(name, raw) {
|
|
|
48060
47866
|
out = out.slice(0, SANITISE_MAX_LEN - 1) + "\u2026";
|
|
48061
47867
|
return out;
|
|
48062
47868
|
}
|
|
48063
|
-
function
|
|
47869
|
+
function basename3(p) {
|
|
48064
47870
|
const idx = p.lastIndexOf("/");
|
|
48065
47871
|
return idx === -1 ? p : p.slice(idx + 1);
|
|
48066
47872
|
}
|
|
@@ -48142,29 +47948,29 @@ function bumpSubagentActivity(db2, args) {
|
|
|
48142
47948
|
|
|
48143
47949
|
// gateway/turn-active-marker.ts
|
|
48144
47950
|
import {
|
|
48145
|
-
closeSync
|
|
48146
|
-
existsSync as
|
|
47951
|
+
closeSync,
|
|
47952
|
+
existsSync as existsSync21,
|
|
48147
47953
|
mkdirSync as mkdirSync10,
|
|
48148
|
-
openSync
|
|
47954
|
+
openSync,
|
|
48149
47955
|
readFileSync as readFileSync20,
|
|
48150
47956
|
statSync as statSync5,
|
|
48151
|
-
unlinkSync as
|
|
47957
|
+
unlinkSync as unlinkSync9,
|
|
48152
47958
|
utimesSync,
|
|
48153
47959
|
writeFileSync as writeFileSync12
|
|
48154
47960
|
} from "node:fs";
|
|
48155
|
-
import { join as
|
|
47961
|
+
import { join as join18 } from "node:path";
|
|
48156
47962
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
48157
47963
|
function touchTurnActiveMarker(stateDir) {
|
|
48158
|
-
const path =
|
|
48159
|
-
if (!
|
|
47964
|
+
const path = join18(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
47965
|
+
if (!existsSync21(path))
|
|
48160
47966
|
return;
|
|
48161
47967
|
const now = new Date;
|
|
48162
47968
|
try {
|
|
48163
47969
|
utimesSync(path, now, now);
|
|
48164
47970
|
} catch {
|
|
48165
47971
|
try {
|
|
48166
|
-
const fd =
|
|
48167
|
-
|
|
47972
|
+
const fd = openSync(path, "r+");
|
|
47973
|
+
closeSync(fd);
|
|
48168
47974
|
} catch {}
|
|
48169
47975
|
}
|
|
48170
47976
|
}
|
|
@@ -48378,11 +48184,11 @@ function startSubagentWatcher(config) {
|
|
|
48378
48184
|
clearTimeout(ref.ref);
|
|
48379
48185
|
});
|
|
48380
48186
|
const fs2 = config.fs ?? {
|
|
48381
|
-
existsSync:
|
|
48187
|
+
existsSync: existsSync22,
|
|
48382
48188
|
readdirSync: readdirSync3,
|
|
48383
48189
|
statSync: statSync6,
|
|
48384
|
-
openSync:
|
|
48385
|
-
closeSync:
|
|
48190
|
+
openSync: openSync2,
|
|
48191
|
+
closeSync: closeSync2,
|
|
48386
48192
|
readSync,
|
|
48387
48193
|
watch
|
|
48388
48194
|
};
|
|
@@ -48547,7 +48353,7 @@ function startSubagentWatcher(config) {
|
|
|
48547
48353
|
if (idleMs >= threshold) {
|
|
48548
48354
|
entry.stallNotified = true;
|
|
48549
48355
|
entry.stalledAt = n;
|
|
48550
|
-
const desc =
|
|
48356
|
+
const desc = escapeHtml8(truncate5(entry.description, 80));
|
|
48551
48357
|
const idleSec = Math.floor(idleMs / 1000);
|
|
48552
48358
|
log?.(`subagent-watcher: stall detected for ${entry.agentId} (idle ${idleSec}s): ${desc}`);
|
|
48553
48359
|
if (db2 != null) {
|
|
@@ -48612,8 +48418,8 @@ function startSubagentWatcher(config) {
|
|
|
48612
48418
|
function rescanSubagentDirs() {
|
|
48613
48419
|
if (stopped)
|
|
48614
48420
|
return;
|
|
48615
|
-
const claudeHome =
|
|
48616
|
-
const projectsRoot =
|
|
48421
|
+
const claudeHome = join19(agentDir, ".claude");
|
|
48422
|
+
const projectsRoot = join19(claudeHome, "projects");
|
|
48617
48423
|
if (!fs2.existsSync(projectsRoot))
|
|
48618
48424
|
return;
|
|
48619
48425
|
let projectDirs;
|
|
@@ -48630,7 +48436,7 @@ function startSubagentWatcher(config) {
|
|
|
48630
48436
|
}
|
|
48631
48437
|
continue;
|
|
48632
48438
|
}
|
|
48633
|
-
const projectPath =
|
|
48439
|
+
const projectPath = join19(projectsRoot, pDir);
|
|
48634
48440
|
let sessionDirs;
|
|
48635
48441
|
try {
|
|
48636
48442
|
sessionDirs = fs2.readdirSync(projectPath);
|
|
@@ -48640,7 +48446,7 @@ function startSubagentWatcher(config) {
|
|
|
48640
48446
|
for (const sDir of sessionDirs) {
|
|
48641
48447
|
if (sDir.endsWith(".jsonl"))
|
|
48642
48448
|
continue;
|
|
48643
|
-
const subagentsPath =
|
|
48449
|
+
const subagentsPath = join19(projectPath, sDir, "subagents");
|
|
48644
48450
|
if (!fs2.existsSync(subagentsPath))
|
|
48645
48451
|
continue;
|
|
48646
48452
|
if (!dirWatchers.has(subagentsPath)) {
|
|
@@ -48648,7 +48454,7 @@ function startSubagentWatcher(config) {
|
|
|
48648
48454
|
const w = fs2.watch(subagentsPath, (_event, filename) => {
|
|
48649
48455
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
48650
48456
|
return;
|
|
48651
|
-
const filePath =
|
|
48457
|
+
const filePath = join19(subagentsPath, filename.toString());
|
|
48652
48458
|
if (!knownFiles.has(filePath)) {
|
|
48653
48459
|
scanSubagentsDir(subagentsPath);
|
|
48654
48460
|
}
|
|
@@ -48673,7 +48479,7 @@ function startSubagentWatcher(config) {
|
|
|
48673
48479
|
for (const e of entries) {
|
|
48674
48480
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
48675
48481
|
continue;
|
|
48676
|
-
const filePath =
|
|
48482
|
+
const filePath = join19(subagentsPath, e);
|
|
48677
48483
|
if (knownFiles.has(filePath))
|
|
48678
48484
|
continue;
|
|
48679
48485
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -48790,15 +48596,15 @@ function determineRestartReason(opts) {
|
|
|
48790
48596
|
init_boot_card();
|
|
48791
48597
|
|
|
48792
48598
|
// gateway/update-announce.ts
|
|
48793
|
-
import { existsSync as
|
|
48794
|
-
import { join as
|
|
48599
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync13, openSync as openSync3, closeSync as closeSync3, readFileSync as readFileSync25 } from "node:fs";
|
|
48600
|
+
import { join as join24 } from "node:path";
|
|
48795
48601
|
import { homedir as homedir10 } from "node:os";
|
|
48796
48602
|
|
|
48797
48603
|
// ../src/host-control/audit-reader.ts
|
|
48798
48604
|
import { homedir as homedir9 } from "node:os";
|
|
48799
|
-
import { join as
|
|
48605
|
+
import { join as join23 } from "node:path";
|
|
48800
48606
|
function defaultAuditLogPath(home2 = homedir9()) {
|
|
48801
|
-
return
|
|
48607
|
+
return join23(home2, ".switchroom", "host-control-audit.log");
|
|
48802
48608
|
}
|
|
48803
48609
|
function parseAuditLine(line) {
|
|
48804
48610
|
const trimmed = line.trim();
|
|
@@ -48904,7 +48710,7 @@ function readAndFilter(raw, filters, limit) {
|
|
|
48904
48710
|
var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
|
|
48905
48711
|
function readLastTerminalUpdateAudit(opts = {}) {
|
|
48906
48712
|
const path = opts.auditLogPath ?? defaultAuditLogPath();
|
|
48907
|
-
const exists = opts.exists ??
|
|
48713
|
+
const exists = opts.exists ?? existsSync26;
|
|
48908
48714
|
const readFile = opts.readFile ?? ((p) => readFileSync25(p, "utf-8"));
|
|
48909
48715
|
if (!exists(path))
|
|
48910
48716
|
return null;
|
|
@@ -48966,18 +48772,18 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
48966
48772
|
`);
|
|
48967
48773
|
}
|
|
48968
48774
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
48969
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
48970
|
-
const dir =
|
|
48775
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join24(homedir10(), ".switchroom");
|
|
48776
|
+
const dir = join24(stateDir, "update-announced");
|
|
48971
48777
|
try {
|
|
48972
48778
|
mkdirSync13(dir, { recursive: true });
|
|
48973
48779
|
} catch {
|
|
48974
48780
|
return false;
|
|
48975
48781
|
}
|
|
48976
48782
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
48977
|
-
const path =
|
|
48783
|
+
const path = join24(dir, safeId);
|
|
48978
48784
|
try {
|
|
48979
|
-
const fd =
|
|
48980
|
-
|
|
48785
|
+
const fd = openSync3(path, "wx");
|
|
48786
|
+
closeSync3(fd);
|
|
48981
48787
|
return true;
|
|
48982
48788
|
} catch {
|
|
48983
48789
|
return false;
|
|
@@ -49021,7 +48827,7 @@ function renderIssuesCard(opts) {
|
|
|
49021
48827
|
const maxSeverity = sorted[0].severity;
|
|
49022
48828
|
const headerEmoji = SEVERITY_EMOJI[maxSeverity];
|
|
49023
48829
|
const count = sorted.length;
|
|
49024
|
-
const header = `${headerEmoji} <b>${
|
|
48830
|
+
const header = `${headerEmoji} <b>${escapeHtml8(opts.agentName)}</b> \u00b7 ${count} ${count === 1 ? "issue" : "issues"}`;
|
|
49025
48831
|
const maxRows = opts.maxRows ?? DEFAULT_MAX_ROWS;
|
|
49026
48832
|
const visible = sorted.slice(0, maxRows);
|
|
49027
48833
|
const overflow = sorted.length - visible.length;
|
|
@@ -49030,10 +48836,10 @@ function renderIssuesCard(opts) {
|
|
|
49030
48836
|
const emoji = SEVERITY_EMOJI[e.severity];
|
|
49031
48837
|
const occ = e.occurrences > 1 ? ` <i>(\u00d7${e.occurrences})</i>` : "";
|
|
49032
48838
|
const ago = relTime(now - e.last_seen);
|
|
49033
|
-
const head = `${emoji} <code>${
|
|
48839
|
+
const head = `${emoji} <code>${escapeHtml8(e.fingerprint)}</code> ${escapeHtml8(e.summary)}${occ} \u2014 <i>${ago}</i>`;
|
|
49034
48840
|
const remediation = formatRemediation(e.detail);
|
|
49035
48841
|
return remediation == null ? head : `${head}
|
|
49036
|
-
\u2192 <i>${
|
|
48842
|
+
\u2192 <i>${escapeHtml8(remediation)}</i>`;
|
|
49037
48843
|
});
|
|
49038
48844
|
const lines = [header, "", ...rows];
|
|
49039
48845
|
if (overflow > 0) {
|
|
@@ -49194,24 +49000,24 @@ function createIssuesCardHandle(opts) {
|
|
|
49194
49000
|
}
|
|
49195
49001
|
|
|
49196
49002
|
// issues-watcher.ts
|
|
49197
|
-
import { existsSync as
|
|
49198
|
-
import { join as
|
|
49003
|
+
import { existsSync as existsSync28, statSync as statSync8 } from "node:fs";
|
|
49004
|
+
import { join as join26 } from "node:path";
|
|
49199
49005
|
|
|
49200
49006
|
// ../src/issues/store.ts
|
|
49201
49007
|
import {
|
|
49202
|
-
closeSync as
|
|
49203
|
-
existsSync as
|
|
49008
|
+
closeSync as closeSync4,
|
|
49009
|
+
existsSync as existsSync27,
|
|
49204
49010
|
mkdirSync as mkdirSync14,
|
|
49205
|
-
openSync as
|
|
49011
|
+
openSync as openSync4,
|
|
49206
49012
|
readdirSync as readdirSync5,
|
|
49207
49013
|
readFileSync as readFileSync27,
|
|
49208
49014
|
renameSync as renameSync10,
|
|
49209
49015
|
statSync as statSync7,
|
|
49210
|
-
unlinkSync as
|
|
49016
|
+
unlinkSync as unlinkSync10,
|
|
49211
49017
|
writeFileSync as writeFileSync16,
|
|
49212
49018
|
writeSync
|
|
49213
49019
|
} from "node:fs";
|
|
49214
|
-
import { join as
|
|
49020
|
+
import { join as join25 } from "node:path";
|
|
49215
49021
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
49216
49022
|
import { execSync } from "node:child_process";
|
|
49217
49023
|
|
|
@@ -49227,8 +49033,8 @@ var SEVERITY_RANK2 = {
|
|
|
49227
49033
|
var ISSUES_FILE = "issues.jsonl";
|
|
49228
49034
|
var ISSUES_LOCK = "issues.lock";
|
|
49229
49035
|
function readAll(stateDir) {
|
|
49230
|
-
const path =
|
|
49231
|
-
if (!
|
|
49036
|
+
const path = join25(stateDir, ISSUES_FILE);
|
|
49037
|
+
if (!existsSync27(path))
|
|
49232
49038
|
return [];
|
|
49233
49039
|
let raw;
|
|
49234
49040
|
try {
|
|
@@ -49264,7 +49070,7 @@ function list(stateDir, opts = {}) {
|
|
|
49264
49070
|
});
|
|
49265
49071
|
}
|
|
49266
49072
|
function resolve6(stateDir, fingerprint, nowFn = Date.now) {
|
|
49267
|
-
if (!
|
|
49073
|
+
if (!existsSync27(join25(stateDir, ISSUES_FILE)))
|
|
49268
49074
|
return 0;
|
|
49269
49075
|
return withLock(stateDir, () => {
|
|
49270
49076
|
const all = readAll(stateDir);
|
|
@@ -49282,7 +49088,7 @@ function resolve6(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
49282
49088
|
});
|
|
49283
49089
|
}
|
|
49284
49090
|
function writeAll(stateDir, events) {
|
|
49285
|
-
const path =
|
|
49091
|
+
const path = join25(stateDir, ISSUES_FILE);
|
|
49286
49092
|
sweepOrphanTmpFiles(stateDir);
|
|
49287
49093
|
const tmp = `${path}.tmp-${process.pid}-${randomBytes4(4).toString("hex")}`;
|
|
49288
49094
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -49304,11 +49110,11 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
49304
49110
|
for (const entry of entries) {
|
|
49305
49111
|
if (!entry.startsWith(TMP_PREFIX))
|
|
49306
49112
|
continue;
|
|
49307
|
-
const tmpPath2 =
|
|
49113
|
+
const tmpPath2 = join25(stateDir, entry);
|
|
49308
49114
|
try {
|
|
49309
49115
|
const stat = statSync7(tmpPath2);
|
|
49310
49116
|
if (stat.mtimeMs < cutoff) {
|
|
49311
|
-
|
|
49117
|
+
unlinkSync10(tmpPath2);
|
|
49312
49118
|
}
|
|
49313
49119
|
} catch {}
|
|
49314
49120
|
}
|
|
@@ -49316,12 +49122,12 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
49316
49122
|
var LOCK_RETRY_MS = 25;
|
|
49317
49123
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
49318
49124
|
function withLock(stateDir, fn) {
|
|
49319
|
-
const lockPath =
|
|
49125
|
+
const lockPath = join25(stateDir, ISSUES_LOCK);
|
|
49320
49126
|
const startedAt = Date.now();
|
|
49321
49127
|
let fd = null;
|
|
49322
49128
|
while (fd === null) {
|
|
49323
49129
|
try {
|
|
49324
|
-
fd =
|
|
49130
|
+
fd = openSync4(lockPath, "wx");
|
|
49325
49131
|
try {
|
|
49326
49132
|
writeSync(fd, String(process.pid));
|
|
49327
49133
|
} catch {}
|
|
@@ -49341,10 +49147,10 @@ function withLock(stateDir, fn) {
|
|
|
49341
49147
|
return fn();
|
|
49342
49148
|
} finally {
|
|
49343
49149
|
try {
|
|
49344
|
-
|
|
49150
|
+
closeSync4(fd);
|
|
49345
49151
|
} catch {}
|
|
49346
49152
|
try {
|
|
49347
|
-
|
|
49153
|
+
unlinkSync10(lockPath);
|
|
49348
49154
|
} catch {}
|
|
49349
49155
|
}
|
|
49350
49156
|
}
|
|
@@ -49358,13 +49164,13 @@ function tryStealStaleLock(lockPath) {
|
|
|
49358
49164
|
const pid = Number(pidStr);
|
|
49359
49165
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
49360
49166
|
try {
|
|
49361
|
-
|
|
49167
|
+
unlinkSync10(lockPath);
|
|
49362
49168
|
} catch {}
|
|
49363
49169
|
return true;
|
|
49364
49170
|
}
|
|
49365
49171
|
if (pid === process.pid) {
|
|
49366
49172
|
try {
|
|
49367
|
-
|
|
49173
|
+
unlinkSync10(lockPath);
|
|
49368
49174
|
} catch {}
|
|
49369
49175
|
return true;
|
|
49370
49176
|
}
|
|
@@ -49379,7 +49185,7 @@ function tryStealStaleLock(lockPath) {
|
|
|
49379
49185
|
return false;
|
|
49380
49186
|
}
|
|
49381
49187
|
try {
|
|
49382
|
-
|
|
49188
|
+
unlinkSync10(lockPath);
|
|
49383
49189
|
} catch {}
|
|
49384
49190
|
return true;
|
|
49385
49191
|
}
|
|
@@ -49401,7 +49207,7 @@ function isIssueEvent(v) {
|
|
|
49401
49207
|
// issues-watcher.ts
|
|
49402
49208
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
49403
49209
|
function startIssuesWatcher(opts) {
|
|
49404
|
-
const path =
|
|
49210
|
+
const path = join26(opts.stateDir, ISSUES_FILE);
|
|
49405
49211
|
const log = opts.log ?? (() => {});
|
|
49406
49212
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
49407
49213
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -49449,7 +49255,7 @@ function startIssuesWatcher(opts) {
|
|
|
49449
49255
|
};
|
|
49450
49256
|
}
|
|
49451
49257
|
function defaultSignatureProvider(path) {
|
|
49452
|
-
if (!
|
|
49258
|
+
if (!existsSync28(path))
|
|
49453
49259
|
return null;
|
|
49454
49260
|
try {
|
|
49455
49261
|
const stat = statSync8(path);
|
|
@@ -49462,7 +49268,7 @@ function defaultReadEvents(stateDir) {
|
|
|
49462
49268
|
return readAll(stateDir);
|
|
49463
49269
|
}
|
|
49464
49270
|
// permission-title.ts
|
|
49465
|
-
import { basename as
|
|
49271
|
+
import { basename as basename5 } from "node:path";
|
|
49466
49272
|
var COMMAND_TITLE_MAX = 40;
|
|
49467
49273
|
var PATH_TITLE_MAX = 40;
|
|
49468
49274
|
var DESCRIPTION_LINE_MAX = 240;
|
|
@@ -49513,13 +49319,13 @@ function summarizeToolForTitle(toolName, inputPreview) {
|
|
|
49513
49319
|
return `${toolName} (${skill})`;
|
|
49514
49320
|
const command = readString(input, "command");
|
|
49515
49321
|
if (command)
|
|
49516
|
-
return `${toolName}: ${
|
|
49322
|
+
return `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}`;
|
|
49517
49323
|
const argHint = firstScalarArgHint(input);
|
|
49518
49324
|
return argHint ? `${toolName} (${argHint})` : toolName;
|
|
49519
49325
|
}
|
|
49520
49326
|
case "Bash": {
|
|
49521
49327
|
const command = readString(input, "command");
|
|
49522
|
-
return command ? `${toolName}: ${
|
|
49328
|
+
return command ? `${toolName}: ${truncate6(command, COMMAND_TITLE_MAX)}` : toolName;
|
|
49523
49329
|
}
|
|
49524
49330
|
case "Read":
|
|
49525
49331
|
case "Edit":
|
|
@@ -49527,17 +49333,17 @@ function summarizeToolForTitle(toolName, inputPreview) {
|
|
|
49527
49333
|
case "MultiEdit":
|
|
49528
49334
|
case "NotebookEdit": {
|
|
49529
49335
|
const filePath = readString(input, "file_path") ?? readString(input, "notebook_path");
|
|
49530
|
-
return filePath ? `${toolName}: ${
|
|
49336
|
+
return filePath ? `${toolName}: ${truncate6(basename5(filePath), PATH_TITLE_MAX)}` : toolName;
|
|
49531
49337
|
}
|
|
49532
49338
|
case "Glob":
|
|
49533
49339
|
case "Grep": {
|
|
49534
49340
|
const pattern = readString(input, "pattern");
|
|
49535
|
-
return pattern ? `${toolName}: ${
|
|
49341
|
+
return pattern ? `${toolName}: ${truncate6(pattern, COMMAND_TITLE_MAX)}` : toolName;
|
|
49536
49342
|
}
|
|
49537
49343
|
case "WebFetch":
|
|
49538
49344
|
case "WebSearch": {
|
|
49539
49345
|
const query2 = readString(input, "url") ?? readString(input, "query");
|
|
49540
|
-
return query2 ? `${toolName}: ${
|
|
49346
|
+
return query2 ? `${toolName}: ${truncate6(query2, COMMAND_TITLE_MAX)}` : toolName;
|
|
49541
49347
|
}
|
|
49542
49348
|
default:
|
|
49543
49349
|
return toolName;
|
|
@@ -49576,7 +49382,7 @@ function firstScalarArgHint(input) {
|
|
|
49576
49382
|
if (SKIP.has(key))
|
|
49577
49383
|
continue;
|
|
49578
49384
|
if (typeof value === "string" && value.length > 0) {
|
|
49579
|
-
return `${key}: ${
|
|
49385
|
+
return `${key}: ${truncate6(value, INPUT_VALUE_MAX)}`;
|
|
49580
49386
|
}
|
|
49581
49387
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
49582
49388
|
return `${key}: ${String(value)}`;
|
|
@@ -49608,10 +49414,10 @@ function skillBasenameFromPath(input) {
|
|
|
49608
49414
|
return null;
|
|
49609
49415
|
const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
|
|
49610
49416
|
const lastSlash = trimmed.lastIndexOf("/");
|
|
49611
|
-
const
|
|
49612
|
-
return
|
|
49417
|
+
const basename6 = lastSlash >= 0 ? trimmed.slice(lastSlash + 1) : trimmed;
|
|
49418
|
+
return basename6.length > 0 ? basename6 : null;
|
|
49613
49419
|
}
|
|
49614
|
-
function
|
|
49420
|
+
function truncate6(text, max) {
|
|
49615
49421
|
const collapsed = text.replace(/\s+/g, " ").trim();
|
|
49616
49422
|
if (collapsed.length <= max)
|
|
49617
49423
|
return collapsed;
|
|
@@ -49619,7 +49425,7 @@ function truncate7(text, max) {
|
|
|
49619
49425
|
}
|
|
49620
49426
|
|
|
49621
49427
|
// permission-rule.ts
|
|
49622
|
-
import { basename as
|
|
49428
|
+
import { basename as basename6 } from "node:path";
|
|
49623
49429
|
function resolveAlwaysAllowRule(toolName, inputPreview) {
|
|
49624
49430
|
if (!toolName)
|
|
49625
49431
|
return null;
|
|
@@ -49685,12 +49491,12 @@ function skillBasenameFromPath2(input) {
|
|
|
49685
49491
|
if (!path)
|
|
49686
49492
|
return null;
|
|
49687
49493
|
const trimmed = path.replace(/\/SKILL\.md$/i, "").replace(/\/$/, "");
|
|
49688
|
-
return
|
|
49494
|
+
return basename6(trimmed) || null;
|
|
49689
49495
|
}
|
|
49690
49496
|
|
|
49691
49497
|
// credits-watch.ts
|
|
49692
|
-
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, existsSync as
|
|
49693
|
-
import { join as
|
|
49498
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, existsSync as existsSync29, mkdirSync as mkdirSync15 } from "fs";
|
|
49499
|
+
import { join as join27 } from "path";
|
|
49694
49500
|
var STATE_FILE = "credits-watch.json";
|
|
49695
49501
|
var FATAL_REASONS = new Set([
|
|
49696
49502
|
"out_of_credits",
|
|
@@ -49702,8 +49508,8 @@ function emptyCreditState() {
|
|
|
49702
49508
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
49703
49509
|
}
|
|
49704
49510
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
49705
|
-
const path =
|
|
49706
|
-
if (!
|
|
49511
|
+
const path = join27(claudeConfigDir, ".claude.json");
|
|
49512
|
+
if (!existsSync29(path))
|
|
49707
49513
|
return null;
|
|
49708
49514
|
let raw;
|
|
49709
49515
|
try {
|
|
@@ -49731,7 +49537,7 @@ function evaluateCreditState(args) {
|
|
|
49731
49537
|
if (!currentIsFatal && prevIsFatal) {
|
|
49732
49538
|
return {
|
|
49733
49539
|
kind: "notify",
|
|
49734
|
-
message: `\u2705 <b>${
|
|
49540
|
+
message: `\u2705 <b>${escapeHtml10(agentName3)}</b>: credits restored \u2014 agent should resume normal operation.`,
|
|
49735
49541
|
newState: { lastNotifiedReason: null, lastNotifiedAt: now },
|
|
49736
49542
|
transition: "exited"
|
|
49737
49543
|
};
|
|
@@ -49760,12 +49566,12 @@ function evaluateCreditState(args) {
|
|
|
49760
49566
|
function buildEntryMessage(agentName3, reason) {
|
|
49761
49567
|
const desc = humanizeReason(reason);
|
|
49762
49568
|
return [
|
|
49763
|
-
`\u26a0\ufe0f <b>${
|
|
49569
|
+
`\u26a0\ufe0f <b>${escapeHtml10(agentName3)}</b>: ${desc}`,
|
|
49764
49570
|
``,
|
|
49765
49571
|
`Cron tasks and inbound replies will fail until this is resolved. Check`,
|
|
49766
49572
|
`your subscription or pre-paid usage at <a href="https://console.anthropic.com">console.anthropic.com</a>.`,
|
|
49767
49573
|
``,
|
|
49768
|
-
`<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${
|
|
49574
|
+
`<i>Source: Claude CLI cache (cachedExtraUsageDisabledReason=${escapeHtml10(reason)})</i>`
|
|
49769
49575
|
].join(`
|
|
49770
49576
|
`);
|
|
49771
49577
|
}
|
|
@@ -49783,12 +49589,12 @@ function humanizeReason(reason) {
|
|
|
49783
49589
|
return `usage disabled (${reason})`;
|
|
49784
49590
|
}
|
|
49785
49591
|
}
|
|
49786
|
-
function
|
|
49592
|
+
function escapeHtml10(s) {
|
|
49787
49593
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
49788
49594
|
}
|
|
49789
49595
|
function loadCreditState(stateDir) {
|
|
49790
|
-
const path =
|
|
49791
|
-
if (!
|
|
49596
|
+
const path = join27(stateDir, STATE_FILE);
|
|
49597
|
+
if (!existsSync29(path))
|
|
49792
49598
|
return emptyCreditState();
|
|
49793
49599
|
try {
|
|
49794
49600
|
const raw = readFileSync28(path, "utf-8");
|
|
@@ -49804,54 +49610,54 @@ function loadCreditState(stateDir) {
|
|
|
49804
49610
|
}
|
|
49805
49611
|
function saveCreditState(stateDir, state4) {
|
|
49806
49612
|
mkdirSync15(stateDir, { recursive: true });
|
|
49807
|
-
const path =
|
|
49613
|
+
const path = join27(stateDir, STATE_FILE);
|
|
49808
49614
|
writeFileSync17(path, JSON.stringify(state4, null, 2) + `
|
|
49809
49615
|
`, { mode: 384 });
|
|
49810
49616
|
}
|
|
49811
49617
|
|
|
49812
49618
|
// gateway/turn-active-marker.ts
|
|
49813
49619
|
import {
|
|
49814
|
-
closeSync as
|
|
49815
|
-
existsSync as
|
|
49620
|
+
closeSync as closeSync5,
|
|
49621
|
+
existsSync as existsSync30,
|
|
49816
49622
|
mkdirSync as mkdirSync16,
|
|
49817
|
-
openSync as
|
|
49623
|
+
openSync as openSync5,
|
|
49818
49624
|
readFileSync as readFileSync29,
|
|
49819
49625
|
statSync as statSync9,
|
|
49820
|
-
unlinkSync as
|
|
49626
|
+
unlinkSync as unlinkSync11,
|
|
49821
49627
|
utimesSync as utimesSync2,
|
|
49822
49628
|
writeFileSync as writeFileSync18
|
|
49823
49629
|
} from "node:fs";
|
|
49824
|
-
import { join as
|
|
49630
|
+
import { join as join28 } from "node:path";
|
|
49825
49631
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
49826
49632
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
49827
49633
|
try {
|
|
49828
49634
|
mkdirSync16(stateDir, { recursive: true });
|
|
49829
|
-
writeFileSync18(
|
|
49635
|
+
writeFileSync18(join28(stateDir, TURN_ACTIVE_MARKER_FILE2), JSON.stringify(marker, null, 2) + `
|
|
49830
49636
|
`, { mode: 384 });
|
|
49831
49637
|
} catch {}
|
|
49832
49638
|
}
|
|
49833
49639
|
function touchTurnActiveMarker2(stateDir) {
|
|
49834
|
-
const path =
|
|
49835
|
-
if (!
|
|
49640
|
+
const path = join28(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
49641
|
+
if (!existsSync30(path))
|
|
49836
49642
|
return;
|
|
49837
49643
|
const now = new Date;
|
|
49838
49644
|
try {
|
|
49839
49645
|
utimesSync2(path, now, now);
|
|
49840
49646
|
} catch {
|
|
49841
49647
|
try {
|
|
49842
|
-
const fd =
|
|
49843
|
-
|
|
49648
|
+
const fd = openSync5(path, "r+");
|
|
49649
|
+
closeSync5(fd);
|
|
49844
49650
|
} catch {}
|
|
49845
49651
|
}
|
|
49846
49652
|
}
|
|
49847
49653
|
function removeTurnActiveMarker(stateDir) {
|
|
49848
49654
|
try {
|
|
49849
|
-
|
|
49655
|
+
unlinkSync11(join28(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
49850
49656
|
} catch {}
|
|
49851
49657
|
}
|
|
49852
49658
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
49853
|
-
const path =
|
|
49854
|
-
if (!
|
|
49659
|
+
const path = join28(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
49660
|
+
if (!existsSync30(path))
|
|
49855
49661
|
return false;
|
|
49856
49662
|
const now = opts.now ?? Date.now();
|
|
49857
49663
|
try {
|
|
@@ -49865,7 +49671,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
49865
49671
|
try {
|
|
49866
49672
|
payload = readFileSync29(path, "utf8");
|
|
49867
49673
|
} catch {}
|
|
49868
|
-
|
|
49674
|
+
unlinkSync11(path);
|
|
49869
49675
|
if (opts.onRemove) {
|
|
49870
49676
|
try {
|
|
49871
49677
|
opts.onRemove({
|
|
@@ -49882,10 +49688,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
49882
49688
|
}
|
|
49883
49689
|
|
|
49884
49690
|
// ../src/build-info.ts
|
|
49885
|
-
var VERSION = "0.13.
|
|
49886
|
-
var COMMIT_SHA = "
|
|
49887
|
-
var COMMIT_DATE = "2026-05-
|
|
49888
|
-
var LATEST_PR =
|
|
49691
|
+
var VERSION = "0.13.59";
|
|
49692
|
+
var COMMIT_SHA = "0f0b953e";
|
|
49693
|
+
var COMMIT_DATE = "2026-05-28T00:31:56Z";
|
|
49694
|
+
var LATEST_PR = 1936;
|
|
49889
49695
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
49890
49696
|
|
|
49891
49697
|
// gateway/boot-version.ts
|
|
@@ -49959,11 +49765,11 @@ init_peercred();
|
|
|
49959
49765
|
import * as net4 from "node:net";
|
|
49960
49766
|
import * as fs2 from "node:fs";
|
|
49961
49767
|
import { homedir as homedir11 } from "node:os";
|
|
49962
|
-
import { join as
|
|
49768
|
+
import { join as join29 } from "node:path";
|
|
49963
49769
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
49964
49770
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
49965
|
-
var LEGACY_SOCKET_PATH2 =
|
|
49966
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
49771
|
+
var LEGACY_SOCKET_PATH2 = join29(homedir11(), ".switchroom", "vault-broker.sock");
|
|
49772
|
+
var OPERATOR_SOCKET_PATH2 = join29(homedir11(), ".switchroom", "broker-operator", "sock");
|
|
49967
49773
|
function defaultBrokerSocketPath2() {
|
|
49968
49774
|
if (fs2.existsSync(OPERATOR_SOCKET_PATH2))
|
|
49969
49775
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -50186,7 +49992,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
50186
49992
|
|
|
50187
49993
|
// registry/turns-schema.ts
|
|
50188
49994
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync17 } from "fs";
|
|
50189
|
-
import { join as
|
|
49995
|
+
import { join as join30 } from "path";
|
|
50190
49996
|
var DatabaseClass2 = null;
|
|
50191
49997
|
function loadDatabaseClass2() {
|
|
50192
49998
|
if (DatabaseClass2 != null)
|
|
@@ -50245,9 +50051,9 @@ function applySchema(db2) {
|
|
|
50245
50051
|
}
|
|
50246
50052
|
function openTurnsDb(agentDir) {
|
|
50247
50053
|
const Database = loadDatabaseClass2();
|
|
50248
|
-
const dir =
|
|
50054
|
+
const dir = join30(agentDir, "telegram");
|
|
50249
50055
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
50250
|
-
const path =
|
|
50056
|
+
const path = join30(dir, "registry.db");
|
|
50251
50057
|
const db2 = new Database(path, { create: true });
|
|
50252
50058
|
applySchema(db2);
|
|
50253
50059
|
try {
|
|
@@ -50388,11 +50194,11 @@ installGlobalErrorHandlers();
|
|
|
50388
50194
|
process.on("beforeExit", () => {
|
|
50389
50195
|
shutdownAnalytics();
|
|
50390
50196
|
});
|
|
50391
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
50392
|
-
var ACCESS_FILE =
|
|
50393
|
-
var APPROVED_DIR =
|
|
50394
|
-
var ENV_FILE =
|
|
50395
|
-
var INBOX_DIR =
|
|
50197
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join32(homedir12(), ".claude", "channels", "telegram");
|
|
50198
|
+
var ACCESS_FILE = join32(STATE_DIR, "access.json");
|
|
50199
|
+
var APPROVED_DIR = join32(STATE_DIR, "approved");
|
|
50200
|
+
var ENV_FILE = join32(STATE_DIR, ".env");
|
|
50201
|
+
var INBOX_DIR = join32(STATE_DIR, "inbox");
|
|
50396
50202
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
50397
50203
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
50398
50204
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -50583,7 +50389,7 @@ function assertSendable(f) {
|
|
|
50583
50389
|
} catch {
|
|
50584
50390
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
50585
50391
|
}
|
|
50586
|
-
const inbox =
|
|
50392
|
+
const inbox = join32(stateReal, "inbox");
|
|
50587
50393
|
if (real.startsWith(stateReal + sep3) && !real.startsWith(inbox + sep3)) {
|
|
50588
50394
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
50589
50395
|
}
|
|
@@ -50689,7 +50495,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
50689
50495
|
if (HISTORY_ENABLED) {
|
|
50690
50496
|
try {
|
|
50691
50497
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
50692
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
50498
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join32(STATE_DIR, "history.db")}
|
|
50693
50499
|
`);
|
|
50694
50500
|
} catch (err) {
|
|
50695
50501
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -50706,10 +50512,10 @@ try {
|
|
|
50706
50512
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s) as ended_via='restart'
|
|
50707
50513
|
`);
|
|
50708
50514
|
} else {
|
|
50709
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
50515
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join32(agentDir, "telegram", "registry.db")}
|
|
50710
50516
|
`);
|
|
50711
50517
|
}
|
|
50712
|
-
const pendingEnvPath =
|
|
50518
|
+
const pendingEnvPath = join32(agentDir, ".pending-turn.env");
|
|
50713
50519
|
try {
|
|
50714
50520
|
const pending2 = findMostRecentInterruptedTurn(turnsDb);
|
|
50715
50521
|
if (pending2 != null) {
|
|
@@ -50729,7 +50535,7 @@ try {
|
|
|
50729
50535
|
renameSync12(pendingEnvTmp, pendingEnvPath);
|
|
50730
50536
|
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
50731
50537
|
`);
|
|
50732
|
-
} else if (
|
|
50538
|
+
} else if (existsSync34(pendingEnvPath)) {
|
|
50733
50539
|
rmSync4(pendingEnvPath, { force: true });
|
|
50734
50540
|
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
50735
50541
|
`);
|
|
@@ -50783,7 +50589,7 @@ function checkApprovals() {
|
|
|
50783
50589
|
return;
|
|
50784
50590
|
}
|
|
50785
50591
|
for (const senderId of files) {
|
|
50786
|
-
const file =
|
|
50592
|
+
const file = join32(APPROVED_DIR, senderId);
|
|
50787
50593
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync4(file, { force: true }), (err) => {
|
|
50788
50594
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
50789
50595
|
`);
|
|
@@ -51660,11 +51466,11 @@ var unpinProgressCardForChat = null;
|
|
|
51660
51466
|
var getPinnedProgressCardMessageId = null;
|
|
51661
51467
|
var completeProgressCardTurn = null;
|
|
51662
51468
|
var subagentWatcher = null;
|
|
51663
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
51469
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join32(STATE_DIR, "gateway.sock");
|
|
51664
51470
|
mkdirSync21(STATE_DIR, { recursive: true, mode: 448 });
|
|
51665
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
51666
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
51667
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
51471
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join32(STATE_DIR, "gateway.pid.json");
|
|
51472
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join32(STATE_DIR, "gateway-session.json");
|
|
51473
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join32(STATE_DIR, "clean-shutdown.json");
|
|
51668
51474
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
51669
51475
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
51670
51476
|
var activeBootCard = null;
|
|
@@ -51693,7 +51499,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
51693
51499
|
bot: botApi,
|
|
51694
51500
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
51695
51501
|
`),
|
|
51696
|
-
persistPath:
|
|
51502
|
+
persistPath: join32(stateDir, "issues-card.json")
|
|
51697
51503
|
});
|
|
51698
51504
|
activeIssuesWatcher = startIssuesWatcher({
|
|
51699
51505
|
stateDir,
|
|
@@ -51862,13 +51668,13 @@ startTimer2({
|
|
|
51862
51668
|
}
|
|
51863
51669
|
});
|
|
51864
51670
|
var inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
51865
|
-
path:
|
|
51671
|
+
path: join32(STATE_DIR, "inbound-spool.jsonl"),
|
|
51866
51672
|
fs: {
|
|
51867
51673
|
appendFileSync: (p, d) => appendFileSync3(p, d),
|
|
51868
51674
|
readFileSync: (p) => readFileSync32(p, "utf8"),
|
|
51869
51675
|
writeFileSync: (p, d) => writeFileSync21(p, d),
|
|
51870
51676
|
renameSync: (a, b) => renameSync12(a, b),
|
|
51871
|
-
existsSync: (p) =>
|
|
51677
|
+
existsSync: (p) => existsSync34(p),
|
|
51872
51678
|
statSizeSync: (p) => statSync13(p).size
|
|
51873
51679
|
}
|
|
51874
51680
|
});
|
|
@@ -52096,7 +51902,7 @@ ${reminder}
|
|
|
52096
51902
|
noteSubagentDispatch(key);
|
|
52097
51903
|
}
|
|
52098
51904
|
if (ev.toolUseId != null && ev.toolUseId.length > 0 && !isTelegramSurfaceTool(ev.toolName)) {
|
|
52099
|
-
const label =
|
|
51905
|
+
const label = toolLabel(ev.toolName, ev.input, undefined, ev.precomputedLabel);
|
|
52100
51906
|
noteToolStart(key, ev.toolUseId, ev.toolName, label.length > 0 ? label : null, Date.now());
|
|
52101
51907
|
const evInput = ev.input;
|
|
52102
51908
|
if (ev.toolName === "Agent" || ev.toolName === "Task" || ev.toolName === "Bash" && evInput?.run_in_background === true) {
|
|
@@ -52681,12 +52487,6 @@ ${url}`;
|
|
|
52681
52487
|
});
|
|
52682
52488
|
noteOutbound(statusKey(chat_id, threadId), Date.now());
|
|
52683
52489
|
noteOutbound2(statusKey(chat_id, threadId), Date.now());
|
|
52684
|
-
try {
|
|
52685
|
-
markAckSent();
|
|
52686
|
-
} catch (err) {
|
|
52687
|
-
process.stderr.write(`telegram gateway: markAckSent failed: ${err}
|
|
52688
|
-
`);
|
|
52689
|
-
}
|
|
52690
52490
|
if (isFinalAnswerReply({ text: rawText, disableNotification })) {
|
|
52691
52491
|
clearSilentEndState(statusKey(chat_id, threadId));
|
|
52692
52492
|
}
|
|
@@ -53014,12 +52814,6 @@ async function executeStreamReply(args) {
|
|
|
53014
52814
|
const sKey = statusKey(streamChatId, streamThreadId);
|
|
53015
52815
|
noteOutbound(sKey, Date.now());
|
|
53016
52816
|
noteOutbound2(sKey, Date.now());
|
|
53017
|
-
try {
|
|
53018
|
-
markAckSent();
|
|
53019
|
-
} catch (err) {
|
|
53020
|
-
process.stderr.write(`telegram gateway: markAckSent (stream_reply) failed: ${err}
|
|
53021
|
-
`);
|
|
53022
|
-
}
|
|
53023
52817
|
if (isFinalAnswerReply({
|
|
53024
52818
|
text: args.text ?? "",
|
|
53025
52819
|
disableNotification: args.disable_notification === true,
|
|
@@ -53370,10 +53164,10 @@ async function executeSendGif(rawArgs) {
|
|
|
53370
53164
|
};
|
|
53371
53165
|
}
|
|
53372
53166
|
async function publishToTelegraph(text, shortName, authorName) {
|
|
53373
|
-
const accountPath =
|
|
53167
|
+
const accountPath = join32(STATE_DIR, "telegraph-account.json");
|
|
53374
53168
|
let account = null;
|
|
53375
53169
|
try {
|
|
53376
|
-
if (
|
|
53170
|
+
if (existsSync34(accountPath)) {
|
|
53377
53171
|
const raw = readFileSync32(accountPath, "utf-8");
|
|
53378
53172
|
const parsed = JSON.parse(raw);
|
|
53379
53173
|
if (parsed.shortName && parsed.accessToken) {
|
|
@@ -53859,6 +53653,74 @@ function closeProgressLane(chatId, threadId) {
|
|
|
53859
53653
|
}
|
|
53860
53654
|
}
|
|
53861
53655
|
}
|
|
53656
|
+
async function drainActivitySummary(turn) {
|
|
53657
|
+
try {
|
|
53658
|
+
while (turn.activityPendingRender !== turn.activityLastSentRender) {
|
|
53659
|
+
const target = turn.activityPendingRender;
|
|
53660
|
+
if (target == null)
|
|
53661
|
+
break;
|
|
53662
|
+
const html = `<i>${target}</i>`;
|
|
53663
|
+
const chat = turn.sessionChatId;
|
|
53664
|
+
const thread = turn.sessionThreadId;
|
|
53665
|
+
const useDraft = turn.isDm && thread == null && sendMessageDraftFn != null;
|
|
53666
|
+
try {
|
|
53667
|
+
if (useDraft) {
|
|
53668
|
+
if (turn.activityDraftId == null) {
|
|
53669
|
+
turn.activityDraftId = allocateDraftId();
|
|
53670
|
+
}
|
|
53671
|
+
const draftId = turn.activityDraftId;
|
|
53672
|
+
await sendMessageDraftFn(chat, draftId, html, undefined);
|
|
53673
|
+
} else if (turn.activityMessageId == null) {
|
|
53674
|
+
const sent = await robustApiCall(() => bot.api.sendMessage(chat, html, {
|
|
53675
|
+
...thread != null ? { message_thread_id: thread } : {},
|
|
53676
|
+
parse_mode: "HTML",
|
|
53677
|
+
disable_notification: true
|
|
53678
|
+
}), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.send" });
|
|
53679
|
+
turn.activityMessageId = sent.message_id;
|
|
53680
|
+
} else {
|
|
53681
|
+
const id = turn.activityMessageId;
|
|
53682
|
+
await robustApiCall(() => bot.api.editMessageText(chat, id, html, { parse_mode: "HTML" }), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.edit" });
|
|
53683
|
+
}
|
|
53684
|
+
turn.activityLastSentRender = target;
|
|
53685
|
+
} catch (err) {
|
|
53686
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
53687
|
+
if (!msg.includes("message is not modified")) {
|
|
53688
|
+
process.stderr.write(`telegram gateway: activity-summary drain failed: ${msg}
|
|
53689
|
+
`);
|
|
53690
|
+
}
|
|
53691
|
+
turn.activityLastSentRender = target;
|
|
53692
|
+
}
|
|
53693
|
+
}
|
|
53694
|
+
} finally {
|
|
53695
|
+
turn.activityInFlight = null;
|
|
53696
|
+
}
|
|
53697
|
+
}
|
|
53698
|
+
function clearActivitySummary(turn) {
|
|
53699
|
+
const chat = turn.sessionChatId;
|
|
53700
|
+
const thread = turn.sessionThreadId;
|
|
53701
|
+
const inFlight = turn.activityInFlight ?? Promise.resolve();
|
|
53702
|
+
inFlight.then(async () => {
|
|
53703
|
+
if (turn.activityDraftId != null && sendMessageDraftFn != null) {
|
|
53704
|
+
const draftId = turn.activityDraftId;
|
|
53705
|
+
turn.activityDraftId = null;
|
|
53706
|
+
try {
|
|
53707
|
+
await sendMessageDraftFn(chat, draftId, "", undefined);
|
|
53708
|
+
} catch (err) {
|
|
53709
|
+
process.stderr.write(`telegram gateway: activity-summary draft-clear failed: ${err}
|
|
53710
|
+
`);
|
|
53711
|
+
}
|
|
53712
|
+
} else if (turn.activityMessageId != null) {
|
|
53713
|
+
const id = turn.activityMessageId;
|
|
53714
|
+
turn.activityMessageId = null;
|
|
53715
|
+
try {
|
|
53716
|
+
await robustApiCall(() => bot.api.deleteMessage(chat, id), { chat_id: chat, ...thread != null ? { threadId: thread } : {}, verb: "activity-summary.delete" });
|
|
53717
|
+
} catch (err) {
|
|
53718
|
+
process.stderr.write(`telegram gateway: activity-summary delete failed: ${err}
|
|
53719
|
+
`);
|
|
53720
|
+
}
|
|
53721
|
+
}
|
|
53722
|
+
});
|
|
53723
|
+
}
|
|
53862
53724
|
function handleSessionEvent(ev) {
|
|
53863
53725
|
switch (ev.kind) {
|
|
53864
53726
|
case "enqueue": {
|
|
@@ -53866,7 +53728,6 @@ function handleSessionEvent(ev) {
|
|
|
53866
53728
|
if (ev.chatId) {
|
|
53867
53729
|
const enqThreadId = ev.threadId != null ? Number(ev.threadId) : undefined;
|
|
53868
53730
|
clearPending(statusKey(ev.chatId, enqThreadId), "handback");
|
|
53869
|
-
clearAckSent();
|
|
53870
53731
|
}
|
|
53871
53732
|
if (ev.chatId) {
|
|
53872
53733
|
const prior = currentTurn;
|
|
@@ -53892,7 +53753,12 @@ function handleSessionEvent(ev) {
|
|
|
53892
53753
|
lastAssistantMsgId: null,
|
|
53893
53754
|
lastAssistantDone: false,
|
|
53894
53755
|
toolCallCount: 0,
|
|
53895
|
-
|
|
53756
|
+
toolActivity: makeEmptyActivityState(),
|
|
53757
|
+
activityMessageId: null,
|
|
53758
|
+
activityDraftId: null,
|
|
53759
|
+
activityInFlight: null,
|
|
53760
|
+
activityPendingRender: null,
|
|
53761
|
+
activityLastSentRender: null,
|
|
53896
53762
|
answerStream: null,
|
|
53897
53763
|
isDm: isDmChatId(ev.chatId)
|
|
53898
53764
|
};
|
|
@@ -53952,37 +53818,23 @@ function handleSessionEvent(ev) {
|
|
|
53952
53818
|
const ctrl = activeStatusReactions.get(statusKey(turn.sessionChatId, turn.sessionThreadId));
|
|
53953
53819
|
const name = ev.toolName;
|
|
53954
53820
|
if (isTelegramReplyTool(name)) {
|
|
53821
|
+
const wasFirstReply = !turn.replyCalled;
|
|
53955
53822
|
turn.replyCalled = true;
|
|
53956
53823
|
if (turn.orphanedReplyTimeoutId != null) {
|
|
53957
53824
|
clearTimeout(turn.orphanedReplyTimeoutId);
|
|
53958
53825
|
turn.orphanedReplyTimeoutId = null;
|
|
53959
53826
|
}
|
|
53827
|
+
if (wasFirstReply) {
|
|
53828
|
+
clearActivitySummary(turn);
|
|
53829
|
+
}
|
|
53960
53830
|
}
|
|
53961
|
-
if (!turn.replyCalled && !
|
|
53962
|
-
turn.
|
|
53963
|
-
|
|
53964
|
-
|
|
53965
|
-
|
|
53966
|
-
|
|
53967
|
-
} catch (err) {
|
|
53968
|
-
process.stderr.write(`telegram gateway: intent-surface markAckSent failed: ${err}
|
|
53969
|
-
`);
|
|
53831
|
+
if (!turn.replyCalled && !isTelegramSurfaceTool(name)) {
|
|
53832
|
+
const rendered = registerAndRender(turn.toolActivity, name);
|
|
53833
|
+
if (rendered != null) {
|
|
53834
|
+
turn.activityPendingRender = rendered;
|
|
53835
|
+
if (turn.activityInFlight == null) {
|
|
53836
|
+
turn.activityInFlight = drainActivitySummary(turn);
|
|
53970
53837
|
}
|
|
53971
|
-
const surfaceChat = turn.sessionChatId;
|
|
53972
|
-
const surfaceThread = turn.sessionThreadId;
|
|
53973
|
-
const surfaceText = surface.text;
|
|
53974
|
-
(async () => {
|
|
53975
|
-
try {
|
|
53976
|
-
await robustApiCall(() => bot.api.sendMessage(surfaceChat, surfaceText, {
|
|
53977
|
-
...surfaceThread != null ? { message_thread_id: surfaceThread } : {},
|
|
53978
|
-
parse_mode: "HTML",
|
|
53979
|
-
disable_notification: true
|
|
53980
|
-
}), { chat_id: surfaceChat, ...surfaceThread != null ? { threadId: surfaceThread } : {}, verb: "intent-surface" });
|
|
53981
|
-
} catch (err) {
|
|
53982
|
-
process.stderr.write(`telegram gateway: intent-surface send failed: ${err}
|
|
53983
|
-
`);
|
|
53984
|
-
}
|
|
53985
|
-
})();
|
|
53986
53838
|
}
|
|
53987
53839
|
}
|
|
53988
53840
|
if (!ctrl)
|
|
@@ -55339,7 +55191,7 @@ function getMyAgentName() {
|
|
|
55339
55191
|
const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
|
|
55340
55192
|
if (fromEnv && fromEnv.trim().length > 0)
|
|
55341
55193
|
return fromEnv.trim();
|
|
55342
|
-
return
|
|
55194
|
+
return basename7(process.cwd());
|
|
55343
55195
|
}
|
|
55344
55196
|
function isSelfTargetingCommand(name) {
|
|
55345
55197
|
if (name === "all")
|
|
@@ -55352,7 +55204,7 @@ function restartMarkerPath() {
|
|
|
55352
55204
|
const agentDir = resolveAgentDirFromEnv();
|
|
55353
55205
|
if (!agentDir)
|
|
55354
55206
|
return null;
|
|
55355
|
-
return
|
|
55207
|
+
return join32(agentDir, "restart-pending.json");
|
|
55356
55208
|
}
|
|
55357
55209
|
function writeRestartMarker(marker) {
|
|
55358
55210
|
const p = restartMarkerPath();
|
|
@@ -55476,7 +55328,7 @@ var _dockerReachable;
|
|
|
55476
55328
|
function isDockerReachable() {
|
|
55477
55329
|
if (_dockerReachable !== undefined)
|
|
55478
55330
|
return _dockerReachable;
|
|
55479
|
-
if (!
|
|
55331
|
+
if (!existsSync34("/var/run/docker.sock")) {
|
|
55480
55332
|
_dockerReachable = false;
|
|
55481
55333
|
return _dockerReachable;
|
|
55482
55334
|
}
|
|
@@ -55493,11 +55345,11 @@ function _resetDockerReachableCache() {
|
|
|
55493
55345
|
}
|
|
55494
55346
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
55495
55347
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
55496
|
-
const logPath =
|
|
55348
|
+
const logPath = join32(STATE_DIR, "detached-spawn.log");
|
|
55497
55349
|
let outFd = null;
|
|
55498
55350
|
try {
|
|
55499
55351
|
mkdirSync21(STATE_DIR, { recursive: true });
|
|
55500
|
-
outFd =
|
|
55352
|
+
outFd = openSync8(logPath, "a");
|
|
55501
55353
|
writeFileSync21(logPath, `
|
|
55502
55354
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
55503
55355
|
`, { flag: "a" });
|
|
@@ -55512,7 +55364,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
55512
55364
|
});
|
|
55513
55365
|
if (outFd != null) {
|
|
55514
55366
|
try {
|
|
55515
|
-
|
|
55367
|
+
closeSync8(outFd);
|
|
55516
55368
|
} catch {}
|
|
55517
55369
|
}
|
|
55518
55370
|
if (onFailure) {
|
|
@@ -55866,8 +55718,8 @@ bot.use(async (ctx, next) => {
|
|
|
55866
55718
|
});
|
|
55867
55719
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
55868
55720
|
try {
|
|
55869
|
-
const auditPath =
|
|
55870
|
-
if (!
|
|
55721
|
+
const auditPath = join32(homedir12(), ".switchroom", "vault-audit.log");
|
|
55722
|
+
if (!existsSync34(auditPath))
|
|
55871
55723
|
return [];
|
|
55872
55724
|
const raw = readFileSync32(auditPath, "utf8");
|
|
55873
55725
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
@@ -55920,7 +55772,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
55920
55772
|
try {
|
|
55921
55773
|
const agentDir = resolveAgentDirFromEnv();
|
|
55922
55774
|
if (agentDir) {
|
|
55923
|
-
const raw = readFileSync32(
|
|
55775
|
+
const raw = readFileSync32(join32(agentDir, ".claude", ".claude.json"), "utf8");
|
|
55924
55776
|
claudeJson = JSON.parse(raw);
|
|
55925
55777
|
}
|
|
55926
55778
|
} catch {}
|
|
@@ -56134,10 +55986,10 @@ bot.command("restart", async (ctx) => {
|
|
|
56134
55986
|
function flushAgentHandoff(agentDir) {
|
|
56135
55987
|
let removed = 0;
|
|
56136
55988
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
56137
|
-
const p =
|
|
55989
|
+
const p = join32(agentDir, fname);
|
|
56138
55990
|
try {
|
|
56139
|
-
if (
|
|
56140
|
-
|
|
55991
|
+
if (existsSync34(p)) {
|
|
55992
|
+
unlinkSync14(p);
|
|
56141
55993
|
removed++;
|
|
56142
55994
|
}
|
|
56143
55995
|
} catch (err) {
|
|
@@ -56192,7 +56044,7 @@ async function handleNewOrResetCommand(ctx, kind) {
|
|
|
56192
56044
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
56193
56045
|
if (agentDir != null) {
|
|
56194
56046
|
try {
|
|
56195
|
-
writeFileSync21(
|
|
56047
|
+
writeFileSync21(join32(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
56196
56048
|
`, "utf8");
|
|
56197
56049
|
} catch (err) {
|
|
56198
56050
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -56553,14 +56405,14 @@ bot.command("interrupt", async (ctx) => {
|
|
|
56553
56405
|
var lockoutOps = {
|
|
56554
56406
|
readFileSync: (p, enc) => readFileSync32(p, enc),
|
|
56555
56407
|
writeFileSync: (p, data, opts) => writeFileSync21(p, data, opts),
|
|
56556
|
-
existsSync: (p) =>
|
|
56408
|
+
existsSync: (p) => existsSync34(p),
|
|
56557
56409
|
mkdirSync: (p, opts) => mkdirSync21(p, opts),
|
|
56558
|
-
joinPath: (...parts) =>
|
|
56410
|
+
joinPath: (...parts) => join32(...parts)
|
|
56559
56411
|
};
|
|
56560
56412
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
56561
56413
|
function isAuthBrokerSocketReachable() {
|
|
56562
56414
|
try {
|
|
56563
|
-
return
|
|
56415
|
+
return existsSync34(resolveAuthBrokerSocketPath2());
|
|
56564
56416
|
} catch {
|
|
56565
56417
|
return false;
|
|
56566
56418
|
}
|
|
@@ -56621,7 +56473,7 @@ async function runCreditWatch() {
|
|
|
56621
56473
|
if (!agentDir)
|
|
56622
56474
|
return;
|
|
56623
56475
|
const agentName3 = getMyAgentName();
|
|
56624
|
-
const claudeConfigDir =
|
|
56476
|
+
const claudeConfigDir = join32(agentDir, ".claude");
|
|
56625
56477
|
const stateDir = STATE_DIR;
|
|
56626
56478
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
56627
56479
|
const prev = loadCreditState(stateDir);
|
|
@@ -56831,9 +56683,9 @@ async function handleVaultRecentDenialCallback(ctx, data) {
|
|
|
56831
56683
|
return;
|
|
56832
56684
|
}
|
|
56833
56685
|
const { token, id } = result;
|
|
56834
|
-
const tokenPath =
|
|
56686
|
+
const tokenPath = join32(homedir12(), ".switchroom", "agents", agentName3, ".vault-token");
|
|
56835
56687
|
try {
|
|
56836
|
-
mkdirSync21(
|
|
56688
|
+
mkdirSync21(join32(homedir12(), ".switchroom", "agents", agentName3), { recursive: true });
|
|
56837
56689
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
56838
56690
|
} catch (err) {
|
|
56839
56691
|
await switchroomReply(ctx, `<b>Grant created (${escapeHtmlForTg(id)}) but token write failed:</b> ${escapeHtmlForTg(String(err))}
|
|
@@ -56910,9 +56762,9 @@ async function performVaultAccessApproval(ctx, pending2, stageId, senderId, atte
|
|
|
56910
56762
|
return;
|
|
56911
56763
|
}
|
|
56912
56764
|
const { token, id } = result;
|
|
56913
|
-
const tokenPath =
|
|
56765
|
+
const tokenPath = join32(homedir12(), ".switchroom", "agents", pending2.agent, ".vault-token");
|
|
56914
56766
|
try {
|
|
56915
|
-
mkdirSync21(
|
|
56767
|
+
mkdirSync21(join32(homedir12(), ".switchroom", "agents", pending2.agent), { recursive: true });
|
|
56916
56768
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
56917
56769
|
} catch (err) {
|
|
56918
56770
|
await switchroomReply(ctx, `<b>Grant created (${escapeHtmlForTg(id)}) but token write failed:</b> ${escapeHtmlForTg(String(err))}
|
|
@@ -57388,9 +57240,9 @@ async function executeGrantWizard(ctx, chatId, state4) {
|
|
|
57388
57240
|
return;
|
|
57389
57241
|
}
|
|
57390
57242
|
const { token, id } = result;
|
|
57391
|
-
const tokenPath =
|
|
57243
|
+
const tokenPath = join32(homedir12(), ".switchroom", "agents", state4.agent, ".vault-token");
|
|
57392
57244
|
try {
|
|
57393
|
-
mkdirSync21(
|
|
57245
|
+
mkdirSync21(join32(homedir12(), ".switchroom", "agents", state4.agent), { recursive: true });
|
|
57394
57246
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
57395
57247
|
} catch (err) {
|
|
57396
57248
|
await switchroomReply(ctx, `<b>Grant created but token write failed:</b> ${escapeHtmlForTg(String(err))}`, { html: true });
|
|
@@ -58248,7 +58100,7 @@ bot.command("usage", async (ctx) => {
|
|
|
58248
58100
|
await switchroomReply(ctx, "<b>/usage:</b> cannot resolve agent dir.", { html: true });
|
|
58249
58101
|
return;
|
|
58250
58102
|
}
|
|
58251
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
58103
|
+
const result = await fetchQuota2({ claudeConfigDir: join32(agentDir, ".claude") });
|
|
58252
58104
|
if (!result.ok) {
|
|
58253
58105
|
await switchroomReply(ctx, `<b>/usage:</b> ${escapeHtmlForTg(result.reason)}`, { html: true });
|
|
58254
58106
|
return;
|
|
@@ -58793,7 +58645,7 @@ async function maybeTranscribeVoice(fileId, mimeType, language) {
|
|
|
58793
58645
|
let apiKey = null;
|
|
58794
58646
|
try {
|
|
58795
58647
|
const path = __require("path").join(__require("os").homedir(), ".switchroom", "openai-api-key");
|
|
58796
|
-
if (
|
|
58648
|
+
if (existsSync34(path)) {
|
|
58797
58649
|
apiKey = readFileSync32(path, "utf-8").trim();
|
|
58798
58650
|
}
|
|
58799
58651
|
} catch (err) {
|
|
@@ -59654,7 +59506,7 @@ var didOneTimeSetup = false;
|
|
|
59654
59506
|
agentName: agentDisplayName,
|
|
59655
59507
|
agentSlug,
|
|
59656
59508
|
version: formatBootVersion(),
|
|
59657
|
-
agentDir: agentDir ??
|
|
59509
|
+
agentDir: agentDir ?? join32(homedir12(), ".switchroom", "agents", agentSlug),
|
|
59658
59510
|
gatewayInfo: { pid: process.pid, startedAtMs: GATEWAY_STARTED_AT_MS },
|
|
59659
59511
|
restartReason: reason,
|
|
59660
59512
|
restartAgeMs: markerAgeMs,
|