switchroom 0.21.7 → 0.21.8
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/bin/tmp-reaper.sh +234 -0
- package/dist/agent-scheduler/index.js +1 -1
- package/dist/auth-broker/index.js +2 -2
- package/dist/cli/notion-write-pretool.mjs +1 -1
- package/dist/cli/switchroom.js +3421 -2744
- package/dist/host-control/main.js +177 -13
- package/dist/vault/approvals/kernel-server.js +2 -2
- package/dist/vault/broker/server.js +2 -2
- package/package.json +5 -4
- package/profiles/_base/start.sh.hbs +115 -0
- package/profiles/_shared/local-time.md.hbs +6 -0
- package/profiles/default/CLAUDE.md.hbs +0 -12
- package/telegram-plugin/dist/gateway/gateway.js +1017 -465
- package/telegram-plugin/gateway/agent-process-liveness.ts +558 -0
- package/telegram-plugin/gateway/approval-hold.ts +32 -1
- package/telegram-plugin/gateway/approval-outcome-sources.ts +274 -0
- package/telegram-plugin/gateway/bridge-dead-watchdog.ts +21 -9
- package/telegram-plugin/gateway/callback-query-handlers.ts +87 -15
- package/telegram-plugin/gateway/eval-case-proposal-inbound-builders.ts +197 -0
- package/telegram-plugin/gateway/gateway.ts +12 -10
- package/telegram-plugin/gateway/pending-inbound-buffer.ts +167 -11
- package/telegram-plugin/gateway/self-improve-proposal-wiring.test.ts +333 -0
- package/telegram-plugin/gateway/self-improve-proposal-wiring.ts +152 -3
- package/telegram-plugin/gateway/subagent-handback-marker.ts +19 -0
- package/telegram-plugin/tests/agent-process-liveness.test.ts +406 -0
- package/telegram-plugin/tests/approval-hold-record.test.ts +21 -8
- package/telegram-plugin/tests/boot-resume-gateway-only-respawn.test.ts +752 -0
- package/telegram-plugin/tests/boot-resume-guard-wiring.test.ts +203 -0
- package/telegram-plugin/tests/callback-query-handlers.test.ts +143 -1
- package/telegram-plugin/tests/eval-case-proposal-inbound-builders.test.ts +144 -0
- package/telegram-plugin/tests/hermes-messages-paging.test.ts +149 -0
- package/telegram-plugin/tests/hermes-session-search.test.ts +146 -0
- package/telegram-plugin/tests/pending-inbound-buffer.test.ts +443 -2
- package/telegram-plugin/tests/subagent-handback-marker.test.ts +14 -0
|
@@ -22355,7 +22355,7 @@ var init_schema = __esm(() => {
|
|
|
22355
22355
|
repos: exports_external.record(exports_external.string().regex(/^[a-z0-9][a-z0-9-]*$/, "Repo slug must be kebab-case ASCII: start with a lowercase letter or digit, contain only lowercase letters, digits, and hyphens"), exports_external.object({
|
|
22356
22356
|
url: exports_external.string().min(1).describe("Git remote URL for the repo (e.g. 'git@github.com:org/repo.git' or " + "'https://github.com/org/repo.git'). Used verbatim for git clone."),
|
|
22357
22357
|
branch_default: exports_external.string().optional().describe("Default branch to track (defaults to the remote's HEAD, typically 'main'). " + "The per-agent branch 'agent/<agentName>/main' fast-forwards to this branch " + "when the worktree is clean on session start.")
|
|
22358
|
-
})).optional().describe("Repos this agent operates on. Switchroom provisions a dedicated
|
|
22358
|
+
})).optional().describe("Repos this agent operates on. Switchroom provisions a dedicated standing tree for " + "each repo at <agentDir>/work/<slug>/ on branch agent/<agentName>/main \u2014 an " + "independent clone (own refs/stash, hardlinked objects) seeded from a shared bare " + "clone at ~/.switchroom/repos/<slug>.git. The tree's path is injected " + "into the agent's environment as SWITCHROOM_REPO_<SLUG_UPPER>. " + "Agents without this field continue to work unchanged."),
|
|
22359
22359
|
experimental: exports_external.object({
|
|
22360
22360
|
legacy_pty: exports_external.boolean().optional().describe("Opt out of the default tmux supervisor (#725) and run the agent " + "under the legacy PTY supervisor instead. Default: false."),
|
|
22361
22361
|
legacy_autoaccept_expect: exports_external.boolean().optional().describe("Opt the autoaccept gateway back into the legacy expect-script " + "behaviour instead of the tmux send-keys path. Default: false.")
|
|
@@ -24113,7 +24113,7 @@ var init_approval_card = __esm(() => {
|
|
|
24113
24113
|
});
|
|
24114
24114
|
|
|
24115
24115
|
// flood-429-ledger.ts
|
|
24116
|
-
import { readFileSync as readFileSync15, writeFileSync as
|
|
24116
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync14, mkdirSync as mkdirSync17, chmodSync as chmodSync4, unlinkSync as unlinkSync10 } from "node:fs";
|
|
24117
24117
|
import { dirname as dirname9, join as join20 } from "node:path";
|
|
24118
24118
|
function flood429LedgerPathFromFloodState(floodStatePath) {
|
|
24119
24119
|
return join20(dirname9(floodStatePath), FLOOD_429_LEDGER_FILE);
|
|
@@ -24217,7 +24217,7 @@ function writeFlood429Ledger(path2, episodes, log = (l) => process.stderr.write(
|
|
|
24217
24217
|
mkdirSync17(dirname9(path2), { recursive: true });
|
|
24218
24218
|
} catch {}
|
|
24219
24219
|
try {
|
|
24220
|
-
|
|
24220
|
+
writeFileSync14(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
|
|
24221
24221
|
try {
|
|
24222
24222
|
chmodSync4(path2, FLOOD_429_LEDGER_MODE);
|
|
24223
24223
|
} catch {}
|
|
@@ -24230,8 +24230,8 @@ function writeFlood429Ledger(path2, episodes, log = (l) => process.stderr.write(
|
|
|
24230
24230
|
return;
|
|
24231
24231
|
}
|
|
24232
24232
|
try {
|
|
24233
|
-
|
|
24234
|
-
|
|
24233
|
+
unlinkSync10(path2);
|
|
24234
|
+
writeFileSync14(path2, payload, { mode: FLOOD_429_LEDGER_MODE });
|
|
24235
24235
|
} catch (err2) {
|
|
24236
24236
|
log(`telegram gateway: 429-ledger: cannot persist the 429 pressure ledger to ${path2} ` + `(${code2}, recreate failed: ${err2?.message ?? String(err2)}). ` + `Flood-pressure history will be missing from \`switchroom doctor\`
|
|
24237
24237
|
`);
|
|
@@ -24253,11 +24253,11 @@ var init_flood_429_ledger = __esm(() => {
|
|
|
24253
24253
|
import {
|
|
24254
24254
|
existsSync as existsSync14,
|
|
24255
24255
|
readFileSync as readFileSync16,
|
|
24256
|
-
writeFileSync as
|
|
24256
|
+
writeFileSync as writeFileSync15,
|
|
24257
24257
|
mkdirSync as mkdirSync18,
|
|
24258
24258
|
chmodSync as chmodSync5,
|
|
24259
|
-
unlinkSync as
|
|
24260
|
-
renameSync as
|
|
24259
|
+
unlinkSync as unlinkSync11,
|
|
24260
|
+
renameSync as renameSync11
|
|
24261
24261
|
} from "node:fs";
|
|
24262
24262
|
import { dirname as dirname10, join as join21 } from "node:path";
|
|
24263
24263
|
function floodStatePath(stateDir) {
|
|
@@ -24313,7 +24313,7 @@ function writeFloodState(path2, state, log = (l) => process.stderr.write(l)) {
|
|
|
24313
24313
|
mkdirSync18(dirname10(path2), { recursive: true });
|
|
24314
24314
|
} catch {}
|
|
24315
24315
|
try {
|
|
24316
|
-
|
|
24316
|
+
writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE });
|
|
24317
24317
|
try {
|
|
24318
24318
|
chmodSync5(path2, FLOOD_STATE_MODE);
|
|
24319
24319
|
} catch {}
|
|
@@ -24326,8 +24326,8 @@ function writeFloodState(path2, state, log = (l) => process.stderr.write(l)) {
|
|
|
24326
24326
|
return;
|
|
24327
24327
|
}
|
|
24328
24328
|
try {
|
|
24329
|
-
|
|
24330
|
-
|
|
24329
|
+
unlinkSync11(path2);
|
|
24330
|
+
writeFileSync15(path2, payload, { mode: FLOOD_STATE_MODE });
|
|
24331
24331
|
log(`telegram gateway: flood-breaker: recreated ${path2} \u2014 it was owned by another uid ` + `and could not be updated (${code2}); the breaker was blind (issue #3106)
|
|
24332
24332
|
`);
|
|
24333
24333
|
} catch (err2) {
|
|
@@ -30636,7 +30636,7 @@ var init_turn_flush_suppression = () => {};
|
|
|
30636
30636
|
|
|
30637
30637
|
// ../src/agents/generation-stamp.ts
|
|
30638
30638
|
import { createHash as createHash6 } from "node:crypto";
|
|
30639
|
-
import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as
|
|
30639
|
+
import { existsSync as existsSync36, readFileSync as readFileSync35, writeFileSync as writeFileSync31 } from "node:fs";
|
|
30640
30640
|
import { join as join44 } from "node:path";
|
|
30641
30641
|
function sha256Text(s) {
|
|
30642
30642
|
return createHash6("sha256").update(s, "utf-8").digest("hex");
|
|
@@ -36473,7 +36473,7 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
|
|
|
36473
36473
|
}
|
|
36474
36474
|
|
|
36475
36475
|
// gateway/quota-cache.ts
|
|
36476
|
-
import { existsSync as existsSync49, readFileSync as readFileSync49, writeFileSync as
|
|
36476
|
+
import { existsSync as existsSync49, readFileSync as readFileSync49, writeFileSync as writeFileSync41, mkdirSync as mkdirSync42 } from "fs";
|
|
36477
36477
|
import { join as join59, dirname as dirname25 } from "path";
|
|
36478
36478
|
function defaultCachePath() {
|
|
36479
36479
|
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join59(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
@@ -36512,7 +36512,7 @@ function writeQuotaCache(result, opts = {}) {
|
|
|
36512
36512
|
};
|
|
36513
36513
|
try {
|
|
36514
36514
|
mkdirSync42(dirname25(path3), { recursive: true });
|
|
36515
|
-
|
|
36515
|
+
writeFileSync41(path3, JSON.stringify(entry, null, 2), { mode: 384 });
|
|
36516
36516
|
} catch {}
|
|
36517
36517
|
}
|
|
36518
36518
|
var DEFAULT_TTL_MS4, RATE_LIMIT_TTL_MS;
|
|
@@ -37383,7 +37383,7 @@ var init_boot_probes = __esm(() => {
|
|
|
37383
37383
|
});
|
|
37384
37384
|
|
|
37385
37385
|
// gateway/boot-issue-cache.ts
|
|
37386
|
-
import { existsSync as existsSync51, readFileSync as readFileSync51, writeFileSync as
|
|
37386
|
+
import { existsSync as existsSync51, readFileSync as readFileSync51, writeFileSync as writeFileSync42, mkdirSync as mkdirSync43, renameSync as renameSync25 } from "fs";
|
|
37387
37387
|
import { dirname as dirname26 } from "path";
|
|
37388
37388
|
function fingerprintProbe(key, r) {
|
|
37389
37389
|
if (r.status === "ok")
|
|
@@ -37476,7 +37476,7 @@ function loadCache(path3, now = Date.now) {
|
|
|
37476
37476
|
parsed = JSON.parse(raw);
|
|
37477
37477
|
} catch {
|
|
37478
37478
|
try {
|
|
37479
|
-
|
|
37479
|
+
renameSync25(path3, `${path3}.corrupt-${now()}`);
|
|
37480
37480
|
} catch {}
|
|
37481
37481
|
return { ...EMPTY_CACHE, probes: {} };
|
|
37482
37482
|
}
|
|
@@ -37512,8 +37512,8 @@ function applyAndSave(path3, cache, diff) {
|
|
|
37512
37512
|
try {
|
|
37513
37513
|
mkdirSync43(dirname26(path3), { recursive: true });
|
|
37514
37514
|
const tmp = `${path3}.tmp`;
|
|
37515
|
-
|
|
37516
|
-
|
|
37515
|
+
writeFileSync42(tmp, JSON.stringify(next), { mode: 384 });
|
|
37516
|
+
renameSync25(tmp, path3);
|
|
37517
37517
|
} catch {}
|
|
37518
37518
|
return next;
|
|
37519
37519
|
}
|
|
@@ -37526,7 +37526,7 @@ var init_boot_issue_cache = __esm(() => {
|
|
|
37526
37526
|
|
|
37527
37527
|
// gateway/config-snapshot.ts
|
|
37528
37528
|
import { createHash as createHash7 } from "crypto";
|
|
37529
|
-
import { existsSync as existsSync52, readFileSync as readFileSync52, writeFileSync as
|
|
37529
|
+
import { existsSync as existsSync52, readFileSync as readFileSync52, writeFileSync as writeFileSync43, mkdirSync as mkdirSync44, renameSync as renameSync26 } from "fs";
|
|
37530
37530
|
import { dirname as dirname27 } from "path";
|
|
37531
37531
|
function hashStringArray(items) {
|
|
37532
37532
|
if (!items || items.length === 0)
|
|
@@ -37604,7 +37604,7 @@ function loadSnapshot(path3, now = Date.now) {
|
|
|
37604
37604
|
parsed = JSON.parse(raw);
|
|
37605
37605
|
} catch {
|
|
37606
37606
|
try {
|
|
37607
|
-
|
|
37607
|
+
renameSync26(path3, `${path3}.corrupt-${now()}`);
|
|
37608
37608
|
} catch {}
|
|
37609
37609
|
return null;
|
|
37610
37610
|
}
|
|
@@ -37627,8 +37627,8 @@ function persistSnapshot(path3, snapshot) {
|
|
|
37627
37627
|
try {
|
|
37628
37628
|
mkdirSync44(dirname27(path3), { recursive: true });
|
|
37629
37629
|
const tmp = `${path3}.tmp`;
|
|
37630
|
-
|
|
37631
|
-
|
|
37630
|
+
writeFileSync43(tmp, JSON.stringify(snapshot), { mode: 384 });
|
|
37631
|
+
renameSync26(tmp, path3);
|
|
37632
37632
|
} catch {}
|
|
37633
37633
|
}
|
|
37634
37634
|
var init_config_snapshot = __esm(() => {
|
|
@@ -37636,7 +37636,7 @@ var init_config_snapshot = __esm(() => {
|
|
|
37636
37636
|
});
|
|
37637
37637
|
|
|
37638
37638
|
// gateway/boot-card-msgid.ts
|
|
37639
|
-
import { readFileSync as readFileSync53, writeFileSync as
|
|
37639
|
+
import { readFileSync as readFileSync53, writeFileSync as writeFileSync44 } from "node:fs";
|
|
37640
37640
|
function bootCardChatKey(chatId, threadId) {
|
|
37641
37641
|
return `${chatId}:${threadId ?? ""}`;
|
|
37642
37642
|
}
|
|
@@ -37661,7 +37661,7 @@ function saveBootCardMsgId(path3, chatKey3, messageId) {
|
|
|
37661
37661
|
if (store3[chatKey3] === messageId)
|
|
37662
37662
|
return;
|
|
37663
37663
|
store3[chatKey3] = messageId;
|
|
37664
|
-
|
|
37664
|
+
writeFileSync44(path3, JSON.stringify(store3), "utf8");
|
|
37665
37665
|
} catch {}
|
|
37666
37666
|
}
|
|
37667
37667
|
var init_boot_card_msgid = () => {};
|
|
@@ -38695,7 +38695,7 @@ __export(exports_tmux2, {
|
|
|
38695
38695
|
captureAgentPane: () => captureAgentPane2
|
|
38696
38696
|
});
|
|
38697
38697
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
38698
|
-
import { chmodSync as chmodSync13, mkdirSync as mkdirSync49, readdirSync as
|
|
38698
|
+
import { chmodSync as chmodSync13, mkdirSync as mkdirSync49, readdirSync as readdirSync18, statSync as statSync24, unlinkSync as unlinkSync32, writeFileSync as writeFileSync54 } from "node:fs";
|
|
38699
38699
|
import { resolve as resolve12 } from "node:path";
|
|
38700
38700
|
function captureAgentPane2(opts) {
|
|
38701
38701
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -38746,7 +38746,7 @@ function captureAgentPane2(opts) {
|
|
|
38746
38746
|
` + `
|
|
38747
38747
|
`;
|
|
38748
38748
|
try {
|
|
38749
|
-
|
|
38749
|
+
writeFileSync54(outPath, Buffer.concat([Buffer.from(header, "utf8"), body]), {
|
|
38750
38750
|
mode: 384
|
|
38751
38751
|
});
|
|
38752
38752
|
} catch (err) {
|
|
@@ -38816,7 +38816,7 @@ function sleepSync3(ms) {
|
|
|
38816
38816
|
function pruneOldReports2(dir, retain) {
|
|
38817
38817
|
let entries;
|
|
38818
38818
|
try {
|
|
38819
|
-
entries =
|
|
38819
|
+
entries = readdirSync18(dir);
|
|
38820
38820
|
} catch {
|
|
38821
38821
|
return;
|
|
38822
38822
|
}
|
|
@@ -38830,7 +38830,7 @@ function pruneOldReports2(dir, retain) {
|
|
|
38830
38830
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
38831
38831
|
for (const stale of files.slice(retain)) {
|
|
38832
38832
|
try {
|
|
38833
|
-
|
|
38833
|
+
unlinkSync32(stale.full);
|
|
38834
38834
|
} catch {}
|
|
38835
38835
|
}
|
|
38836
38836
|
}
|
|
@@ -39640,7 +39640,7 @@ __export(exports_materialize_bot_token, {
|
|
|
39640
39640
|
materializeBotToken: () => materializeBotToken,
|
|
39641
39641
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
39642
39642
|
});
|
|
39643
|
-
import { existsSync as
|
|
39643
|
+
import { existsSync as existsSync64 } from "node:fs";
|
|
39644
39644
|
function pickConfiguredToken(config, agentName3) {
|
|
39645
39645
|
if (agentName3) {
|
|
39646
39646
|
const agent = config.agents?.[agentName3];
|
|
@@ -39654,7 +39654,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
|
|
|
39654
39654
|
if (!passphrase)
|
|
39655
39655
|
return null;
|
|
39656
39656
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
39657
|
-
if (!
|
|
39657
|
+
if (!existsSync64(vaultPath))
|
|
39658
39658
|
return null;
|
|
39659
39659
|
try {
|
|
39660
39660
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -39809,19 +39809,19 @@ var import_runner3 = __toESM(require_mod3(), 1);
|
|
|
39809
39809
|
import { randomBytes as randomBytes12, createHash as createHash8 } from "crypto";
|
|
39810
39810
|
import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
39811
39811
|
import {
|
|
39812
|
-
readFileSync as
|
|
39813
|
-
writeFileSync as
|
|
39812
|
+
readFileSync as readFileSync67,
|
|
39813
|
+
writeFileSync as writeFileSync55,
|
|
39814
39814
|
mkdirSync as mkdirSync50,
|
|
39815
|
-
readdirSync as
|
|
39815
|
+
readdirSync as readdirSync19,
|
|
39816
39816
|
rmSync as rmSync9,
|
|
39817
39817
|
statSync as statSync25,
|
|
39818
|
-
renameSync as
|
|
39818
|
+
renameSync as renameSync32,
|
|
39819
39819
|
realpathSync as realpathSync6,
|
|
39820
39820
|
chmodSync as chmodSync14,
|
|
39821
39821
|
openSync as openSync18,
|
|
39822
39822
|
closeSync as closeSync18,
|
|
39823
|
-
existsSync as
|
|
39824
|
-
unlinkSync as
|
|
39823
|
+
existsSync as existsSync65,
|
|
39824
|
+
unlinkSync as unlinkSync33,
|
|
39825
39825
|
appendFileSync as appendFileSync11
|
|
39826
39826
|
} from "fs";
|
|
39827
39827
|
|
|
@@ -39839,7 +39839,7 @@ function fsyncPathSync(path) {
|
|
|
39839
39839
|
|
|
39840
39840
|
// gateway/gateway.ts
|
|
39841
39841
|
import { homedir as homedir22 } from "os";
|
|
39842
|
-
import { join as
|
|
39842
|
+
import { join as join77, sep as sep6, basename as basename19 } from "path";
|
|
39843
39843
|
|
|
39844
39844
|
// plugin-logger.ts
|
|
39845
39845
|
import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
|
|
@@ -50974,7 +50974,7 @@ function createSweepableCardStore(deps) {
|
|
|
50974
50974
|
init_rich_send();
|
|
50975
50975
|
var import_grammy4 = __toESM(require_mod2(), 1);
|
|
50976
50976
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
50977
|
-
import { mkdirSync as mkdirSync15, writeFileSync as
|
|
50977
|
+
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync11 } from "fs";
|
|
50978
50978
|
import { dirname as dirname7 } from "path";
|
|
50979
50979
|
init_client2();
|
|
50980
50980
|
|
|
@@ -51754,11 +51754,15 @@ import {
|
|
|
51754
51754
|
mkdirSync as mkdirSync14,
|
|
51755
51755
|
openSync as openSync8,
|
|
51756
51756
|
readFileSync as readFileSync13,
|
|
51757
|
+
renameSync as renameSync10,
|
|
51758
|
+
unlinkSync as unlinkSync6,
|
|
51759
|
+
writeFileSync as writeFileSync10,
|
|
51757
51760
|
writeSync as writeSync7
|
|
51758
51761
|
} from "node:fs";
|
|
51759
51762
|
import { join as join15 } from "node:path";
|
|
51760
51763
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
51761
51764
|
var EVAL_CASE_PROPOSALS_FILE = "eval-case-proposals.jsonl";
|
|
51765
|
+
var MAX_EVAL_CASE_PROPOSALS = 200;
|
|
51762
51766
|
function proposalsPath2(stateDir) {
|
|
51763
51767
|
return join15(stateDir, EVAL_CASE_PROPOSALS_FILE);
|
|
51764
51768
|
}
|
|
@@ -51801,6 +51805,49 @@ function readEvalCaseProposals(stateDir) {
|
|
|
51801
51805
|
}
|
|
51802
51806
|
return [...byId.values()];
|
|
51803
51807
|
}
|
|
51808
|
+
function withinBound(all, now) {
|
|
51809
|
+
const isLiveRejection = (r) => {
|
|
51810
|
+
if (r.status !== "rejected")
|
|
51811
|
+
return false;
|
|
51812
|
+
const age = now - new Date(r.created_at).getTime();
|
|
51813
|
+
return !Number.isFinite(age) || age <= REJECTION_TTL_MS;
|
|
51814
|
+
};
|
|
51815
|
+
const keepTail = (rows) => rows.length > MAX_EVAL_CASE_PROPOSALS ? rows.slice(rows.length - MAX_EVAL_CASE_PROPOSALS) : rows;
|
|
51816
|
+
const keep = new Set([
|
|
51817
|
+
...keepTail(all.filter(isLiveRejection)).map((r) => r.id),
|
|
51818
|
+
...keepTail(all.filter((r) => !isLiveRejection(r))).map((r) => r.id)
|
|
51819
|
+
]);
|
|
51820
|
+
return all.filter((r) => keep.has(r.id));
|
|
51821
|
+
}
|
|
51822
|
+
function compactIfOversized(stateDir, now) {
|
|
51823
|
+
const path = proposalsPath2(stateDir);
|
|
51824
|
+
let raw;
|
|
51825
|
+
try {
|
|
51826
|
+
raw = readFileSync13(path, "utf-8");
|
|
51827
|
+
} catch {
|
|
51828
|
+
return;
|
|
51829
|
+
}
|
|
51830
|
+
const lines = raw.split(`
|
|
51831
|
+
`).filter((l) => l.trim().length > 0);
|
|
51832
|
+
if (lines.length <= MAX_EVAL_CASE_PROPOSALS * 2)
|
|
51833
|
+
return;
|
|
51834
|
+
const kept = withinBound(readEvalCaseProposals(stateDir), now);
|
|
51835
|
+
if (kept.length >= lines.length)
|
|
51836
|
+
return;
|
|
51837
|
+
const tmp = `${path}.tmp.${process.pid}`;
|
|
51838
|
+
try {
|
|
51839
|
+
writeFileSync10(tmp, kept.map((r) => JSON.stringify(r) + `
|
|
51840
|
+
`).join(""), {
|
|
51841
|
+
encoding: "utf-8",
|
|
51842
|
+
mode: 420
|
|
51843
|
+
});
|
|
51844
|
+
renameSync10(tmp, path);
|
|
51845
|
+
} catch {
|
|
51846
|
+
try {
|
|
51847
|
+
unlinkSync6(tmp);
|
|
51848
|
+
} catch {}
|
|
51849
|
+
}
|
|
51850
|
+
}
|
|
51804
51851
|
function getEvalCaseProposal(stateDir, id) {
|
|
51805
51852
|
return readEvalCaseProposals(stateDir).find((p) => p.id === id);
|
|
51806
51853
|
}
|
|
@@ -51814,6 +51861,7 @@ function enqueueEvalCaseProposal(stateDir, input, opts = {}) {
|
|
|
51814
51861
|
...input
|
|
51815
51862
|
};
|
|
51816
51863
|
appendLine2(proposalsPath2(stateDir), proposal);
|
|
51864
|
+
compactIfOversized(stateDir, now());
|
|
51817
51865
|
return proposal;
|
|
51818
51866
|
}
|
|
51819
51867
|
function setEvalCaseProposalStatus(stateDir, id, status) {
|
|
@@ -51822,8 +51870,94 @@ function setEvalCaseProposalStatus(stateDir, id, status) {
|
|
|
51822
51870
|
return;
|
|
51823
51871
|
const next = { ...cur, status };
|
|
51824
51872
|
appendLine2(proposalsPath2(stateDir), next);
|
|
51873
|
+
compactIfOversized(stateDir, Date.now());
|
|
51825
51874
|
return next;
|
|
51826
51875
|
}
|
|
51876
|
+
|
|
51877
|
+
// gateway/eval-case-proposal-inbound-builders.ts
|
|
51878
|
+
function commonMeta(opts) {
|
|
51879
|
+
return {
|
|
51880
|
+
agent: opts.ctx.agent,
|
|
51881
|
+
...opts.ctx.threadId != null ? { message_thread_id: String(opts.ctx.threadId) } : {},
|
|
51882
|
+
proposal_id: opts.proposalId,
|
|
51883
|
+
skill_slug: opts.skillSlug,
|
|
51884
|
+
held_out: String(opts.heldOut),
|
|
51885
|
+
operator_id: opts.operatorId
|
|
51886
|
+
};
|
|
51887
|
+
}
|
|
51888
|
+
function buildEvalCaseAppliedInbound(opts) {
|
|
51889
|
+
const ts = opts.nowMs ?? Date.now();
|
|
51890
|
+
const sink2 = opts.heldOut ? "the held-out sink" : `\`${opts.skillSlug}\`'s \`evals.json\``;
|
|
51891
|
+
return {
|
|
51892
|
+
type: "inbound",
|
|
51893
|
+
chatId: opts.ctx.chat_id,
|
|
51894
|
+
...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
|
|
51895
|
+
messageId: ts,
|
|
51896
|
+
user: "self-improve",
|
|
51897
|
+
userId: 0,
|
|
51898
|
+
ts,
|
|
51899
|
+
text: `\u2705 Operator approved your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}). The case was applied DETERMINISTICALLY by ` + `the gateway and is already written to ${sink2} \u2014 do NOT write it yourself ` + `and do NOT re-propose it. Resume whatever you were doing.`,
|
|
51900
|
+
meta: {
|
|
51901
|
+
source: "eval_case_applied",
|
|
51902
|
+
...commonMeta({
|
|
51903
|
+
ctx: opts.ctx,
|
|
51904
|
+
proposalId: opts.proposalId,
|
|
51905
|
+
skillSlug: opts.skillSlug,
|
|
51906
|
+
heldOut: opts.heldOut,
|
|
51907
|
+
operatorId: opts.operatorId
|
|
51908
|
+
})
|
|
51909
|
+
}
|
|
51910
|
+
};
|
|
51911
|
+
}
|
|
51912
|
+
function buildEvalCaseRejectedInbound(opts) {
|
|
51913
|
+
const ts = opts.nowMs ?? Date.now();
|
|
51914
|
+
return {
|
|
51915
|
+
type: "inbound",
|
|
51916
|
+
chatId: opts.ctx.chat_id,
|
|
51917
|
+
...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
|
|
51918
|
+
messageId: ts,
|
|
51919
|
+
user: "self-improve",
|
|
51920
|
+
userId: 0,
|
|
51921
|
+
ts,
|
|
51922
|
+
text: `\uD83D\uDEAB Operator dismissed your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}). NOTHING was written \u2014 no eval case was ` + `added. Carry on with the original task without it. Do NOT re-propose the ` + `same case without first asking the user.`,
|
|
51923
|
+
meta: {
|
|
51924
|
+
source: "eval_case_rejected",
|
|
51925
|
+
...commonMeta({
|
|
51926
|
+
ctx: opts.ctx,
|
|
51927
|
+
proposalId: opts.proposalId,
|
|
51928
|
+
skillSlug: opts.skillSlug,
|
|
51929
|
+
heldOut: opts.heldOut,
|
|
51930
|
+
operatorId: opts.operatorId
|
|
51931
|
+
})
|
|
51932
|
+
}
|
|
51933
|
+
};
|
|
51934
|
+
}
|
|
51935
|
+
function buildEvalCaseApplyFailedInbound(opts) {
|
|
51936
|
+
const ts = opts.nowMs ?? Date.now();
|
|
51937
|
+
const tail = opts.applyOut.trim().slice(0, 500);
|
|
51938
|
+
return {
|
|
51939
|
+
type: "inbound",
|
|
51940
|
+
chatId: opts.ctx.chat_id,
|
|
51941
|
+
...opts.ctx.threadId != null ? { threadId: opts.ctx.threadId } : {},
|
|
51942
|
+
messageId: ts,
|
|
51943
|
+
user: "self-improve",
|
|
51944
|
+
userId: 0,
|
|
51945
|
+
ts,
|
|
51946
|
+
text: `\u26a0\ufe0f The operator approved your proposed eval case for \`${opts.skillSlug}\` ` + `(proposal ${opts.proposalId}) but the applier FAILED. The case was NOT ` + `written \u2014 do NOT assume the regression test exists. Applier output:
|
|
51947
|
+
` + `${tail.length > 0 ? tail : "(no output)"}
|
|
51948
|
+
` + `Carry on with the original task; report the failure to the operator if it ` + `still matters.`,
|
|
51949
|
+
meta: {
|
|
51950
|
+
source: "eval_case_apply_failed",
|
|
51951
|
+
...commonMeta({
|
|
51952
|
+
ctx: opts.ctx,
|
|
51953
|
+
proposalId: opts.proposalId,
|
|
51954
|
+
skillSlug: opts.skillSlug,
|
|
51955
|
+
heldOut: opts.heldOut,
|
|
51956
|
+
operatorId: opts.operatorId
|
|
51957
|
+
})
|
|
51958
|
+
}
|
|
51959
|
+
};
|
|
51960
|
+
}
|
|
51827
51961
|
// gateway/callback-query-handlers.ts
|
|
51828
51962
|
init_auth_snapshot_format();
|
|
51829
51963
|
|
|
@@ -52003,13 +52137,14 @@ var AgentSmokeRequestSchema = exports_external.object({
|
|
|
52003
52137
|
deep: exports_external.boolean().optional()
|
|
52004
52138
|
})
|
|
52005
52139
|
});
|
|
52140
|
+
var CANONICAL_CONFIG_PATH = "/state/config/switchroom.yaml";
|
|
52006
52141
|
var ConfigProposeEditRequestSchema = exports_external.object({
|
|
52007
52142
|
...RequestEnvelope,
|
|
52008
52143
|
op: exports_external.literal("config_propose_edit"),
|
|
52009
52144
|
args: exports_external.object({
|
|
52010
52145
|
unified_diff: exports_external.string().min(1).max(MAX_FRAME_BYTES3 - 1024),
|
|
52011
52146
|
reason: exports_external.string().min(1).max(500),
|
|
52012
|
-
target_path: exports_external.literal(
|
|
52147
|
+
target_path: exports_external.literal(CANONICAL_CONFIG_PATH)
|
|
52013
52148
|
})
|
|
52014
52149
|
});
|
|
52015
52150
|
var RequestSchema3 = exports_external.discriminatedUnion("op", [
|
|
@@ -52335,6 +52470,20 @@ function createCallbackQueryHandlers(deps) {
|
|
|
52335
52470
|
const listViaBroker2 = deps.brokerList ?? listViaBroker;
|
|
52336
52471
|
const listGrantsViaBroker2 = deps.brokerListGrants ?? listGrantsViaBroker;
|
|
52337
52472
|
const vaultTokenFilePath2 = deps.brokerVaultTokenFilePath ?? vaultTokenFilePath;
|
|
52473
|
+
const runEvalCaseApply = deps.runEvalCaseApply ?? ((id) => {
|
|
52474
|
+
const cli = process.env.SWITCHROOM_CLI_PATH ?? "switchroom";
|
|
52475
|
+
try {
|
|
52476
|
+
const out = execFileSync3(cli, ["self-improve", "apply-eval-case", "--id", id], { encoding: "utf8", timeout: 15000, env: process.env }).trim();
|
|
52477
|
+
return { ok: true, out };
|
|
52478
|
+
} catch (err) {
|
|
52479
|
+
const e = err;
|
|
52480
|
+
return {
|
|
52481
|
+
ok: false,
|
|
52482
|
+
out: [e.stdout, e.stderr, e.message].filter(Boolean).join(`
|
|
52483
|
+
`).trim()
|
|
52484
|
+
};
|
|
52485
|
+
}
|
|
52486
|
+
});
|
|
52338
52487
|
async function handleVaultRecentDenialCallback(ctx, data) {
|
|
52339
52488
|
const senderId = String(ctx.from?.id ?? "");
|
|
52340
52489
|
const access = loadAccess();
|
|
@@ -52375,7 +52524,7 @@ function createCallbackQueryHandlers(deps) {
|
|
|
52375
52524
|
const tokenPath = vaultTokenFilePath2(agentName);
|
|
52376
52525
|
try {
|
|
52377
52526
|
mkdirSync15(dirname7(tokenPath), { recursive: true });
|
|
52378
|
-
|
|
52527
|
+
writeFileSync11(tokenPath, token, { mode: 384 });
|
|
52379
52528
|
} catch (err) {
|
|
52380
52529
|
await switchroomReply(ctx, `**Grant created (${escapeHtmlForTg2(id)}) but token write failed:** ` + `${escapeHtmlForTg2(String(err))}
|
|
52381
52530
|
` + `_Recover with: \`switchroom vault grant ${escapeHtmlForTg2(agentName)} ` + `--keys ${escapeHtmlForTg2(keyName)} --duration 30d\` on the host._`, { html: true });
|
|
@@ -52527,7 +52676,7 @@ function createCallbackQueryHandlers(deps) {
|
|
|
52527
52676
|
const tokenPath = vaultTokenFilePath2(pending.agent);
|
|
52528
52677
|
try {
|
|
52529
52678
|
mkdirSync15(dirname7(tokenPath), { recursive: true });
|
|
52530
|
-
|
|
52679
|
+
writeFileSync11(tokenPath, token, { mode: 384 });
|
|
52531
52680
|
} catch (err) {
|
|
52532
52681
|
await switchroomReply(ctx, `**Grant created (${escapeHtmlForTg2(id)}) but token write failed:** ` + `${escapeHtmlForTg2(String(err))}
|
|
52533
52682
|
` + `_Recover with: \`switchroom vault grant ${escapeHtmlForTg2(pending.agent)} ` + `--keys ${escapeHtmlForTg2(pending.key)} --duration ${Math.round(pending.ttl_seconds / 86400)}d\` on the host._`, { html: true });
|
|
@@ -52668,36 +52817,57 @@ _Approver verified by Telegram identity \u2014 broker auto-unlocked at startup._
|
|
|
52668
52817
|
}
|
|
52669
52818
|
return;
|
|
52670
52819
|
}
|
|
52820
|
+
const cbChatId = String(ctx.chat?.id ?? ctx.from?.id ?? "");
|
|
52821
|
+
const cbThreadId = resolveThreadId(cbChatId, ctx.callbackQuery?.message?.message_thread_id);
|
|
52822
|
+
const inboundCtx = {
|
|
52823
|
+
agent,
|
|
52824
|
+
chat_id: cbChatId,
|
|
52825
|
+
...cbThreadId != null ? { threadId: cbThreadId } : {}
|
|
52826
|
+
};
|
|
52671
52827
|
if (parsed.action === "deny") {
|
|
52672
52828
|
setEvalCaseProposalStatus(stateDir, parsed.id, "rejected");
|
|
52829
|
+
const denied = deliverResumeSyntheticOrBuffer(agent, buildEvalCaseRejectedInbound({
|
|
52830
|
+
ctx: inboundCtx,
|
|
52831
|
+
proposalId: proposal.id,
|
|
52832
|
+
skillSlug: proposal.skill_slug,
|
|
52833
|
+
heldOut: proposal.held_out,
|
|
52834
|
+
operatorId: senderId
|
|
52835
|
+
}));
|
|
52673
52836
|
await ctx.answerCallbackQuery({ text: "\uD83D\uDEAB Dismissed." }).catch(() => {});
|
|
52674
52837
|
if (ctx.callbackQuery?.message && "text" in ctx.callbackQuery.message) {
|
|
52675
52838
|
await ctx.editMessageText(`${escapeHtmlForTg2(ctx.callbackQuery.message.text ?? "")}
|
|
52676
52839
|
|
|
52677
52840
|
\uD83D\uDEAB <i>Dismissed.</i>`, { parse_mode: "HTML", reply_markup: { inline_keyboard: [] } }).catch(() => {});
|
|
52678
52841
|
}
|
|
52842
|
+
process.stderr.write(`telegram gateway: eval_case_rejected agent=${agent} proposal=${proposal.id} ` + `slug=${proposal.skill_slug} delivered=${denied}
|
|
52843
|
+
`);
|
|
52679
52844
|
return;
|
|
52680
52845
|
}
|
|
52681
52846
|
setEvalCaseProposalStatus(stateDir, parsed.id, "approved");
|
|
52682
52847
|
await ctx.answerCallbackQuery({ text: "\u2705 Adding the eval case\u2026" }).catch(() => {});
|
|
52683
|
-
const
|
|
52684
|
-
let applyOk = true;
|
|
52685
|
-
let applyOut = "";
|
|
52686
|
-
try {
|
|
52687
|
-
applyOut = execFileSync3(cli, ["self-improve", "apply-eval-case", "--id", parsed.id], { encoding: "utf8", timeout: 15000, env: process.env }).trim();
|
|
52688
|
-
} catch (err) {
|
|
52689
|
-
applyOk = false;
|
|
52690
|
-
const e = err;
|
|
52691
|
-
applyOut = [e.stdout, e.stderr, e.message].filter(Boolean).join(`
|
|
52692
|
-
`).trim();
|
|
52693
|
-
}
|
|
52848
|
+
const { ok: applyOk, out: applyOut } = runEvalCaseApply(parsed.id);
|
|
52694
52849
|
const footer = applyOk ? "\u2705 <i>Added as a regression test.</i>" : `\u26a0\ufe0f <i>Apply failed:</i> ${escapeHtmlForTg2(applyOut.slice(0, 200))}`;
|
|
52695
52850
|
if (ctx.callbackQuery?.message && "text" in ctx.callbackQuery.message) {
|
|
52696
52851
|
await ctx.editMessageText(`${escapeHtmlForTg2(ctx.callbackQuery.message.text ?? "")}
|
|
52697
52852
|
|
|
52698
52853
|
${footer}`, { parse_mode: "HTML", reply_markup: { inline_keyboard: [] } }).catch(() => {});
|
|
52699
52854
|
}
|
|
52700
|
-
|
|
52855
|
+
const outcomeInbound = applyOk ? buildEvalCaseAppliedInbound({
|
|
52856
|
+
ctx: inboundCtx,
|
|
52857
|
+
proposalId: proposal.id,
|
|
52858
|
+
skillSlug: proposal.skill_slug,
|
|
52859
|
+
heldOut: proposal.held_out,
|
|
52860
|
+
operatorId: senderId
|
|
52861
|
+
}) : buildEvalCaseApplyFailedInbound({
|
|
52862
|
+
ctx: inboundCtx,
|
|
52863
|
+
proposalId: proposal.id,
|
|
52864
|
+
skillSlug: proposal.skill_slug,
|
|
52865
|
+
heldOut: proposal.held_out,
|
|
52866
|
+
operatorId: senderId,
|
|
52867
|
+
applyOut
|
|
52868
|
+
});
|
|
52869
|
+
const delivered = deliverResumeSyntheticOrBuffer(agent, outcomeInbound);
|
|
52870
|
+
process.stderr.write(`telegram gateway: eval_case_apply agent=${agent} proposal=${proposal.id} ` + `slug=${proposal.skill_slug} ok=${applyOk} delivered=${delivered}
|
|
52701
52871
|
`);
|
|
52702
52872
|
}
|
|
52703
52873
|
async function handleMentalModelProposeCallback(ctx, data) {
|
|
@@ -53421,7 +53591,7 @@ ${keyList}`,
|
|
|
53421
53591
|
const tokenPath = vaultTokenFilePath2(state.agent);
|
|
53422
53592
|
try {
|
|
53423
53593
|
mkdirSync15(dirname7(tokenPath), { recursive: true });
|
|
53424
|
-
|
|
53594
|
+
writeFileSync11(tokenPath, token, { mode: 384 });
|
|
53425
53595
|
} catch (err) {
|
|
53426
53596
|
await switchroomReply(ctx, `**Grant created but token write failed:** ${escapeHtmlForTg2(String(err))}`, { html: true });
|
|
53427
53597
|
return;
|
|
@@ -54480,7 +54650,7 @@ function hangStalenessMs(env = process.env) {
|
|
|
54480
54650
|
|
|
54481
54651
|
// gateway/missed-approvals-store.ts
|
|
54482
54652
|
init_state_owner();
|
|
54483
|
-
import { unlinkSync as
|
|
54653
|
+
import { unlinkSync as unlinkSync7 } from "node:fs";
|
|
54484
54654
|
import { join as join17 } from "node:path";
|
|
54485
54655
|
var MAX_PENDING = 50;
|
|
54486
54656
|
var MAX_DELIVERED = 20;
|
|
@@ -54565,7 +54735,7 @@ function createMissedApprovalsStore(stateDir, log = (l) => process.stderr.write(
|
|
|
54565
54735
|
},
|
|
54566
54736
|
clear() {
|
|
54567
54737
|
try {
|
|
54568
|
-
|
|
54738
|
+
unlinkSync7(filePath);
|
|
54569
54739
|
} catch {}
|
|
54570
54740
|
}
|
|
54571
54741
|
};
|
|
@@ -54573,7 +54743,7 @@ function createMissedApprovalsStore(stateDir, log = (l) => process.stderr.write(
|
|
|
54573
54743
|
|
|
54574
54744
|
// gateway/always-allow-persist-queue.ts
|
|
54575
54745
|
init_state_owner();
|
|
54576
|
-
import { unlinkSync as
|
|
54746
|
+
import { unlinkSync as unlinkSync8 } from "node:fs";
|
|
54577
54747
|
import { join as join18 } from "node:path";
|
|
54578
54748
|
var MAX_ATTEMPTS = 5;
|
|
54579
54749
|
var MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
@@ -54710,7 +54880,7 @@ function createAlwaysAllowPersistQueue(stateDir, writeFileSyncFn = atomicWriteSe
|
|
|
54710
54880
|
},
|
|
54711
54881
|
clear() {
|
|
54712
54882
|
try {
|
|
54713
|
-
|
|
54883
|
+
unlinkSync8(filePath);
|
|
54714
54884
|
} catch {}
|
|
54715
54885
|
}
|
|
54716
54886
|
};
|
|
@@ -54873,7 +55043,7 @@ function pickRecoveredPermissionOrigin(recentTurns, now, maxAgeMs) {
|
|
|
54873
55043
|
}
|
|
54874
55044
|
|
|
54875
55045
|
// gateway/approval-hold.ts
|
|
54876
|
-
import { mkdirSync as mkdirSync16, writeFileSync as
|
|
55046
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync13, readFileSync as readFileSync14, unlinkSync as unlinkSync9, chmodSync as chmodSync3, lstatSync as lstatSync2 } from "node:fs";
|
|
54877
55047
|
import { join as join19, dirname as dirname8 } from "node:path";
|
|
54878
55048
|
var BLOCKED_APPROVAL_FILE_MODE = 420;
|
|
54879
55049
|
var BLOCKED_APPROVAL_DIR_MODE = 1023;
|
|
@@ -54902,7 +55072,8 @@ var ACTION_SAFE_WITH_INPUT2 = new Set([
|
|
|
54902
55072
|
function safeActionForRecord(naturalAction2, toolName, inputPreview) {
|
|
54903
55073
|
return ACTION_SAFE_WITH_INPUT2.has(toolName) ? naturalAction2(toolName, inputPreview) : naturalAction2(toolName, undefined);
|
|
54904
55074
|
}
|
|
54905
|
-
function createBlockedApprovalStore(dir, agent, fallbackDir) {
|
|
55075
|
+
function createBlockedApprovalStore(dir, agent, fallbackDir, deps = {}) {
|
|
55076
|
+
const write_ = deps.writeFileSync ?? writeFileSync13;
|
|
54906
55077
|
const primary = join19(dir, `${agent}.json`);
|
|
54907
55078
|
const fallback = fallbackDir != null ? join19(fallbackDir, "blocked-approval.json") : null;
|
|
54908
55079
|
let active = primary;
|
|
@@ -54919,7 +55090,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
|
|
|
54919
55090
|
chmodSync3(parent, dirMode);
|
|
54920
55091
|
} catch {}
|
|
54921
55092
|
}
|
|
54922
|
-
|
|
55093
|
+
write_(target, body, { encoding: "utf-8", mode: BLOCKED_APPROVAL_FILE_MODE });
|
|
54923
55094
|
chmodSync3(target, BLOCKED_APPROVAL_FILE_MODE);
|
|
54924
55095
|
return true;
|
|
54925
55096
|
} catch {
|
|
@@ -54937,7 +55108,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
|
|
|
54937
55108
|
active = primary;
|
|
54938
55109
|
if (fallback != null) {
|
|
54939
55110
|
try {
|
|
54940
|
-
|
|
55111
|
+
unlinkSync9(fallback);
|
|
54941
55112
|
} catch {}
|
|
54942
55113
|
}
|
|
54943
55114
|
return;
|
|
@@ -54956,7 +55127,7 @@ function createBlockedApprovalStore(dir, agent, fallbackDir) {
|
|
|
54956
55127
|
if (p == null)
|
|
54957
55128
|
continue;
|
|
54958
55129
|
try {
|
|
54959
|
-
|
|
55130
|
+
unlinkSync9(p);
|
|
54960
55131
|
} catch {}
|
|
54961
55132
|
}
|
|
54962
55133
|
active = primary;
|
|
@@ -67336,11 +67507,11 @@ init_flood_429_ledger();
|
|
|
67336
67507
|
import {
|
|
67337
67508
|
existsSync as existsSync15,
|
|
67338
67509
|
readFileSync as readFileSync17,
|
|
67339
|
-
writeFileSync as
|
|
67510
|
+
writeFileSync as writeFileSync16,
|
|
67340
67511
|
mkdirSync as mkdirSync19,
|
|
67341
67512
|
chmodSync as chmodSync6,
|
|
67342
|
-
unlinkSync as
|
|
67343
|
-
renameSync as
|
|
67513
|
+
unlinkSync as unlinkSync12,
|
|
67514
|
+
renameSync as renameSync12
|
|
67344
67515
|
} from "node:fs";
|
|
67345
67516
|
import { dirname as dirname11, join as join22 } from "node:path";
|
|
67346
67517
|
var FLOOD_STATE_FILE2 = "flood-wait.json";
|
|
@@ -67398,7 +67569,7 @@ function writeFloodState2(path2, state, log = (l) => process.stderr.write(l)) {
|
|
|
67398
67569
|
mkdirSync19(dirname11(path2), { recursive: true });
|
|
67399
67570
|
} catch {}
|
|
67400
67571
|
try {
|
|
67401
|
-
|
|
67572
|
+
writeFileSync16(path2, payload, { mode: FLOOD_STATE_MODE2 });
|
|
67402
67573
|
try {
|
|
67403
67574
|
chmodSync6(path2, FLOOD_STATE_MODE2);
|
|
67404
67575
|
} catch {}
|
|
@@ -67411,8 +67582,8 @@ function writeFloodState2(path2, state, log = (l) => process.stderr.write(l)) {
|
|
|
67411
67582
|
return;
|
|
67412
67583
|
}
|
|
67413
67584
|
try {
|
|
67414
|
-
|
|
67415
|
-
|
|
67585
|
+
unlinkSync12(path2);
|
|
67586
|
+
writeFileSync16(path2, payload, { mode: FLOOD_STATE_MODE2 });
|
|
67416
67587
|
log(`telegram gateway: flood-breaker: recreated ${path2} \u2014 it was owned by another uid ` + `and could not be updated (${code2}); the breaker was blind (issue #3106)
|
|
67417
67588
|
`);
|
|
67418
67589
|
} catch (err2) {
|
|
@@ -67546,8 +67717,8 @@ function writeFloodWindow(path2, record, now) {
|
|
|
67546
67717
|
}
|
|
67547
67718
|
const arr = [...byScope.values()];
|
|
67548
67719
|
const tmp = `${path2}.tmp-${process.pid}`;
|
|
67549
|
-
|
|
67550
|
-
|
|
67720
|
+
writeFileSync16(tmp, JSON.stringify(arr), { mode: FLOOD_STATE_MODE2 });
|
|
67721
|
+
renameSync12(tmp, path2);
|
|
67551
67722
|
try {
|
|
67552
67723
|
chmodSync6(path2, FLOOD_STATE_MODE2);
|
|
67553
67724
|
} catch {}
|
|
@@ -72144,7 +72315,7 @@ class PostHog extends PostHogBackendClient {
|
|
|
72144
72315
|
}
|
|
72145
72316
|
|
|
72146
72317
|
// analytics-posthog.ts
|
|
72147
|
-
import { existsSync as existsSync16, mkdirSync as mkdirSync20, readFileSync as readFileSync18, writeFileSync as
|
|
72318
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync20, readFileSync as readFileSync18, writeFileSync as writeFileSync17 } from "node:fs";
|
|
72148
72319
|
import { dirname as dirname13, join as join24 } from "node:path";
|
|
72149
72320
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
72150
72321
|
var DEFAULT_KEY = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
|
|
@@ -72185,7 +72356,7 @@ function getDistinctId() {
|
|
|
72185
72356
|
cachedDistinctId = id;
|
|
72186
72357
|
try {
|
|
72187
72358
|
mkdirSync20(dirname13(fallbackPath), { recursive: true });
|
|
72188
|
-
|
|
72359
|
+
writeFileSync17(fallbackPath, id, "utf-8");
|
|
72189
72360
|
} catch {}
|
|
72190
72361
|
return id;
|
|
72191
72362
|
}
|
|
@@ -72260,7 +72431,7 @@ import { mkdirSync as mkdirSync22, appendFileSync as appendFileSync4 } from "nod
|
|
|
72260
72431
|
import { dirname as dirname15, join as join26 } from "node:path";
|
|
72261
72432
|
|
|
72262
72433
|
// analytics-posthog.ts
|
|
72263
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync21, readFileSync as readFileSync19, writeFileSync as
|
|
72434
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync21, readFileSync as readFileSync19, writeFileSync as writeFileSync18 } from "node:fs";
|
|
72264
72435
|
import { dirname as dirname14, join as join25 } from "node:path";
|
|
72265
72436
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
72266
72437
|
var DEFAULT_KEY2 = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
|
|
@@ -72300,7 +72471,7 @@ function getDistinctId2() {
|
|
|
72300
72471
|
cachedDistinctId2 = id;
|
|
72301
72472
|
try {
|
|
72302
72473
|
mkdirSync21(dirname14(fallbackPath), { recursive: true });
|
|
72303
|
-
|
|
72474
|
+
writeFileSync18(fallbackPath, id, "utf-8");
|
|
72304
72475
|
} catch {}
|
|
72305
72476
|
return id;
|
|
72306
72477
|
}
|
|
@@ -73036,7 +73207,7 @@ function __resetAllForTests3() {
|
|
|
73036
73207
|
}
|
|
73037
73208
|
|
|
73038
73209
|
// silent-end.ts
|
|
73039
|
-
import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as
|
|
73210
|
+
import { existsSync as existsSync19, readFileSync as readFileSync20, writeFileSync as writeFileSync19, unlinkSync as unlinkSync13, mkdirSync as mkdirSync23 } from "node:fs";
|
|
73040
73211
|
import { dirname as dirname16, join as join27 } from "node:path";
|
|
73041
73212
|
import { homedir as homedir5 } from "node:os";
|
|
73042
73213
|
var SILENT_END_MAX_RETRIES = 2;
|
|
@@ -73081,7 +73252,7 @@ function writeSilentEndState(args, deps) {
|
|
|
73081
73252
|
};
|
|
73082
73253
|
try {
|
|
73083
73254
|
mkdirSync23(dirname16(statePath), { recursive: true });
|
|
73084
|
-
|
|
73255
|
+
writeFileSync19(statePath, JSON.stringify(state3), "utf8");
|
|
73085
73256
|
emitLog(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
|
|
73086
73257
|
`);
|
|
73087
73258
|
} catch (err) {
|
|
@@ -73097,7 +73268,7 @@ function clearSilentEndState(turnKey3, deps) {
|
|
|
73097
73268
|
const prev = JSON.parse(readFileSync20(statePath, "utf8"));
|
|
73098
73269
|
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
73099
73270
|
return;
|
|
73100
|
-
|
|
73271
|
+
unlinkSync13(statePath);
|
|
73101
73272
|
emitLog(deps, `silent-end: cleared state file turnKey=${turnKey3}
|
|
73102
73273
|
`);
|
|
73103
73274
|
} catch {}
|
|
@@ -74028,7 +74199,7 @@ async function gatewayStartupRetry(fn, opts = {}) {
|
|
|
74028
74199
|
}
|
|
74029
74200
|
|
|
74030
74201
|
// gateway/quarantine.ts
|
|
74031
|
-
import { mkdirSync as mkdirSync24, writeFileSync as
|
|
74202
|
+
import { mkdirSync as mkdirSync24, writeFileSync as writeFileSync20 } from "node:fs";
|
|
74032
74203
|
import { join as join30 } from "node:path";
|
|
74033
74204
|
var QUARANTINE_FILENAME = "quarantine.json";
|
|
74034
74205
|
function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.now) {
|
|
@@ -74039,7 +74210,7 @@ function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.no
|
|
|
74039
74210
|
ts: nowFn(),
|
|
74040
74211
|
detail
|
|
74041
74212
|
};
|
|
74042
|
-
|
|
74213
|
+
writeFileSync20(join30(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
|
|
74043
74214
|
`, "utf-8");
|
|
74044
74215
|
}
|
|
74045
74216
|
|
|
@@ -75512,7 +75683,7 @@ async function materializeSidecarToken2(opts = {}, logger2 = (line) => process.s
|
|
|
75512
75683
|
}
|
|
75513
75684
|
|
|
75514
75685
|
// ../src/setup/host-capabilities.ts
|
|
75515
|
-
import { mkdirSync as mkdirSync25, readFileSync as readFileSync22, writeFileSync as
|
|
75686
|
+
import { mkdirSync as mkdirSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "node:fs";
|
|
75516
75687
|
init_paths();
|
|
75517
75688
|
function hostCapabilitiesPath() {
|
|
75518
75689
|
return resolveStatePath("host-capabilities.json");
|
|
@@ -75676,7 +75847,7 @@ function resolveExhaustUntil(resetAtMs, now = Date.now()) {
|
|
|
75676
75847
|
|
|
75677
75848
|
// gateway/auth-add-flow.ts
|
|
75678
75849
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
75679
|
-
import { existsSync as existsSync24, mkdirSync as mkdirSync27, readFileSync as readFileSync24, readdirSync as readdirSync7, rmSync as rmSync6, statSync as statSync10, writeFileSync as
|
|
75850
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync27, readFileSync as readFileSync24, readdirSync as readdirSync7, rmSync as rmSync6, statSync as statSync10, writeFileSync as writeFileSync23 } from "node:fs";
|
|
75680
75851
|
import { homedir as homedir8 } from "node:os";
|
|
75681
75852
|
import { join as join32 } from "node:path";
|
|
75682
75853
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
@@ -75686,7 +75857,7 @@ import {
|
|
|
75686
75857
|
readFileSync as readFileSync23,
|
|
75687
75858
|
readdirSync as readdirSync6,
|
|
75688
75859
|
existsSync as existsSync23,
|
|
75689
|
-
writeFileSync as
|
|
75860
|
+
writeFileSync as writeFileSync22,
|
|
75690
75861
|
mkdirSync as mkdirSync26,
|
|
75691
75862
|
mkdtempSync as mkdtempSync2,
|
|
75692
75863
|
rmSync as rmSync5,
|
|
@@ -75847,7 +76018,7 @@ async function startAccountAuthSession(label, opts = {}) {
|
|
|
75847
76018
|
const tmuxSocket = `switchroom-${agentName3}`;
|
|
75848
76019
|
const tmuxSession = `auth-add-${label}-${hexSuffix}`.slice(0, 64);
|
|
75849
76020
|
try {
|
|
75850
|
-
|
|
76021
|
+
writeFileSync23(join32(scratchDir, AUTH_TMUX_SESSION_FILE), `${tmuxSocket}
|
|
75851
76022
|
${tmuxSession}`, "utf8");
|
|
75852
76023
|
} catch {}
|
|
75853
76024
|
const sessionEnv = {
|
|
@@ -78836,7 +79007,7 @@ function startRestartWatchdog(config) {
|
|
|
78836
79007
|
}
|
|
78837
79008
|
|
|
78838
79009
|
// gateway/access-store.ts
|
|
78839
|
-
import { mkdirSync as mkdirSync28, readFileSync as readFileSync25, renameSync as
|
|
79010
|
+
import { mkdirSync as mkdirSync28, readFileSync as readFileSync25, renameSync as renameSync13, writeFileSync as writeFileSync24 } from "node:fs";
|
|
78840
79011
|
|
|
78841
79012
|
// gateway/access-validator.ts
|
|
78842
79013
|
function validateStringArray(field, value, tag = "gateway") {
|
|
@@ -78900,7 +79071,7 @@ function createAccessStore(deps) {
|
|
|
78900
79071
|
if (err.code === "ENOENT")
|
|
78901
79072
|
return defaultAccess();
|
|
78902
79073
|
try {
|
|
78903
|
-
|
|
79074
|
+
renameSync13(accessFile, `${accessFile}.corrupt-${Date.now()}`);
|
|
78904
79075
|
} catch {}
|
|
78905
79076
|
process.stderr.write(`telegram gateway: access.json is corrupt, moved aside. Starting fresh.
|
|
78906
79077
|
`);
|
|
@@ -78945,9 +79116,9 @@ function createAccessStore(deps) {
|
|
|
78945
79116
|
return;
|
|
78946
79117
|
mkdirSync28(stateDir, { recursive: true, mode: 448 });
|
|
78947
79118
|
const tmp = accessFile + ".tmp";
|
|
78948
|
-
|
|
79119
|
+
writeFileSync24(tmp, JSON.stringify(a, null, 2) + `
|
|
78949
79120
|
`, { mode: 384 });
|
|
78950
|
-
|
|
79121
|
+
renameSync13(tmp, accessFile);
|
|
78951
79122
|
}
|
|
78952
79123
|
function pruneExpired(a) {
|
|
78953
79124
|
const now = Date.now();
|
|
@@ -79784,10 +79955,10 @@ import {
|
|
|
79784
79955
|
mkdirSync as mkdirSync29,
|
|
79785
79956
|
readFileSync as readFileSync26,
|
|
79786
79957
|
readdirSync as readdirSync8,
|
|
79787
|
-
renameSync as
|
|
79958
|
+
renameSync as renameSync14,
|
|
79788
79959
|
statSync as statSync11,
|
|
79789
|
-
unlinkSync as
|
|
79790
|
-
writeFileSync as
|
|
79960
|
+
unlinkSync as unlinkSync14,
|
|
79961
|
+
writeFileSync as writeFileSync25,
|
|
79791
79962
|
appendFileSync as appendFileSync5
|
|
79792
79963
|
} from "node:fs";
|
|
79793
79964
|
import { join as join34 } from "node:path";
|
|
@@ -79891,8 +80062,8 @@ function writeOutboxRecordAtomic(record, stateDir) {
|
|
|
79891
80062
|
if (existsSync26(finalPath))
|
|
79892
80063
|
return true;
|
|
79893
80064
|
const tmpPath = join34(dir, `.${record.turnNonce}.${process.pid}.tmp`);
|
|
79894
|
-
|
|
79895
|
-
|
|
80065
|
+
writeFileSync25(tmpPath, JSON.stringify(record), { mode: 384 });
|
|
80066
|
+
renameSync14(tmpPath, finalPath);
|
|
79896
80067
|
return true;
|
|
79897
80068
|
} catch {
|
|
79898
80069
|
return false;
|
|
@@ -79919,7 +80090,7 @@ function claimRecord(nonce, stateDir) {
|
|
|
79919
80090
|
const from = join34(dir, `${nonce}.json`);
|
|
79920
80091
|
const to = join34(dir, `${nonce}.sending`);
|
|
79921
80092
|
try {
|
|
79922
|
-
|
|
80093
|
+
renameSync14(from, to);
|
|
79923
80094
|
return to;
|
|
79924
80095
|
} catch {
|
|
79925
80096
|
return null;
|
|
@@ -79928,12 +80099,12 @@ function claimRecord(nonce, stateDir) {
|
|
|
79928
80099
|
function releaseClaim(nonce, stateDir) {
|
|
79929
80100
|
const dir = resolveOutboxDir(stateDir);
|
|
79930
80101
|
try {
|
|
79931
|
-
|
|
80102
|
+
renameSync14(join34(dir, `${nonce}.sending`), join34(dir, `${nonce}.json`));
|
|
79932
80103
|
} catch {}
|
|
79933
80104
|
}
|
|
79934
80105
|
function removeClaimed(nonce, stateDir) {
|
|
79935
80106
|
try {
|
|
79936
|
-
|
|
80107
|
+
unlinkSync14(join34(resolveOutboxDir(stateDir), `${nonce}.sending`));
|
|
79937
80108
|
} catch {}
|
|
79938
80109
|
}
|
|
79939
80110
|
function reclaimStaleSending(stateDir, now = Date.now()) {
|
|
@@ -79948,7 +80119,7 @@ function reclaimStaleSending(stateDir, now = Date.now()) {
|
|
|
79948
80119
|
try {
|
|
79949
80120
|
const st = statSync11(join34(dir, f));
|
|
79950
80121
|
if (now - st.mtimeMs > OUTBOX_SENDING_TIMEOUT_MS) {
|
|
79951
|
-
|
|
80122
|
+
renameSync14(join34(dir, f), join34(dir, f.replace(/\.sending$/, ".json")));
|
|
79952
80123
|
}
|
|
79953
80124
|
} catch {}
|
|
79954
80125
|
}
|
|
@@ -80019,17 +80190,17 @@ function compactJournalIfLarge(path2) {
|
|
|
80019
80190
|
return;
|
|
80020
80191
|
const kept = lines.slice(lines.length - JOURNAL_KEEP);
|
|
80021
80192
|
const tmp = `${path2}.${process.pid}.compact`;
|
|
80022
|
-
|
|
80193
|
+
writeFileSync25(tmp, kept.join(`
|
|
80023
80194
|
`) + `
|
|
80024
80195
|
`, { mode: 384 });
|
|
80025
|
-
|
|
80196
|
+
renameSync14(tmp, path2);
|
|
80026
80197
|
} catch {}
|
|
80027
80198
|
}
|
|
80028
80199
|
function clearOutboxRecord(nonce, stateDir) {
|
|
80029
80200
|
const dir = resolveOutboxDir(stateDir);
|
|
80030
80201
|
for (const suffix of [".json", ".sending"]) {
|
|
80031
80202
|
try {
|
|
80032
|
-
|
|
80203
|
+
unlinkSync14(join34(dir, `${nonce}${suffix}`));
|
|
80033
80204
|
} catch {}
|
|
80034
80205
|
}
|
|
80035
80206
|
}
|
|
@@ -80097,8 +80268,8 @@ import {
|
|
|
80097
80268
|
existsSync as existsSync27,
|
|
80098
80269
|
mkdirSync as mkdirSync30,
|
|
80099
80270
|
readFileSync as readFileSync27,
|
|
80100
|
-
renameSync as
|
|
80101
|
-
writeFileSync as
|
|
80271
|
+
renameSync as renameSync15,
|
|
80272
|
+
writeFileSync as writeFileSync26,
|
|
80102
80273
|
appendFileSync as appendFileSync6
|
|
80103
80274
|
} from "node:fs";
|
|
80104
80275
|
import { join as join35 } from "node:path";
|
|
@@ -80227,10 +80398,10 @@ function compactIfLarge(path2) {
|
|
|
80227
80398
|
return;
|
|
80228
80399
|
const kept = lines.slice(lines.length - SHOWN_LEDGER_KEEP);
|
|
80229
80400
|
const tmp = `${path2}.${process.pid}.compact`;
|
|
80230
|
-
|
|
80401
|
+
writeFileSync26(tmp, kept.join(`
|
|
80231
80402
|
`) + `
|
|
80232
80403
|
`, { mode: 384 });
|
|
80233
|
-
|
|
80404
|
+
renameSync15(tmp, path2);
|
|
80234
80405
|
} catch {}
|
|
80235
80406
|
}
|
|
80236
80407
|
|
|
@@ -80750,6 +80921,10 @@ var INBOUND_SOURCE_CLASSIFICATION = {
|
|
|
80750
80921
|
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
80751
80922
|
webhook: { decoupledCompletion: false },
|
|
80752
80923
|
linear: { decoupledCompletion: false },
|
|
80924
|
+
eval_case_applied: { decoupledCompletion: false },
|
|
80925
|
+
eval_case_rejected: { decoupledCompletion: false },
|
|
80926
|
+
eval_case_apply_failed: { decoupledCompletion: false },
|
|
80927
|
+
eval_case_suppressed: { decoupledCompletion: false },
|
|
80753
80928
|
buzz: { decoupledCompletion: false },
|
|
80754
80929
|
boot_briefing: { decoupledCompletion: false }
|
|
80755
80930
|
};
|
|
@@ -80988,7 +81163,7 @@ function monotonicNowMs2() {
|
|
|
80988
81163
|
}
|
|
80989
81164
|
|
|
80990
81165
|
// silent-end.ts
|
|
80991
|
-
import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as
|
|
81166
|
+
import { existsSync as existsSync28, readFileSync as readFileSync28, writeFileSync as writeFileSync27, unlinkSync as unlinkSync15, mkdirSync as mkdirSync31 } from "node:fs";
|
|
80992
81167
|
import { dirname as dirname17, join as join36 } from "node:path";
|
|
80993
81168
|
import { homedir as homedir10 } from "node:os";
|
|
80994
81169
|
var SILENT_END_MAX_RETRIES2 = 2;
|
|
@@ -81037,7 +81212,7 @@ function writeSilentEndState2(args, deps) {
|
|
|
81037
81212
|
};
|
|
81038
81213
|
try {
|
|
81039
81214
|
mkdirSync31(dirname17(statePath), { recursive: true });
|
|
81040
|
-
|
|
81215
|
+
writeFileSync27(statePath, JSON.stringify(state3), "utf8");
|
|
81041
81216
|
emitLog2(deps, `silent-end: wrote state file turnKey=${args.turnKey} retryCount=${retryCount}
|
|
81042
81217
|
`);
|
|
81043
81218
|
} catch (err) {
|
|
@@ -81053,7 +81228,7 @@ function clearSilentEndState2(turnKey3, deps) {
|
|
|
81053
81228
|
const prev = JSON.parse(readFileSync28(statePath, "utf8"));
|
|
81054
81229
|
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
81055
81230
|
return;
|
|
81056
|
-
|
|
81231
|
+
unlinkSync15(statePath);
|
|
81057
81232
|
emitLog2(deps, `silent-end: cleared state file turnKey=${turnKey3}
|
|
81058
81233
|
`);
|
|
81059
81234
|
} catch {}
|
|
@@ -83416,7 +83591,7 @@ import {
|
|
|
83416
83591
|
openSync as openSync10,
|
|
83417
83592
|
readFileSync as readFileSync29,
|
|
83418
83593
|
statSync as statSync13,
|
|
83419
|
-
unlinkSync as
|
|
83594
|
+
unlinkSync as unlinkSync16,
|
|
83420
83595
|
utimesSync
|
|
83421
83596
|
} from "node:fs";
|
|
83422
83597
|
import { join as join39 } from "node:path";
|
|
@@ -83445,7 +83620,7 @@ function touchTurnActiveMarker(stateDir) {
|
|
|
83445
83620
|
}
|
|
83446
83621
|
function removeTurnActiveMarker(stateDir) {
|
|
83447
83622
|
try {
|
|
83448
|
-
|
|
83623
|
+
unlinkSync16(join39(stateDir, TURN_ACTIVE_MARKER_FILE));
|
|
83449
83624
|
} catch {}
|
|
83450
83625
|
}
|
|
83451
83626
|
function readTurnActiveMarkerAgeMs(stateDir, now) {
|
|
@@ -85770,7 +85945,7 @@ function resolveAgentDirFromEnv() {
|
|
|
85770
85945
|
}
|
|
85771
85946
|
|
|
85772
85947
|
// active-reactions.ts
|
|
85773
|
-
import { readFileSync as readFileSync30, writeFileSync as
|
|
85948
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync28, renameSync as renameSync16, existsSync as existsSync32, unlinkSync as unlinkSync17 } from "node:fs";
|
|
85774
85949
|
import { join as join40 } from "node:path";
|
|
85775
85950
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
85776
85951
|
function reactionsPath(agentDir) {
|
|
@@ -85808,15 +85983,15 @@ function writeActiveReactions(agentDir, reactions) {
|
|
|
85808
85983
|
const p = reactionsPath(agentDir);
|
|
85809
85984
|
if (reactions.length === 0) {
|
|
85810
85985
|
try {
|
|
85811
|
-
|
|
85986
|
+
unlinkSync17(p);
|
|
85812
85987
|
} catch {}
|
|
85813
85988
|
return;
|
|
85814
85989
|
}
|
|
85815
85990
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
85816
85991
|
try {
|
|
85817
|
-
|
|
85992
|
+
writeFileSync28(tmp, JSON.stringify(reactions) + `
|
|
85818
85993
|
`, "utf-8");
|
|
85819
|
-
|
|
85994
|
+
renameSync16(tmp, p);
|
|
85820
85995
|
} catch {}
|
|
85821
85996
|
}
|
|
85822
85997
|
function addActiveReaction(agentDir, reaction) {
|
|
@@ -85833,12 +86008,12 @@ function removeActiveReaction(agentDir, chatId, messageId) {
|
|
|
85833
86008
|
}
|
|
85834
86009
|
function clearActiveReactions(agentDir) {
|
|
85835
86010
|
try {
|
|
85836
|
-
|
|
86011
|
+
unlinkSync17(reactionsPath(agentDir));
|
|
85837
86012
|
} catch {}
|
|
85838
86013
|
}
|
|
85839
86014
|
|
|
85840
86015
|
// active-reactions.ts
|
|
85841
|
-
import { readFileSync as readFileSync31, writeFileSync as
|
|
86016
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync29, renameSync as renameSync17, existsSync as existsSync33, unlinkSync as unlinkSync18 } from "node:fs";
|
|
85842
86017
|
import { join as join41 } from "node:path";
|
|
85843
86018
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
85844
86019
|
function reactionsPath2(agentDir) {
|
|
@@ -85874,7 +86049,7 @@ function readActiveReactions2(agentDir) {
|
|
|
85874
86049
|
}
|
|
85875
86050
|
function clearActiveReactions2(agentDir) {
|
|
85876
86051
|
try {
|
|
85877
|
-
|
|
86052
|
+
unlinkSync18(reactionsPath2(agentDir));
|
|
85878
86053
|
} catch {}
|
|
85879
86054
|
}
|
|
85880
86055
|
|
|
@@ -88116,15 +88291,15 @@ async function menuWithBannerStatic(deps, banner) {
|
|
|
88116
88291
|
}
|
|
88117
88292
|
|
|
88118
88293
|
// gateway/session-model-file.ts
|
|
88119
|
-
import { readFileSync as readFileSync33, writeFileSync as
|
|
88294
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync30, renameSync as renameSync18, rmSync as rmSync7 } from "node:fs";
|
|
88120
88295
|
import { join as join43 } from "node:path";
|
|
88121
88296
|
var SESSION_MODEL_FILE = ".session-model";
|
|
88122
88297
|
var CONFIGURED_DEFAULT_MODEL_FILE = ".configured-default-model";
|
|
88123
88298
|
var SESSION_MODEL_BOOT_ATTEMPTS_FILE = ".session-model-boot-attempts";
|
|
88124
88299
|
function atomicWrite(path2, content3) {
|
|
88125
88300
|
const tmp = `${path2}.tmp-${process.pid}-${Date.now()}`;
|
|
88126
|
-
|
|
88127
|
-
|
|
88301
|
+
writeFileSync30(tmp, content3, "utf8");
|
|
88302
|
+
renameSync18(tmp, path2);
|
|
88128
88303
|
}
|
|
88129
88304
|
function serializeSessionModel(rec) {
|
|
88130
88305
|
return `${JSON.stringify({
|
|
@@ -88652,7 +88827,7 @@ var AUDIT_ROOT = join45(homedir11(), ".switchroom", "audit");
|
|
|
88652
88827
|
|
|
88653
88828
|
// ../src/agents/profiles.ts
|
|
88654
88829
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
88655
|
-
import { readFileSync as readFileSync36, writeFileSync as
|
|
88830
|
+
import { readFileSync as readFileSync36, writeFileSync as writeFileSync32, existsSync as existsSync37, readdirSync as readdirSync9, statSync as statSync14, copyFileSync, mkdirSync as mkdirSync33, realpathSync as realpathSync4 } from "node:fs";
|
|
88656
88831
|
import { resolve as resolve8, join as join46, sep as pathSep } from "node:path";
|
|
88657
88832
|
function resolveProfilesRootDetailed() {
|
|
88658
88833
|
return resolveShippedAsset(PROFILES_ASSET, {
|
|
@@ -88670,7 +88845,7 @@ import_handlebars.default.registerHelper("isNumber", (value) => {
|
|
|
88670
88845
|
return typeof value === "number" && Number.isFinite(value);
|
|
88671
88846
|
});
|
|
88672
88847
|
var SHARED_FRAGMENTS_DIR = resolve8(PROFILES_ROOT, "_shared");
|
|
88673
|
-
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
|
|
88848
|
+
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol", "local-time"];
|
|
88674
88849
|
for (const name of SHARED_FRAGMENTS) {
|
|
88675
88850
|
const fragPath = join46(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
88676
88851
|
if (existsSync37(fragPath)) {
|
|
@@ -90623,7 +90798,7 @@ function numField(obj, key) {
|
|
|
90623
90798
|
}
|
|
90624
90799
|
|
|
90625
90800
|
// gateway/context-occupancy.ts
|
|
90626
|
-
import { mkdirSync as mkdirSync34, writeFileSync as
|
|
90801
|
+
import { mkdirSync as mkdirSync34, writeFileSync as writeFileSync33 } from "node:fs";
|
|
90627
90802
|
import { join as join47 } from "node:path";
|
|
90628
90803
|
var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
|
|
90629
90804
|
var TIGHT_FRACTION = 0.8;
|
|
@@ -90649,7 +90824,7 @@ function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
|
|
|
90649
90824
|
try {
|
|
90650
90825
|
const path2 = join47(stateDir, CONTEXT_OCCUPANCY_FILENAME);
|
|
90651
90826
|
(deps?.mkdir ?? ((p, o) => mkdirSync34(p, o)))(stateDir, { recursive: true });
|
|
90652
|
-
(deps?.writeFile ?? ((p, d) =>
|
|
90827
|
+
(deps?.writeFile ?? ((p, d) => writeFileSync33(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
|
|
90653
90828
|
`);
|
|
90654
90829
|
} catch {}
|
|
90655
90830
|
}
|
|
@@ -92031,7 +92206,7 @@ import {
|
|
|
92031
92206
|
openSync as openSync11,
|
|
92032
92207
|
readdirSync as readdirSync10,
|
|
92033
92208
|
statSync as statSync15,
|
|
92034
|
-
writeFileSync as
|
|
92209
|
+
writeFileSync as writeFileSync34
|
|
92035
92210
|
} from "node:fs";
|
|
92036
92211
|
import { dirname as dirname21, join as join51, relative as relative2, sep as sep5 } from "node:path";
|
|
92037
92212
|
var NOFOLLOW2 = constants5.O_NOFOLLOW ?? 0;
|
|
@@ -92114,7 +92289,7 @@ function mkdirStateSync2(path2, options = { recursive: true }, log = defaultLog3
|
|
|
92114
92289
|
function writeStateFileSync2(path2, data, options, log = defaultLog3) {
|
|
92115
92290
|
const owner = resolveStateOwner2(dirname21(path2));
|
|
92116
92291
|
if (!owner) {
|
|
92117
|
-
|
|
92292
|
+
writeFileSync34(path2, data, options);
|
|
92118
92293
|
return;
|
|
92119
92294
|
}
|
|
92120
92295
|
const mode = options?.mode ?? 438;
|
|
@@ -92122,7 +92297,7 @@ function writeStateFileSync2(path2, data, options, log = defaultLog3) {
|
|
|
92122
92297
|
let fd = null;
|
|
92123
92298
|
try {
|
|
92124
92299
|
fd = openSync11(path2, constants5.O_WRONLY | constants5.O_CREAT | constants5.O_TRUNC | NOFOLLOW2, mode);
|
|
92125
|
-
|
|
92300
|
+
writeFileSync34(fd, buf);
|
|
92126
92301
|
try {
|
|
92127
92302
|
fchownSync4(fd, owner.uid, owner.gid);
|
|
92128
92303
|
} catch (err) {
|
|
@@ -92136,7 +92311,7 @@ function writeStateFileSync2(path2, data, options, log = defaultLog3) {
|
|
|
92136
92311
|
fd = null;
|
|
92137
92312
|
}
|
|
92138
92313
|
noteFailure2("write", path2, err, log);
|
|
92139
|
-
|
|
92314
|
+
writeFileSync34(path2, data, options);
|
|
92140
92315
|
return;
|
|
92141
92316
|
} finally {
|
|
92142
92317
|
if (fd !== null) {
|
|
@@ -92261,7 +92436,7 @@ function adoptAndReport(path2, owner, log) {
|
|
|
92261
92436
|
|
|
92262
92437
|
// gateway/webhook-ingest-server.ts
|
|
92263
92438
|
import net4 from "node:net";
|
|
92264
|
-
import { chmodSync as chmodSync10, existsSync as existsSync43, unlinkSync as
|
|
92439
|
+
import { chmodSync as chmodSync10, existsSync as existsSync43, unlinkSync as unlinkSync19 } from "node:fs";
|
|
92265
92440
|
var MAX_REQUEST_BYTES = 1024 * 1024;
|
|
92266
92441
|
function fdOf(conn) {
|
|
92267
92442
|
const handle = conn._handle;
|
|
@@ -92274,7 +92449,7 @@ function startWebhookIngestServer(opts) {
|
|
|
92274
92449
|
const allowed = new Set(opts.allowedUids);
|
|
92275
92450
|
try {
|
|
92276
92451
|
if (existsSync43(opts.socketPath))
|
|
92277
|
-
|
|
92452
|
+
unlinkSync19(opts.socketPath);
|
|
92278
92453
|
} catch (err) {
|
|
92279
92454
|
log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
|
|
92280
92455
|
`);
|
|
@@ -92367,7 +92542,7 @@ function startWebhookIngestServer(opts) {
|
|
|
92367
92542
|
} catch {}
|
|
92368
92543
|
try {
|
|
92369
92544
|
if (existsSync43(opts.socketPath))
|
|
92370
|
-
|
|
92545
|
+
unlinkSync19(opts.socketPath);
|
|
92371
92546
|
} catch {}
|
|
92372
92547
|
}
|
|
92373
92548
|
};
|
|
@@ -92379,7 +92554,7 @@ import { join as join55 } from "path";
|
|
|
92379
92554
|
import { homedir as homedir16 } from "os";
|
|
92380
92555
|
|
|
92381
92556
|
// ../src/web/webhook-handler.ts
|
|
92382
|
-
import { appendFileSync as appendFileSync9, existsSync as existsSync45, mkdirSync as mkdirSync38, readFileSync as readFileSync41, writeFileSync as
|
|
92557
|
+
import { appendFileSync as appendFileSync9, existsSync as existsSync45, mkdirSync as mkdirSync38, readFileSync as readFileSync41, writeFileSync as writeFileSync35 } from "fs";
|
|
92383
92558
|
import { join as join53 } from "path";
|
|
92384
92559
|
|
|
92385
92560
|
// ../src/util/log-rotation.ts
|
|
@@ -92734,7 +92909,7 @@ function saveDedupFile(path3, deliveries, now) {
|
|
|
92734
92909
|
}
|
|
92735
92910
|
const sorted = Object.entries(pruned).sort((a, b) => b[1] - a[1]).slice(0, DEDUP_MAX);
|
|
92736
92911
|
const final = Object.fromEntries(sorted);
|
|
92737
|
-
|
|
92912
|
+
writeFileSync35(path3, JSON.stringify({ deliveries: final }), {
|
|
92738
92913
|
mode: 384
|
|
92739
92914
|
});
|
|
92740
92915
|
}
|
|
@@ -92764,7 +92939,7 @@ var tokenBuckets = new Map;
|
|
|
92764
92939
|
var throttleIssueWindow = new Map;
|
|
92765
92940
|
|
|
92766
92941
|
// ../src/web/webhook-dispatch.ts
|
|
92767
|
-
import { existsSync as existsSync46, mkdirSync as mkdirSync39, readFileSync as readFileSync42, writeFileSync as
|
|
92942
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync39, readFileSync as readFileSync42, writeFileSync as writeFileSync36 } from "fs";
|
|
92768
92943
|
import { join as join54 } from "path";
|
|
92769
92944
|
import { homedir as homedir15 } from "os";
|
|
92770
92945
|
|
|
@@ -93074,7 +93249,7 @@ function loadCooldownFile(path3) {
|
|
|
93074
93249
|
}
|
|
93075
93250
|
function saveCooldownFile(path3, dispatches) {
|
|
93076
93251
|
try {
|
|
93077
|
-
|
|
93252
|
+
writeFileSync36(path3, JSON.stringify({ dispatches }), {
|
|
93078
93253
|
mode: 384
|
|
93079
93254
|
});
|
|
93080
93255
|
} catch {}
|
|
@@ -93420,7 +93595,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
93420
93595
|
|
|
93421
93596
|
// gateway/ipc-server.ts
|
|
93422
93597
|
init_format();
|
|
93423
|
-
import { renameSync as
|
|
93598
|
+
import { renameSync as renameSync20, unlinkSync as unlinkSync21, chmodSync as chmodSync11 } from "fs";
|
|
93424
93599
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
93425
93600
|
var VALID_OPERATOR_KINDS = new Set(OPERATOR_EVENT_KINDS);
|
|
93426
93601
|
var AGENT_NAME_RE3 = /^[a-z0-9][a-z0-9_-]{0,50}$/;
|
|
@@ -93674,10 +93849,10 @@ function createIpcServer(options) {
|
|
|
93674
93849
|
return false;
|
|
93675
93850
|
};
|
|
93676
93851
|
try {
|
|
93677
|
-
|
|
93852
|
+
renameSync20(socketPath, socketPath + ".bak");
|
|
93678
93853
|
} catch {}
|
|
93679
93854
|
try {
|
|
93680
|
-
|
|
93855
|
+
unlinkSync21(socketPath + ".bak");
|
|
93681
93856
|
} catch {}
|
|
93682
93857
|
const clients = new Set;
|
|
93683
93858
|
const agentIndex = new Map;
|
|
@@ -94131,7 +94306,7 @@ function createIpcServer(options) {
|
|
|
94131
94306
|
clientBySocketId.clear();
|
|
94132
94307
|
server.stop(true);
|
|
94133
94308
|
try {
|
|
94134
|
-
|
|
94309
|
+
renameSync20(socketPath, socketPath + ".bak");
|
|
94135
94310
|
} catch {}
|
|
94136
94311
|
}
|
|
94137
94312
|
};
|
|
@@ -94705,8 +94880,132 @@ function buildDiffPreviewCard(input) {
|
|
|
94705
94880
|
return { text: text4, reply_markup: kb };
|
|
94706
94881
|
}
|
|
94707
94882
|
|
|
94883
|
+
// gateway/approval-outcome-sources.ts
|
|
94884
|
+
var APPROVAL_OUTCOME_SOURCES = Object.freeze(new Set([
|
|
94885
|
+
"vault_grant_approved",
|
|
94886
|
+
"vault_grant_denied",
|
|
94887
|
+
"vault_grant_timeout",
|
|
94888
|
+
"vault_save_completed",
|
|
94889
|
+
"vault_save_discarded",
|
|
94890
|
+
"vault_save_failed",
|
|
94891
|
+
"vault_save_timeout",
|
|
94892
|
+
"secret_provided",
|
|
94893
|
+
"secret_declined",
|
|
94894
|
+
"secret_provide_failed",
|
|
94895
|
+
"secret_request_timeout",
|
|
94896
|
+
"mental_model_proposal_applied",
|
|
94897
|
+
"mental_model_proposal_denied",
|
|
94898
|
+
"mental_model_proposal_failed",
|
|
94899
|
+
"mental_model_propose_timeout",
|
|
94900
|
+
"skill_proposal_apply",
|
|
94901
|
+
"eval_case_applied",
|
|
94902
|
+
"eval_case_rejected",
|
|
94903
|
+
"eval_case_apply_failed",
|
|
94904
|
+
"eval_case_suppressed"
|
|
94905
|
+
]));
|
|
94906
|
+
var APPROVAL_OUTCOME_DROPPED_SOURCE = "approval_outcome_dropped";
|
|
94907
|
+
function isApprovalOutcome(msg) {
|
|
94908
|
+
const meta = msg.meta;
|
|
94909
|
+
if (meta == null)
|
|
94910
|
+
return false;
|
|
94911
|
+
if (meta.source != null && APPROVAL_OUTCOME_SOURCES.has(meta.source))
|
|
94912
|
+
return true;
|
|
94913
|
+
return meta.button_callback === "true";
|
|
94914
|
+
}
|
|
94915
|
+
function approvalOutcomeLabel(msg) {
|
|
94916
|
+
const src = msg.meta?.source;
|
|
94917
|
+
if (src != null && src !== "")
|
|
94918
|
+
return src;
|
|
94919
|
+
if (msg.meta?.button_callback === "true")
|
|
94920
|
+
return "button_callback";
|
|
94921
|
+
return "-";
|
|
94922
|
+
}
|
|
94923
|
+
function buildApprovalOutcomeDroppedInbound(opts) {
|
|
94924
|
+
const ts = opts.nowMs ?? Date.now();
|
|
94925
|
+
const list2 = opts.sources.length > 0 ? opts.sources.join(", ") : "unknown";
|
|
94926
|
+
const plural = opts.sources.length === 1 ? "an approval outcome" : "approval outcomes";
|
|
94927
|
+
const msg = {
|
|
94928
|
+
type: "inbound",
|
|
94929
|
+
chatId: opts.chatId,
|
|
94930
|
+
...opts.threadId != null ? { threadId: opts.threadId } : {},
|
|
94931
|
+
messageId: ts,
|
|
94932
|
+
user: "gateway",
|
|
94933
|
+
userId: 0,
|
|
94934
|
+
ts,
|
|
94935
|
+
text: `\u26a0\ufe0f Your inbound buffer overflowed while every queued message was ${plural}, ` + `so the oldest had to be dropped: ${list2}. Do NOT keep waiting on it \u2014 ` + `re-check the underlying state directly (e.g. retry the vault read to see ` + `whether the grant exists) and tell the operator plainly what was lost.`,
|
|
94936
|
+
meta: {
|
|
94937
|
+
source: APPROVAL_OUTCOME_DROPPED_SOURCE,
|
|
94938
|
+
agent: opts.agent,
|
|
94939
|
+
...opts.threadId != null ? { message_thread_id: String(opts.threadId) } : {},
|
|
94940
|
+
dropped_sources: list2,
|
|
94941
|
+
dropped_count: String(opts.sources.length)
|
|
94942
|
+
}
|
|
94943
|
+
};
|
|
94944
|
+
return msg;
|
|
94945
|
+
}
|
|
94946
|
+
var APPROVAL_OUTCOME_NOTICE_HOPS = 2;
|
|
94947
|
+
function createApprovalOutcomeDropNotifier(opts) {
|
|
94948
|
+
const log = opts.log ?? ((line) => process.stderr.write(line));
|
|
94949
|
+
const defer = opts.defer ?? ((fn) => queueMicrotask(fn));
|
|
94950
|
+
const hops = opts.hops ?? APPROVAL_OUTCOME_NOTICE_HOPS;
|
|
94951
|
+
const pending = new Map;
|
|
94952
|
+
const scheduled = new Set;
|
|
94953
|
+
return (agent, evicted) => {
|
|
94954
|
+
const label = approvalOutcomeLabel(evicted);
|
|
94955
|
+
log(`telegram gateway: APPROVAL-OUTCOME-DROPPED agent=${agent} source=${label} ` + `chat=${evicted.chatId} ts=${evicted.ts}
|
|
94956
|
+
`);
|
|
94957
|
+
const list2 = pending.get(agent) ?? [];
|
|
94958
|
+
list2.push(label);
|
|
94959
|
+
pending.set(agent, list2);
|
|
94960
|
+
if (scheduled.has(agent))
|
|
94961
|
+
return;
|
|
94962
|
+
scheduled.add(agent);
|
|
94963
|
+
const chatId = evicted.chatId;
|
|
94964
|
+
const threadId = evicted.threadId;
|
|
94965
|
+
const flush = (budget) => {
|
|
94966
|
+
const sources = [...pending.get(agent) ?? []];
|
|
94967
|
+
const before = sources.length;
|
|
94968
|
+
try {
|
|
94969
|
+
opts.push(agent, buildApprovalOutcomeDroppedInbound({
|
|
94970
|
+
agent,
|
|
94971
|
+
chatId,
|
|
94972
|
+
...threadId != null ? { threadId } : {},
|
|
94973
|
+
sources,
|
|
94974
|
+
...opts.nowMs != null ? { nowMs: opts.nowMs() } : {}
|
|
94975
|
+
}));
|
|
94976
|
+
} catch (e) {
|
|
94977
|
+
log(`telegram gateway: APPROVAL-OUTCOME-DROPPED notice push failed: ${String(e)}
|
|
94978
|
+
`);
|
|
94979
|
+
} finally {
|
|
94980
|
+
scheduled.delete(agent);
|
|
94981
|
+
}
|
|
94982
|
+
if (budget > 0 && (pending.get(agent)?.length ?? 0) > before) {
|
|
94983
|
+
scheduled.add(agent);
|
|
94984
|
+
defer(() => flush(budget - 1));
|
|
94985
|
+
} else {
|
|
94986
|
+
pending.delete(agent);
|
|
94987
|
+
}
|
|
94988
|
+
};
|
|
94989
|
+
defer(() => flush(hops));
|
|
94990
|
+
};
|
|
94991
|
+
}
|
|
94992
|
+
|
|
94708
94993
|
// gateway/pending-inbound-buffer.ts
|
|
94709
94994
|
var DEFAULT_PENDING_INBOUND_CAP = 32;
|
|
94995
|
+
var APPROVAL_OUTCOME_PROTECTION_MS = 15 * 60 * 1000;
|
|
94996
|
+
function selectEvictionVictim(q, nowMs3, protectMaxAgeMs = APPROVAL_OUTCOME_PROTECTION_MS) {
|
|
94997
|
+
for (let i = 0;i < q.length; i++) {
|
|
94998
|
+
if (!isApprovalOutcome(q[i]))
|
|
94999
|
+
return { index: i, reason: "non-outcome" };
|
|
95000
|
+
}
|
|
95001
|
+
for (let i = 0;i < q.length; i++) {
|
|
95002
|
+
const ts = q[i].ts;
|
|
95003
|
+
if (typeof ts === "number" && Number.isFinite(ts) && nowMs3 - ts >= protectMaxAgeMs) {
|
|
95004
|
+
return { index: i, reason: "stale-outcome" };
|
|
95005
|
+
}
|
|
95006
|
+
}
|
|
95007
|
+
return { index: 0, reason: "all-outcomes" };
|
|
95008
|
+
}
|
|
94710
95009
|
function redeliverBufferedInbound(buffer, agent, send, spool, onDelivered) {
|
|
94711
95010
|
const pending = buffer.drain(agent);
|
|
94712
95011
|
let redelivered = 0;
|
|
@@ -94815,8 +95114,10 @@ function createPendingInboundBuffer(opts = {}) {
|
|
|
94815
95114
|
const cap = opts.capPerAgent ?? DEFAULT_PENDING_INBOUND_CAP;
|
|
94816
95115
|
const log = opts.log ?? ((line) => process.stderr.write(line));
|
|
94817
95116
|
const spool = opts.spool;
|
|
95117
|
+
const now = opts.now ?? (() => Date.now());
|
|
95118
|
+
const protectionMs = opts.approvalOutcomeProtectionMs ?? APPROVAL_OUTCOME_PROTECTION_MS;
|
|
94818
95119
|
const queues = new Map;
|
|
94819
|
-
|
|
95120
|
+
const buffer = {
|
|
94820
95121
|
push(agent, msg) {
|
|
94821
95122
|
let q = queues.get(agent);
|
|
94822
95123
|
if (q == null) {
|
|
@@ -94825,14 +95126,19 @@ function createPendingInboundBuffer(opts = {}) {
|
|
|
94825
95126
|
}
|
|
94826
95127
|
let evicted = false;
|
|
94827
95128
|
if (q.length >= cap) {
|
|
94828
|
-
const
|
|
95129
|
+
const { index: index2, reason } = selectEvictionVictim(q, now(), protectionMs);
|
|
95130
|
+
const dropped = q.splice(index2, 1)[0];
|
|
94829
95131
|
evicted = true;
|
|
94830
|
-
log(`pending-inbound-buffer: agent=${agent} cap=${cap} reached \u2014 ` + `dropped
|
|
95132
|
+
log(`pending-inbound-buffer: agent=${agent} cap=${cap} reached \u2014 ` + `dropped entry idx=${index2} reason=${reason} ` + `source=${dropped?.meta?.source ?? "-"} ts=${dropped?.ts ?? "-"}
|
|
94831
95133
|
`);
|
|
94832
|
-
if (dropped != null
|
|
94833
|
-
|
|
94834
|
-
|
|
94835
|
-
|
|
95134
|
+
if (dropped != null) {
|
|
95135
|
+
const critical = reason !== "non-outcome";
|
|
95136
|
+
const cb = critical ? onEvictCritical : opts.onEvict;
|
|
95137
|
+
if (cb != null) {
|
|
95138
|
+
try {
|
|
95139
|
+
cb(agent, dropped);
|
|
95140
|
+
} catch {}
|
|
95141
|
+
}
|
|
94836
95142
|
}
|
|
94837
95143
|
}
|
|
94838
95144
|
q.push(msg);
|
|
@@ -94866,6 +95172,13 @@ function createPendingInboundBuffer(opts = {}) {
|
|
|
94866
95172
|
},
|
|
94867
95173
|
beforeRedeliver: opts.beforeRedeliver
|
|
94868
95174
|
};
|
|
95175
|
+
const onEvictCritical = opts.onEvictCritical ?? createApprovalOutcomeDropNotifier({
|
|
95176
|
+
push: (a, m) => {
|
|
95177
|
+
buffer.push(a, m);
|
|
95178
|
+
},
|
|
95179
|
+
log
|
|
95180
|
+
});
|
|
95181
|
+
return buffer;
|
|
94869
95182
|
}
|
|
94870
95183
|
|
|
94871
95184
|
// gateway/represent-guard.ts
|
|
@@ -94928,6 +95241,7 @@ function makeSessionBusyDrainDeferral(boundMs, staleGapMs = DEFAULT_DRAIN_DEFER_
|
|
|
94928
95241
|
}
|
|
94929
95242
|
|
|
94930
95243
|
// gateway/pending-inbound-buffer.ts
|
|
95244
|
+
var APPROVAL_OUTCOME_PROTECTION_MS2 = 15 * 60 * 1000;
|
|
94931
95245
|
function redeliverBufferedInbound2(buffer, agent, send, spool, onDelivered) {
|
|
94932
95246
|
const pending = buffer.drain(agent);
|
|
94933
95247
|
let redelivered = 0;
|
|
@@ -97832,7 +98146,7 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
|
|
|
97832
98146
|
}
|
|
97833
98147
|
|
|
97834
98148
|
// gateway/compaction-marker.ts
|
|
97835
|
-
import { statSync as statSync17, unlinkSync as
|
|
98149
|
+
import { statSync as statSync17, unlinkSync as unlinkSync22 } from "node:fs";
|
|
97836
98150
|
import { homedir as homedir17 } from "node:os";
|
|
97837
98151
|
import { join as join56 } from "node:path";
|
|
97838
98152
|
var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
|
|
@@ -97849,7 +98163,7 @@ function readCompactionMarkerAgeMs(stateDir, now) {
|
|
|
97849
98163
|
}
|
|
97850
98164
|
function removeCompactionMarker(stateDir) {
|
|
97851
98165
|
try {
|
|
97852
|
-
|
|
98166
|
+
unlinkSync22(join56(stateDir, COMPACTION_MARKER_FILE));
|
|
97853
98167
|
} catch {}
|
|
97854
98168
|
}
|
|
97855
98169
|
|
|
@@ -98609,6 +98923,26 @@ function maybeFireWarmup(ctx) {
|
|
|
98609
98923
|
}
|
|
98610
98924
|
|
|
98611
98925
|
// gateway/self-improve-proposal-wiring.ts
|
|
98926
|
+
function buildEvalCaseSuppressedInbound(opts) {
|
|
98927
|
+
const ts = opts.nowMs ?? Date.now();
|
|
98928
|
+
return {
|
|
98929
|
+
type: "inbound",
|
|
98930
|
+
chatId: opts.chatId,
|
|
98931
|
+
...opts.threadId != null ? { threadId: opts.threadId } : {},
|
|
98932
|
+
messageId: ts,
|
|
98933
|
+
user: "self-improve",
|
|
98934
|
+
userId: 0,
|
|
98935
|
+
ts,
|
|
98936
|
+
text: `\u2139\ufe0f Your proposed eval case for \`${opts.skillSlug}\` was NOT posted as a ` + `card: the operator already dismissed this exact case, and the dismissal ` + `is still in effect. This is EXPECTED and is not an error or a failure on ` + `your part \u2014 nothing was written and no card is pending, so do NOT wait ` + `for an approval tap. Do NOT re-propose this case. Carry on with the ` + `original task without it.`,
|
|
98937
|
+
meta: {
|
|
98938
|
+
source: "eval_case_suppressed",
|
|
98939
|
+
agent: opts.agent,
|
|
98940
|
+
...opts.threadId != null ? { message_thread_id: String(opts.threadId) } : {},
|
|
98941
|
+
skill_slug: opts.skillSlug,
|
|
98942
|
+
fingerprint: opts.fingerprint
|
|
98943
|
+
}
|
|
98944
|
+
};
|
|
98945
|
+
}
|
|
98612
98946
|
function handlePostSkillProposal(msg, deps) {
|
|
98613
98947
|
const { bot, assertAllowedChat, swallowingApiCall } = deps;
|
|
98614
98948
|
const self = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -98665,8 +98999,28 @@ function handlePostSkillProposal(msg, deps) {
|
|
|
98665
98999
|
process.stderr.write(`telegram gateway: post_skill_proposal agent=${msg.agentName} chat=${msg.chatId} ` + `proposal=${proposal.id} slug=${proposal.skill_slug} new=${proposal.is_new}
|
|
98666
99000
|
`);
|
|
98667
99001
|
}
|
|
99002
|
+
function isEvalCaseProposalSuppressed(stateDir, candidate, opts = {}) {
|
|
99003
|
+
if (typeof candidate.fingerprint !== "string" || candidate.fingerprint.length === 0) {
|
|
99004
|
+
return false;
|
|
99005
|
+
}
|
|
99006
|
+
const now = (opts.now ?? Date.now)();
|
|
99007
|
+
const ttl = opts.ttlMs ?? REJECTION_TTL_MS;
|
|
99008
|
+
for (const p of readEvalCaseProposals(stateDir)) {
|
|
99009
|
+
if (p.status !== "rejected")
|
|
99010
|
+
continue;
|
|
99011
|
+
if (p.skill_slug !== candidate.skillSlug)
|
|
99012
|
+
continue;
|
|
99013
|
+
if (p.fingerprint !== candidate.fingerprint)
|
|
99014
|
+
continue;
|
|
99015
|
+
const age = now - new Date(p.created_at).getTime();
|
|
99016
|
+
if (!Number.isFinite(age) || age > ttl)
|
|
99017
|
+
continue;
|
|
99018
|
+
return true;
|
|
99019
|
+
}
|
|
99020
|
+
return false;
|
|
99021
|
+
}
|
|
98668
99022
|
function handlePostEvalCaseProposal(msg, deps) {
|
|
98669
|
-
const { bot, assertAllowedChat, swallowingApiCall } = deps;
|
|
99023
|
+
const { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer } = deps;
|
|
98670
99024
|
const self = process.env.SWITCHROOM_AGENT_NAME;
|
|
98671
99025
|
if (self && msg.agentName !== self) {
|
|
98672
99026
|
process.stderr.write(`telegram gateway: post_eval_case_proposal rejected \u2014 agent mismatch (${msg.agentName} != ${self})
|
|
@@ -98683,6 +99037,21 @@ function handlePostEvalCaseProposal(msg, deps) {
|
|
|
98683
99037
|
const stateDir = process.env.TELEGRAM_STATE_DIR;
|
|
98684
99038
|
if (stateDir == null || stateDir.length === 0) {
|
|
98685
99039
|
process.stderr.write(`telegram gateway: post_eval_case_proposal: TELEGRAM_STATE_DIR unset, skipping
|
|
99040
|
+
`);
|
|
99041
|
+
return;
|
|
99042
|
+
}
|
|
99043
|
+
if (isEvalCaseProposalSuppressed(stateDir, {
|
|
99044
|
+
skillSlug: msg.skillSlug,
|
|
99045
|
+
fingerprint: msg.fingerprint
|
|
99046
|
+
})) {
|
|
99047
|
+
const delivered = deliverResumeSyntheticOrBuffer(msg.agentName, buildEvalCaseSuppressedInbound({
|
|
99048
|
+
agent: msg.agentName,
|
|
99049
|
+
chatId: msg.chatId,
|
|
99050
|
+
...msg.threadId != null ? { threadId: msg.threadId } : {},
|
|
99051
|
+
skillSlug: msg.skillSlug,
|
|
99052
|
+
fingerprint: msg.fingerprint
|
|
99053
|
+
}));
|
|
99054
|
+
process.stderr.write(`telegram gateway: post_eval_case_proposal suppressed (dismissed before) ` + `slug=${msg.skillSlug} fp=${msg.fingerprint} delivered=${delivered}
|
|
98686
99055
|
`);
|
|
98687
99056
|
return;
|
|
98688
99057
|
}
|
|
@@ -99214,15 +99583,15 @@ function escapeBody2(s) {
|
|
|
99214
99583
|
}
|
|
99215
99584
|
|
|
99216
99585
|
// gateway/pid-file.ts
|
|
99217
|
-
import { writeFileSync as
|
|
99586
|
+
import { writeFileSync as writeFileSync37, readFileSync as readFileSync43, unlinkSync as unlinkSync23, renameSync as renameSync21 } from "node:fs";
|
|
99218
99587
|
function writePidFile(path3, record) {
|
|
99219
99588
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
99220
|
-
|
|
99221
|
-
|
|
99589
|
+
writeFileSync37(tmp, JSON.stringify(record), "utf-8");
|
|
99590
|
+
renameSync21(tmp, path3);
|
|
99222
99591
|
}
|
|
99223
99592
|
function clearPidFile(path3) {
|
|
99224
99593
|
try {
|
|
99225
|
-
|
|
99594
|
+
unlinkSync23(path3);
|
|
99226
99595
|
} catch {}
|
|
99227
99596
|
}
|
|
99228
99597
|
|
|
@@ -99439,11 +99808,11 @@ function safeCount(fn) {
|
|
|
99439
99808
|
}
|
|
99440
99809
|
|
|
99441
99810
|
// gateway/session-marker.ts
|
|
99442
|
-
import { writeFileSync as
|
|
99811
|
+
import { writeFileSync as writeFileSync38, readFileSync as readFileSync45, renameSync as renameSync22, unlinkSync as unlinkSync24 } from "node:fs";
|
|
99443
99812
|
function writeSessionMarker(path3, marker) {
|
|
99444
99813
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
99445
|
-
|
|
99446
|
-
|
|
99814
|
+
writeFileSync38(tmp, JSON.stringify(marker), "utf-8");
|
|
99815
|
+
renameSync22(tmp, path3);
|
|
99447
99816
|
}
|
|
99448
99817
|
function readSessionMarker(path3) {
|
|
99449
99818
|
try {
|
|
@@ -99469,12 +99838,12 @@ function shouldFireRestartBanner(input) {
|
|
|
99469
99838
|
}
|
|
99470
99839
|
|
|
99471
99840
|
// gateway/clean-shutdown-marker.ts
|
|
99472
|
-
import { writeFileSync as
|
|
99841
|
+
import { writeFileSync as writeFileSync39, readFileSync as readFileSync46, renameSync as renameSync23, unlinkSync as unlinkSync25 } from "node:fs";
|
|
99473
99842
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
99474
99843
|
function writeCleanShutdownMarker(path3, marker) {
|
|
99475
99844
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
99476
|
-
|
|
99477
|
-
|
|
99845
|
+
writeFileSync39(tmp, JSON.stringify(marker), "utf-8");
|
|
99846
|
+
renameSync23(tmp, path3);
|
|
99478
99847
|
}
|
|
99479
99848
|
function readCleanShutdownMarker(path3) {
|
|
99480
99849
|
try {
|
|
@@ -99493,7 +99862,7 @@ function readCleanShutdownMarker(path3) {
|
|
|
99493
99862
|
}
|
|
99494
99863
|
function clearCleanShutdownMarker(path3) {
|
|
99495
99864
|
try {
|
|
99496
|
-
|
|
99865
|
+
unlinkSync25(path3);
|
|
99497
99866
|
} catch {}
|
|
99498
99867
|
}
|
|
99499
99868
|
function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
@@ -101409,31 +101778,31 @@ function startSubagentWatcher(config) {
|
|
|
101409
101778
|
// ../src/worktree/registry.ts
|
|
101410
101779
|
import {
|
|
101411
101780
|
mkdirSync as mkdirSync41,
|
|
101412
|
-
writeFileSync as
|
|
101781
|
+
writeFileSync as writeFileSync40,
|
|
101413
101782
|
readFileSync as readFileSync48,
|
|
101414
101783
|
readdirSync as readdirSync13,
|
|
101415
|
-
unlinkSync as
|
|
101784
|
+
unlinkSync as unlinkSync26,
|
|
101416
101785
|
existsSync as existsSync48,
|
|
101417
|
-
renameSync as
|
|
101786
|
+
renameSync as renameSync24
|
|
101418
101787
|
} from "node:fs";
|
|
101419
101788
|
import { join as join58, resolve as resolve10 } from "node:path";
|
|
101420
101789
|
import { homedir as homedir18 } from "node:os";
|
|
101421
|
-
function
|
|
101790
|
+
function registryDir2() {
|
|
101422
101791
|
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join58(homedir18(), ".switchroom", "worktrees"));
|
|
101423
101792
|
}
|
|
101424
101793
|
function recordPath(id) {
|
|
101425
|
-
return join58(
|
|
101794
|
+
return join58(registryDir2(), `${id}.json`);
|
|
101426
101795
|
}
|
|
101427
101796
|
function ensureDir4() {
|
|
101428
|
-
mkdirSync41(
|
|
101797
|
+
mkdirSync41(registryDir2(), { recursive: true });
|
|
101429
101798
|
}
|
|
101430
|
-
function
|
|
101799
|
+
function writeRecord2(record) {
|
|
101431
101800
|
ensureDir4();
|
|
101432
101801
|
const target = recordPath(record.id);
|
|
101433
101802
|
const tmp = `${target}.tmp${process.pid}`;
|
|
101434
|
-
|
|
101803
|
+
writeFileSync40(tmp, JSON.stringify(record, null, 2) + `
|
|
101435
101804
|
`, { mode: 384 });
|
|
101436
|
-
|
|
101805
|
+
renameSync24(tmp, target);
|
|
101437
101806
|
}
|
|
101438
101807
|
function readRecord(id) {
|
|
101439
101808
|
const path3 = recordPath(id);
|
|
@@ -101446,7 +101815,7 @@ function readRecord(id) {
|
|
|
101446
101815
|
}
|
|
101447
101816
|
function listRecords() {
|
|
101448
101817
|
ensureDir4();
|
|
101449
|
-
const dir =
|
|
101818
|
+
const dir = registryDir2();
|
|
101450
101819
|
const records = [];
|
|
101451
101820
|
for (const entry of readdirSync13(dir)) {
|
|
101452
101821
|
if (!entry.endsWith(".json"))
|
|
@@ -101465,7 +101834,7 @@ function touchHeartbeat(id, onAfterRead) {
|
|
|
101465
101834
|
onAfterRead?.();
|
|
101466
101835
|
if (!recordExists(id))
|
|
101467
101836
|
return;
|
|
101468
|
-
|
|
101837
|
+
writeRecord2({ ...rec, heartbeatAt: new Date().toISOString() });
|
|
101469
101838
|
}
|
|
101470
101839
|
function recordExists(id) {
|
|
101471
101840
|
return existsSync48(recordPath(id));
|
|
@@ -101845,7 +102214,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
|
|
|
101845
102214
|
|
|
101846
102215
|
// issues-card.ts
|
|
101847
102216
|
init_card_format();
|
|
101848
|
-
import { readFileSync as readFileSync56, writeFileSync as
|
|
102217
|
+
import { readFileSync as readFileSync56, writeFileSync as writeFileSync45 } from "node:fs";
|
|
101849
102218
|
var SEVERITY_EMOJI = {
|
|
101850
102219
|
info: "\u2139\ufe0f",
|
|
101851
102220
|
warn: "\u26a0\ufe0f",
|
|
@@ -101953,7 +102322,7 @@ function readPersistedMessageId(path3, log) {
|
|
|
101953
102322
|
}
|
|
101954
102323
|
function writePersistedMessageId(path3, messageId, log) {
|
|
101955
102324
|
try {
|
|
101956
|
-
|
|
102325
|
+
writeFileSync45(path3, JSON.stringify({ messageId }) + `
|
|
101957
102326
|
`, { mode: 384 });
|
|
101958
102327
|
} catch (err) {
|
|
101959
102328
|
log(`issues-card: persist write failed (${err.message})`);
|
|
@@ -102057,10 +102426,10 @@ import {
|
|
|
102057
102426
|
openSync as openSync15,
|
|
102058
102427
|
readdirSync as readdirSync15,
|
|
102059
102428
|
readFileSync as readFileSync57,
|
|
102060
|
-
renameSync as
|
|
102429
|
+
renameSync as renameSync27,
|
|
102061
102430
|
statSync as statSync20,
|
|
102062
|
-
unlinkSync as
|
|
102063
|
-
writeFileSync as
|
|
102431
|
+
unlinkSync as unlinkSync27,
|
|
102432
|
+
writeFileSync as writeFileSync46,
|
|
102064
102433
|
writeSync as writeSync8
|
|
102065
102434
|
} from "node:fs";
|
|
102066
102435
|
import { join as join64 } from "node:path";
|
|
@@ -102143,8 +102512,8 @@ function writeAll(stateDir, events) {
|
|
|
102143
102512
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
102144
102513
|
`) + `
|
|
102145
102514
|
`;
|
|
102146
|
-
|
|
102147
|
-
|
|
102515
|
+
writeFileSync46(tmp, body, "utf-8");
|
|
102516
|
+
renameSync27(tmp, path3);
|
|
102148
102517
|
}
|
|
102149
102518
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
102150
102519
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -102163,7 +102532,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
102163
102532
|
try {
|
|
102164
102533
|
const stat = statSync20(tmpPath2);
|
|
102165
102534
|
if (stat.mtimeMs < cutoff) {
|
|
102166
|
-
|
|
102535
|
+
unlinkSync27(tmpPath2);
|
|
102167
102536
|
}
|
|
102168
102537
|
} catch {}
|
|
102169
102538
|
}
|
|
@@ -102199,7 +102568,7 @@ function withLock(stateDir, fn) {
|
|
|
102199
102568
|
closeSync15(fd);
|
|
102200
102569
|
} catch {}
|
|
102201
102570
|
try {
|
|
102202
|
-
|
|
102571
|
+
unlinkSync27(lockPath);
|
|
102203
102572
|
} catch {}
|
|
102204
102573
|
}
|
|
102205
102574
|
}
|
|
@@ -102213,13 +102582,13 @@ function tryStealStaleLock(lockPath) {
|
|
|
102213
102582
|
const pid = Number(pidStr);
|
|
102214
102583
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
102215
102584
|
try {
|
|
102216
|
-
|
|
102585
|
+
unlinkSync27(lockPath);
|
|
102217
102586
|
} catch {}
|
|
102218
102587
|
return true;
|
|
102219
102588
|
}
|
|
102220
102589
|
if (pid === process.pid) {
|
|
102221
102590
|
try {
|
|
102222
|
-
|
|
102591
|
+
unlinkSync27(lockPath);
|
|
102223
102592
|
} catch {}
|
|
102224
102593
|
return true;
|
|
102225
102594
|
}
|
|
@@ -102234,7 +102603,7 @@ function tryStealStaleLock(lockPath) {
|
|
|
102234
102603
|
return false;
|
|
102235
102604
|
}
|
|
102236
102605
|
try {
|
|
102237
|
-
|
|
102606
|
+
unlinkSync27(lockPath);
|
|
102238
102607
|
} catch {}
|
|
102239
102608
|
return true;
|
|
102240
102609
|
}
|
|
@@ -103436,7 +103805,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
103436
103805
|
|
|
103437
103806
|
// credits-watch.ts
|
|
103438
103807
|
init_card_format();
|
|
103439
|
-
import { readFileSync as readFileSync58, writeFileSync as
|
|
103808
|
+
import { readFileSync as readFileSync58, writeFileSync as writeFileSync47, existsSync as existsSync56, mkdirSync as mkdirSync47 } from "fs";
|
|
103440
103809
|
import { join as join67 } from "path";
|
|
103441
103810
|
var STATE_FILE = "credits-watch.json";
|
|
103442
103811
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
@@ -103560,14 +103929,14 @@ function loadCreditState(stateDir) {
|
|
|
103560
103929
|
function saveCreditState(stateDir, state7) {
|
|
103561
103930
|
mkdirSync47(stateDir, { recursive: true });
|
|
103562
103931
|
const path3 = join67(stateDir, STATE_FILE);
|
|
103563
|
-
|
|
103932
|
+
writeFileSync47(path3, JSON.stringify(state7, null, 2) + `
|
|
103564
103933
|
`, { mode: 384 });
|
|
103565
103934
|
}
|
|
103566
103935
|
|
|
103567
103936
|
// quota-watch.ts
|
|
103568
103937
|
init_auth_snapshot_format();
|
|
103569
103938
|
init_card_format();
|
|
103570
|
-
import { readFileSync as readFileSync59, writeFileSync as
|
|
103939
|
+
import { readFileSync as readFileSync59, writeFileSync as writeFileSync48, existsSync as existsSync57, mkdirSync as mkdirSync48 } from "fs";
|
|
103571
103940
|
import { join as join68 } from "path";
|
|
103572
103941
|
var STATE_FILE2 = "quota-watch.json";
|
|
103573
103942
|
function emptyQuotaWatchState() {
|
|
@@ -103829,7 +104198,7 @@ function loadQuotaWatchState(stateDir) {
|
|
|
103829
104198
|
function saveQuotaWatchState(stateDir, state7) {
|
|
103830
104199
|
mkdirSync48(stateDir, { recursive: true });
|
|
103831
104200
|
const path3 = join68(stateDir, STATE_FILE2);
|
|
103832
|
-
|
|
104201
|
+
writeFileSync48(path3, JSON.stringify(state7, null, 2) + `
|
|
103833
104202
|
`, { mode: 384 });
|
|
103834
104203
|
}
|
|
103835
104204
|
function patchQuotaWatchState(current, accountLabel, accountState) {
|
|
@@ -103882,7 +104251,7 @@ import {
|
|
|
103882
104251
|
openSync as openSync16,
|
|
103883
104252
|
readFileSync as readFileSync60,
|
|
103884
104253
|
statSync as statSync22,
|
|
103885
|
-
unlinkSync as
|
|
104254
|
+
unlinkSync as unlinkSync28,
|
|
103886
104255
|
utimesSync as utimesSync2
|
|
103887
104256
|
} from "node:fs";
|
|
103888
104257
|
import { join as join69 } from "node:path";
|
|
@@ -103891,7 +104260,7 @@ var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
|
103891
104260
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
103892
104261
|
function removeTurnActiveMarker2(stateDir) {
|
|
103893
104262
|
try {
|
|
103894
|
-
|
|
104263
|
+
unlinkSync28(join69(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
103895
104264
|
} catch {}
|
|
103896
104265
|
}
|
|
103897
104266
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
@@ -103910,7 +104279,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
103910
104279
|
try {
|
|
103911
104280
|
payload = readFileSync60(path3, "utf8");
|
|
103912
104281
|
} catch {}
|
|
103913
|
-
|
|
104282
|
+
unlinkSync28(path3);
|
|
103914
104283
|
if (opts.onRemove) {
|
|
103915
104284
|
try {
|
|
103916
104285
|
opts.onRemove({
|
|
@@ -103972,9 +104341,9 @@ import {
|
|
|
103972
104341
|
fsyncSync as fsyncSync6,
|
|
103973
104342
|
openSync as openSync17,
|
|
103974
104343
|
readFileSync as readFileSync61,
|
|
103975
|
-
renameSync as
|
|
103976
|
-
unlinkSync as
|
|
103977
|
-
writeFileSync as
|
|
104344
|
+
renameSync as renameSync28,
|
|
104345
|
+
unlinkSync as unlinkSync29,
|
|
104346
|
+
writeFileSync as writeFileSync49
|
|
103978
104347
|
} from "node:fs";
|
|
103979
104348
|
import { join as join71 } from "node:path";
|
|
103980
104349
|
var BOOT_BEACON_FILE = "gateway-beacon.json";
|
|
@@ -104081,12 +104450,12 @@ function writeBootBeaconFile(stateDir, beacon) {
|
|
|
104081
104450
|
try {
|
|
104082
104451
|
mkdirStateSync(stateDir, { recursive: true, mode: 448 });
|
|
104083
104452
|
fd = openSync17(tmp, "w", 384);
|
|
104084
|
-
|
|
104453
|
+
writeFileSync49(fd, serializeBootBeacon(beacon));
|
|
104085
104454
|
adoptStateOwnershipFd(fd, stateDir);
|
|
104086
104455
|
fsyncSync6(fd);
|
|
104087
104456
|
closeSync17(fd);
|
|
104088
104457
|
fd = undefined;
|
|
104089
|
-
|
|
104458
|
+
renameSync28(tmp, path3);
|
|
104090
104459
|
return true;
|
|
104091
104460
|
} catch {
|
|
104092
104461
|
if (fd !== undefined) {
|
|
@@ -104095,7 +104464,7 @@ function writeBootBeaconFile(stateDir, beacon) {
|
|
|
104095
104464
|
} catch {}
|
|
104096
104465
|
}
|
|
104097
104466
|
try {
|
|
104098
|
-
|
|
104467
|
+
unlinkSync29(tmp);
|
|
104099
104468
|
} catch {}
|
|
104100
104469
|
return false;
|
|
104101
104470
|
}
|
|
@@ -104467,10 +104836,10 @@ function startOutboxSweep(deps) {
|
|
|
104467
104836
|
}
|
|
104468
104837
|
|
|
104469
104838
|
// ../src/build-info.ts
|
|
104470
|
-
var VERSION2 = "0.21.
|
|
104471
|
-
var COMMIT_SHA = "
|
|
104472
|
-
var COMMIT_DATE = "2026-08-
|
|
104473
|
-
var LATEST_PR =
|
|
104839
|
+
var VERSION2 = "0.21.8";
|
|
104840
|
+
var COMMIT_SHA = "d778afb6";
|
|
104841
|
+
var COMMIT_DATE = "2026-08-13T03:44:10Z";
|
|
104842
|
+
var LATEST_PR = 4677;
|
|
104474
104843
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
104475
104844
|
|
|
104476
104845
|
// gateway/boot-version.ts
|
|
@@ -105852,7 +106221,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
105852
106221
|
}
|
|
105853
106222
|
|
|
105854
106223
|
// gateway/boot-briefing-wiring.ts
|
|
105855
|
-
import { existsSync as existsSync60, readFileSync as readFileSync63, writeFileSync as
|
|
106224
|
+
import { existsSync as existsSync60, readFileSync as readFileSync63, writeFileSync as writeFileSync50 } from "node:fs";
|
|
105856
106225
|
import { join as join74 } from "node:path";
|
|
105857
106226
|
init_history();
|
|
105858
106227
|
|
|
@@ -106208,7 +106577,7 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106208
106577
|
if (!bootId)
|
|
106209
106578
|
return;
|
|
106210
106579
|
try {
|
|
106211
|
-
|
|
106580
|
+
writeFileSync50(genMarkerPath, `${bootId}
|
|
106212
106581
|
`);
|
|
106213
106582
|
} catch {}
|
|
106214
106583
|
};
|
|
@@ -106282,7 +106651,7 @@ async function maybeQueueBootBriefing(opts) {
|
|
|
106282
106651
|
}
|
|
106283
106652
|
|
|
106284
106653
|
// gateway/pending-turn-env.ts
|
|
106285
|
-
import { existsSync as existsSync61, renameSync as
|
|
106654
|
+
import { existsSync as existsSync61, renameSync as renameSync29, rmSync as rmSync8, writeFileSync as writeFileSync51 } from "node:fs";
|
|
106286
106655
|
import { join as join75 } from "node:path";
|
|
106287
106656
|
function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.write(l)) {
|
|
106288
106657
|
const pendingEnvPath = join75(agentDir, ".pending-turn.env");
|
|
@@ -106299,10 +106668,10 @@ function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.writ
|
|
|
106299
106668
|
pending.interrupt_reason != null ? `SWITCHROOM_PENDING_INTERRUPT_REASON=${pending.interrupt_reason}` : `SWITCHROOM_PENDING_INTERRUPT_REASON=`
|
|
106300
106669
|
];
|
|
106301
106670
|
const pendingEnvTmp = `${pendingEnvPath}.tmp-${process.pid}`;
|
|
106302
|
-
|
|
106671
|
+
writeFileSync51(pendingEnvTmp, lines.join(`
|
|
106303
106672
|
`) + `
|
|
106304
106673
|
`, { mode: 384 });
|
|
106305
|
-
|
|
106674
|
+
renameSync29(pendingEnvTmp, pendingEnvPath);
|
|
106306
106675
|
log(`telegram gateway: pending-turn env written to ${pendingEnvPath} ` + `turnKey=${pending.turn_key} endedVia=${pending.ended_via ?? "open"}
|
|
106307
106676
|
`);
|
|
106308
106677
|
} else if (existsSync61(pendingEnvPath)) {
|
|
@@ -106316,8 +106685,184 @@ function writePendingTurnEnv(agentDir, pending, log = (l) => process.stderr.writ
|
|
|
106316
106685
|
}
|
|
106317
106686
|
}
|
|
106318
106687
|
|
|
106688
|
+
// gateway/agent-process-liveness.ts
|
|
106689
|
+
import { existsSync as existsSync62, readFileSync as readFileSync64, writeFileSync as writeFileSync52, renameSync as renameSync30, unlinkSync as unlinkSync30, readdirSync as readdirSync16 } from "node:fs";
|
|
106690
|
+
import { join as join76, dirname as dirname28, basename as basename18 } from "node:path";
|
|
106691
|
+
var AGENT_PROCESS_RECORD_FILE = "agent-process.json";
|
|
106692
|
+
var BOOT_RESUME_DONE_FILE = ".boot-resume-done";
|
|
106693
|
+
function parseProcStat(raw) {
|
|
106694
|
+
const close = raw.lastIndexOf(") ");
|
|
106695
|
+
const open = raw.indexOf(" (");
|
|
106696
|
+
if (close < 0 || open < 0 || close < open)
|
|
106697
|
+
return null;
|
|
106698
|
+
const comm = raw.slice(open + 2, close);
|
|
106699
|
+
const rest = raw.slice(close + 2).trim().split(/\s+/);
|
|
106700
|
+
const state7 = rest[0];
|
|
106701
|
+
const starttime = rest[19];
|
|
106702
|
+
if (state7 == null || state7.length === 0)
|
|
106703
|
+
return null;
|
|
106704
|
+
if (starttime == null || !/^\d+$/.test(starttime))
|
|
106705
|
+
return null;
|
|
106706
|
+
return { comm, state: state7, starttime };
|
|
106707
|
+
}
|
|
106708
|
+
function readProcIdentity(pid, procRoot = "/proc") {
|
|
106709
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
106710
|
+
return null;
|
|
106711
|
+
let identity;
|
|
106712
|
+
try {
|
|
106713
|
+
identity = parseProcStat(readFileSync64(join76(procRoot, String(pid), "stat"), "utf8"));
|
|
106714
|
+
} catch {
|
|
106715
|
+
return null;
|
|
106716
|
+
}
|
|
106717
|
+
if (identity != null && identity.state === "Z")
|
|
106718
|
+
return null;
|
|
106719
|
+
return identity;
|
|
106720
|
+
}
|
|
106721
|
+
function readAgentProcessRecord(path3) {
|
|
106722
|
+
let parsed;
|
|
106723
|
+
try {
|
|
106724
|
+
parsed = JSON.parse(readFileSync64(path3, "utf8"));
|
|
106725
|
+
} catch {
|
|
106726
|
+
return null;
|
|
106727
|
+
}
|
|
106728
|
+
if (parsed == null || typeof parsed !== "object")
|
|
106729
|
+
return null;
|
|
106730
|
+
const o = parsed;
|
|
106731
|
+
const pid = typeof o.pid === "number" ? o.pid : Number(o.pid);
|
|
106732
|
+
const starttime = typeof o.starttime === "string" ? o.starttime : String(o.starttime ?? "");
|
|
106733
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
106734
|
+
return null;
|
|
106735
|
+
if (!/^\d+$/.test(starttime))
|
|
106736
|
+
return null;
|
|
106737
|
+
const rec = { pid, starttime };
|
|
106738
|
+
if (typeof o.comm === "string" && o.comm.length > 0)
|
|
106739
|
+
rec.comm = o.comm;
|
|
106740
|
+
if (typeof o.boot_at === "number" && Number.isFinite(o.boot_at))
|
|
106741
|
+
rec.boot_at = o.boot_at;
|
|
106742
|
+
return rec;
|
|
106743
|
+
}
|
|
106744
|
+
function bootResumeDonePath(stateDir) {
|
|
106745
|
+
return join76(stateDir, BOOT_RESUME_DONE_FILE);
|
|
106746
|
+
}
|
|
106747
|
+
function containerBootIdentity(procRoot = "/proc") {
|
|
106748
|
+
return readProcIdentity(1, procRoot)?.starttime ?? null;
|
|
106749
|
+
}
|
|
106750
|
+
function readBootResumeSentinel(path3, opts = {}) {
|
|
106751
|
+
let raw;
|
|
106752
|
+
try {
|
|
106753
|
+
if (!existsSync62(path3))
|
|
106754
|
+
return { present: false, stale: false };
|
|
106755
|
+
raw = readFileSync64(path3, "utf8");
|
|
106756
|
+
} catch {
|
|
106757
|
+
return { present: false, stale: false };
|
|
106758
|
+
}
|
|
106759
|
+
let stamped = null;
|
|
106760
|
+
try {
|
|
106761
|
+
const parsed = JSON.parse(raw);
|
|
106762
|
+
if (parsed != null && typeof parsed === "object" && typeof parsed.boot === "string" && parsed.boot.length > 0) {
|
|
106763
|
+
stamped = parsed.boot;
|
|
106764
|
+
}
|
|
106765
|
+
} catch {}
|
|
106766
|
+
const live = containerBootIdentity(opts.procRoot);
|
|
106767
|
+
if (stamped != null && live != null && stamped !== live)
|
|
106768
|
+
return { present: true, stale: true };
|
|
106769
|
+
return { present: true, stale: false };
|
|
106770
|
+
}
|
|
106771
|
+
function sweepStrayTmps(path3) {
|
|
106772
|
+
const prefix = `${basename18(path3)}.tmp.`;
|
|
106773
|
+
try {
|
|
106774
|
+
for (const name of readdirSync16(dirname28(path3))) {
|
|
106775
|
+
if (!name.startsWith(prefix))
|
|
106776
|
+
continue;
|
|
106777
|
+
try {
|
|
106778
|
+
unlinkSync30(join76(dirname28(path3), name));
|
|
106779
|
+
} catch {}
|
|
106780
|
+
}
|
|
106781
|
+
} catch {}
|
|
106782
|
+
}
|
|
106783
|
+
function markBootResumeComplete(stateDir, opts = {}) {
|
|
106784
|
+
const path3 = opts.path ?? bootResumeDonePath(stateDir);
|
|
106785
|
+
const tmp = `${path3}.tmp.${process.pid}`;
|
|
106786
|
+
const boot = containerBootIdentity(opts.procRoot);
|
|
106787
|
+
try {
|
|
106788
|
+
const token = { pid: process.pid, at: opts.now ?? Date.now() };
|
|
106789
|
+
if (boot != null)
|
|
106790
|
+
token.boot = boot;
|
|
106791
|
+
writeFileSync52(tmp, JSON.stringify(token) + `
|
|
106792
|
+
`);
|
|
106793
|
+
renameSync30(tmp, path3);
|
|
106794
|
+
sweepStrayTmps(path3);
|
|
106795
|
+
} catch (err) {
|
|
106796
|
+
try {
|
|
106797
|
+
unlinkSync30(tmp);
|
|
106798
|
+
} catch {}
|
|
106799
|
+
const log = opts.log ?? ((s) => process.stderr.write(s));
|
|
106800
|
+
log(`telegram gateway: boot: could not stamp ${BOOT_RESUME_DONE_FILE} ` + `(${err.message}) \u2014 a gateway respawn may repeat the boot resume (#4641)
|
|
106801
|
+
`);
|
|
106802
|
+
}
|
|
106803
|
+
}
|
|
106804
|
+
function decideGatewayOnlyRespawn(input) {
|
|
106805
|
+
const { sentinelPresent, sentinelStale, record: record2, live } = input;
|
|
106806
|
+
if (!sentinelPresent) {
|
|
106807
|
+
return { gatewayOnly: false, reason: "no-boot-resume-sentinel", pid: record2?.pid ?? null };
|
|
106808
|
+
}
|
|
106809
|
+
if (sentinelStale === true) {
|
|
106810
|
+
return { gatewayOnly: false, reason: "stale-boot-token", pid: record2?.pid ?? null };
|
|
106811
|
+
}
|
|
106812
|
+
if (record2 == null) {
|
|
106813
|
+
return { gatewayOnly: true, reason: "gateway-only-respawn-no-record", pid: null };
|
|
106814
|
+
}
|
|
106815
|
+
if (live == null)
|
|
106816
|
+
return { gatewayOnly: false, reason: "agent-process-dead", pid: record2.pid };
|
|
106817
|
+
if (live.starttime !== record2.starttime) {
|
|
106818
|
+
return { gatewayOnly: false, reason: "starttime-mismatch", pid: record2.pid };
|
|
106819
|
+
}
|
|
106820
|
+
if (record2.comm != null && record2.comm !== live.comm) {
|
|
106821
|
+
return { gatewayOnly: false, reason: "comm-mismatch", pid: record2.pid };
|
|
106822
|
+
}
|
|
106823
|
+
return { gatewayOnly: true, reason: "gateway-only-respawn", pid: record2.pid };
|
|
106824
|
+
}
|
|
106825
|
+
function detectGatewayOnlyRespawn(opts) {
|
|
106826
|
+
if (opts.enabled === false)
|
|
106827
|
+
return { gatewayOnly: false, reason: "guard-disabled", pid: null };
|
|
106828
|
+
const procRoot = opts.procRoot ?? "/proc";
|
|
106829
|
+
const sentinel = readBootResumeSentinel(opts.sentinelPath ?? bootResumeDonePath(opts.stateDir), { procRoot });
|
|
106830
|
+
const recordPath2 = opts.recordPath ?? join76(opts.stateDir, AGENT_PROCESS_RECORD_FILE);
|
|
106831
|
+
const record2 = readAgentProcessRecord(recordPath2);
|
|
106832
|
+
const live = record2 == null ? null : readProcIdentity(record2.pid, procRoot);
|
|
106833
|
+
return decideGatewayOnlyRespawn({
|
|
106834
|
+
sentinelPresent: sentinel.present,
|
|
106835
|
+
sentinelStale: sentinel.stale,
|
|
106836
|
+
record: record2,
|
|
106837
|
+
live
|
|
106838
|
+
});
|
|
106839
|
+
}
|
|
106840
|
+
function shouldSkipBootResumeForGatewayOnlyRespawn(stateDir, opts = {}) {
|
|
106841
|
+
const log = opts.log ?? ((s) => process.stderr.write(s));
|
|
106842
|
+
let decision;
|
|
106843
|
+
try {
|
|
106844
|
+
decision = detectGatewayOnlyRespawn({
|
|
106845
|
+
...opts,
|
|
106846
|
+
stateDir,
|
|
106847
|
+
enabled: opts.enabled ?? process.env.SWITCHROOM_GATEWAY_RESPAWN_GUARD !== "0"
|
|
106848
|
+
});
|
|
106849
|
+
} catch (err) {
|
|
106850
|
+
log(`telegram gateway: boot: agent-liveness probe failed (${err.message}) \u2014 assuming agent restart
|
|
106851
|
+
`);
|
|
106852
|
+
return false;
|
|
106853
|
+
}
|
|
106854
|
+
if (decision.gatewayOnly) {
|
|
106855
|
+
log(`telegram gateway: boot: GATEWAY-ONLY respawn \u2014 this container generation's boot resume is already ` + `done (${BOOT_RESUME_DONE_FILE} present, reason=${decision.reason}, agent pid=${decision.pid ?? "unrecorded"}). ` + `Skipping the orphan-turn reaper, the bridge-dead marker, the resume synthetic, crash-redelivery capture ` + `and .pending-turn.env (#4641): the claude session, its in-flight turn and its sub-agents were never interrupted.
|
|
106856
|
+
`);
|
|
106857
|
+
return true;
|
|
106858
|
+
}
|
|
106859
|
+
log(`telegram gateway: boot: agent-liveness probe \u2192 treating as agent restart (reason=${decision.reason})
|
|
106860
|
+
`);
|
|
106861
|
+
return false;
|
|
106862
|
+
}
|
|
106863
|
+
|
|
106319
106864
|
// gateway/bridge-dead-watchdog.ts
|
|
106320
|
-
import { readFileSync as
|
|
106865
|
+
import { readFileSync as readFileSync65, writeFileSync as writeFileSync53, renameSync as renameSync31, unlinkSync as unlinkSync31 } from "node:fs";
|
|
106321
106866
|
|
|
106322
106867
|
// gateway/cron-session.ts
|
|
106323
106868
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -106350,7 +106895,7 @@ function readFreshCrashLogTail(path3, opts = {}) {
|
|
|
106350
106895
|
const nowMs3 = opts.nowMs ?? Date.now();
|
|
106351
106896
|
const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
|
|
106352
106897
|
const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
|
|
106353
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
106898
|
+
const readFile = opts.readFile ?? ((p) => readFileSync65(p, "utf8"));
|
|
106354
106899
|
let raw;
|
|
106355
106900
|
try {
|
|
106356
106901
|
raw = readFile(path3);
|
|
@@ -106371,13 +106916,13 @@ function readFreshCrashLogTail(path3, opts = {}) {
|
|
|
106371
106916
|
}
|
|
106372
106917
|
function writeBridgeDeadEscalationMarker(path3, marker) {
|
|
106373
106918
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
106374
|
-
|
|
106375
|
-
|
|
106919
|
+
writeFileSync53(tmp, JSON.stringify(marker), "utf8");
|
|
106920
|
+
renameSync31(tmp, path3);
|
|
106376
106921
|
}
|
|
106377
106922
|
function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
|
|
106378
106923
|
let marker = null;
|
|
106379
106924
|
try {
|
|
106380
|
-
const parsed = JSON.parse(
|
|
106925
|
+
const parsed = JSON.parse(readFileSync65(path3, "utf8"));
|
|
106381
106926
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
|
|
106382
106927
|
const age = nowMs3 - parsed.ts;
|
|
106383
106928
|
if (age >= 0 && age < maxAgeMs) {
|
|
@@ -106389,7 +106934,7 @@ function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs
|
|
|
106389
106934
|
}
|
|
106390
106935
|
} catch {}
|
|
106391
106936
|
try {
|
|
106392
|
-
|
|
106937
|
+
unlinkSync31(path3);
|
|
106393
106938
|
} catch {}
|
|
106394
106939
|
return marker;
|
|
106395
106940
|
}
|
|
@@ -106530,7 +107075,7 @@ function createBridgeDeadWatchdog(opts) {
|
|
|
106530
107075
|
}
|
|
106531
107076
|
|
|
106532
107077
|
// gateway/boot-probes.ts
|
|
106533
|
-
import { readFileSync as
|
|
107078
|
+
import { readFileSync as readFileSync66, readdirSync as readdirSync17, existsSync as existsSync63 } from "fs";
|
|
106534
107079
|
init_quota_cache();
|
|
106535
107080
|
init_generation_stamp();
|
|
106536
107081
|
init_quota_check();
|
|
@@ -106538,8 +107083,8 @@ import { execFile as execFileCb2 } from "child_process";
|
|
|
106538
107083
|
import { promisify as promisify2 } from "util";
|
|
106539
107084
|
var execFile2 = promisify2(execFileCb2);
|
|
106540
107085
|
var realProcFs2 = {
|
|
106541
|
-
readdir: (p) =>
|
|
106542
|
-
readFile: (p) =>
|
|
107086
|
+
readdir: (p) => readdirSync17(p),
|
|
107087
|
+
readFile: (p) => readFileSync66(p, "utf-8")
|
|
106543
107088
|
};
|
|
106544
107089
|
function findAgentProcessInContainer2(fs4 = realProcFs2) {
|
|
106545
107090
|
let entries;
|
|
@@ -106840,7 +107385,7 @@ if (isGatewayMain) {
|
|
|
106840
107385
|
shutdownAnalytics();
|
|
106841
107386
|
});
|
|
106842
107387
|
}
|
|
106843
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
107388
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join77(homedir22(), ".claude", "channels", "telegram");
|
|
106844
107389
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
106845
107390
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
106846
107391
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -106879,7 +107424,7 @@ function alwaysAllowDrainDeps() {
|
|
|
106879
107424
|
return {
|
|
106880
107425
|
readConfigText: () => {
|
|
106881
107426
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
106882
|
-
return
|
|
107427
|
+
return readFileSync67(cfgPath, "utf8");
|
|
106883
107428
|
},
|
|
106884
107429
|
resolveAllowList: (_configText, agentName3) => {
|
|
106885
107430
|
const cfg = loadConfig2();
|
|
@@ -106940,11 +107485,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
106940
107485
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
106941
107486
|
timer3.unref?.();
|
|
106942
107487
|
}
|
|
106943
|
-
var ACCESS_FILE =
|
|
106944
|
-
var APPROVED_DIR =
|
|
106945
|
-
var ENV_FILE =
|
|
106946
|
-
var INBOX_DIR =
|
|
106947
|
-
var PEOPLE_FILE =
|
|
107488
|
+
var ACCESS_FILE = join77(STATE_DIR, "access.json");
|
|
107489
|
+
var APPROVED_DIR = join77(STATE_DIR, "approved");
|
|
107490
|
+
var ENV_FILE = join77(STATE_DIR, ".env");
|
|
107491
|
+
var INBOX_DIR = join77(STATE_DIR, "inbox");
|
|
107492
|
+
var PEOPLE_FILE = join77(STATE_DIR, "people.json");
|
|
106948
107493
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
106949
107494
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
106950
107495
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -107009,7 +107554,7 @@ function formatBootVersion() {
|
|
|
107009
107554
|
}
|
|
107010
107555
|
try {
|
|
107011
107556
|
chmodSync14(ENV_FILE, 384);
|
|
107012
|
-
for (const line of
|
|
107557
|
+
for (const line of readFileSync67(ENV_FILE, "utf8").split(`
|
|
107013
107558
|
`)) {
|
|
107014
107559
|
const m = line.match(/^(\w+)=(.*)$/);
|
|
107015
107560
|
if (m && process.env[m[1]] === undefined)
|
|
@@ -107030,7 +107575,7 @@ var bot;
|
|
|
107030
107575
|
var lastGetUpdatesHeartbeatMs = Date.now();
|
|
107031
107576
|
var GRAMMY_VERSION = (() => {
|
|
107032
107577
|
try {
|
|
107033
|
-
const raw =
|
|
107578
|
+
const raw = readFileSync67(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
|
|
107034
107579
|
return JSON.parse(raw).version ?? "unknown";
|
|
107035
107580
|
} catch {
|
|
107036
107581
|
return "unknown";
|
|
@@ -107071,7 +107616,7 @@ function assertSendable(f) {
|
|
|
107071
107616
|
} catch {
|
|
107072
107617
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
107073
107618
|
}
|
|
107074
|
-
const inbox =
|
|
107619
|
+
const inbox = join77(stateReal, "inbox");
|
|
107075
107620
|
if (real.startsWith(stateReal + sep6) && !real.startsWith(inbox + sep6)) {
|
|
107076
107621
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
107077
107622
|
}
|
|
@@ -107100,7 +107645,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
107100
107645
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
107101
107646
|
try {
|
|
107102
107647
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
107103
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
107648
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join77(STATE_DIR, "history.db")}
|
|
107104
107649
|
`);
|
|
107105
107650
|
} catch (err) {
|
|
107106
107651
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -107111,174 +107656,179 @@ var turnsDb = null;
|
|
|
107111
107656
|
var bootResumeInbound = null;
|
|
107112
107657
|
var pendingRedelivery = null;
|
|
107113
107658
|
var bridgeDeadPriorStreak = 0;
|
|
107114
|
-
|
|
107115
|
-
|
|
107116
|
-
|
|
107117
|
-
turnsDb = openTurnsDb(agentDir);
|
|
107118
|
-
applySubagentsSchema(turnsDb);
|
|
107119
|
-
let markerTurnKey = null;
|
|
107120
|
-
let markerAgeMs = null;
|
|
107659
|
+
var bootResumeThrew = false;
|
|
107660
|
+
bootResumeInit:
|
|
107661
|
+
if (isGatewayMain)
|
|
107121
107662
|
try {
|
|
107122
|
-
const
|
|
107123
|
-
|
|
107124
|
-
|
|
107125
|
-
|
|
107126
|
-
|
|
107127
|
-
|
|
107128
|
-
|
|
107129
|
-
|
|
107130
|
-
|
|
107131
|
-
|
|
107132
|
-
|
|
107133
|
-
|
|
107134
|
-
|
|
107135
|
-
|
|
107136
|
-
|
|
107137
|
-
|
|
107138
|
-
|
|
107139
|
-
|
|
107140
|
-
|
|
107141
|
-
|
|
107142
|
-
|
|
107143
|
-
|
|
107144
|
-
|
|
107145
|
-
|
|
107146
|
-
|
|
107147
|
-
|
|
107148
|
-
|
|
107149
|
-
|
|
107150
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join76(STATE_DIR, "bridge-dead-escalation.json"));
|
|
107151
|
-
if (bridgeDeadMarker != null) {
|
|
107152
|
-
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
107153
|
-
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
107154
|
-
`);
|
|
107155
|
-
}
|
|
107156
|
-
const bridgeDeadRestartCause = bridgeDeadMarker != null ? {
|
|
107157
|
-
reason: bridgeDeadMarker.reason,
|
|
107158
|
-
note: "The framework itself triggered this restart: your Telegram MCP bridge process had died " + "(chat tools were unavailable \u2014 you could not send replies), so the container was bounced " + "to restore the chat surface. This was NOT an operator-initiated restart and NOT a hang-watchdog kill."
|
|
107159
|
-
} : undefined;
|
|
107160
|
-
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
107161
|
-
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
107162
|
-
if (pending2 != null && selfAgent) {
|
|
107163
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join76(STATE_DIR, "clean-shutdown.json");
|
|
107164
|
-
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
107165
|
-
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
107166
|
-
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
107167
|
-
const bootResumeSuppressed = shouldSuppressBootResume(bootResumeCleanMarker, Date.now(), {
|
|
107168
|
-
forceAlways: bootResumeForceAlways,
|
|
107169
|
-
mode: bootResumeMode
|
|
107170
|
-
});
|
|
107171
|
-
const RESUME_MAX_AGE_MS = (() => {
|
|
107172
|
-
const v = Number(process.env.SWITCHROOM_RESUME_MAX_AGE_MS);
|
|
107173
|
-
return Number.isFinite(v) && v > 0 ? v : 10800000;
|
|
107174
|
-
})();
|
|
107175
|
-
const bootResumeKind = decideBootResumeKind({
|
|
107176
|
-
pending: pending2,
|
|
107177
|
-
suppressed: bootResumeSuppressed,
|
|
107178
|
-
ageMs: Math.max(0, Date.now() - pending2.started_at),
|
|
107179
|
-
maxAgeMs: RESUME_MAX_AGE_MS
|
|
107180
|
-
});
|
|
107181
|
-
const redeliverCapture = decideRedeliverCapture({
|
|
107182
|
-
willBeResumed: bootResumeKind === "resume",
|
|
107183
|
-
hasSessionId: Boolean(pending2.session_id)
|
|
107663
|
+
const agentDir = STATE_DIR.endsWith("/telegram") ? STATE_DIR.slice(0, -"/telegram".length) : STATE_DIR;
|
|
107664
|
+
turnsDb = openTurnsDb(agentDir);
|
|
107665
|
+
applySubagentsSchema(turnsDb);
|
|
107666
|
+
if (shouldSkipBootResumeForGatewayOnlyRespawn(STATE_DIR))
|
|
107667
|
+
break bootResumeInit;
|
|
107668
|
+
let markerTurnKey = null;
|
|
107669
|
+
let markerAgeMs = null;
|
|
107670
|
+
try {
|
|
107671
|
+
const markerPath = join77(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
107672
|
+
if (existsSync65(markerPath)) {
|
|
107673
|
+
const st = statSync25(markerPath);
|
|
107674
|
+
markerAgeMs = Date.now() - st.mtimeMs;
|
|
107675
|
+
try {
|
|
107676
|
+
const payload = JSON.parse(readFileSync67(markerPath, "utf8"));
|
|
107677
|
+
if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
|
|
107678
|
+
markerTurnKey = payload.turnKey;
|
|
107679
|
+
}
|
|
107680
|
+
} catch {}
|
|
107681
|
+
}
|
|
107682
|
+
} catch {}
|
|
107683
|
+
const hangSecs = Number(process.env.TURN_HANG_SECS);
|
|
107684
|
+
const hangThresholdMs = (Number.isFinite(hangSecs) && hangSecs > 0 ? hangSecs : 300) * 1000;
|
|
107685
|
+
const reasonSnapshot = markerAgeMs != null ? JSON.stringify({ idleMs: Math.round(markerAgeMs) }) : null;
|
|
107686
|
+
const { reaped, timeoutTurnKey } = markOrphanedWithTimeoutClassification(turnsDb, {
|
|
107687
|
+
markerTurnKey,
|
|
107688
|
+
markerAgeMs,
|
|
107689
|
+
hangThresholdMs,
|
|
107690
|
+
reasonSnapshot
|
|
107184
107691
|
});
|
|
107185
|
-
if (
|
|
107186
|
-
|
|
107187
|
-
} else if (redeliverCapture.skipReason === "will-be-resumed") {
|
|
107188
|
-
process.stderr.write(`telegram gateway: crash-redelivery suppressed \u2014 interrupted turnKey=${pending2.turn_key} will be ` + `RESUMED (bootResumeKind=resume); the fresh re-answer supersedes the recovered draft (no double-send)
|
|
107692
|
+
if (reaped > 0) {
|
|
107693
|
+
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
107189
107694
|
`);
|
|
107190
107695
|
} else {
|
|
107191
|
-
process.stderr.write(`telegram gateway:
|
|
107696
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join77(agentDir, "telegram", "registry.db")}
|
|
107192
107697
|
`);
|
|
107193
107698
|
}
|
|
107194
|
-
|
|
107195
|
-
|
|
107196
|
-
|
|
107197
|
-
|
|
107198
|
-
process.stderr.write(`telegram gateway: boot-resume subagent lookup failed (${err.message}) \u2014 continuing without worker list
|
|
107699
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join77(STATE_DIR, "bridge-dead-escalation.json"));
|
|
107700
|
+
if (bridgeDeadMarker != null) {
|
|
107701
|
+
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
107702
|
+
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
107199
107703
|
`);
|
|
107200
107704
|
}
|
|
107201
|
-
|
|
107202
|
-
|
|
107203
|
-
|
|
107204
|
-
|
|
107205
|
-
|
|
107206
|
-
|
|
107207
|
-
|
|
107208
|
-
|
|
107209
|
-
|
|
107210
|
-
|
|
107211
|
-
|
|
107212
|
-
|
|
107213
|
-
|
|
107214
|
-
|
|
107215
|
-
|
|
107216
|
-
|
|
107217
|
-
|
|
107705
|
+
const bridgeDeadRestartCause = bridgeDeadMarker != null ? {
|
|
107706
|
+
reason: bridgeDeadMarker.reason,
|
|
107707
|
+
note: "The framework itself triggered this restart: your Telegram MCP bridge process had died " + "(chat tools were unavailable \u2014 you could not send replies), so the container was bounced " + "to restore the chat surface. This was NOT an operator-initiated restart and NOT a hang-watchdog kill."
|
|
107708
|
+
} : undefined;
|
|
107709
|
+
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
107710
|
+
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
107711
|
+
if (pending2 != null && selfAgent) {
|
|
107712
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join77(STATE_DIR, "clean-shutdown.json");
|
|
107713
|
+
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
107714
|
+
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
107715
|
+
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
107716
|
+
const bootResumeSuppressed = shouldSuppressBootResume(bootResumeCleanMarker, Date.now(), {
|
|
107717
|
+
forceAlways: bootResumeForceAlways,
|
|
107718
|
+
mode: bootResumeMode
|
|
107719
|
+
});
|
|
107720
|
+
const RESUME_MAX_AGE_MS = (() => {
|
|
107721
|
+
const v = Number(process.env.SWITCHROOM_RESUME_MAX_AGE_MS);
|
|
107722
|
+
return Number.isFinite(v) && v > 0 ? v : 10800000;
|
|
107723
|
+
})();
|
|
107724
|
+
const bootResumeKind = decideBootResumeKind({
|
|
107725
|
+
pending: pending2,
|
|
107726
|
+
suppressed: bootResumeSuppressed,
|
|
107727
|
+
ageMs: Math.max(0, Date.now() - pending2.started_at),
|
|
107728
|
+
maxAgeMs: RESUME_MAX_AGE_MS
|
|
107729
|
+
});
|
|
107730
|
+
const redeliverCapture = decideRedeliverCapture({
|
|
107731
|
+
willBeResumed: bootResumeKind === "resume",
|
|
107732
|
+
hasSessionId: Boolean(pending2.session_id)
|
|
107733
|
+
});
|
|
107734
|
+
if (redeliverCapture.capture) {
|
|
107735
|
+
pendingRedelivery = { turn: pending2, maxAgeMs: RESUME_MAX_AGE_MS };
|
|
107736
|
+
} else if (redeliverCapture.skipReason === "will-be-resumed") {
|
|
107737
|
+
process.stderr.write(`telegram gateway: crash-redelivery suppressed \u2014 interrupted turnKey=${pending2.turn_key} will be ` + `RESUMED (bootResumeKind=resume); the fresh re-answer supersedes the recovered draft (no double-send)
|
|
107738
|
+
`);
|
|
107739
|
+
} else {
|
|
107740
|
+
process.stderr.write(`telegram gateway: crash-redelivery skipped \u2014 interrupted turnKey=${pending2.turn_key} has no ` + `pinned session_id (pre-feature turn or no session event seen); cannot resolve exact transcript
|
|
107741
|
+
`);
|
|
107218
107742
|
}
|
|
107219
|
-
|
|
107220
|
-
|
|
107221
|
-
|
|
107222
|
-
|
|
107223
|
-
|
|
107224
|
-
turn: pending2,
|
|
107225
|
-
idleMs,
|
|
107226
|
-
subagents: interruptedSubagents,
|
|
107227
|
-
restartCause: bridgeDeadRestartCause
|
|
107228
|
-
})
|
|
107229
|
-
};
|
|
107230
|
-
} else if (bootResumeKind === "defer-loop" || bootResumeKind === "defer-suppressed") {
|
|
107231
|
-
bootResumeInbound = {
|
|
107232
|
-
agent: selfAgent,
|
|
107233
|
-
msg: buildResumeDeferredReportInbound({
|
|
107234
|
-
turn: pending2,
|
|
107235
|
-
reason: bootResumeKind === "defer-loop" ? "loop-guard" : "clean-restart-suppressed",
|
|
107236
|
-
subagents: interruptedSubagents,
|
|
107237
|
-
restartCause: bridgeDeadRestartCause
|
|
107238
|
-
})
|
|
107239
|
-
};
|
|
107240
|
-
}
|
|
107241
|
-
if (bootResumeKind === "defer-suppressed") {
|
|
107242
|
-
process.stderr.write(`telegram gateway: boot-resume suppressed (clean shutdown` + `${bootResumeCleanMarker?.reason ? ` reason=${JSON.stringify(bootResumeCleanMarker.reason)}` : ""}` + `, mode=${bootResumeMode}) \u2014 passive report delivered for turnKey=${pending2.turn_key}
|
|
107743
|
+
let interruptedSubagents = [];
|
|
107744
|
+
try {
|
|
107745
|
+
interruptedSubagents = listNonTerminalSubagentsForTurn(turnsDb, pending2.turn_key).map((s) => ({ agentType: s.agent_type, description: s.description, status: s.status }));
|
|
107746
|
+
} catch (err) {
|
|
107747
|
+
process.stderr.write(`telegram gateway: boot-resume subagent lookup failed (${err.message}) \u2014 continuing without worker list
|
|
107243
107748
|
`);
|
|
107244
|
-
|
|
107245
|
-
|
|
107749
|
+
}
|
|
107750
|
+
if (bootResumeKind === "resume") {
|
|
107751
|
+
bootResumeInbound = {
|
|
107752
|
+
agent: selfAgent,
|
|
107753
|
+
msg: buildResumeInterruptedInbound({
|
|
107754
|
+
turn: pending2,
|
|
107755
|
+
subagents: interruptedSubagents,
|
|
107756
|
+
restartCause: bridgeDeadRestartCause
|
|
107757
|
+
})
|
|
107758
|
+
};
|
|
107759
|
+
} else if (bootResumeKind === "report") {
|
|
107760
|
+
let idleMs = pending2.turn_key === timeoutTurnKey && markerAgeMs != null ? markerAgeMs : null;
|
|
107761
|
+
if (idleMs == null && pending2.interrupt_reason) {
|
|
107762
|
+
try {
|
|
107763
|
+
const parsed = JSON.parse(pending2.interrupt_reason);
|
|
107764
|
+
if (typeof parsed.idleMs === "number" && Number.isFinite(parsed.idleMs))
|
|
107765
|
+
idleMs = parsed.idleMs;
|
|
107766
|
+
} catch {}
|
|
107767
|
+
}
|
|
107768
|
+
if (idleMs == null)
|
|
107769
|
+
idleMs = Math.max(0, Date.now() - pending2.started_at);
|
|
107770
|
+
bootResumeInbound = {
|
|
107771
|
+
agent: selfAgent,
|
|
107772
|
+
msg: buildResumeWatchdogReportInbound({
|
|
107773
|
+
turn: pending2,
|
|
107774
|
+
idleMs,
|
|
107775
|
+
subagents: interruptedSubagents,
|
|
107776
|
+
restartCause: bridgeDeadRestartCause
|
|
107777
|
+
})
|
|
107778
|
+
};
|
|
107779
|
+
} else if (bootResumeKind === "defer-loop" || bootResumeKind === "defer-suppressed") {
|
|
107780
|
+
bootResumeInbound = {
|
|
107781
|
+
agent: selfAgent,
|
|
107782
|
+
msg: buildResumeDeferredReportInbound({
|
|
107783
|
+
turn: pending2,
|
|
107784
|
+
reason: bootResumeKind === "defer-loop" ? "loop-guard" : "clean-restart-suppressed",
|
|
107785
|
+
subagents: interruptedSubagents,
|
|
107786
|
+
restartCause: bridgeDeadRestartCause
|
|
107787
|
+
})
|
|
107788
|
+
};
|
|
107789
|
+
}
|
|
107790
|
+
if (bootResumeKind === "defer-suppressed") {
|
|
107791
|
+
process.stderr.write(`telegram gateway: boot-resume suppressed (clean shutdown` + `${bootResumeCleanMarker?.reason ? ` reason=${JSON.stringify(bootResumeCleanMarker.reason)}` : ""}` + `, mode=${bootResumeMode}) \u2014 passive report delivered for turnKey=${pending2.turn_key}
|
|
107246
107792
|
`);
|
|
107247
|
-
|
|
107248
|
-
|
|
107249
|
-
process.stderr.write(`telegram gateway: boot-resume queued kind=${bootResumeKind} mode=${bootResumeMode} ` + `turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"} chat=${pending2.chat_id}
|
|
107793
|
+
} else if (bootResumeKind === "defer-loop") {
|
|
107794
|
+
process.stderr.write(`telegram gateway: boot-resume loop-guard tripped (interrupted turn was itself a resume) ` + `\u2014 passive report delivered instead of re-resuming turnKey=${pending2.turn_key}
|
|
107250
107795
|
`);
|
|
107251
|
-
}
|
|
107252
|
-
}
|
|
107253
|
-
if (bridgeDeadMarker != null && bootResumeInbound == null && selfAgent) {
|
|
107254
|
-
const idleNoticeChat = (() => {
|
|
107255
|
-
try {
|
|
107256
|
-
return loadAccess().allowFrom[0] ?? null;
|
|
107257
|
-
} catch {
|
|
107258
|
-
return null;
|
|
107259
107796
|
}
|
|
107260
|
-
|
|
107261
|
-
|
|
107262
|
-
bootResumeInbound = {
|
|
107263
|
-
agent: selfAgent,
|
|
107264
|
-
msg: buildBridgeDeadIdleNoticeInbound({
|
|
107265
|
-
chatId: String(idleNoticeChat),
|
|
107266
|
-
marker: bridgeDeadMarker
|
|
107267
|
-
})
|
|
107268
|
-
};
|
|
107269
|
-
process.stderr.write(`telegram gateway: boot: bridge-dead idle notice queued chat=${idleNoticeChat} (no turn was in flight)
|
|
107797
|
+
if (bootResumeInbound != null) {
|
|
107798
|
+
process.stderr.write(`telegram gateway: boot-resume queued kind=${bootResumeKind} mode=${bootResumeMode} ` + `turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"} chat=${pending2.chat_id}
|
|
107270
107799
|
`);
|
|
107271
|
-
|
|
107272
|
-
|
|
107800
|
+
}
|
|
107801
|
+
}
|
|
107802
|
+
if (bridgeDeadMarker != null && bootResumeInbound == null && selfAgent) {
|
|
107803
|
+
const idleNoticeChat = (() => {
|
|
107804
|
+
try {
|
|
107805
|
+
return loadAccess().allowFrom[0] ?? null;
|
|
107806
|
+
} catch {
|
|
107807
|
+
return null;
|
|
107808
|
+
}
|
|
107809
|
+
})();
|
|
107810
|
+
if (idleNoticeChat != null) {
|
|
107811
|
+
bootResumeInbound = {
|
|
107812
|
+
agent: selfAgent,
|
|
107813
|
+
msg: buildBridgeDeadIdleNoticeInbound({
|
|
107814
|
+
chatId: String(idleNoticeChat),
|
|
107815
|
+
marker: bridgeDeadMarker
|
|
107816
|
+
})
|
|
107817
|
+
};
|
|
107818
|
+
process.stderr.write(`telegram gateway: boot: bridge-dead idle notice queued chat=${idleNoticeChat} (no turn was in flight)
|
|
107273
107819
|
`);
|
|
107820
|
+
} else {
|
|
107821
|
+
process.stderr.write(`telegram gateway: boot: bridge-dead idle notice skipped \u2014 no allowFrom chat to surface it in
|
|
107822
|
+
`);
|
|
107823
|
+
}
|
|
107274
107824
|
}
|
|
107275
|
-
|
|
107276
|
-
|
|
107277
|
-
|
|
107278
|
-
process.stderr.write(`telegram gateway: turn-registry init failed (${err.message}) \u2014 turn tracking disabled
|
|
107825
|
+
writePendingTurnEnv(agentDir, pending2);
|
|
107826
|
+
} catch (err) {
|
|
107827
|
+
process.stderr.write(`telegram gateway: turn-registry init failed (${err.message}) \u2014 turn tracking disabled
|
|
107279
107828
|
`);
|
|
107280
|
-
|
|
107281
|
-
|
|
107829
|
+
turnsDb = null;
|
|
107830
|
+
bootResumeThrew = true;
|
|
107831
|
+
}
|
|
107282
107832
|
function resolveSubagentOriginChat(agentId) {
|
|
107283
107833
|
if (turnsDb == null)
|
|
107284
107834
|
return null;
|
|
@@ -107361,12 +107911,12 @@ if (isGatewayMain && !STATIC)
|
|
|
107361
107911
|
function checkApprovals() {
|
|
107362
107912
|
let files;
|
|
107363
107913
|
try {
|
|
107364
|
-
files =
|
|
107914
|
+
files = readdirSync19(APPROVED_DIR);
|
|
107365
107915
|
} catch {
|
|
107366
107916
|
return;
|
|
107367
107917
|
}
|
|
107368
107918
|
for (const senderId of files) {
|
|
107369
|
-
const file =
|
|
107919
|
+
const file = join77(APPROVED_DIR, senderId);
|
|
107370
107920
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync9(file, { force: true }), (err) => {
|
|
107371
107921
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
107372
107922
|
`);
|
|
@@ -107544,15 +108094,15 @@ function noteAgentOutputAt(key, ts) {
|
|
|
107544
108094
|
lastAgentOutputAt.delete(oldest);
|
|
107545
108095
|
}
|
|
107546
108096
|
}
|
|
107547
|
-
var OBLIGATION_STORE_PATH =
|
|
108097
|
+
var OBLIGATION_STORE_PATH = join77(STATE_DIR, "obligations.json");
|
|
107548
108098
|
var obligationStoreFs = {
|
|
107549
|
-
readFileSync: (p) =>
|
|
108099
|
+
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
107550
108100
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
107551
|
-
renameSync: (a, b) =>
|
|
107552
|
-
existsSync: (p) =>
|
|
108101
|
+
renameSync: (a, b) => renameSync32(a, b),
|
|
108102
|
+
existsSync: (p) => existsSync65(p),
|
|
107553
108103
|
fsyncFileSync: fsyncPathSync,
|
|
107554
108104
|
fsyncDirSync: fsyncPathSync,
|
|
107555
|
-
unlinkSync:
|
|
108105
|
+
unlinkSync: unlinkSync33
|
|
107556
108106
|
};
|
|
107557
108107
|
var obligationLedger = new ObligationLedger(OBLIGATION_REPRESENT_MAX, {
|
|
107558
108108
|
onChange: STATIC || !OBLIGATION_LEDGER_ENABLED ? undefined : (snapshot) => persistObligations(OBLIGATION_STORE_PATH, obligationStoreFs, snapshot)
|
|
@@ -108311,7 +108861,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
108311
108861
|
return;
|
|
108312
108862
|
}
|
|
108313
108863
|
},
|
|
108314
|
-
rename: (from, to) =>
|
|
108864
|
+
rename: (from, to) => renameSync32(from, to)
|
|
108315
108865
|
});
|
|
108316
108866
|
appendFileSync11(turnsPath, rec);
|
|
108317
108867
|
} catch {}
|
|
@@ -109882,28 +110432,28 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
109882
110432
|
})();
|
|
109883
110433
|
var statusPinClaims = new Map;
|
|
109884
110434
|
var statusPinRightsCache = new PinRightsCache2;
|
|
109885
|
-
var STATUS_PIN_STORE_PATH =
|
|
110435
|
+
var STATUS_PIN_STORE_PATH = join77(STATE_DIR, "status-pins.json");
|
|
109886
110436
|
var statusPinStoreFs = {
|
|
109887
|
-
readFileSync: (p) =>
|
|
110437
|
+
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
109888
110438
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
109889
|
-
renameSync: (a, b) =>
|
|
109890
|
-
existsSync: (p) =>
|
|
110439
|
+
renameSync: (a, b) => renameSync32(a, b),
|
|
110440
|
+
existsSync: (p) => existsSync65(p)
|
|
109891
110441
|
};
|
|
109892
110442
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
109893
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
110443
|
+
var ACTIVITY_CARD_STORE_PATH = join77(STATE_DIR, "activity-cards-pending.json");
|
|
109894
110444
|
var activityCardStoreFs = {
|
|
109895
|
-
readFileSync: (p) =>
|
|
110445
|
+
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
109896
110446
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
109897
|
-
renameSync: (a, b) =>
|
|
109898
|
-
existsSync: (p) =>
|
|
110447
|
+
renameSync: (a, b) => renameSync32(a, b),
|
|
110448
|
+
existsSync: (p) => existsSync65(p)
|
|
109899
110449
|
};
|
|
109900
110450
|
var activityCardPersistEnabled = !STATIC;
|
|
109901
|
-
var QUEUED_CARD_STORE_PATH =
|
|
110451
|
+
var QUEUED_CARD_STORE_PATH = join77(STATE_DIR, "queued-cards-pending.json");
|
|
109902
110452
|
var queuedCardStoreFs = {
|
|
109903
|
-
readFileSync: (p) =>
|
|
110453
|
+
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
109904
110454
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
109905
|
-
renameSync: (a, b) =>
|
|
109906
|
-
existsSync: (p) =>
|
|
110455
|
+
renameSync: (a, b) => renameSync32(a, b),
|
|
110456
|
+
existsSync: (p) => existsSync65(p)
|
|
109907
110457
|
};
|
|
109908
110458
|
var queuedCardPersistEnabled = !STATIC;
|
|
109909
110459
|
function persistQueuedCard(key, chatId, threadId, messageId) {
|
|
@@ -110186,11 +110736,11 @@ async function unpinAllStatusPins() {
|
|
|
110186
110736
|
}
|
|
110187
110737
|
}
|
|
110188
110738
|
var stalePinSweepEligible = false;
|
|
110189
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
110739
|
+
var STALE_PIN_SWEEP_STORE_PATH = join77(STATE_DIR, "stale-pin-sweep.json");
|
|
110190
110740
|
var sweepStoreFs = {
|
|
110191
|
-
readFileSync: (p) =>
|
|
110741
|
+
readFileSync: (p) => readFileSync67(p, "utf-8"),
|
|
110192
110742
|
writeFileSync: (p, data) => atomicWriteStateFileSync2(p, data, 384),
|
|
110193
|
-
existsSync: (p) =>
|
|
110743
|
+
existsSync: (p) => existsSync65(p)
|
|
110194
110744
|
};
|
|
110195
110745
|
var stalePinSweeper = createGatewayStalePinSweeper({
|
|
110196
110746
|
telegram: { handle: () => lockedBot, call: robustApiCall },
|
|
@@ -110227,12 +110777,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
110227
110777
|
var completeProgressCardTurn = null;
|
|
110228
110778
|
var subagentWatcher = null;
|
|
110229
110779
|
var workerActivityFeed = null;
|
|
110230
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
110780
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join77(STATE_DIR, "gateway.sock");
|
|
110231
110781
|
if (isGatewayMain)
|
|
110232
110782
|
mkdirStateSync2(STATE_DIR, { recursive: true, mode: 448 });
|
|
110233
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
110234
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
110235
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
110783
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join77(STATE_DIR, "gateway.pid.json");
|
|
110784
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join77(STATE_DIR, "gateway-session.json");
|
|
110785
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join77(STATE_DIR, "clean-shutdown.json");
|
|
110236
110786
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
110237
110787
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
110238
110788
|
var activeBootCard = null;
|
|
@@ -110262,7 +110812,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
110262
110812
|
bot: botApi,
|
|
110263
110813
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
110264
110814
|
`),
|
|
110265
|
-
persistPath:
|
|
110815
|
+
persistPath: join77(stateDir, "issues-card.json")
|
|
110266
110816
|
});
|
|
110267
110817
|
activeIssuesWatcher = startIssuesWatcher({
|
|
110268
110818
|
stateDir,
|
|
@@ -110467,13 +111017,13 @@ if (isGatewayMain)
|
|
|
110467
111017
|
var inboundSpool;
|
|
110468
111018
|
if (isGatewayMain)
|
|
110469
111019
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
110470
|
-
path:
|
|
111020
|
+
path: join77(STATE_DIR, "inbound-spool.jsonl"),
|
|
110471
111021
|
fs: {
|
|
110472
111022
|
appendFileSync: (p, d) => appendStateFileSync(p, d),
|
|
110473
|
-
readFileSync: (p) =>
|
|
111023
|
+
readFileSync: (p) => readFileSync67(p, "utf8"),
|
|
110474
111024
|
writeFileSync: (p, d) => writeStateFileSync2(p, d),
|
|
110475
|
-
renameSync: (a, b) =>
|
|
110476
|
-
existsSync: (p) =>
|
|
111025
|
+
renameSync: (a, b) => renameSync32(a, b),
|
|
111026
|
+
existsSync: (p) => existsSync65(p),
|
|
110477
111027
|
statSizeSync: (p) => statSync25(p).size,
|
|
110478
111028
|
fsyncFileSync: fsyncPathSync,
|
|
110479
111029
|
fsyncDirSync: fsyncPathSync
|
|
@@ -110538,13 +111088,13 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
110538
111088
|
let transcriptText;
|
|
110539
111089
|
try {
|
|
110540
111090
|
const projectsDir = getProjectsDirForCwd();
|
|
110541
|
-
const path3 =
|
|
110542
|
-
if (!
|
|
111091
|
+
const path3 = join77(projectsDir, `${sessionId}.jsonl`);
|
|
111092
|
+
if (!existsSync65(path3)) {
|
|
110543
111093
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
110544
111094
|
`);
|
|
110545
111095
|
return;
|
|
110546
111096
|
}
|
|
110547
|
-
transcriptText =
|
|
111097
|
+
transcriptText = readFileSync67(path3, "utf8");
|
|
110548
111098
|
} catch (err) {
|
|
110549
111099
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
|
|
110550
111100
|
`);
|
|
@@ -110638,6 +111188,8 @@ if (isGatewayMain && bootResumeInbound != null) {
|
|
|
110638
111188
|
}
|
|
110639
111189
|
}
|
|
110640
111190
|
}
|
|
111191
|
+
if (isGatewayMain && !bootResumeThrew)
|
|
111192
|
+
markBootResumeComplete(STATE_DIR);
|
|
110641
111193
|
if (isGatewayMain && inboundSpool != null) {
|
|
110642
111194
|
const replay = inboundSpool.liveEntries();
|
|
110643
111195
|
for (const e of replay)
|
|
@@ -110711,8 +111263,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
110711
111263
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
110712
111264
|
isShuttingDown: () => shuttingDown,
|
|
110713
111265
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
110714
|
-
crashLogPath:
|
|
110715
|
-
markerPath:
|
|
111266
|
+
crashLogPath: join77(STATE_DIR, "bridge-crash.log"),
|
|
111267
|
+
markerPath: join77(STATE_DIR, "bridge-dead-escalation.json"),
|
|
110716
111268
|
log: (line) => process.stderr.write(`${line}
|
|
110717
111269
|
`),
|
|
110718
111270
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -110819,8 +111371,8 @@ if (isGatewayMain)
|
|
|
110819
111371
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
110820
111372
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
110821
111373
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
110822
|
-
configSnapshotPath:
|
|
110823
|
-
bootCardStatePath:
|
|
111374
|
+
configSnapshotPath: join77(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
111375
|
+
bootCardStatePath: join77(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
110824
111376
|
floodStatePath: FLOOD_STATE_PATH,
|
|
110825
111377
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
110826
111378
|
}, ackMsgId).then((handle) => {
|
|
@@ -110920,7 +111472,7 @@ if (isGatewayMain)
|
|
|
110920
111472
|
if (turnsDb != null && msg.activeFile != null) {
|
|
110921
111473
|
const stampKey = currentTurn?.registryKey ?? null;
|
|
110922
111474
|
if (stampKey != null && stampKey !== lastSessionStampedTurnKey) {
|
|
110923
|
-
const sessionId =
|
|
111475
|
+
const sessionId = basename19(msg.activeFile).replace(/\.jsonl$/, "");
|
|
110924
111476
|
if (sessionId) {
|
|
110925
111477
|
try {
|
|
110926
111478
|
stampTurnSessionId(turnsDb, stampKey, sessionId);
|
|
@@ -111418,10 +111970,10 @@ if (isGatewayMain)
|
|
|
111418
111970
|
}
|
|
111419
111971
|
},
|
|
111420
111972
|
onPostSkillProposal(_client, msg) {
|
|
111421
|
-
handlePostSkillProposal(msg, { bot, assertAllowedChat, swallowingApiCall });
|
|
111973
|
+
handlePostSkillProposal(msg, { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer });
|
|
111422
111974
|
},
|
|
111423
111975
|
onPostEvalCaseProposal(_client, msg) {
|
|
111424
|
-
handlePostEvalCaseProposal(msg, { bot, assertAllowedChat, swallowingApiCall });
|
|
111976
|
+
handlePostEvalCaseProposal(msg, { bot, assertAllowedChat, swallowingApiCall, deliverResumeSyntheticOrBuffer });
|
|
111425
111977
|
},
|
|
111426
111978
|
onBuzzPublishResult: (_c, m) => getBuzzMirror()?.onPublishResult(m),
|
|
111427
111979
|
log: (msg) => process.stderr.write(`telegram gateway: ipc \u2014 ${msg}
|
|
@@ -111454,7 +112006,7 @@ if (isGatewayMain)
|
|
|
111454
112006
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
111455
112007
|
if (Number.isInteger(receiverUid))
|
|
111456
112008
|
allowedUids.push(receiverUid);
|
|
111457
|
-
const socketPath =
|
|
112009
|
+
const socketPath = join77(STATE_DIR, "webhook.sock");
|
|
111458
112010
|
const webhookInject = (agentName3, inbound) => {
|
|
111459
112011
|
const msg = inbound;
|
|
111460
112012
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -111706,9 +112258,9 @@ function redactOutboundText(text5, site) {
|
|
|
111706
112258
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
111707
112259
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
111708
112260
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
111709
|
-
persistPath:
|
|
112261
|
+
persistPath: join77(STATE_DIR, "voice-ondemand.json")
|
|
111710
112262
|
});
|
|
111711
|
-
var VOICE_CACHE_DIR =
|
|
112263
|
+
var VOICE_CACHE_DIR = join77(STATE_DIR, "voice-cache");
|
|
111712
112264
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
111713
112265
|
runJob: async (job) => {
|
|
111714
112266
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -112116,11 +112668,11 @@ async function executeSendGif(rawArgs) {
|
|
|
112116
112668
|
};
|
|
112117
112669
|
}
|
|
112118
112670
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
112119
|
-
const accountPath =
|
|
112671
|
+
const accountPath = join77(STATE_DIR, "telegraph-account.json");
|
|
112120
112672
|
let account = null;
|
|
112121
112673
|
try {
|
|
112122
|
-
if (
|
|
112123
|
-
const raw =
|
|
112674
|
+
if (existsSync65(accountPath)) {
|
|
112675
|
+
const raw = readFileSync67(accountPath, "utf-8");
|
|
112124
112676
|
const parsed = JSON.parse(raw);
|
|
112125
112677
|
if (parsed.shortName && parsed.accessToken) {
|
|
112126
112678
|
account = parsed;
|
|
@@ -112140,7 +112692,7 @@ async function publishToTelegraph(text5, shortName, authorName) {
|
|
|
112140
112692
|
account = created.value;
|
|
112141
112693
|
try {
|
|
112142
112694
|
mkdirStateSync2(STATE_DIR, { recursive: true, mode: 448 });
|
|
112143
|
-
|
|
112695
|
+
writeFileSync55(accountPath, JSON.stringify(account, null, 2), { mode: 384 });
|
|
112144
112696
|
} catch (err) {
|
|
112145
112697
|
process.stderr.write(`telegram gateway: telegraph cache write failed: ${err.message}
|
|
112146
112698
|
`);
|
|
@@ -112256,7 +112808,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
|
|
|
112256
112808
|
}
|
|
112257
112809
|
function readLiveSwitchroomConfigText() {
|
|
112258
112810
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
112259
|
-
return
|
|
112811
|
+
return readFileSync67(cfgPath, "utf8");
|
|
112260
112812
|
}
|
|
112261
112813
|
async function executeReact(args) {
|
|
112262
112814
|
if (!args.chat_id)
|
|
@@ -112297,7 +112849,7 @@ async function executeDownloadAttachment(args) {
|
|
|
112297
112849
|
});
|
|
112298
112850
|
mkdirSync50(INBOX_DIR, { recursive: true, mode: 448 });
|
|
112299
112851
|
assertInsideInbox2(INBOX_DIR, dlPath);
|
|
112300
|
-
|
|
112852
|
+
writeFileSync55(dlPath, buf, { mode: 384 });
|
|
112301
112853
|
return { content: [{ type: "text", text: dlPath }] };
|
|
112302
112854
|
}
|
|
112303
112855
|
async function executeEditMessage(args) {
|
|
@@ -113653,7 +114205,7 @@ function getMyAgentName() {
|
|
|
113653
114205
|
const fromEnv = process.env.SWITCHROOM_AGENT_NAME;
|
|
113654
114206
|
if (fromEnv && fromEnv.trim().length > 0)
|
|
113655
114207
|
return fromEnv.trim();
|
|
113656
|
-
return
|
|
114208
|
+
return basename19(process.cwd());
|
|
113657
114209
|
}
|
|
113658
114210
|
function isSelfTargetingCommand(name) {
|
|
113659
114211
|
if (name === "all")
|
|
@@ -113666,14 +114218,14 @@ function restartMarkerPath() {
|
|
|
113666
114218
|
const agentDir = resolveAgentDirFromEnv();
|
|
113667
114219
|
if (!agentDir)
|
|
113668
114220
|
return null;
|
|
113669
|
-
return
|
|
114221
|
+
return join77(agentDir, "restart-pending.json");
|
|
113670
114222
|
}
|
|
113671
114223
|
function writeRestartMarker(marker) {
|
|
113672
114224
|
const p = restartMarkerPath();
|
|
113673
114225
|
if (!p)
|
|
113674
114226
|
return;
|
|
113675
114227
|
try {
|
|
113676
|
-
|
|
114228
|
+
writeFileSync55(p, JSON.stringify(marker));
|
|
113677
114229
|
lastPlannedRestartAt = Date.now();
|
|
113678
114230
|
process.stderr.write(`telegram gateway: restart-marker: write chat_id=${marker.chat_id} thread_id=${marker.thread_id ?? "-"} ack=${marker.ack_message_id ?? "-"} path=${p}
|
|
113679
114231
|
`);
|
|
@@ -113692,7 +114244,7 @@ function readRestartMarker() {
|
|
|
113692
114244
|
if (!p)
|
|
113693
114245
|
return null;
|
|
113694
114246
|
try {
|
|
113695
|
-
return JSON.parse(
|
|
114247
|
+
return JSON.parse(readFileSync67(p, "utf8"));
|
|
113696
114248
|
} catch {
|
|
113697
114249
|
return null;
|
|
113698
114250
|
}
|
|
@@ -113841,7 +114393,7 @@ var _dockerReachable;
|
|
|
113841
114393
|
function isDockerReachable() {
|
|
113842
114394
|
if (_dockerReachable !== undefined)
|
|
113843
114395
|
return _dockerReachable;
|
|
113844
|
-
if (!
|
|
114396
|
+
if (!existsSync65("/var/run/docker.sock")) {
|
|
113845
114397
|
_dockerReachable = false;
|
|
113846
114398
|
return _dockerReachable;
|
|
113847
114399
|
}
|
|
@@ -113858,12 +114410,12 @@ function _resetDockerReachableCache() {
|
|
|
113858
114410
|
}
|
|
113859
114411
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
113860
114412
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
113861
|
-
const logPath =
|
|
114413
|
+
const logPath = join77(STATE_DIR, "detached-spawn.log");
|
|
113862
114414
|
let outFd = null;
|
|
113863
114415
|
try {
|
|
113864
114416
|
mkdirStateSync2(STATE_DIR, { recursive: true });
|
|
113865
114417
|
outFd = openSync18(logPath, "a");
|
|
113866
|
-
|
|
114418
|
+
writeFileSync55(logPath, `
|
|
113867
114419
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
113868
114420
|
`, { flag: "a" });
|
|
113869
114421
|
} catch {}
|
|
@@ -113889,7 +114441,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
113889
114441
|
return;
|
|
113890
114442
|
let tail = "";
|
|
113891
114443
|
try {
|
|
113892
|
-
const full =
|
|
114444
|
+
const full = readFileSync67(logPath, "utf8");
|
|
113893
114445
|
tail = full.split(`
|
|
113894
114446
|
`).slice(-30).join(`
|
|
113895
114447
|
`).trim();
|
|
@@ -114151,10 +114703,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
114151
114703
|
}
|
|
114152
114704
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
114153
114705
|
try {
|
|
114154
|
-
const auditPath =
|
|
114155
|
-
if (!
|
|
114706
|
+
const auditPath = join77(homedir22(), ".switchroom", "vault-audit.log");
|
|
114707
|
+
if (!existsSync65(auditPath))
|
|
114156
114708
|
return [];
|
|
114157
|
-
const raw =
|
|
114709
|
+
const raw = readFileSync67(auditPath, "utf8");
|
|
114158
114710
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
114159
114711
|
} catch {
|
|
114160
114712
|
return [];
|
|
@@ -114205,7 +114757,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
114205
114757
|
try {
|
|
114206
114758
|
const agentDir = resolveAgentDirFromEnv();
|
|
114207
114759
|
if (agentDir) {
|
|
114208
|
-
const raw =
|
|
114760
|
+
const raw = readFileSync67(join77(agentDir, ".claude", ".claude.json"), "utf8");
|
|
114209
114761
|
claudeJson = JSON.parse(raw);
|
|
114210
114762
|
}
|
|
114211
114763
|
} catch {}
|
|
@@ -114334,7 +114886,7 @@ function buildModelDeps(restartCtx) {
|
|
|
114334
114886
|
try {
|
|
114335
114887
|
const agentDir = resolveAgentDirFromEnv();
|
|
114336
114888
|
if (agentDir) {
|
|
114337
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
114889
|
+
const local = await fetchQuota2({ claudeConfigDir: join77(agentDir, ".claude") });
|
|
114338
114890
|
if (local.ok)
|
|
114339
114891
|
return formatQuotaLine2(local.data);
|
|
114340
114892
|
}
|
|
@@ -114581,10 +115133,10 @@ function effortMenuReplyMarkup(reply) {
|
|
|
114581
115133
|
function flushAgentHandoff(agentDir) {
|
|
114582
115134
|
let removed = 0;
|
|
114583
115135
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
114584
|
-
const p =
|
|
115136
|
+
const p = join77(agentDir, fname);
|
|
114585
115137
|
try {
|
|
114586
|
-
if (
|
|
114587
|
-
|
|
115138
|
+
if (existsSync65(p)) {
|
|
115139
|
+
unlinkSync33(p);
|
|
114588
115140
|
removed++;
|
|
114589
115141
|
}
|
|
114590
115142
|
} catch (err) {
|
|
@@ -114639,7 +115191,7 @@ async function handleNewCommand(ctx) {
|
|
|
114639
115191
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
114640
115192
|
if (agentDir != null) {
|
|
114641
115193
|
try {
|
|
114642
|
-
|
|
115194
|
+
writeFileSync55(join77(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
114643
115195
|
`, "utf8");
|
|
114644
115196
|
} catch (err) {
|
|
114645
115197
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -114752,16 +115304,16 @@ function buildFolderPickerDeps() {
|
|
|
114752
115304
|
};
|
|
114753
115305
|
}
|
|
114754
115306
|
var lockoutOps = {
|
|
114755
|
-
readFileSync: (p, enc) =>
|
|
115307
|
+
readFileSync: (p, enc) => readFileSync67(p, enc),
|
|
114756
115308
|
writeFileSync: (p, data, opts) => writeStateFileSync2(p, data, opts),
|
|
114757
|
-
existsSync: (p) =>
|
|
115309
|
+
existsSync: (p) => existsSync65(p),
|
|
114758
115310
|
mkdirSync: (p, opts) => mkdirStateSync2(p, opts),
|
|
114759
|
-
joinPath: (...parts) =>
|
|
115311
|
+
joinPath: (...parts) => join77(...parts)
|
|
114760
115312
|
};
|
|
114761
115313
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
114762
115314
|
function isAuthBrokerSocketReachable() {
|
|
114763
115315
|
try {
|
|
114764
|
-
return
|
|
115316
|
+
return existsSync65(resolveAuthBrokerSocketPath2());
|
|
114765
115317
|
} catch {
|
|
114766
115318
|
return false;
|
|
114767
115319
|
}
|
|
@@ -115017,7 +115569,7 @@ async function runCreditWatch() {
|
|
|
115017
115569
|
if (!agentDir)
|
|
115018
115570
|
return;
|
|
115019
115571
|
const agentName3 = getMyAgentName();
|
|
115020
|
-
const claudeConfigDir =
|
|
115572
|
+
const claudeConfigDir = join77(agentDir, ".claude");
|
|
115021
115573
|
const stateDir = STATE_DIR;
|
|
115022
115574
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
115023
115575
|
const prev = loadCreditState(stateDir);
|
|
@@ -116787,7 +117339,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
116787
117339
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
116788
117340
|
return;
|
|
116789
117341
|
}
|
|
116790
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
117342
|
+
const result = await fetchQuota2({ claudeConfigDir: join77(agentDir, ".claude") });
|
|
116791
117343
|
if (!result.ok) {
|
|
116792
117344
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
116793
117345
|
return;
|
|
@@ -117178,7 +117730,7 @@ ${interimLabel}` : interimLabel
|
|
|
117178
117730
|
const unifiedDiff = (() => {
|
|
117179
117731
|
try {
|
|
117180
117732
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
117181
|
-
const raw =
|
|
117733
|
+
const raw = readFileSync67(cfgPath, "utf8");
|
|
117182
117734
|
return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
|
|
117183
117735
|
} catch (err) {
|
|
117184
117736
|
process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
|
|
@@ -118053,7 +118605,7 @@ async function startGateway() {
|
|
|
118053
118605
|
return;
|
|
118054
118606
|
}
|
|
118055
118607
|
})();
|
|
118056
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
118608
|
+
const resolvedAgentDirForBootCard = agentDir ?? join77(homedir22(), ".switchroom", "agents", agentSlug);
|
|
118057
118609
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
118058
118610
|
agentName: agentDisplayName,
|
|
118059
118611
|
agentSlug,
|
|
@@ -118067,8 +118619,8 @@ async function startGateway() {
|
|
|
118067
118619
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
118068
118620
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
118069
118621
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
118070
|
-
configSnapshotPath:
|
|
118071
|
-
bootCardStatePath:
|
|
118622
|
+
configSnapshotPath: join77(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
118623
|
+
bootCardStatePath: join77(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
118072
118624
|
floodStatePath: FLOOD_STATE_PATH,
|
|
118073
118625
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
118074
118626
|
}, ackMsgId);
|
|
@@ -118101,7 +118653,7 @@ async function startGateway() {
|
|
|
118101
118653
|
if (smAgentDir) {
|
|
118102
118654
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
118103
118655
|
const resolved = await waitForSessionModelResolution({
|
|
118104
|
-
barrierExists: () =>
|
|
118656
|
+
barrierExists: () => existsSync65(join77(smAgentDir, ".session-model-resolved")),
|
|
118105
118657
|
timeoutMs: resolutionTimeoutMs
|
|
118106
118658
|
});
|
|
118107
118659
|
if (!resolved) {
|
|
@@ -118109,10 +118661,10 @@ async function startGateway() {
|
|
|
118109
118661
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
118110
118662
|
`);
|
|
118111
118663
|
} else {
|
|
118112
|
-
const activePath =
|
|
118113
|
-
if (
|
|
118664
|
+
const activePath = join77(smAgentDir, ".active-session-model");
|
|
118665
|
+
if (existsSync65(activePath)) {
|
|
118114
118666
|
try {
|
|
118115
|
-
const launched =
|
|
118667
|
+
const launched = readFileSync67(activePath, "utf8").trim();
|
|
118116
118668
|
const configured = (() => {
|
|
118117
118669
|
const d = switchroomExecJson(["agent", "list"]);
|
|
118118
118670
|
const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
|
|
@@ -118145,29 +118697,29 @@ async function startGateway() {
|
|
|
118145
118697
|
deliverModelSwitchBootNotice({
|
|
118146
118698
|
...modelBootCardDeps,
|
|
118147
118699
|
confirmation,
|
|
118148
|
-
hasSessionModelAlert:
|
|
118700
|
+
hasSessionModelAlert: existsSync65(join77(smAgentDir, ".session-model-alert"))
|
|
118149
118701
|
});
|
|
118150
118702
|
}
|
|
118151
118703
|
} catch {}
|
|
118152
118704
|
}
|
|
118153
|
-
const activeEffortPath =
|
|
118154
|
-
if (
|
|
118705
|
+
const activeEffortPath = join77(smAgentDir, ".active-session-effort");
|
|
118706
|
+
if (existsSync65(activeEffortPath)) {
|
|
118155
118707
|
try {
|
|
118156
|
-
const launchedEffort =
|
|
118708
|
+
const launchedEffort = readFileSync67(activeEffortPath, "utf8").trim();
|
|
118157
118709
|
const configuredEffort = getConfiguredEffortForPersist();
|
|
118158
118710
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
118159
118711
|
} catch {}
|
|
118160
118712
|
}
|
|
118161
|
-
const alertPath =
|
|
118162
|
-
if (
|
|
118713
|
+
const alertPath = join77(smAgentDir, ".session-model-alert");
|
|
118714
|
+
if (existsSync65(alertPath)) {
|
|
118163
118715
|
let alertText = null;
|
|
118164
118716
|
try {
|
|
118165
|
-
alertText =
|
|
118717
|
+
alertText = readFileSync67(alertPath, "utf8").trim();
|
|
118166
118718
|
} catch {
|
|
118167
118719
|
alertText = null;
|
|
118168
118720
|
}
|
|
118169
118721
|
try {
|
|
118170
|
-
|
|
118722
|
+
unlinkSync33(alertPath);
|
|
118171
118723
|
} catch {}
|
|
118172
118724
|
if (alertText && alertText.length > 0) {
|
|
118173
118725
|
const operators = loadAccess().allowFrom;
|