switchroom 0.19.38 → 0.19.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-scheduler/index.js +10 -1
- package/dist/auth-broker/index.js +15 -6
- package/dist/cli/notion-write-pretool.mjs +10 -1
- package/dist/cli/switchroom.js +1141 -566
- package/dist/host-control/main.js +220 -8
- package/dist/vault/approvals/kernel-server.js +15 -6
- package/dist/vault/broker/server.js +15 -6
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +10 -0
- package/telegram-plugin/dist/bridge/bridge.js +8 -0
- package/telegram-plugin/dist/gateway/gateway.js +450 -206
- package/telegram-plugin/dist/server.js +8 -0
- package/telegram-plugin/gateway/backstop-delivery.ts +48 -0
- package/telegram-plugin/gateway/compaction-marker.ts +84 -0
- package/telegram-plugin/gateway/gateway.ts +3 -3
- package/telegram-plugin/gateway/handback-preturn-signal.ts +16 -0
- package/telegram-plugin/gateway/liveness-wiring.ts +15 -0
- package/telegram-plugin/gateway/outbound-send-path.ts +20 -0
- package/telegram-plugin/gateway/outbox-sweep.ts +116 -18
- package/telegram-plugin/gateway/silence-poke-session-event.ts +13 -0
- package/telegram-plugin/gateway/stream-render.ts +277 -18
- package/telegram-plugin/hooks/compaction-marker-precompact.mjs +70 -0
- package/telegram-plugin/hooks/hooks.json +11 -0
- package/telegram-plugin/hooks/tool-label-pretool.mjs +119 -1
- package/telegram-plugin/session-tail.ts +20 -0
- package/telegram-plugin/silence-poke.ts +28 -0
- package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +19 -12
- package/telegram-plugin/tests/fixtures/pretool-main-2.1.219.json +15 -0
- package/telegram-plugin/tests/fixtures/pretool-subagent-2.1.219.json +16 -0
- package/telegram-plugin/tests/outbox-delivery.test.ts +38 -1
- package/telegram-plugin/tests/outbox-flush-ack-claim-race.test.ts +213 -0
- package/telegram-plugin/tests/outbox-reply-then-recap-e2e.test.ts +1 -1
- package/telegram-plugin/tests/outbox-sweep-flood-breaker.test.ts +4 -4
- package/telegram-plugin/tests/outbox-sweep-listen-button.test.ts +71 -8
- package/telegram-plugin/tests/queued-card-surface.test.ts +262 -0
- package/telegram-plugin/tests/send-reply-golden.test.ts +47 -0
- package/telegram-plugin/tests/sidechain-label-filter-pretool.test.ts +272 -0
- package/telegram-plugin/tests/silence-poke-compaction.test.ts +222 -0
- package/vendor/hindsight-memory/scripts/lib/client.py +7 -4
- package/vendor/hindsight-memory/scripts/lib/config.py +151 -0
- package/vendor/hindsight-memory/scripts/retain.py +19 -15
- package/vendor/hindsight-memory/scripts/tests/test_backfill.py +14 -1
- package/vendor/hindsight-memory/scripts/tests/test_observation_scopes.py +192 -3
- package/vendor/hindsight-memory/scripts/tests/test_reconcile_durability.py +18 -2
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +57 -4
|
@@ -21726,7 +21726,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
21726
21726
|
});
|
|
21727
21727
|
|
|
21728
21728
|
// ../src/memory/observation-scopes.ts
|
|
21729
|
-
var OBSERVATION_SCOPES;
|
|
21729
|
+
var OBSERVATION_SCOPES, OBSERVATION_SCOPE_STRATEGIES;
|
|
21730
21730
|
var init_observation_scopes = __esm(() => {
|
|
21731
21731
|
OBSERVATION_SCOPES = [
|
|
21732
21732
|
"per_tag",
|
|
@@ -21734,10 +21734,16 @@ var init_observation_scopes = __esm(() => {
|
|
|
21734
21734
|
"all_combinations",
|
|
21735
21735
|
"shared"
|
|
21736
21736
|
];
|
|
21737
|
+
OBSERVATION_SCOPE_STRATEGIES = [
|
|
21738
|
+
"curated",
|
|
21739
|
+
"shared",
|
|
21740
|
+
"combined",
|
|
21741
|
+
"off"
|
|
21742
|
+
];
|
|
21737
21743
|
});
|
|
21738
21744
|
|
|
21739
21745
|
// ../src/config/schema.ts
|
|
21740
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
21746
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
21741
21747
|
var init_schema = __esm(() => {
|
|
21742
21748
|
init_zod();
|
|
21743
21749
|
init_observation_scopes();
|
|
@@ -21852,7 +21858,8 @@ var init_schema = __esm(() => {
|
|
|
21852
21858
|
allow: exports_external.array(exports_external.string()).default([]).describe("Allowed tools (use ['all'] for unrestricted)"),
|
|
21853
21859
|
deny: exports_external.array(exports_external.string()).default([]).describe("Denied tools (overrides allow)")
|
|
21854
21860
|
}).optional();
|
|
21855
|
-
ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("
|
|
21861
|
+
ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("Operator PIN for the per-row observation scope, overriding the " + 'default `curated` strategy (see docs/configuration.md). "shared" ' + "forces Hindsight's consolidation to write EVERY observation into ONE " + "global untagged scope \u2014 what several agents pooling one bank want so " + "their observations merge rather than sitting in parallel silos. " + '"combined" is the pin form of opting out (restores the pre-#4035 ' + "engine default). UNSET does NOT mean 'nothing on the wire': the " + "`curated` strategy still computes a scope per retain. Applies to " + "every retain path (Stop hook, " + "sidechain, boot reconcile, queue drain, backfill, session-handoff " + "mirror) and is carried on the queued payload, so a retain that fails " + "now and drains later still lands in this scope. Accepted values: " + `${OBSERVATION_SCOPES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
21862
|
+
ObservationScopeStrategySchema = exports_external.enum(OBSERVATION_SCOPE_STRATEGIES).optional().describe("Per-retain strategy that decides how the observation scope is " + 'computed when no `observation_scopes` pin is set. "curated" ' + "(the default since #4035) strips volatile per-session provenance " + "tags from each retain's consolidation scope \u2014 keeping the stable " + "semantic ones on the source fact \u2014 so an agent's observations dedup " + "and merge across sessions instead of pocketing one-per-session. " + '"shared" sends every retain to the one global untagged scope. ' + '"combined" / "off" opt OUT: no per-row scope goes on the wire, ' + "restoring the pre-feature engine default (byte-identical to an " + "unconfigured client). OMITTED BY DEFAULT: unset leaves the plugin's " + "own default (`curated`) in force. A manual `observation_scopes` pin " + "wins over this strategy. Accepted values: " + `${OBSERVATION_SCOPE_STRATEGIES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
21856
21863
|
AgentMemorySchema = exports_external.object({
|
|
21857
21864
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
21858
21865
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
@@ -21888,6 +21895,7 @@ var init_schema = __esm(() => {
|
|
|
21888
21895
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis \u2014 a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
21889
21896
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true \u2014 Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never \u2026", "from now on \u2026", ' + `"stop doing \u2026", a stated preference, "that's wrong, it's \u2026") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex \u2014 the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
21890
21897
|
observation_scopes: ObservationScopesSchema,
|
|
21898
|
+
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
21891
21899
|
recall: exports_external.object({
|
|
21892
21900
|
max_memories: exports_external.number().int().min(0).optional().describe("Cap on the number of memories injected into the prompt by " + "auto-recall, regardless of token budget. Plugin default is 12. " + "0 disables the cap (all memories Hindsight returns are injected)."),
|
|
21893
21901
|
cache_ttl_secs: exports_external.number().int().min(0).optional().describe("Per-session recall cache TTL in seconds. When > 0, identical " + "(prompt, bank) within the same session reuse the cached recall " + "result instead of round-tripping to Hindsight. 0 disables. " + "Default is 600 (10 min) for switchroom-managed agents."),
|
|
@@ -22288,6 +22296,7 @@ var init_schema = __esm(() => {
|
|
|
22288
22296
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
22289
22297
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
22290
22298
|
observation_scopes: ObservationScopesSchema,
|
|
22299
|
+
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
22291
22300
|
recall: exports_external.object({
|
|
22292
22301
|
max_memories: exports_external.number().int().min(0).optional(),
|
|
22293
22302
|
cache_ttl_secs: exports_external.number().int().min(0).optional(),
|
|
@@ -35875,9 +35884,9 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
|
|
|
35875
35884
|
|
|
35876
35885
|
// gateway/quota-cache.ts
|
|
35877
35886
|
import { existsSync as existsSync44, readFileSync as readFileSync44, writeFileSync as writeFileSync37, mkdirSync as mkdirSync39 } from "fs";
|
|
35878
|
-
import { join as
|
|
35887
|
+
import { join as join54, dirname as dirname22 } from "path";
|
|
35879
35888
|
function defaultCachePath() {
|
|
35880
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
35889
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join54(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
35881
35890
|
}
|
|
35882
35891
|
function readQuotaCache(opts = {}) {
|
|
35883
35892
|
const path3 = opts.path ?? defaultCachePath();
|
|
@@ -35924,7 +35933,7 @@ var init_quota_cache = __esm(() => {
|
|
|
35924
35933
|
|
|
35925
35934
|
// gateway/boot-probes.ts
|
|
35926
35935
|
import { readFileSync as readFileSync45, readdirSync as readdirSync12, existsSync as existsSync45 } from "fs";
|
|
35927
|
-
import { join as
|
|
35936
|
+
import { join as join55 } from "path";
|
|
35928
35937
|
import { execFile as execFileCb } from "child_process";
|
|
35929
35938
|
import { promisify } from "util";
|
|
35930
35939
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -35966,8 +35975,8 @@ function mapPlan(billingType, hasExtra) {
|
|
|
35966
35975
|
}
|
|
35967
35976
|
async function probeAccount(agentDir) {
|
|
35968
35977
|
return withTimeout("Account", (async () => {
|
|
35969
|
-
const claudeDir =
|
|
35970
|
-
const claudeJsonPath =
|
|
35978
|
+
const claudeDir = join55(agentDir, ".claude");
|
|
35979
|
+
const claudeJsonPath = join55(claudeDir, ".claude.json");
|
|
35971
35980
|
let cfg = {};
|
|
35972
35981
|
try {
|
|
35973
35982
|
const raw = readFileSync45(claudeJsonPath, "utf8");
|
|
@@ -35988,8 +35997,8 @@ async function probeAccount(agentDir) {
|
|
|
35988
35997
|
let tokenStr = "";
|
|
35989
35998
|
let status = "ok";
|
|
35990
35999
|
for (const candidate of [
|
|
35991
|
-
|
|
35992
|
-
|
|
36000
|
+
join55(claudeDir, ".oauth-token.meta.json"),
|
|
36001
|
+
join55(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
35993
36002
|
]) {
|
|
35994
36003
|
if (existsSync45(candidate)) {
|
|
35995
36004
|
try {
|
|
@@ -36375,9 +36384,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
36375
36384
|
let claudeDirForProbe = null;
|
|
36376
36385
|
for (const candidate of [
|
|
36377
36386
|
claudeConfigDir,
|
|
36378
|
-
|
|
36387
|
+
join55(claudeConfigDir, "accounts", "default")
|
|
36379
36388
|
]) {
|
|
36380
|
-
if (existsSync45(
|
|
36389
|
+
if (existsSync45(join55(candidate, ".oauth-token"))) {
|
|
36381
36390
|
claudeDirForProbe = candidate;
|
|
36382
36391
|
break;
|
|
36383
36392
|
}
|
|
@@ -36612,7 +36621,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
36612
36621
|
return withTimeout("Skills", (async () => {
|
|
36613
36622
|
const fs3 = opts.fs ?? realSkillsFs;
|
|
36614
36623
|
const max = opts.maxNamesShown ?? 3;
|
|
36615
|
-
const skillsDir =
|
|
36624
|
+
const skillsDir = join55(agentDir, ".claude", "skills");
|
|
36616
36625
|
if (!fs3.exists(skillsDir)) {
|
|
36617
36626
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
36618
36627
|
}
|
|
@@ -36627,17 +36636,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
36627
36636
|
}
|
|
36628
36637
|
const dangling = [];
|
|
36629
36638
|
for (const name of entries) {
|
|
36630
|
-
const skillPath =
|
|
36639
|
+
const skillPath = join55(skillsDir, name);
|
|
36631
36640
|
if (!fs3.exists(skillPath)) {
|
|
36632
36641
|
dangling.push(name);
|
|
36633
36642
|
continue;
|
|
36634
36643
|
}
|
|
36635
|
-
const skillMd =
|
|
36644
|
+
const skillMd = join55(skillPath, "SKILL.md");
|
|
36636
36645
|
if (!fs3.exists(skillMd) && !fs3.exists(skillPath + ".md")) {
|
|
36637
36646
|
continue;
|
|
36638
36647
|
}
|
|
36639
36648
|
}
|
|
36640
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
36649
|
+
const overlayDir = opts.overlaySkillsDir ?? join55(agentDir, "skills.d");
|
|
36641
36650
|
const overlaySlugs = new Set;
|
|
36642
36651
|
if (fs3.exists(overlayDir)) {
|
|
36643
36652
|
let overlayEntries = [];
|
|
@@ -36679,7 +36688,7 @@ function renderBucketedSkills(switchroom, agent) {
|
|
|
36679
36688
|
}
|
|
36680
36689
|
async function probeConnections(agentDir, opts = {}) {
|
|
36681
36690
|
return withTimeout("Connections", (async () => {
|
|
36682
|
-
const path3 =
|
|
36691
|
+
const path3 = join55(agentDir, ".claude", "connection-health.json");
|
|
36683
36692
|
const read = opts.readFileImpl ?? ((p) => readFileSync45(p, "utf8"));
|
|
36684
36693
|
let issues = [];
|
|
36685
36694
|
try {
|
|
@@ -36720,7 +36729,7 @@ async function probeDrift(agentDir, opts = {}) {
|
|
|
36720
36729
|
}
|
|
36721
36730
|
} catch {}
|
|
36722
36731
|
try {
|
|
36723
|
-
const raw = readFileSync45(
|
|
36732
|
+
const raw = readFileSync45(join55(agentDir, ".switchroom-drift.json"), "utf8");
|
|
36724
36733
|
const report = JSON.parse(raw);
|
|
36725
36734
|
if (report?.version === 1 && Array.isArray(report.findings)) {
|
|
36726
36735
|
const gen = report.generatedAt ? Date.parse(report.generatedAt) : NaN;
|
|
@@ -36772,8 +36781,8 @@ var init_boot_probes = __esm(() => {
|
|
|
36772
36781
|
realSchedulerFs = {
|
|
36773
36782
|
readFile: (p) => readFileSync45(p, "utf-8"),
|
|
36774
36783
|
mtimeMs: (p) => {
|
|
36775
|
-
const { statSync:
|
|
36776
|
-
return
|
|
36784
|
+
const { statSync: statSync17 } = __require("fs");
|
|
36785
|
+
return statSync17(p).mtimeMs;
|
|
36777
36786
|
},
|
|
36778
36787
|
exists: (p) => existsSync45(p)
|
|
36779
36788
|
};
|
|
@@ -37080,8 +37089,8 @@ __export(exports_boot_card, {
|
|
|
37080
37089
|
readRoutingMode: () => readRoutingMode,
|
|
37081
37090
|
containerBootStartMs: () => containerBootStartMs
|
|
37082
37091
|
});
|
|
37083
|
-
import { join as
|
|
37084
|
-
import { readFileSync as readFileSync49, statSync as
|
|
37092
|
+
import { join as join56 } from "path";
|
|
37093
|
+
import { readFileSync as readFileSync49, statSync as statSync17 } from "fs";
|
|
37085
37094
|
function resolvePersonaName(slug, loadConfig3) {
|
|
37086
37095
|
try {
|
|
37087
37096
|
const config = loadConfig3 ? loadConfig3() : loadConfig();
|
|
@@ -37124,8 +37133,8 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync49 }) {
|
|
|
37124
37133
|
return null;
|
|
37125
37134
|
}
|
|
37126
37135
|
}
|
|
37127
|
-
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync:
|
|
37128
|
-
const path3 =
|
|
37136
|
+
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync49, statSync: statSync17 }) {
|
|
37137
|
+
const path3 = join56(agentDir, ".routing-mode");
|
|
37129
37138
|
try {
|
|
37130
37139
|
const raw = fsImpl.readFileSync(path3, "utf-8");
|
|
37131
37140
|
const line = raw.split(`
|
|
@@ -37232,7 +37241,7 @@ function renderBootCard(opts) {
|
|
|
37232
37241
|
return stackCardLines(flatLines);
|
|
37233
37242
|
}
|
|
37234
37243
|
async function runAllProbes(opts) {
|
|
37235
|
-
const claudeDir =
|
|
37244
|
+
const claudeDir = join56(opts.agentDir, ".claude");
|
|
37236
37245
|
const probes = {};
|
|
37237
37246
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
37238
37247
|
await Promise.allSettled([
|
|
@@ -38094,7 +38103,7 @@ __export(exports_tmux2, {
|
|
|
38094
38103
|
captureAgentPane: () => captureAgentPane2
|
|
38095
38104
|
});
|
|
38096
38105
|
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
38097
|
-
import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as
|
|
38106
|
+
import { chmodSync as chmodSync13, mkdirSync as mkdirSync50, readdirSync as readdirSync15, statSync as statSync22, unlinkSync as unlinkSync30, writeFileSync as writeFileSync49 } from "node:fs";
|
|
38098
38107
|
import { resolve as resolve12 } from "node:path";
|
|
38099
38108
|
function captureAgentPane2(opts) {
|
|
38100
38109
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -38223,13 +38232,13 @@ function pruneOldReports2(dir, retain) {
|
|
|
38223
38232
|
const full = resolve12(dir, n);
|
|
38224
38233
|
let mtimeMs = 0;
|
|
38225
38234
|
try {
|
|
38226
|
-
mtimeMs =
|
|
38235
|
+
mtimeMs = statSync22(full).mtimeMs;
|
|
38227
38236
|
} catch {}
|
|
38228
38237
|
return { full, mtimeMs };
|
|
38229
38238
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
38230
38239
|
for (const stale of files.slice(retain)) {
|
|
38231
38240
|
try {
|
|
38232
|
-
|
|
38241
|
+
unlinkSync30(stale.full);
|
|
38233
38242
|
} catch {}
|
|
38234
38243
|
}
|
|
38235
38244
|
}
|
|
@@ -39203,14 +39212,14 @@ import {
|
|
|
39203
39212
|
mkdirSync as mkdirSync51,
|
|
39204
39213
|
readdirSync as readdirSync16,
|
|
39205
39214
|
rmSync as rmSync8,
|
|
39206
|
-
statSync as
|
|
39215
|
+
statSync as statSync23,
|
|
39207
39216
|
renameSync as renameSync27,
|
|
39208
39217
|
realpathSync as realpathSync4,
|
|
39209
39218
|
chmodSync as chmodSync14,
|
|
39210
39219
|
openSync as openSync15,
|
|
39211
39220
|
closeSync as closeSync15,
|
|
39212
39221
|
existsSync as existsSync57,
|
|
39213
|
-
unlinkSync as
|
|
39222
|
+
unlinkSync as unlinkSync31,
|
|
39214
39223
|
appendFileSync as appendFileSync9
|
|
39215
39224
|
} from "fs";
|
|
39216
39225
|
|
|
@@ -39264,8 +39273,8 @@ function fsyncPathSync(path) {
|
|
|
39264
39273
|
}
|
|
39265
39274
|
|
|
39266
39275
|
// gateway/gateway.ts
|
|
39267
|
-
import { homedir as
|
|
39268
|
-
import { join as
|
|
39276
|
+
import { homedir as homedir20 } from "os";
|
|
39277
|
+
import { join as join69, sep as sep4, basename as basename17 } from "path";
|
|
39269
39278
|
|
|
39270
39279
|
// plugin-logger.ts
|
|
39271
39280
|
import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
|
|
@@ -47609,6 +47618,23 @@ function computeLabel(toolName, input) {
|
|
|
47609
47618
|
}
|
|
47610
47619
|
return "Working\u2026";
|
|
47611
47620
|
}
|
|
47621
|
+
function isSubagentToolCall(event) {
|
|
47622
|
+
if (!event || typeof event !== "object")
|
|
47623
|
+
return false;
|
|
47624
|
+
const at = event.agent_type;
|
|
47625
|
+
if (typeof at === "string" && at.length > 0)
|
|
47626
|
+
return at !== "main";
|
|
47627
|
+
const aid = event.agent_id;
|
|
47628
|
+
const sid = event.session_id;
|
|
47629
|
+
return typeof aid === "string" && aid.length > 0 && typeof sid === "string" && sid.length > 0 && aid !== sid;
|
|
47630
|
+
}
|
|
47631
|
+
function hasAttributionSignal(event) {
|
|
47632
|
+
if (!event || typeof event !== "object")
|
|
47633
|
+
return false;
|
|
47634
|
+
const at = event.agent_type;
|
|
47635
|
+
const aid = event.agent_id;
|
|
47636
|
+
return typeof at === "string" && at.length > 0 || typeof aid === "string" && aid.length > 0;
|
|
47637
|
+
}
|
|
47612
47638
|
function main() {
|
|
47613
47639
|
const raw = readStdin().trim();
|
|
47614
47640
|
if (!raw)
|
|
@@ -47627,6 +47653,14 @@ function main() {
|
|
|
47627
47653
|
const toolName = event.tool_name;
|
|
47628
47654
|
if (!sessionId || !toolUseId || !toolName)
|
|
47629
47655
|
process.exit(0);
|
|
47656
|
+
if (!hasAttributionSignal(event)) {
|
|
47657
|
+
try {
|
|
47658
|
+
process.stderr.write(`[tool-label-pretool] WARNING: PreToolUse payload carries neither ` + `agent_type nor agent_id \u2014 the sidechain-attribution invariant may be ` + `broken by a Claude Code schema change; sub-agent labels may be ` + `mis-attributed to the parent session (tool_use_id=${toolUseId}).
|
|
47659
|
+
`);
|
|
47660
|
+
} catch {}
|
|
47661
|
+
}
|
|
47662
|
+
if (isSubagentToolCall(event))
|
|
47663
|
+
process.exit(0);
|
|
47630
47664
|
let label;
|
|
47631
47665
|
try {
|
|
47632
47666
|
label = computeLabel(toolName, event.tool_input);
|
|
@@ -53507,6 +53541,13 @@ function createHandbackPreturnSignal(deps) {
|
|
|
53507
53541
|
dropEntry(entry);
|
|
53508
53542
|
return adoption;
|
|
53509
53543
|
},
|
|
53544
|
+
hasPendingForTurnId(turnId) {
|
|
53545
|
+
for (const e of byKey.values()) {
|
|
53546
|
+
if (e.adoptTurnId === turnId && !e.consumed)
|
|
53547
|
+
return true;
|
|
53548
|
+
}
|
|
53549
|
+
return false;
|
|
53550
|
+
},
|
|
53510
53551
|
isPreTurnRecord(turnKey2) {
|
|
53511
53552
|
return turnKey2.startsWith(PRETURN_TURNKEY_PREFIX);
|
|
53512
53553
|
},
|
|
@@ -70340,6 +70381,8 @@ function tick(now) {
|
|
|
70340
70381
|
const ceiling = thresholds.fallbackHardCeiling ?? Number.POSITIVE_INFINITY;
|
|
70341
70382
|
const underCeiling = silence < ceiling;
|
|
70342
70383
|
if (underCeiling) {
|
|
70384
|
+
if (activeDeps.isCompactionInFlight?.(key) === true)
|
|
70385
|
+
continue;
|
|
70343
70386
|
const forceDisable = process.env.SWITCHROOM_SILENCE_DEFER_INFLIGHT_TOOLS === "0";
|
|
70344
70387
|
if (!forceDisable && activeDeps.isLegitimatelyWorking != null) {
|
|
70345
70388
|
if (activeDeps.isLegitimatelyWorking(key))
|
|
@@ -71564,6 +71607,14 @@ function projectTranscriptLine(line) {
|
|
|
71564
71607
|
{ kind: "turn_end", durationMs: obj.durationMs ?? 0 }
|
|
71565
71608
|
];
|
|
71566
71609
|
}
|
|
71610
|
+
if (type === "system" && obj.subtype === "compact_boundary") {
|
|
71611
|
+
const meta = obj.compactMetadata;
|
|
71612
|
+
return [{
|
|
71613
|
+
kind: "compact_boundary",
|
|
71614
|
+
trigger: typeof meta?.trigger === "string" ? meta.trigger : null,
|
|
71615
|
+
compactDurationMs: typeof meta?.durationMs === "number" ? meta.durationMs : null
|
|
71616
|
+
}];
|
|
71617
|
+
}
|
|
71567
71618
|
return [];
|
|
71568
71619
|
}
|
|
71569
71620
|
|
|
@@ -77095,6 +77146,10 @@ function compactIfLarge(path2) {
|
|
|
77095
77146
|
} catch {}
|
|
77096
77147
|
}
|
|
77097
77148
|
|
|
77149
|
+
// gateway/outbox-sweep.ts
|
|
77150
|
+
init_rich_send();
|
|
77151
|
+
init_format();
|
|
77152
|
+
|
|
77098
77153
|
// registry/subagents-schema.ts
|
|
77099
77154
|
function countRunningBackgroundSubagents(db2) {
|
|
77100
77155
|
const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
|
|
@@ -78896,13 +78951,28 @@ async function deliverCapturedProse(deps, args) {
|
|
|
78896
78951
|
const plainChunks = splitMarkdownChunks(plain, RICH_MESSAGE_MAX_CHARS);
|
|
78897
78952
|
try {
|
|
78898
78953
|
let liveThreadId = threadId;
|
|
78954
|
+
const plainSentIds = [];
|
|
78955
|
+
const plainSentTexts = [];
|
|
78899
78956
|
for (const c of plainChunks) {
|
|
78900
78957
|
const sent = await retryWithThreadFallback(robustApiCall, (tid) => bot.api.sendMessage(chatId, c, tid != null ? { message_thread_id: tid } : {}), { threadId: liveThreadId, chat_id: chatId, verb: "captured-prose-plain-fallback.sendMessage" });
|
|
78958
|
+
const sentId = sent.message_id;
|
|
78959
|
+
if (sentId != null) {
|
|
78960
|
+
plainSentIds.push(sentId);
|
|
78961
|
+
plainSentTexts.push(c);
|
|
78962
|
+
}
|
|
78901
78963
|
if (liveThreadId != null && sent.message_thread_id == null) {
|
|
78902
78964
|
liveThreadId = undefined;
|
|
78903
78965
|
}
|
|
78904
78966
|
}
|
|
78905
78967
|
outboundDedup.record(chatId, threadId, text4, Date.now(), registryKey);
|
|
78968
|
+
if (HISTORY_ENABLED && plainSentIds.length > 0) {
|
|
78969
|
+
try {
|
|
78970
|
+
recordOutbound2({ chat_id: chatId, thread_id: threadId ?? null, message_ids: plainSentIds, texts: plainSentTexts });
|
|
78971
|
+
} catch (histErr) {
|
|
78972
|
+
process.stderr.write(`telegram gateway: history recordOutbound (captured-prose plain fallback) failed: ${histErr instanceof Error ? histErr.message : String(histErr)}
|
|
78973
|
+
`);
|
|
78974
|
+
}
|
|
78975
|
+
}
|
|
78906
78976
|
process.stderr.write(`telegram gateway: captured-prose recovered via plain-text fallback ` + `(chat=${chatId} origin=${originTurnId})
|
|
78907
78977
|
`);
|
|
78908
78978
|
} catch (plainErr) {
|
|
@@ -80104,23 +80174,35 @@ function decideFallbackTeardownNotice2(input) {
|
|
|
80104
80174
|
// gateway/stream-render.ts
|
|
80105
80175
|
var PARKED_TURN_START_MAX = 16;
|
|
80106
80176
|
var PARKED_TURN_START_TTL_MS = 30 * 60000;
|
|
80177
|
+
var QUEUED_CARD_ENABLED = process.env.SWITCHROOM_QUEUED_CARD !== "0";
|
|
80178
|
+
var QUEUED_CARD_HTML = "\u23f3 Queued \u2014 waiting for the current task to finish\u2026";
|
|
80179
|
+
var QUEUED_CARD_FOLDED_HTML = "\u2705 Folded into the current task.";
|
|
80180
|
+
var QUEUED_CARD_EXPIRED_HTML = "\u26a0\ufe0f This queued message timed out before it could start.";
|
|
80107
80181
|
var parkedTurnStarts = [];
|
|
80108
|
-
function pruneParkedTurnStarts(now) {
|
|
80182
|
+
function pruneParkedTurnStarts(now, onDrop) {
|
|
80109
80183
|
for (let i = parkedTurnStarts.length - 1;i >= 0; i--) {
|
|
80110
80184
|
if (now - parkedTurnStarts[i].parkedAt > PARKED_TURN_START_TTL_MS) {
|
|
80111
80185
|
const [dropped] = parkedTurnStarts.splice(i, 1);
|
|
80112
80186
|
process.stderr.write(`telegram gateway: parked-turn-start expired chat=${dropped.chatId ?? "-"} ` + `msg=${dropped.messageId ?? "-"} age_ms=${now - dropped.parkedAt}
|
|
80113
80187
|
`);
|
|
80188
|
+
try {
|
|
80189
|
+
onDrop?.(dropped);
|
|
80190
|
+
} catch {}
|
|
80114
80191
|
}
|
|
80115
80192
|
}
|
|
80116
80193
|
}
|
|
80117
|
-
function parkTurnStart(env, now) {
|
|
80118
|
-
|
|
80194
|
+
function parkTurnStart(env, now, onEvict) {
|
|
80195
|
+
const entry = { ...env, parkedAt: now };
|
|
80196
|
+
parkedTurnStarts.push(entry);
|
|
80119
80197
|
while (parkedTurnStarts.length > PARKED_TURN_START_MAX) {
|
|
80120
80198
|
const [dropped] = parkedTurnStarts.splice(0, 1);
|
|
80121
80199
|
process.stderr.write(`telegram gateway: parked-turn-start evicted (cap ${PARKED_TURN_START_MAX}) ` + `chat=${dropped.chatId ?? "-"} msg=${dropped.messageId ?? "-"}
|
|
80122
80200
|
`);
|
|
80201
|
+
try {
|
|
80202
|
+
onEvict?.(dropped);
|
|
80203
|
+
} catch {}
|
|
80123
80204
|
}
|
|
80205
|
+
return entry;
|
|
80124
80206
|
}
|
|
80125
80207
|
function takeParkedTurnStart() {
|
|
80126
80208
|
return parkedTurnStarts.pop() ?? null;
|
|
@@ -80128,11 +80210,56 @@ function takeParkedTurnStart() {
|
|
|
80128
80210
|
function discardParkedTurnStart(rawContent) {
|
|
80129
80211
|
for (let i = parkedTurnStarts.length - 1;i >= 0; i--) {
|
|
80130
80212
|
if (parkedTurnStarts[i].rawContent === rawContent) {
|
|
80131
|
-
parkedTurnStarts.splice(i, 1);
|
|
80132
|
-
return
|
|
80213
|
+
const [dropped] = parkedTurnStarts.splice(i, 1);
|
|
80214
|
+
return dropped;
|
|
80133
80215
|
}
|
|
80134
80216
|
}
|
|
80135
|
-
return
|
|
80217
|
+
return null;
|
|
80218
|
+
}
|
|
80219
|
+
async function openQueuedCard(deps, chatId, threadId, replyToMessageId) {
|
|
80220
|
+
try {
|
|
80221
|
+
const sent = await deps.robustApiCall(() => deps.bot.api.sendRichMessage(chatId, richMessage(QUEUED_CARD_HTML), {
|
|
80222
|
+
...threadId != null ? { message_thread_id: threadId } : {},
|
|
80223
|
+
...replyToMessageId != null ? { reply_parameters: { message_id: replyToMessageId, allow_sending_without_reply: true } } : {},
|
|
80224
|
+
disable_notification: true
|
|
80225
|
+
}), {
|
|
80226
|
+
chat_id: chatId,
|
|
80227
|
+
...threadId != null ? { threadId } : {},
|
|
80228
|
+
verb: "queued-card.send"
|
|
80229
|
+
});
|
|
80230
|
+
return sent?.message_id ?? null;
|
|
80231
|
+
} catch (err) {
|
|
80232
|
+
process.stderr.write(`telegram gateway: queued card send failed: ${err.message}
|
|
80233
|
+
`);
|
|
80234
|
+
return null;
|
|
80235
|
+
}
|
|
80236
|
+
}
|
|
80237
|
+
function finalizeQueuedCard(deps, chatId, threadId, messageId, html) {
|
|
80238
|
+
deps.robustApiCall(() => deps.bot.api.editMessageText(chatId, messageId, richMessage(html), {}), {
|
|
80239
|
+
chat_id: chatId,
|
|
80240
|
+
...threadId != null ? { threadId } : {},
|
|
80241
|
+
verb: "queued-card.finalize"
|
|
80242
|
+
}).catch(() => {
|
|
80243
|
+
return;
|
|
80244
|
+
});
|
|
80245
|
+
}
|
|
80246
|
+
function deleteQueuedCard(deps, chatId, messageId) {
|
|
80247
|
+
deps.robustApiCall(() => deps.bot.api.deleteMessage(chatId, messageId), { chat_id: chatId, verb: "queued-card.delete-orphan" }).catch(() => {
|
|
80248
|
+
return;
|
|
80249
|
+
});
|
|
80250
|
+
}
|
|
80251
|
+
function envThreadIdNum(threadId) {
|
|
80252
|
+
if (threadId == null)
|
|
80253
|
+
return null;
|
|
80254
|
+
const n = Number(threadId);
|
|
80255
|
+
return Number.isFinite(n) ? n : null;
|
|
80256
|
+
}
|
|
80257
|
+
function finalizeParkedEntryCard(deps, entry, html) {
|
|
80258
|
+
if (!QUEUED_CARD_ENABLED)
|
|
80259
|
+
return;
|
|
80260
|
+
if (entry.queuedCardMessageId == null || entry.chatId == null)
|
|
80261
|
+
return;
|
|
80262
|
+
finalizeQueuedCard(deps, entry.chatId, envThreadIdNum(entry.threadId), entry.queuedCardMessageId, html);
|
|
80136
80263
|
}
|
|
80137
80264
|
function beginTurn(deps, ev) {
|
|
80138
80265
|
const {
|
|
@@ -80246,6 +80373,16 @@ function beginTurn(deps, ev) {
|
|
|
80246
80373
|
`);
|
|
80247
80374
|
}
|
|
80248
80375
|
}
|
|
80376
|
+
if (QUEUED_CARD_ENABLED && ev.queuedCardMessageId != null && next.activityMessageId == null) {
|
|
80377
|
+
next.activityMessageId = ev.queuedCardMessageId;
|
|
80378
|
+
next.activityEverOpened = true;
|
|
80379
|
+
process.stderr.write(`telegram gateway: queued card adopted turnId=${turnId} card=${ev.queuedCardMessageId}
|
|
80380
|
+
`);
|
|
80381
|
+
} else if (QUEUED_CARD_ENABLED && ev.queuedCardMessageId != null && ev.chatId != null && next.activityMessageId != null && next.activityMessageId !== ev.queuedCardMessageId) {
|
|
80382
|
+
deleteQueuedCard(deps, ev.chatId, ev.queuedCardMessageId);
|
|
80383
|
+
process.stderr.write(`telegram gateway: queued card superseded by handback adoption turnId=${turnId} ` + `queued=${ev.queuedCardMessageId} adopted=${next.activityMessageId}
|
|
80384
|
+
`);
|
|
80385
|
+
}
|
|
80249
80386
|
startTurnTypingLoop(ev.chatId, enqThreadIdNum ?? null);
|
|
80250
80387
|
setCurrentTurn(next, statusKey(ev.chatId, enqThreadIdNum));
|
|
80251
80388
|
scheduleEarlyLivenessOpen(next);
|
|
@@ -80394,7 +80531,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
80394
80531
|
ackDelivery(deliveryQueue, chatKey(ev.chatId, ev.threadId != null ? Number(ev.threadId) : null), ev.messageId, ev.rawContent);
|
|
80395
80532
|
}
|
|
80396
80533
|
}
|
|
80397
|
-
pruneParkedTurnStarts(now);
|
|
80534
|
+
pruneParkedTurnStarts(now, (e) => finalizeParkedEntryCard(deps, e, QUEUED_CARD_EXPIRED_HTML));
|
|
80398
80535
|
if (!ev.chatId) {
|
|
80399
80536
|
beginTurn(deps, ev);
|
|
80400
80537
|
return;
|
|
@@ -80405,18 +80542,38 @@ function handleSessionEvent(deps, ev) {
|
|
|
80405
80542
|
beginTurn(deps, ev);
|
|
80406
80543
|
return;
|
|
80407
80544
|
}
|
|
80408
|
-
parkTurnStart({
|
|
80545
|
+
const parkedEntry = parkTurnStart({
|
|
80409
80546
|
chatId: ev.chatId,
|
|
80410
80547
|
messageId: ev.messageId,
|
|
80411
80548
|
threadId: ev.threadId,
|
|
80412
80549
|
rawContent: ev.rawContent
|
|
80413
|
-
}, now);
|
|
80550
|
+
}, now, (evicted) => finalizeParkedEntryCard(deps, evicted, QUEUED_CARD_EXPIRED_HTML));
|
|
80414
80551
|
process.stderr.write(`telegram gateway: turn-start parked (session busy) chat=${ev.chatId} ` + `thread=${enqThreadIdNum ?? "-"} msg=${ev.messageId ?? "-"} ` + `parked=${parkedTurnStarts.length}
|
|
80415
80552
|
`);
|
|
80553
|
+
const parkTurnId = deriveTurnId(ev.chatId, enqThreadIdNum ?? null, ev.messageId);
|
|
80554
|
+
const handbackOwnsSurface = HANDBACK_PRETURN_ENABLED && parkTurnId != null && handbackPreturnSignal.hasPendingForTurnId(parkTurnId);
|
|
80555
|
+
if (handbackOwnsSurface) {
|
|
80556
|
+
process.stderr.write(`telegram gateway: queued card suppressed (handback owns surface) ` + `turnId=${parkTurnId} msg=${ev.messageId ?? "-"}
|
|
80557
|
+
`);
|
|
80558
|
+
}
|
|
80559
|
+
if (QUEUED_CARD_ENABLED && !handbackOwnsSurface) {
|
|
80560
|
+
const cardChatId = ev.chatId;
|
|
80561
|
+
const replyToRaw = ev.messageId != null ? Number(ev.messageId) : null;
|
|
80562
|
+
const replyTo = replyToRaw != null && Number.isFinite(replyToRaw) ? replyToRaw : null;
|
|
80563
|
+
openQueuedCard(deps, cardChatId, enqThreadIdNum ?? null, replyTo).then((cardId) => {
|
|
80564
|
+
if (cardId == null)
|
|
80565
|
+
return;
|
|
80566
|
+
if (parkedTurnStarts.includes(parkedEntry)) {
|
|
80567
|
+
parkedEntry.queuedCardMessageId = cardId;
|
|
80568
|
+
} else {
|
|
80569
|
+
deleteQueuedCard(deps, cardChatId, cardId);
|
|
80570
|
+
}
|
|
80571
|
+
});
|
|
80572
|
+
}
|
|
80416
80573
|
return;
|
|
80417
80574
|
}
|
|
80418
80575
|
case "dequeue": {
|
|
80419
|
-
pruneParkedTurnStarts(Date.now());
|
|
80576
|
+
pruneParkedTurnStarts(Date.now(), (e) => finalizeParkedEntryCard(deps, e, QUEUED_CARD_EXPIRED_HTML));
|
|
80420
80577
|
const parked = takeParkedTurnStart();
|
|
80421
80578
|
if (parked == null)
|
|
80422
80579
|
return;
|
|
@@ -80424,8 +80581,10 @@ function handleSessionEvent(deps, ev) {
|
|
|
80424
80581
|
return;
|
|
80425
80582
|
}
|
|
80426
80583
|
case "queue_remove": {
|
|
80427
|
-
pruneParkedTurnStarts(Date.now());
|
|
80428
|
-
discardParkedTurnStart(ev.rawContent);
|
|
80584
|
+
pruneParkedTurnStarts(Date.now(), (e) => finalizeParkedEntryCard(deps, e, QUEUED_CARD_EXPIRED_HTML));
|
|
80585
|
+
const removed = discardParkedTurnStart(ev.rawContent);
|
|
80586
|
+
if (removed != null)
|
|
80587
|
+
finalizeParkedEntryCard(deps, removed, QUEUED_CARD_FOLDED_HTML);
|
|
80429
80588
|
return;
|
|
80430
80589
|
}
|
|
80431
80590
|
case "model": {
|
|
@@ -80895,6 +81054,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
80895
81054
|
let sentIds = [];
|
|
80896
81055
|
let chunkCount = 0;
|
|
80897
81056
|
let delivered = false;
|
|
81057
|
+
let earlyJournaled = false;
|
|
80898
81058
|
try {
|
|
80899
81059
|
const delivery = await deliverAnswer({
|
|
80900
81060
|
chatId: backstopChatId,
|
|
@@ -80902,7 +81062,21 @@ function handleSessionEvent(deps, ev) {
|
|
|
80902
81062
|
text: capturedText,
|
|
80903
81063
|
turnId: turn.turnId,
|
|
80904
81064
|
cardMessageId: backstopCardMessageId,
|
|
80905
|
-
replyToMessageId: turn.sourceMessageId
|
|
81065
|
+
replyToMessageId: turn.sourceMessageId,
|
|
81066
|
+
onAckClaim: (ackIds) => {
|
|
81067
|
+
try {
|
|
81068
|
+
journalExternalDelivery({
|
|
81069
|
+
turnNonce: turn.turnId,
|
|
81070
|
+
text: capturedText,
|
|
81071
|
+
tgMessageId: ackIds.length > 0 ? ackIds[0] : undefined,
|
|
81072
|
+
deliverySource: "flush"
|
|
81073
|
+
}, STATE_DIR);
|
|
81074
|
+
earlyJournaled = true;
|
|
81075
|
+
} catch (err) {
|
|
81076
|
+
process.stderr.write(`telegram gateway: turn-flush send-ack journal write failed (non-fatal): ${err.message}
|
|
81077
|
+
`);
|
|
81078
|
+
}
|
|
81079
|
+
}
|
|
80906
81080
|
});
|
|
80907
81081
|
sentIds = delivery.sentIds;
|
|
80908
81082
|
chunkCount = delivery.chunkCount;
|
|
@@ -80948,7 +81122,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
80948
81122
|
chunkCount,
|
|
80949
81123
|
cardMessageId: backstopCardMessageId
|
|
80950
81124
|
});
|
|
80951
|
-
if (delivered) {
|
|
81125
|
+
if (delivered && !earlyJournaled) {
|
|
80952
81126
|
try {
|
|
80953
81127
|
journalExternalDelivery({
|
|
80954
81128
|
turnNonce: turn.turnId,
|
|
@@ -84944,8 +85118,8 @@ var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 16 * 1024;
|
|
|
84944
85118
|
var HINDSIGHT_PG_APP_ANON_MIB = 2560;
|
|
84945
85119
|
var HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048;
|
|
84946
85120
|
var HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB = HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION - HINDSIGHT_PG_APP_ANON_MIB - HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB;
|
|
84947
|
-
var HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB =
|
|
84948
|
-
var HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB =
|
|
85121
|
+
var HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB = 6144;
|
|
85122
|
+
var HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB = 12288;
|
|
84949
85123
|
function pgMib(mib) {
|
|
84950
85124
|
return `${mib}MB`;
|
|
84951
85125
|
}
|
|
@@ -84989,7 +85163,7 @@ var HINDSIGHT_DEFAULT_RERANKER_MAX_CANDIDATES = 150;
|
|
|
84989
85163
|
var HINDSIGHT_DEFAULT_RERANKER_LOCAL_MAX_CONCURRENT = 4;
|
|
84990
85164
|
var HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8;
|
|
84991
85165
|
var HINDSIGHT_DEFAULT_REFLECT_WALL_TIMEOUT_S = 600;
|
|
84992
|
-
var HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND =
|
|
85166
|
+
var HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND = 250;
|
|
84993
85167
|
var HINDSIGHT_DEFAULT_CONSOLIDATION_SLOT_LIMIT = 6;
|
|
84994
85168
|
var HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_SLOTS = 1;
|
|
84995
85169
|
var HINDSIGHT_DEFAULT_RECENCY_DECAY_FUNCTION = "exponential";
|
|
@@ -91731,6 +91905,7 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
|
|
|
91731
91905
|
const stderr = deps.stderr ?? (() => {});
|
|
91732
91906
|
const chunkCount = chunks.length;
|
|
91733
91907
|
let attempts = 0;
|
|
91908
|
+
let ackClaimed = false;
|
|
91734
91909
|
for (let attempt = 1;attempt <= Math.max(1, maxAttempts); attempt++) {
|
|
91735
91910
|
attempts = attempt;
|
|
91736
91911
|
const resume = ledger.unsentIndices(turnId, chunkCount);
|
|
@@ -91754,6 +91929,18 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
|
|
|
91754
91929
|
`);
|
|
91755
91930
|
}
|
|
91756
91931
|
}
|
|
91932
|
+
if (!ackClaimed && deps.onAckClaim != null) {
|
|
91933
|
+
const allLandedNow = chunkCount > 0 && ledger.unsentIndices(turnId, chunkCount).length === 0;
|
|
91934
|
+
if (allLandedNow && backstopReceiptIds(ledger.sentIds(turnId), cardMessageId).length > 0) {
|
|
91935
|
+
ackClaimed = true;
|
|
91936
|
+
try {
|
|
91937
|
+
deps.onAckClaim(ledger.sentIds(turnId));
|
|
91938
|
+
} catch (err) {
|
|
91939
|
+
stderr(`telegram gateway: backstop send-ack claim callback threw for turn ${turnId} ` + `(non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
91940
|
+
`);
|
|
91941
|
+
}
|
|
91942
|
+
}
|
|
91943
|
+
}
|
|
91757
91944
|
let demotedAny = false;
|
|
91758
91945
|
for (const i of ledger.landedUnconfirmedIndices(turnId, chunkCount)) {
|
|
91759
91946
|
if (deps.readBack == null) {
|
|
@@ -93118,6 +93305,28 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
|
|
|
93118
93305
|
return { purged };
|
|
93119
93306
|
}
|
|
93120
93307
|
|
|
93308
|
+
// gateway/compaction-marker.ts
|
|
93309
|
+
import { statSync as statSync15, unlinkSync as unlinkSync21 } from "node:fs";
|
|
93310
|
+
import { homedir as homedir15 } from "node:os";
|
|
93311
|
+
import { join as join50 } from "node:path";
|
|
93312
|
+
var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
|
|
93313
|
+
function resolveTelegramStateDir() {
|
|
93314
|
+
return process.env.TELEGRAM_STATE_DIR ?? join50(homedir15(), ".claude", "channels", "telegram");
|
|
93315
|
+
}
|
|
93316
|
+
function readCompactionMarkerAgeMs(stateDir, now) {
|
|
93317
|
+
try {
|
|
93318
|
+
const st = statSync15(join50(stateDir, COMPACTION_MARKER_FILE));
|
|
93319
|
+
return (now ?? Date.now()) - st.mtimeMs;
|
|
93320
|
+
} catch {
|
|
93321
|
+
return null;
|
|
93322
|
+
}
|
|
93323
|
+
}
|
|
93324
|
+
function removeCompactionMarker(stateDir) {
|
|
93325
|
+
try {
|
|
93326
|
+
unlinkSync21(join50(stateDir, COMPACTION_MARKER_FILE));
|
|
93327
|
+
} catch {}
|
|
93328
|
+
}
|
|
93329
|
+
|
|
93121
93330
|
// gateway/hang-restart-decision.ts
|
|
93122
93331
|
var HUMAN_WAIT_TOOLS2 = new Set(["ask_user"]);
|
|
93123
93332
|
var BACKGROUND_TOOLS2 = new Set(["Task", "Agent"]);
|
|
@@ -93225,6 +93434,10 @@ function buildSilencePokeOptions(deps) {
|
|
|
93225
93434
|
thresholdsMs: { fallback: SILENCE_FALLBACK_MS, fallbackHardCeiling: SILENCE_FALLBACK_HARD_MS, floor: SILENCE_FLOOR_MS },
|
|
93226
93435
|
deferFallbackWhileToolInFlight: SILENCE_DEFER_INFLIGHT_TOOLS,
|
|
93227
93436
|
isLegitimatelyWorking: (key) => isLegitimatelyWorking(key),
|
|
93437
|
+
isCompactionInFlight: () => {
|
|
93438
|
+
const ageMs = readCompactionMarkerAgeMs(STATE_DIR);
|
|
93439
|
+
return ageMs != null && ageMs >= 0 && ageMs < SILENCE_FALLBACK_HARD_MS;
|
|
93440
|
+
},
|
|
93228
93441
|
isTurnLive: (key) => !(activeTurnStartedAt.get(key) == null && getCurrentTurnForKey(key) == null),
|
|
93229
93442
|
emitMetric: (event) => {
|
|
93230
93443
|
emitRuntimeMetric2(event);
|
|
@@ -93648,6 +93861,9 @@ function applySilencePokeSessionEvent(silencePoke, pendingProgress, key, ev) {
|
|
|
93648
93861
|
if (ev.toolUseId != null && ev.toolUseId.length > 0) {
|
|
93649
93862
|
silencePoke.noteToolEnd(key, ev.toolUseId, Date.now());
|
|
93650
93863
|
}
|
|
93864
|
+
} else if (ev.kind === "compact_boundary") {
|
|
93865
|
+
removeCompactionMarker(resolveTelegramStateDir());
|
|
93866
|
+
silencePoke.noteProduction(key, Date.now());
|
|
93651
93867
|
}
|
|
93652
93868
|
applyBackgroundShellLiveness(silencePoke, key, ev);
|
|
93653
93869
|
}
|
|
@@ -93933,17 +94149,17 @@ import {
|
|
|
93933
94149
|
readFileSync as readFileSync37,
|
|
93934
94150
|
writeSync as writeSync6
|
|
93935
94151
|
} from "node:fs";
|
|
93936
|
-
import { join as
|
|
94152
|
+
import { join as join51 } from "node:path";
|
|
93937
94153
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
93938
94154
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
93939
94155
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
93940
94156
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
93941
94157
|
var PROPOSAL_SIM_THRESHOLD = 0.5;
|
|
93942
94158
|
function proposalsPath2(stateDir) {
|
|
93943
|
-
return
|
|
94159
|
+
return join51(stateDir, PROPOSALS_FILE2);
|
|
93944
94160
|
}
|
|
93945
94161
|
function rejectedPath2(stateDir) {
|
|
93946
|
-
return
|
|
94162
|
+
return join51(stateDir, REJECTED_FILE2);
|
|
93947
94163
|
}
|
|
93948
94164
|
function ensureDir3(stateDir) {
|
|
93949
94165
|
if (!existsSync41(stateDir)) {
|
|
@@ -94561,7 +94777,7 @@ function escapeBody2(s) {
|
|
|
94561
94777
|
}
|
|
94562
94778
|
|
|
94563
94779
|
// gateway/pid-file.ts
|
|
94564
|
-
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as
|
|
94780
|
+
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync22, renameSync as renameSync18 } from "node:fs";
|
|
94565
94781
|
function writePidFile(path3, record) {
|
|
94566
94782
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
94567
94783
|
writeFileSync33(tmp, JSON.stringify(record), "utf-8");
|
|
@@ -94569,7 +94785,7 @@ function writePidFile(path3, record) {
|
|
|
94569
94785
|
}
|
|
94570
94786
|
function clearPidFile(path3) {
|
|
94571
94787
|
try {
|
|
94572
|
-
|
|
94788
|
+
unlinkSync22(path3);
|
|
94573
94789
|
} catch {}
|
|
94574
94790
|
}
|
|
94575
94791
|
|
|
@@ -94786,7 +95002,7 @@ function safeCount(fn) {
|
|
|
94786
95002
|
}
|
|
94787
95003
|
|
|
94788
95004
|
// gateway/session-marker.ts
|
|
94789
|
-
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as
|
|
95005
|
+
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as unlinkSync23 } from "node:fs";
|
|
94790
95006
|
function writeSessionMarker(path3, marker) {
|
|
94791
95007
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
94792
95008
|
writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
|
|
@@ -94816,7 +95032,7 @@ function shouldFireRestartBanner(input) {
|
|
|
94816
95032
|
}
|
|
94817
95033
|
|
|
94818
95034
|
// gateway/clean-shutdown-marker.ts
|
|
94819
|
-
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as
|
|
95035
|
+
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as unlinkSync24 } from "node:fs";
|
|
94820
95036
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
94821
95037
|
function writeCleanShutdownMarker(path3, marker) {
|
|
94822
95038
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -94840,7 +95056,7 @@ function readCleanShutdownMarker(path3) {
|
|
|
94840
95056
|
}
|
|
94841
95057
|
function clearCleanShutdownMarker(path3) {
|
|
94842
95058
|
try {
|
|
94843
|
-
|
|
95059
|
+
unlinkSync24(path3);
|
|
94844
95060
|
} catch {}
|
|
94845
95061
|
}
|
|
94846
95062
|
function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
@@ -95200,13 +95416,13 @@ import {
|
|
|
95200
95416
|
existsSync as existsSync42,
|
|
95201
95417
|
openSync as openSync10,
|
|
95202
95418
|
readSync as readSync2,
|
|
95203
|
-
statSync as
|
|
95419
|
+
statSync as statSync16,
|
|
95204
95420
|
closeSync as closeSync10,
|
|
95205
95421
|
watch,
|
|
95206
95422
|
readdirSync as readdirSync10,
|
|
95207
95423
|
readFileSync as readFileSync42
|
|
95208
95424
|
} from "fs";
|
|
95209
|
-
import { join as
|
|
95425
|
+
import { join as join52 } from "path";
|
|
95210
95426
|
|
|
95211
95427
|
// session-tail.ts
|
|
95212
95428
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -96013,7 +96229,7 @@ function startSubagentWatcher(config) {
|
|
|
96013
96229
|
const fs3 = config.fs ?? {
|
|
96014
96230
|
existsSync: existsSync42,
|
|
96015
96231
|
readdirSync: readdirSync10,
|
|
96016
|
-
statSync:
|
|
96232
|
+
statSync: statSync16,
|
|
96017
96233
|
openSync: openSync10,
|
|
96018
96234
|
closeSync: closeSync10,
|
|
96019
96235
|
readSync: readSync2,
|
|
@@ -96529,8 +96745,8 @@ function startSubagentWatcher(config) {
|
|
|
96529
96745
|
if (stopped)
|
|
96530
96746
|
return;
|
|
96531
96747
|
pruneVanishedDirWatchers();
|
|
96532
|
-
const claudeHome =
|
|
96533
|
-
const projectsRoot =
|
|
96748
|
+
const claudeHome = join52(agentDir, ".claude");
|
|
96749
|
+
const projectsRoot = join52(claudeHome, "projects");
|
|
96534
96750
|
if (!fs3.existsSync(projectsRoot))
|
|
96535
96751
|
return;
|
|
96536
96752
|
let projectDirs;
|
|
@@ -96564,7 +96780,7 @@ function startSubagentWatcher(config) {
|
|
|
96564
96780
|
continue;
|
|
96565
96781
|
}
|
|
96566
96782
|
warnedForeignSlugs.delete(pDir);
|
|
96567
|
-
const projectPath =
|
|
96783
|
+
const projectPath = join52(projectsRoot, pDir);
|
|
96568
96784
|
let sessionDirs;
|
|
96569
96785
|
try {
|
|
96570
96786
|
sessionDirs = fs3.readdirSync(projectPath);
|
|
@@ -96574,7 +96790,7 @@ function startSubagentWatcher(config) {
|
|
|
96574
96790
|
for (const sDir of sessionDirs) {
|
|
96575
96791
|
if (sDir.endsWith(".jsonl"))
|
|
96576
96792
|
continue;
|
|
96577
|
-
const subagentsPath =
|
|
96793
|
+
const subagentsPath = join52(projectPath, sDir, "subagents");
|
|
96578
96794
|
if (!fs3.existsSync(subagentsPath))
|
|
96579
96795
|
continue;
|
|
96580
96796
|
const watchAndScan = (dirPath) => {
|
|
@@ -96583,7 +96799,7 @@ function startSubagentWatcher(config) {
|
|
|
96583
96799
|
const w = fs3.watch(dirPath, (_event, filename) => {
|
|
96584
96800
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
96585
96801
|
return;
|
|
96586
|
-
const filePath =
|
|
96802
|
+
const filePath = join52(dirPath, filename.toString());
|
|
96587
96803
|
if (!knownFiles.has(filePath)) {
|
|
96588
96804
|
scanSubagentsDir(dirPath);
|
|
96589
96805
|
}
|
|
@@ -96597,7 +96813,7 @@ function startSubagentWatcher(config) {
|
|
|
96597
96813
|
scanSubagentsDir(dirPath);
|
|
96598
96814
|
};
|
|
96599
96815
|
watchAndScan(subagentsPath);
|
|
96600
|
-
const workflowsPath =
|
|
96816
|
+
const workflowsPath = join52(subagentsPath, "workflows");
|
|
96601
96817
|
if (fs3.existsSync(workflowsPath)) {
|
|
96602
96818
|
let wfDirs;
|
|
96603
96819
|
try {
|
|
@@ -96607,7 +96823,7 @@ function startSubagentWatcher(config) {
|
|
|
96607
96823
|
}
|
|
96608
96824
|
for (const wfDir of wfDirs) {
|
|
96609
96825
|
try {
|
|
96610
|
-
const wfPath =
|
|
96826
|
+
const wfPath = join52(workflowsPath, wfDir);
|
|
96611
96827
|
if (!fs3.statSync(wfPath).isDirectory())
|
|
96612
96828
|
continue;
|
|
96613
96829
|
watchAndScan(wfPath);
|
|
@@ -96627,7 +96843,7 @@ function startSubagentWatcher(config) {
|
|
|
96627
96843
|
for (const e of entries) {
|
|
96628
96844
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
96629
96845
|
continue;
|
|
96630
|
-
const filePath =
|
|
96846
|
+
const filePath = join52(subagentsPath, e);
|
|
96631
96847
|
if (knownFiles.has(filePath))
|
|
96632
96848
|
continue;
|
|
96633
96849
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -96759,17 +96975,17 @@ import {
|
|
|
96759
96975
|
writeFileSync as writeFileSync36,
|
|
96760
96976
|
readFileSync as readFileSync43,
|
|
96761
96977
|
readdirSync as readdirSync11,
|
|
96762
|
-
unlinkSync as
|
|
96978
|
+
unlinkSync as unlinkSync25,
|
|
96763
96979
|
existsSync as existsSync43,
|
|
96764
96980
|
renameSync as renameSync21
|
|
96765
96981
|
} from "node:fs";
|
|
96766
|
-
import { join as
|
|
96767
|
-
import { homedir as
|
|
96982
|
+
import { join as join53, resolve as resolve10 } from "node:path";
|
|
96983
|
+
import { homedir as homedir16 } from "node:os";
|
|
96768
96984
|
function registryDir() {
|
|
96769
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
96985
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join53(homedir16(), ".switchroom", "worktrees"));
|
|
96770
96986
|
}
|
|
96771
96987
|
function recordPath(id) {
|
|
96772
|
-
return
|
|
96988
|
+
return join53(registryDir(), `${id}.json`);
|
|
96773
96989
|
}
|
|
96774
96990
|
function ensureDir4() {
|
|
96775
96991
|
mkdirSync38(registryDir(), { recursive: true });
|
|
@@ -96945,19 +97161,19 @@ function determineRestartReason(opts) {
|
|
|
96945
97161
|
|
|
96946
97162
|
// gateway/update-announce.ts
|
|
96947
97163
|
import { existsSync as existsSync48, mkdirSync as mkdirSync42, openSync as openSync11, closeSync as closeSync11, readFileSync as readFileSync50 } from "node:fs";
|
|
96948
|
-
import { join as
|
|
96949
|
-
import { homedir as
|
|
97164
|
+
import { join as join58 } from "node:path";
|
|
97165
|
+
import { homedir as homedir18 } from "node:os";
|
|
96950
97166
|
|
|
96951
97167
|
// ../src/host-control/audit-reader.ts
|
|
96952
|
-
import { homedir as
|
|
96953
|
-
import { join as
|
|
97168
|
+
import { homedir as homedir17 } from "node:os";
|
|
97169
|
+
import { join as join57 } from "node:path";
|
|
96954
97170
|
|
|
96955
97171
|
// ../src/host-control/audit-rotation-config.ts
|
|
96956
97172
|
var DEFAULT_HOSTD_AUDIT_MAX_BYTES = 32 * 1024 * 1024;
|
|
96957
97173
|
|
|
96958
97174
|
// ../src/host-control/audit-reader.ts
|
|
96959
|
-
function defaultAuditLogPath(home2 =
|
|
96960
|
-
return
|
|
97175
|
+
function defaultAuditLogPath(home2 = homedir17()) {
|
|
97176
|
+
return join57(home2, ".switchroom", "host-control-audit.log");
|
|
96961
97177
|
}
|
|
96962
97178
|
var AUDIT_READ_WINDOW_BYTES = 4 * 1024 * 1024;
|
|
96963
97179
|
function parseAuditLine(line) {
|
|
@@ -97152,15 +97368,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
97152
97368
|
`);
|
|
97153
97369
|
}
|
|
97154
97370
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
97155
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
97156
|
-
const dir =
|
|
97371
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join58(homedir18(), ".switchroom");
|
|
97372
|
+
const dir = join58(stateDir, "update-announced");
|
|
97157
97373
|
try {
|
|
97158
97374
|
mkdirSync42(dir, { recursive: true });
|
|
97159
97375
|
} catch {
|
|
97160
97376
|
return false;
|
|
97161
97377
|
}
|
|
97162
97378
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
97163
|
-
const path3 =
|
|
97379
|
+
const path3 = join58(dir, safeId);
|
|
97164
97380
|
try {
|
|
97165
97381
|
const fd = openSync11(path3, "wx");
|
|
97166
97382
|
closeSync11(fd);
|
|
@@ -97381,8 +97597,8 @@ function createIssuesCardHandle(opts) {
|
|
|
97381
97597
|
}
|
|
97382
97598
|
|
|
97383
97599
|
// issues-watcher.ts
|
|
97384
|
-
import { existsSync as existsSync50, statSync as
|
|
97385
|
-
import { join as
|
|
97600
|
+
import { existsSync as existsSync50, statSync as statSync19 } from "node:fs";
|
|
97601
|
+
import { join as join60 } from "node:path";
|
|
97386
97602
|
|
|
97387
97603
|
// ../src/issues/store.ts
|
|
97388
97604
|
import {
|
|
@@ -97393,12 +97609,12 @@ import {
|
|
|
97393
97609
|
readdirSync as readdirSync13,
|
|
97394
97610
|
readFileSync as readFileSync52,
|
|
97395
97611
|
renameSync as renameSync24,
|
|
97396
|
-
statSync as
|
|
97397
|
-
unlinkSync as
|
|
97612
|
+
statSync as statSync18,
|
|
97613
|
+
unlinkSync as unlinkSync26,
|
|
97398
97614
|
writeFileSync as writeFileSync42,
|
|
97399
97615
|
writeSync as writeSync7
|
|
97400
97616
|
} from "node:fs";
|
|
97401
|
-
import { join as
|
|
97617
|
+
import { join as join59 } from "node:path";
|
|
97402
97618
|
import { randomBytes as randomBytes11 } from "node:crypto";
|
|
97403
97619
|
import { execSync } from "node:child_process";
|
|
97404
97620
|
|
|
@@ -97417,7 +97633,7 @@ init_redact();
|
|
|
97417
97633
|
var ISSUES_FILE = "issues.jsonl";
|
|
97418
97634
|
var ISSUES_LOCK = "issues.lock";
|
|
97419
97635
|
function readAll(stateDir) {
|
|
97420
|
-
const path3 =
|
|
97636
|
+
const path3 = join59(stateDir, ISSUES_FILE);
|
|
97421
97637
|
if (!existsSync49(path3))
|
|
97422
97638
|
return [];
|
|
97423
97639
|
let raw;
|
|
@@ -97454,7 +97670,7 @@ function list2(stateDir, opts = {}) {
|
|
|
97454
97670
|
});
|
|
97455
97671
|
}
|
|
97456
97672
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
97457
|
-
if (!existsSync49(
|
|
97673
|
+
if (!existsSync49(join59(stateDir, ISSUES_FILE)))
|
|
97458
97674
|
return 0;
|
|
97459
97675
|
return withLock(stateDir, () => {
|
|
97460
97676
|
const all2 = readAll(stateDir);
|
|
@@ -97472,7 +97688,7 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
97472
97688
|
});
|
|
97473
97689
|
}
|
|
97474
97690
|
function writeAll(stateDir, events) {
|
|
97475
|
-
const path3 =
|
|
97691
|
+
const path3 = join59(stateDir, ISSUES_FILE);
|
|
97476
97692
|
sweepOrphanTmpFiles(stateDir);
|
|
97477
97693
|
const tmp = `${path3}.tmp-${process.pid}-${randomBytes11(4).toString("hex")}`;
|
|
97478
97694
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -97494,11 +97710,11 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
97494
97710
|
for (const entry of entries) {
|
|
97495
97711
|
if (!entry.startsWith(TMP_PREFIX))
|
|
97496
97712
|
continue;
|
|
97497
|
-
const tmpPath2 =
|
|
97713
|
+
const tmpPath2 = join59(stateDir, entry);
|
|
97498
97714
|
try {
|
|
97499
|
-
const stat =
|
|
97715
|
+
const stat = statSync18(tmpPath2);
|
|
97500
97716
|
if (stat.mtimeMs < cutoff) {
|
|
97501
|
-
|
|
97717
|
+
unlinkSync26(tmpPath2);
|
|
97502
97718
|
}
|
|
97503
97719
|
} catch {}
|
|
97504
97720
|
}
|
|
@@ -97506,7 +97722,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
97506
97722
|
var LOCK_RETRY_MS = 25;
|
|
97507
97723
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
97508
97724
|
function withLock(stateDir, fn) {
|
|
97509
|
-
const lockPath =
|
|
97725
|
+
const lockPath = join59(stateDir, ISSUES_LOCK);
|
|
97510
97726
|
const startedAt = Date.now();
|
|
97511
97727
|
let fd = null;
|
|
97512
97728
|
while (fd === null) {
|
|
@@ -97534,7 +97750,7 @@ function withLock(stateDir, fn) {
|
|
|
97534
97750
|
closeSync12(fd);
|
|
97535
97751
|
} catch {}
|
|
97536
97752
|
try {
|
|
97537
|
-
|
|
97753
|
+
unlinkSync26(lockPath);
|
|
97538
97754
|
} catch {}
|
|
97539
97755
|
}
|
|
97540
97756
|
}
|
|
@@ -97548,13 +97764,13 @@ function tryStealStaleLock(lockPath) {
|
|
|
97548
97764
|
const pid = Number(pidStr);
|
|
97549
97765
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
97550
97766
|
try {
|
|
97551
|
-
|
|
97767
|
+
unlinkSync26(lockPath);
|
|
97552
97768
|
} catch {}
|
|
97553
97769
|
return true;
|
|
97554
97770
|
}
|
|
97555
97771
|
if (pid === process.pid) {
|
|
97556
97772
|
try {
|
|
97557
|
-
|
|
97773
|
+
unlinkSync26(lockPath);
|
|
97558
97774
|
} catch {}
|
|
97559
97775
|
return true;
|
|
97560
97776
|
}
|
|
@@ -97569,7 +97785,7 @@ function tryStealStaleLock(lockPath) {
|
|
|
97569
97785
|
return false;
|
|
97570
97786
|
}
|
|
97571
97787
|
try {
|
|
97572
|
-
|
|
97788
|
+
unlinkSync26(lockPath);
|
|
97573
97789
|
} catch {}
|
|
97574
97790
|
return true;
|
|
97575
97791
|
}
|
|
@@ -97591,7 +97807,7 @@ function isIssueEvent(v) {
|
|
|
97591
97807
|
// issues-watcher.ts
|
|
97592
97808
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
97593
97809
|
function startIssuesWatcher(opts) {
|
|
97594
|
-
const path3 =
|
|
97810
|
+
const path3 = join60(opts.stateDir, ISSUES_FILE);
|
|
97595
97811
|
const log = opts.log ?? (() => {});
|
|
97596
97812
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
97597
97813
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -97642,7 +97858,7 @@ function defaultSignatureProvider(path3) {
|
|
|
97642
97858
|
if (!existsSync50(path3))
|
|
97643
97859
|
return null;
|
|
97644
97860
|
try {
|
|
97645
|
-
const stat =
|
|
97861
|
+
const stat = statSync19(path3);
|
|
97646
97862
|
return `${stat.mtimeMs}:${stat.size}`;
|
|
97647
97863
|
} catch {
|
|
97648
97864
|
return null;
|
|
@@ -98351,7 +98567,7 @@ function readBashCommand(inputPreview) {
|
|
|
98351
98567
|
|
|
98352
98568
|
// gateway/scoped-grant-store.ts
|
|
98353
98569
|
init_atomic();
|
|
98354
|
-
import { join as
|
|
98570
|
+
import { join as join61 } from "node:path";
|
|
98355
98571
|
|
|
98356
98572
|
// scoped-approval.ts
|
|
98357
98573
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -98393,7 +98609,7 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
98393
98609
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
98394
98610
|
}
|
|
98395
98611
|
function createScopedGrantStore(stateDir, env = process.env, log = (l) => process.stderr.write(l)) {
|
|
98396
|
-
const filePath =
|
|
98612
|
+
const filePath = join61(stateDir, "scoped-grants.json");
|
|
98397
98613
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
98398
98614
|
let unreadable = false;
|
|
98399
98615
|
function read() {
|
|
@@ -98772,7 +98988,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
98772
98988
|
// credits-watch.ts
|
|
98773
98989
|
init_card_format();
|
|
98774
98990
|
import { readFileSync as readFileSync53, writeFileSync as writeFileSync43, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
|
|
98775
|
-
import { join as
|
|
98991
|
+
import { join as join62 } from "path";
|
|
98776
98992
|
var STATE_FILE = "credits-watch.json";
|
|
98777
98993
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
98778
98994
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -98794,7 +99010,7 @@ function emptyCreditState() {
|
|
|
98794
99010
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
98795
99011
|
}
|
|
98796
99012
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
98797
|
-
const path3 =
|
|
99013
|
+
const path3 = join62(claudeConfigDir, ".claude.json");
|
|
98798
99014
|
if (!existsSync51(path3))
|
|
98799
99015
|
return null;
|
|
98800
99016
|
let raw;
|
|
@@ -98877,7 +99093,7 @@ function humanizeReason(reason) {
|
|
|
98877
99093
|
}
|
|
98878
99094
|
}
|
|
98879
99095
|
function loadCreditState(stateDir) {
|
|
98880
|
-
const path3 =
|
|
99096
|
+
const path3 = join62(stateDir, STATE_FILE);
|
|
98881
99097
|
if (!existsSync51(path3))
|
|
98882
99098
|
return emptyCreditState();
|
|
98883
99099
|
try {
|
|
@@ -98894,7 +99110,7 @@ function loadCreditState(stateDir) {
|
|
|
98894
99110
|
}
|
|
98895
99111
|
function saveCreditState(stateDir, state7) {
|
|
98896
99112
|
mkdirSync44(stateDir, { recursive: true });
|
|
98897
|
-
const path3 =
|
|
99113
|
+
const path3 = join62(stateDir, STATE_FILE);
|
|
98898
99114
|
writeFileSync43(path3, JSON.stringify(state7, null, 2) + `
|
|
98899
99115
|
`, { mode: 384 });
|
|
98900
99116
|
}
|
|
@@ -98903,7 +99119,7 @@ function saveCreditState(stateDir, state7) {
|
|
|
98903
99119
|
init_auth_snapshot_format();
|
|
98904
99120
|
init_card_format();
|
|
98905
99121
|
import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync52, mkdirSync as mkdirSync45 } from "fs";
|
|
98906
|
-
import { join as
|
|
99122
|
+
import { join as join63 } from "path";
|
|
98907
99123
|
var STATE_FILE2 = "quota-watch.json";
|
|
98908
99124
|
function emptyQuotaWatchState() {
|
|
98909
99125
|
return {};
|
|
@@ -99141,7 +99357,7 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
99141
99357
|
`);
|
|
99142
99358
|
}
|
|
99143
99359
|
function loadQuotaWatchState(stateDir) {
|
|
99144
|
-
const path3 =
|
|
99360
|
+
const path3 = join63(stateDir, STATE_FILE2);
|
|
99145
99361
|
if (!existsSync52(path3))
|
|
99146
99362
|
return emptyQuotaWatchState();
|
|
99147
99363
|
try {
|
|
@@ -99163,7 +99379,7 @@ function loadQuotaWatchState(stateDir) {
|
|
|
99163
99379
|
}
|
|
99164
99380
|
function saveQuotaWatchState(stateDir, state7) {
|
|
99165
99381
|
mkdirSync45(stateDir, { recursive: true });
|
|
99166
|
-
const path3 =
|
|
99382
|
+
const path3 = join63(stateDir, STATE_FILE2);
|
|
99167
99383
|
writeFileSync44(path3, JSON.stringify(state7, null, 2) + `
|
|
99168
99384
|
`, { mode: 384 });
|
|
99169
99385
|
}
|
|
@@ -99216,27 +99432,27 @@ import {
|
|
|
99216
99432
|
mkdirSync as mkdirSync46,
|
|
99217
99433
|
openSync as openSync13,
|
|
99218
99434
|
readFileSync as readFileSync55,
|
|
99219
|
-
statSync as
|
|
99220
|
-
unlinkSync as
|
|
99435
|
+
statSync as statSync20,
|
|
99436
|
+
unlinkSync as unlinkSync27,
|
|
99221
99437
|
utimesSync as utimesSync2,
|
|
99222
99438
|
writeFileSync as writeFileSync45
|
|
99223
99439
|
} from "node:fs";
|
|
99224
|
-
import { join as
|
|
99440
|
+
import { join as join64 } from "node:path";
|
|
99225
99441
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
99226
99442
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
99227
99443
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
99228
99444
|
function removeTurnActiveMarker2(stateDir) {
|
|
99229
99445
|
try {
|
|
99230
|
-
|
|
99446
|
+
unlinkSync27(join64(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
99231
99447
|
} catch {}
|
|
99232
99448
|
}
|
|
99233
99449
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
99234
|
-
const path3 =
|
|
99450
|
+
const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
99235
99451
|
if (!existsSync53(path3))
|
|
99236
99452
|
return false;
|
|
99237
99453
|
const now = opts.now ?? Date.now();
|
|
99238
99454
|
try {
|
|
99239
|
-
const st =
|
|
99455
|
+
const st = statSync20(path3);
|
|
99240
99456
|
const ageMs = now - st.mtimeMs;
|
|
99241
99457
|
const hardExpired = ageMs > opts.hardTtlMs;
|
|
99242
99458
|
const idleExpired = !opts.turnInFlight && ageMs > opts.idleSweepMs;
|
|
@@ -99246,7 +99462,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
99246
99462
|
try {
|
|
99247
99463
|
payload = readFileSync55(path3, "utf8");
|
|
99248
99464
|
} catch {}
|
|
99249
|
-
|
|
99465
|
+
unlinkSync27(path3);
|
|
99250
99466
|
if (opts.onRemove) {
|
|
99251
99467
|
try {
|
|
99252
99468
|
opts.onRemove({
|
|
@@ -99262,9 +99478,9 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
99262
99478
|
}
|
|
99263
99479
|
}
|
|
99264
99480
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
99265
|
-
const path3 =
|
|
99481
|
+
const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
99266
99482
|
try {
|
|
99267
|
-
const st =
|
|
99483
|
+
const st = statSync20(path3);
|
|
99268
99484
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
99269
99485
|
} catch {
|
|
99270
99486
|
return null;
|
|
@@ -99276,11 +99492,11 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
99276
99492
|
|
|
99277
99493
|
// gateway/gateway-heartbeat.ts
|
|
99278
99494
|
import { mkdirSync as mkdirSync47, utimesSync as utimesSync3, writeFileSync as writeFileSync46 } from "node:fs";
|
|
99279
|
-
import { join as
|
|
99495
|
+
import { join as join65 } from "node:path";
|
|
99280
99496
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
99281
99497
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
99282
99498
|
function touchGatewayHeartbeat(stateDir) {
|
|
99283
|
-
const path3 =
|
|
99499
|
+
const path3 = join65(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
99284
99500
|
const now = new Date;
|
|
99285
99501
|
try {
|
|
99286
99502
|
utimesSync3(path3, now, now);
|
|
@@ -99308,10 +99524,10 @@ import {
|
|
|
99308
99524
|
openSync as openSync14,
|
|
99309
99525
|
readFileSync as readFileSync56,
|
|
99310
99526
|
renameSync as renameSync25,
|
|
99311
|
-
unlinkSync as
|
|
99527
|
+
unlinkSync as unlinkSync28,
|
|
99312
99528
|
writeFileSync as writeFileSync47
|
|
99313
99529
|
} from "node:fs";
|
|
99314
|
-
import { join as
|
|
99530
|
+
import { join as join66 } from "node:path";
|
|
99315
99531
|
var BOOT_BEACON_FILE = "gateway-beacon.json";
|
|
99316
99532
|
var HOST_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
|
|
99317
99533
|
var CGROUP_MEMORY_EVENTS_PATH = "/sys/fs/cgroup/memory.events";
|
|
@@ -99410,7 +99626,7 @@ function sampleBeaconHost(paths = {}) {
|
|
|
99410
99626
|
return sample3;
|
|
99411
99627
|
}
|
|
99412
99628
|
function writeBootBeaconFile(stateDir, beacon) {
|
|
99413
|
-
const path3 =
|
|
99629
|
+
const path3 = join66(stateDir, BOOT_BEACON_FILE);
|
|
99414
99630
|
const tmp = `${path3}.tmp-${process.pid}`;
|
|
99415
99631
|
let fd;
|
|
99416
99632
|
try {
|
|
@@ -99429,7 +99645,7 @@ function writeBootBeaconFile(stateDir, beacon) {
|
|
|
99429
99645
|
} catch {}
|
|
99430
99646
|
}
|
|
99431
99647
|
try {
|
|
99432
|
-
|
|
99648
|
+
unlinkSync28(tmp);
|
|
99433
99649
|
} catch {}
|
|
99434
99650
|
return false;
|
|
99435
99651
|
}
|
|
@@ -99457,6 +99673,8 @@ function attachBootBeacon(stateDir, next) {
|
|
|
99457
99673
|
}
|
|
99458
99674
|
|
|
99459
99675
|
// gateway/outbox-sweep.ts
|
|
99676
|
+
init_rich_send();
|
|
99677
|
+
init_format();
|
|
99460
99678
|
init_flood_circuit_breaker();
|
|
99461
99679
|
async function sweepOutbox(deps) {
|
|
99462
99680
|
const now = deps.now?.() ?? Date.now();
|
|
@@ -99529,15 +99747,20 @@ async function sweepOutbox(deps) {
|
|
|
99529
99747
|
}
|
|
99530
99748
|
const resolvedChat = resolved;
|
|
99531
99749
|
try {
|
|
99532
|
-
const
|
|
99750
|
+
const sendResult = await deps.send(resolvedChat.chatId, resolvedChat.threadId, decision.text ?? record2.text);
|
|
99533
99751
|
appendDelivered({
|
|
99534
99752
|
turnNonce: record2.turnNonce,
|
|
99535
99753
|
textSha256: record2.textSha256,
|
|
99536
|
-
tgMessageId: messageId,
|
|
99754
|
+
tgMessageId: sendResult.messageId,
|
|
99537
99755
|
ts: now,
|
|
99538
99756
|
deliverySource: "sweep",
|
|
99539
99757
|
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
99540
99758
|
}, deps.stateDir);
|
|
99759
|
+
if (deps.recordOutbound != null && sendResult.chunks.length > 0) {
|
|
99760
|
+
try {
|
|
99761
|
+
deps.recordOutbound(resolvedChat.chatId, resolvedChat.threadId, sendResult.chunks.map((c) => c.messageId), sendResult.chunks.map((c) => c.text));
|
|
99762
|
+
} catch {}
|
|
99763
|
+
}
|
|
99541
99764
|
removeClaimed(record2.turnNonce, deps.stateDir);
|
|
99542
99765
|
summary.delivered++;
|
|
99543
99766
|
log(`outbox-sweep: delivered nonce=${record2.turnNonce} via=${resolvedChat.via} ` + `source=${record2.source} chars=${record2.text.length}${decision.action === "send-delayed" ? " (delayed)" : ""}
|
|
@@ -99592,27 +99815,42 @@ function createSweepBackoff(cfg = {}) {
|
|
|
99592
99815
|
failures: () => failures
|
|
99593
99816
|
};
|
|
99594
99817
|
}
|
|
99818
|
+
async function sendChunkRich(bot, chatId, chunk2, opts) {
|
|
99819
|
+
try {
|
|
99820
|
+
return await bot.api.sendRichMessage(chatId, richMessage(chunk2), opts);
|
|
99821
|
+
} catch (err) {
|
|
99822
|
+
if (isParseEntitiesError(err)) {
|
|
99823
|
+
return await bot.api.sendMessage(chatId, chunk2, opts);
|
|
99824
|
+
}
|
|
99825
|
+
throw err;
|
|
99826
|
+
}
|
|
99827
|
+
}
|
|
99595
99828
|
function createOutboxSend(deps) {
|
|
99596
99829
|
return async (chatId, threadId, text4) => {
|
|
99597
99830
|
const bot = deps.getBot();
|
|
99598
99831
|
if (bot == null)
|
|
99599
99832
|
throw new Error("outbox-sweep: bot unavailable");
|
|
99600
99833
|
if (text4.length === 0)
|
|
99601
|
-
return;
|
|
99834
|
+
return { messageId: undefined, chunks: [] };
|
|
99602
99835
|
const replyMarkup = deps.resolveReplyMarkup?.(chatId, threadId, text4);
|
|
99603
|
-
|
|
99604
|
-
const
|
|
99605
|
-
for (let
|
|
99606
|
-
const chunk2 =
|
|
99607
|
-
const isLast = idx ===
|
|
99836
|
+
const landed = [];
|
|
99837
|
+
const chunks = splitMarkdownChunks(text4);
|
|
99838
|
+
for (let idx = 0;idx < chunks.length; idx++) {
|
|
99839
|
+
const chunk2 = chunks[idx];
|
|
99840
|
+
const isLast = idx === chunks.length - 1;
|
|
99608
99841
|
const res = await retryWithThreadFallback(deps.retry, (tid) => {
|
|
99609
99842
|
const base = tid != null ? { message_thread_id: tid } : {};
|
|
99610
99843
|
const opts = isLast && replyMarkup != null ? { ...base, reply_markup: replyMarkup } : base;
|
|
99611
|
-
return bot
|
|
99844
|
+
return sendChunkRich(bot, chatId, chunk2, opts);
|
|
99612
99845
|
}, { threadId: threadId ?? undefined, chat_id: chatId, verb: "outbox-sweep.sendMessage" });
|
|
99613
|
-
|
|
99846
|
+
const id = res?.message_id;
|
|
99847
|
+
if (id != null)
|
|
99848
|
+
landed.push({ messageId: id, text: chunk2 });
|
|
99614
99849
|
}
|
|
99615
|
-
return
|
|
99850
|
+
return {
|
|
99851
|
+
messageId: landed.length > 0 ? landed[landed.length - 1].messageId : undefined,
|
|
99852
|
+
chunks: landed
|
|
99853
|
+
};
|
|
99616
99854
|
};
|
|
99617
99855
|
}
|
|
99618
99856
|
function startOutboxSweep(deps) {
|
|
@@ -99643,6 +99881,7 @@ function startOutboxSweep(deps) {
|
|
|
99643
99881
|
stateDir: deps.stateDir,
|
|
99644
99882
|
log: deps.log,
|
|
99645
99883
|
send,
|
|
99884
|
+
...deps.recordOutbound != null ? { recordOutbound: deps.recordOutbound } : {},
|
|
99646
99885
|
floodWaitRemainingMs: floodProbe,
|
|
99647
99886
|
textAlreadyDelivered: (chatId, threadId, text4) => deps.dedupCheck(chatId, threadId ?? undefined, text4),
|
|
99648
99887
|
registryChainLookup: (taskId) => {
|
|
@@ -99678,10 +99917,10 @@ function startOutboxSweep(deps) {
|
|
|
99678
99917
|
}
|
|
99679
99918
|
|
|
99680
99919
|
// ../src/build-info.ts
|
|
99681
|
-
var VERSION2 = "0.19.
|
|
99682
|
-
var COMMIT_SHA = "
|
|
99683
|
-
var COMMIT_DATE = "2026-07-
|
|
99684
|
-
var LATEST_PR =
|
|
99920
|
+
var VERSION2 = "0.19.40";
|
|
99921
|
+
var COMMIT_SHA = "89286b22";
|
|
99922
|
+
var COMMIT_DATE = "2026-07-31T04:28:56Z";
|
|
99923
|
+
var LATEST_PR = 4061;
|
|
99685
99924
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
99686
99925
|
|
|
99687
99926
|
// gateway/boot-version.ts
|
|
@@ -99758,12 +99997,12 @@ init_protocol2();
|
|
|
99758
99997
|
init_peercred();
|
|
99759
99998
|
import * as net5 from "node:net";
|
|
99760
99999
|
import * as fs3 from "node:fs";
|
|
99761
|
-
import { homedir as
|
|
99762
|
-
import { join as
|
|
100000
|
+
import { homedir as homedir19 } from "node:os";
|
|
100001
|
+
import { join as join67 } from "node:path";
|
|
99763
100002
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
99764
100003
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
99765
|
-
var LEGACY_SOCKET_PATH2 =
|
|
99766
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
100004
|
+
var LEGACY_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "vault-broker.sock");
|
|
100005
|
+
var OPERATOR_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "broker-operator", "sock");
|
|
99767
100006
|
function defaultBrokerSocketPath2() {
|
|
99768
100007
|
if (fs3.existsSync(OPERATOR_SOCKET_PATH2))
|
|
99769
100008
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -100646,7 +100885,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
100646
100885
|
|
|
100647
100886
|
// registry/turns-schema.ts
|
|
100648
100887
|
import { chmodSync as chmodSync12, mkdirSync as mkdirSync49 } from "fs";
|
|
100649
|
-
import { join as
|
|
100888
|
+
import { join as join68 } from "path";
|
|
100650
100889
|
var DatabaseClass3 = null;
|
|
100651
100890
|
function loadDatabaseClass3() {
|
|
100652
100891
|
if (DatabaseClass3 != null)
|
|
@@ -100718,9 +100957,9 @@ function applySchema(db3) {
|
|
|
100718
100957
|
}
|
|
100719
100958
|
function openTurnsDb(agentDir) {
|
|
100720
100959
|
const Database = loadDatabaseClass3();
|
|
100721
|
-
const dir =
|
|
100960
|
+
const dir = join68(agentDir, "telegram");
|
|
100722
100961
|
mkdirSync49(dir, { recursive: true, mode: 448 });
|
|
100723
|
-
const path3 =
|
|
100962
|
+
const path3 = join68(dir, "registry.db");
|
|
100724
100963
|
const db3 = new Database(path3, { create: true });
|
|
100725
100964
|
applySchema(db3);
|
|
100726
100965
|
try {
|
|
@@ -101065,7 +101304,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
101065
101304
|
}
|
|
101066
101305
|
|
|
101067
101306
|
// gateway/bridge-dead-watchdog.ts
|
|
101068
|
-
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as
|
|
101307
|
+
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as unlinkSync29 } from "node:fs";
|
|
101069
101308
|
|
|
101070
101309
|
// gateway/cron-session.ts
|
|
101071
101310
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -101137,7 +101376,7 @@ function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs
|
|
|
101137
101376
|
}
|
|
101138
101377
|
} catch {}
|
|
101139
101378
|
try {
|
|
101140
|
-
|
|
101379
|
+
unlinkSync29(path3);
|
|
101141
101380
|
} catch {}
|
|
101142
101381
|
return marker;
|
|
101143
101382
|
}
|
|
@@ -101537,7 +101776,7 @@ if (isGatewayMain) {
|
|
|
101537
101776
|
shutdownAnalytics();
|
|
101538
101777
|
});
|
|
101539
101778
|
}
|
|
101540
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
101779
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join69(homedir20(), ".claude", "channels", "telegram");
|
|
101541
101780
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
101542
101781
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
101543
101782
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -101637,11 +101876,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
101637
101876
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
101638
101877
|
timer3.unref?.();
|
|
101639
101878
|
}
|
|
101640
|
-
var ACCESS_FILE =
|
|
101641
|
-
var APPROVED_DIR =
|
|
101642
|
-
var ENV_FILE =
|
|
101643
|
-
var INBOX_DIR =
|
|
101644
|
-
var PEOPLE_FILE =
|
|
101879
|
+
var ACCESS_FILE = join69(STATE_DIR, "access.json");
|
|
101880
|
+
var APPROVED_DIR = join69(STATE_DIR, "approved");
|
|
101881
|
+
var ENV_FILE = join69(STATE_DIR, ".env");
|
|
101882
|
+
var INBOX_DIR = join69(STATE_DIR, "inbox");
|
|
101883
|
+
var PEOPLE_FILE = join69(STATE_DIR, "people.json");
|
|
101645
101884
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
101646
101885
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
101647
101886
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -101790,7 +102029,7 @@ function assertSendable(f) {
|
|
|
101790
102029
|
} catch {
|
|
101791
102030
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
101792
102031
|
}
|
|
101793
|
-
const inbox =
|
|
102032
|
+
const inbox = join69(stateReal, "inbox");
|
|
101794
102033
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
101795
102034
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
101796
102035
|
}
|
|
@@ -101915,7 +102154,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
101915
102154
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
101916
102155
|
try {
|
|
101917
102156
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
101918
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
102157
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join69(STATE_DIR, "history.db")}
|
|
101919
102158
|
`);
|
|
101920
102159
|
} catch (err) {
|
|
101921
102160
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -101934,9 +102173,9 @@ if (isGatewayMain)
|
|
|
101934
102173
|
let markerTurnKey = null;
|
|
101935
102174
|
let markerAgeMs = null;
|
|
101936
102175
|
try {
|
|
101937
|
-
const markerPath =
|
|
102176
|
+
const markerPath = join69(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
101938
102177
|
if (existsSync57(markerPath)) {
|
|
101939
|
-
const st =
|
|
102178
|
+
const st = statSync23(markerPath);
|
|
101940
102179
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
101941
102180
|
try {
|
|
101942
102181
|
const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
|
|
@@ -101959,10 +102198,10 @@ if (isGatewayMain)
|
|
|
101959
102198
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
101960
102199
|
`);
|
|
101961
102200
|
} else {
|
|
101962
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
102201
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join69(agentDir, "telegram", "registry.db")}
|
|
101963
102202
|
`);
|
|
101964
102203
|
}
|
|
101965
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
102204
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join69(STATE_DIR, "bridge-dead-escalation.json"));
|
|
101966
102205
|
if (bridgeDeadMarker != null) {
|
|
101967
102206
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
101968
102207
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -101975,7 +102214,7 @@ if (isGatewayMain)
|
|
|
101975
102214
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
101976
102215
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
101977
102216
|
if (pending2 != null && selfAgent) {
|
|
101978
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
102217
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
|
|
101979
102218
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
101980
102219
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
101981
102220
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -102088,7 +102327,7 @@ if (isGatewayMain)
|
|
|
102088
102327
|
`);
|
|
102089
102328
|
}
|
|
102090
102329
|
}
|
|
102091
|
-
const pendingEnvPath =
|
|
102330
|
+
const pendingEnvPath = join69(agentDir, ".pending-turn.env");
|
|
102092
102331
|
try {
|
|
102093
102332
|
if (pending2 != null) {
|
|
102094
102333
|
const lines = [
|
|
@@ -102216,7 +102455,7 @@ function checkApprovals() {
|
|
|
102216
102455
|
return;
|
|
102217
102456
|
}
|
|
102218
102457
|
for (const senderId of files) {
|
|
102219
|
-
const file =
|
|
102458
|
+
const file = join69(APPROVED_DIR, senderId);
|
|
102220
102459
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync8(file, { force: true }), (err) => {
|
|
102221
102460
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
102222
102461
|
`);
|
|
@@ -102302,6 +102541,7 @@ async function deliverAnswer(args) {
|
|
|
102302
102541
|
const result = await runBackstopDelivery(backstopDeliveryLedger, turnId, chunks, args.resume ? null : args.cardMessageId, {
|
|
102303
102542
|
sendChunk,
|
|
102304
102543
|
readBack,
|
|
102544
|
+
onAckClaim: args.onAckClaim,
|
|
102305
102545
|
recordOutbound: HISTORY_ENABLED ? (messageIds, texts) => {
|
|
102306
102546
|
try {
|
|
102307
102547
|
recordOutbound({
|
|
@@ -102390,7 +102630,7 @@ function noteAgentOutputAt(key, ts) {
|
|
|
102390
102630
|
lastAgentOutputAt.delete(oldest);
|
|
102391
102631
|
}
|
|
102392
102632
|
}
|
|
102393
|
-
var OBLIGATION_STORE_PATH =
|
|
102633
|
+
var OBLIGATION_STORE_PATH = join69(STATE_DIR, "obligations.json");
|
|
102394
102634
|
var obligationStoreFs = {
|
|
102395
102635
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
102396
102636
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -103167,7 +103407,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
103167
103407
|
maybeRotate(turnsPath, {
|
|
103168
103408
|
statSize: (p) => {
|
|
103169
103409
|
try {
|
|
103170
|
-
return
|
|
103410
|
+
return statSync23(p).size;
|
|
103171
103411
|
} catch {
|
|
103172
103412
|
return;
|
|
103173
103413
|
}
|
|
@@ -104735,7 +104975,7 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
104735
104975
|
})();
|
|
104736
104976
|
var statusPinClaims = new Map;
|
|
104737
104977
|
var statusPinRightsCache = new PinRightsCache2;
|
|
104738
|
-
var STATUS_PIN_STORE_PATH =
|
|
104978
|
+
var STATUS_PIN_STORE_PATH = join69(STATE_DIR, "status-pins.json");
|
|
104739
104979
|
var statusPinStoreFs = {
|
|
104740
104980
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104741
104981
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -104743,7 +104983,7 @@ var statusPinStoreFs = {
|
|
|
104743
104983
|
existsSync: (p) => existsSync57(p)
|
|
104744
104984
|
};
|
|
104745
104985
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
104746
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
104986
|
+
var ACTIVITY_CARD_STORE_PATH = join69(STATE_DIR, "activity-cards-pending.json");
|
|
104747
104987
|
var activityCardStoreFs = {
|
|
104748
104988
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104749
104989
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -104751,7 +104991,7 @@ var activityCardStoreFs = {
|
|
|
104751
104991
|
existsSync: (p) => existsSync57(p)
|
|
104752
104992
|
};
|
|
104753
104993
|
var activityCardPersistEnabled = !STATIC;
|
|
104754
|
-
var QUEUED_CARD_STORE_PATH =
|
|
104994
|
+
var QUEUED_CARD_STORE_PATH = join69(STATE_DIR, "queued-cards-pending.json");
|
|
104755
104995
|
var queuedCardStoreFs = {
|
|
104756
104996
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104757
104997
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -105043,7 +105283,7 @@ async function unpinAllStatusPins() {
|
|
|
105043
105283
|
}
|
|
105044
105284
|
}
|
|
105045
105285
|
var stalePinSweepEligible = false;
|
|
105046
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
105286
|
+
var STALE_PIN_SWEEP_STORE_PATH = join69(STATE_DIR, "stale-pin-sweep.json");
|
|
105047
105287
|
var stalePinSweeper = createGatewayStalePinSweeper({
|
|
105048
105288
|
telegram: { handle: () => lockedBot, call: robustApiCall },
|
|
105049
105289
|
claims: () => statusPinClaims.values(),
|
|
@@ -105084,12 +105324,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
105084
105324
|
var completeProgressCardTurn = null;
|
|
105085
105325
|
var subagentWatcher = null;
|
|
105086
105326
|
var workerActivityFeed = null;
|
|
105087
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
105327
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join69(STATE_DIR, "gateway.sock");
|
|
105088
105328
|
if (isGatewayMain)
|
|
105089
105329
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
105090
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
105091
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
105092
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
105330
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join69(STATE_DIR, "gateway.pid.json");
|
|
105331
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join69(STATE_DIR, "gateway-session.json");
|
|
105332
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
|
|
105093
105333
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
105094
105334
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
105095
105335
|
var activeBootCard = null;
|
|
@@ -105118,7 +105358,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
105118
105358
|
bot: botApi,
|
|
105119
105359
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
105120
105360
|
`),
|
|
105121
|
-
persistPath:
|
|
105361
|
+
persistPath: join69(stateDir, "issues-card.json")
|
|
105122
105362
|
});
|
|
105123
105363
|
activeIssuesWatcher = startIssuesWatcher({
|
|
105124
105364
|
stateDir,
|
|
@@ -105296,7 +105536,11 @@ function runDeliveryConfirmSweep() {
|
|
|
105296
105536
|
}
|
|
105297
105537
|
var _deliveryConfirmSweep = isGatewayMain ? setInterval(runDeliveryConfirmSweep, DELIVERY_CONFIRM_SWEEP_MS) : undefined;
|
|
105298
105538
|
_deliveryConfirmSweep?.unref?.();
|
|
105299
|
-
startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null,
|
|
105539
|
+
startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null, recordOutbound: HISTORY_ENABLED ? (chatId, threadId, message_ids, texts) => {
|
|
105540
|
+
try {
|
|
105541
|
+
recordOutbound({ chat_id: chatId, thread_id: threadId, message_ids, texts });
|
|
105542
|
+
} catch {}
|
|
105543
|
+
} : undefined, resolveReplyMarkup: makeOutboxListenMarkupResolver({ resolveVoiceOutPlan: (t) => resolveVoiceOutPlan(loadAccess().voice_out, t), cachePut: (token, payload) => voiceOnDemandCache.put(token, payload), eagerVoiceEnabled, enqueuePreSynth: (j) => voicePreSynthQueue.enqueue(j) }), log: (l) => process.stderr.write(l) });
|
|
105300
105544
|
if (isGatewayMain)
|
|
105301
105545
|
startTimer2({
|
|
105302
105546
|
editMessage: async (ctx) => {
|
|
@@ -105318,14 +105562,14 @@ if (isGatewayMain)
|
|
|
105318
105562
|
var inboundSpool;
|
|
105319
105563
|
if (isGatewayMain)
|
|
105320
105564
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
105321
|
-
path:
|
|
105565
|
+
path: join69(STATE_DIR, "inbound-spool.jsonl"),
|
|
105322
105566
|
fs: {
|
|
105323
105567
|
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
105324
105568
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
105325
105569
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
105326
105570
|
renameSync: (a, b) => renameSync27(a, b),
|
|
105327
105571
|
existsSync: (p) => existsSync57(p),
|
|
105328
|
-
statSizeSync: (p) =>
|
|
105572
|
+
statSizeSync: (p) => statSync23(p).size,
|
|
105329
105573
|
fsyncFileSync: fsyncPathSync,
|
|
105330
105574
|
fsyncDirSync: fsyncPathSync
|
|
105331
105575
|
},
|
|
@@ -105388,7 +105632,7 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
105388
105632
|
let transcriptText;
|
|
105389
105633
|
try {
|
|
105390
105634
|
const projectsDir = getProjectsDirForCwd();
|
|
105391
|
-
const path3 =
|
|
105635
|
+
const path3 = join69(projectsDir, `${sessionId}.jsonl`);
|
|
105392
105636
|
if (!existsSync57(path3)) {
|
|
105393
105637
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
105394
105638
|
`);
|
|
@@ -105553,8 +105797,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
105553
105797
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
105554
105798
|
isShuttingDown: () => shuttingDown,
|
|
105555
105799
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
105556
|
-
crashLogPath:
|
|
105557
|
-
markerPath:
|
|
105800
|
+
crashLogPath: join69(STATE_DIR, "bridge-crash.log"),
|
|
105801
|
+
markerPath: join69(STATE_DIR, "bridge-dead-escalation.json"),
|
|
105558
105802
|
log: (line) => process.stderr.write(`${line}
|
|
105559
105803
|
`),
|
|
105560
105804
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -105660,8 +105904,8 @@ if (isGatewayMain)
|
|
|
105660
105904
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
105661
105905
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
105662
105906
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
105663
|
-
configSnapshotPath:
|
|
105664
|
-
bootCardStatePath:
|
|
105907
|
+
configSnapshotPath: join69(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
105908
|
+
bootCardStatePath: join69(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
105665
105909
|
floodStatePath: FLOOD_STATE_PATH,
|
|
105666
105910
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
105667
105911
|
}, ackMsgId).then((handle) => {
|
|
@@ -106329,7 +106573,7 @@ if (isGatewayMain)
|
|
|
106329
106573
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
106330
106574
|
if (Number.isInteger(receiverUid))
|
|
106331
106575
|
allowedUids.push(receiverUid);
|
|
106332
|
-
const socketPath =
|
|
106576
|
+
const socketPath = join69(STATE_DIR, "webhook.sock");
|
|
106333
106577
|
const webhookInject = (agentName3, inbound) => {
|
|
106334
106578
|
const msg = inbound;
|
|
106335
106579
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -106557,9 +106801,9 @@ function redactOutboundText(text5, site) {
|
|
|
106557
106801
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
106558
106802
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
106559
106803
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
106560
|
-
persistPath:
|
|
106804
|
+
persistPath: join69(STATE_DIR, "voice-ondemand.json")
|
|
106561
106805
|
});
|
|
106562
|
-
var VOICE_CACHE_DIR =
|
|
106806
|
+
var VOICE_CACHE_DIR = join69(STATE_DIR, "voice-cache");
|
|
106563
106807
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
106564
106808
|
runJob: async (job) => {
|
|
106565
106809
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -106961,7 +107205,7 @@ async function executeSendGif(rawArgs) {
|
|
|
106961
107205
|
};
|
|
106962
107206
|
}
|
|
106963
107207
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
106964
|
-
const accountPath =
|
|
107208
|
+
const accountPath = join69(STATE_DIR, "telegraph-account.json");
|
|
106965
107209
|
let account = null;
|
|
106966
107210
|
try {
|
|
106967
107211
|
if (existsSync57(accountPath)) {
|
|
@@ -108516,7 +108760,7 @@ function restartMarkerPath() {
|
|
|
108516
108760
|
const agentDir = resolveAgentDirFromEnv();
|
|
108517
108761
|
if (!agentDir)
|
|
108518
108762
|
return null;
|
|
108519
|
-
return
|
|
108763
|
+
return join69(agentDir, "restart-pending.json");
|
|
108520
108764
|
}
|
|
108521
108765
|
function writeRestartMarker(marker) {
|
|
108522
108766
|
const p = restartMarkerPath();
|
|
@@ -108708,7 +108952,7 @@ function _resetDockerReachableCache() {
|
|
|
108708
108952
|
}
|
|
108709
108953
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
108710
108954
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
108711
|
-
const logPath =
|
|
108955
|
+
const logPath = join69(STATE_DIR, "detached-spawn.log");
|
|
108712
108956
|
let outFd = null;
|
|
108713
108957
|
try {
|
|
108714
108958
|
mkdirSync51(STATE_DIR, { recursive: true });
|
|
@@ -109001,7 +109245,7 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
109001
109245
|
}
|
|
109002
109246
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
109003
109247
|
try {
|
|
109004
|
-
const auditPath =
|
|
109248
|
+
const auditPath = join69(homedir20(), ".switchroom", "vault-audit.log");
|
|
109005
109249
|
if (!existsSync57(auditPath))
|
|
109006
109250
|
return [];
|
|
109007
109251
|
const raw = readFileSync60(auditPath, "utf8");
|
|
@@ -109055,7 +109299,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
109055
109299
|
try {
|
|
109056
109300
|
const agentDir = resolveAgentDirFromEnv();
|
|
109057
109301
|
if (agentDir) {
|
|
109058
|
-
const raw = readFileSync60(
|
|
109302
|
+
const raw = readFileSync60(join69(agentDir, ".claude", ".claude.json"), "utf8");
|
|
109059
109303
|
claudeJson = JSON.parse(raw);
|
|
109060
109304
|
}
|
|
109061
109305
|
} catch {}
|
|
@@ -109184,7 +109428,7 @@ function buildModelDeps(restartCtx) {
|
|
|
109184
109428
|
try {
|
|
109185
109429
|
const agentDir = resolveAgentDirFromEnv();
|
|
109186
109430
|
if (agentDir) {
|
|
109187
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
109431
|
+
const local = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
|
|
109188
109432
|
if (local.ok)
|
|
109189
109433
|
return formatQuotaLine2(local.data);
|
|
109190
109434
|
}
|
|
@@ -109431,10 +109675,10 @@ function effortMenuReplyMarkup(reply) {
|
|
|
109431
109675
|
function flushAgentHandoff(agentDir) {
|
|
109432
109676
|
let removed = 0;
|
|
109433
109677
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
109434
|
-
const p =
|
|
109678
|
+
const p = join69(agentDir, fname);
|
|
109435
109679
|
try {
|
|
109436
109680
|
if (existsSync57(p)) {
|
|
109437
|
-
|
|
109681
|
+
unlinkSync31(p);
|
|
109438
109682
|
removed++;
|
|
109439
109683
|
}
|
|
109440
109684
|
} catch (err) {
|
|
@@ -109489,7 +109733,7 @@ async function handleNewCommand(ctx) {
|
|
|
109489
109733
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
109490
109734
|
if (agentDir != null) {
|
|
109491
109735
|
try {
|
|
109492
|
-
writeFileSync50(
|
|
109736
|
+
writeFileSync50(join69(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
109493
109737
|
`, "utf8");
|
|
109494
109738
|
} catch (err) {
|
|
109495
109739
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -109606,7 +109850,7 @@ var lockoutOps = {
|
|
|
109606
109850
|
writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
|
|
109607
109851
|
existsSync: (p) => existsSync57(p),
|
|
109608
109852
|
mkdirSync: (p, opts) => mkdirSync51(p, opts),
|
|
109609
|
-
joinPath: (...parts) =>
|
|
109853
|
+
joinPath: (...parts) => join69(...parts)
|
|
109610
109854
|
};
|
|
109611
109855
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
109612
109856
|
function isAuthBrokerSocketReachable() {
|
|
@@ -109866,7 +110110,7 @@ async function runCreditWatch() {
|
|
|
109866
110110
|
if (!agentDir)
|
|
109867
110111
|
return;
|
|
109868
110112
|
const agentName3 = getMyAgentName();
|
|
109869
|
-
const claudeConfigDir =
|
|
110113
|
+
const claudeConfigDir = join69(agentDir, ".claude");
|
|
109870
110114
|
const stateDir = STATE_DIR;
|
|
109871
110115
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
109872
110116
|
const prev = loadCreditState(stateDir);
|
|
@@ -111622,7 +111866,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
111622
111866
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
111623
111867
|
return;
|
|
111624
111868
|
}
|
|
111625
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
111869
|
+
const result = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
|
|
111626
111870
|
if (!result.ok) {
|
|
111627
111871
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
111628
111872
|
return;
|
|
@@ -112878,7 +113122,7 @@ async function startGateway() {
|
|
|
112878
113122
|
return;
|
|
112879
113123
|
}
|
|
112880
113124
|
})();
|
|
112881
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
113125
|
+
const resolvedAgentDirForBootCard = agentDir ?? join69(homedir20(), ".switchroom", "agents", agentSlug);
|
|
112882
113126
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
112883
113127
|
agentName: agentDisplayName,
|
|
112884
113128
|
agentSlug,
|
|
@@ -112892,8 +113136,8 @@ async function startGateway() {
|
|
|
112892
113136
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
112893
113137
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
112894
113138
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
112895
|
-
configSnapshotPath:
|
|
112896
|
-
bootCardStatePath:
|
|
113139
|
+
configSnapshotPath: join69(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
113140
|
+
bootCardStatePath: join69(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
112897
113141
|
floodStatePath: FLOOD_STATE_PATH,
|
|
112898
113142
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
112899
113143
|
}, ackMsgId);
|
|
@@ -112926,7 +113170,7 @@ async function startGateway() {
|
|
|
112926
113170
|
if (smAgentDir) {
|
|
112927
113171
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
112928
113172
|
const resolved = await waitForSessionModelResolution({
|
|
112929
|
-
barrierExists: () => existsSync57(
|
|
113173
|
+
barrierExists: () => existsSync57(join69(smAgentDir, ".session-model-resolved")),
|
|
112930
113174
|
timeoutMs: resolutionTimeoutMs
|
|
112931
113175
|
});
|
|
112932
113176
|
if (!resolved) {
|
|
@@ -112934,7 +113178,7 @@ async function startGateway() {
|
|
|
112934
113178
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
112935
113179
|
`);
|
|
112936
113180
|
} else {
|
|
112937
|
-
const activePath =
|
|
113181
|
+
const activePath = join69(smAgentDir, ".active-session-model");
|
|
112938
113182
|
if (existsSync57(activePath)) {
|
|
112939
113183
|
try {
|
|
112940
113184
|
const launched = readFileSync60(activePath, "utf8").trim();
|
|
@@ -112970,12 +113214,12 @@ async function startGateway() {
|
|
|
112970
113214
|
deliverModelSwitchBootNotice({
|
|
112971
113215
|
...modelBootCardDeps,
|
|
112972
113216
|
confirmation,
|
|
112973
|
-
hasSessionModelAlert: existsSync57(
|
|
113217
|
+
hasSessionModelAlert: existsSync57(join69(smAgentDir, ".session-model-alert"))
|
|
112974
113218
|
});
|
|
112975
113219
|
}
|
|
112976
113220
|
} catch {}
|
|
112977
113221
|
}
|
|
112978
|
-
const activeEffortPath =
|
|
113222
|
+
const activeEffortPath = join69(smAgentDir, ".active-session-effort");
|
|
112979
113223
|
if (existsSync57(activeEffortPath)) {
|
|
112980
113224
|
try {
|
|
112981
113225
|
const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
|
|
@@ -112983,7 +113227,7 @@ async function startGateway() {
|
|
|
112983
113227
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
112984
113228
|
} catch {}
|
|
112985
113229
|
}
|
|
112986
|
-
const alertPath =
|
|
113230
|
+
const alertPath = join69(smAgentDir, ".session-model-alert");
|
|
112987
113231
|
if (existsSync57(alertPath)) {
|
|
112988
113232
|
let alertText = null;
|
|
112989
113233
|
try {
|
|
@@ -112992,7 +113236,7 @@ async function startGateway() {
|
|
|
112992
113236
|
alertText = null;
|
|
112993
113237
|
}
|
|
112994
113238
|
try {
|
|
112995
|
-
|
|
113239
|
+
unlinkSync31(alertPath);
|
|
112996
113240
|
} catch {}
|
|
112997
113241
|
if (alertText && alertText.length > 0) {
|
|
112998
113242
|
const operators = loadAccess().allowFrom;
|