switchroom 0.19.39 → 0.19.41
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 +12 -3
- package/dist/cli/notion-write-pretool.mjs +10 -1
- package/dist/cli/switchroom.js +562 -196
- package/dist/host-control/main.js +287 -20
- package/dist/vault/approvals/kernel-server.js +12 -3
- package/dist/vault/broker/server.js +12 -3
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +10 -0
- package/telegram-plugin/bridge/bridge.ts +2 -2
- package/telegram-plugin/dist/bridge/bridge.js +10 -2
- package/telegram-plugin/dist/gateway/gateway.js +549 -232
- package/telegram-plugin/dist/server.js +10 -2
- package/telegram-plugin/gateway/backstop-delivery.ts +48 -0
- package/telegram-plugin/gateway/checklist-fallback.ts +370 -0
- package/telegram-plugin/gateway/compaction-marker.ts +84 -0
- package/telegram-plugin/gateway/gateway.ts +72 -72
- 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 +39 -1
- package/telegram-plugin/gateway/turn-record-status.ts +80 -0
- package/telegram-plugin/hooks/compaction-marker-precompact.mjs +70 -0
- package/telegram-plugin/hooks/hooks.json +11 -0
- package/telegram-plugin/session-tail.ts +20 -0
- package/telegram-plugin/silence-poke.ts +28 -0
- package/telegram-plugin/tests/checklist-fallback.test.ts +317 -0
- package/telegram-plugin/tests/gateway-outbound-redact.test.ts +10 -6
- 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/send-reply-golden.test.ts +47 -0
- package/telegram-plugin/tests/silence-poke-compaction.test.ts +222 -0
- package/telegram-plugin/tests/turn-record-status.test.ts +62 -0
|
@@ -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";
|
|
@@ -39495,6 +39504,178 @@ function redactChecklistFields(title, tasks, redact) {
|
|
|
39495
39504
|
};
|
|
39496
39505
|
}
|
|
39497
39506
|
|
|
39507
|
+
// gateway/checklist-fallback.ts
|
|
39508
|
+
var CHECKLIST_MAX_TASKS = 30;
|
|
39509
|
+
function buildChecklistTasks(tasks) {
|
|
39510
|
+
if (tasks.length > CHECKLIST_MAX_TASKS) {
|
|
39511
|
+
throw new Error(`checklist exceeds ${CHECKLIST_MAX_TASKS}-task limit (got ${tasks.length})`);
|
|
39512
|
+
}
|
|
39513
|
+
return tasks.map((t, i) => ({ id: i + 1, text: t.text, done: t.done === true }));
|
|
39514
|
+
}
|
|
39515
|
+
function renderChecklistText(cl, opts) {
|
|
39516
|
+
const header = opts?.literal ? cl.title : `**${cl.title}**`;
|
|
39517
|
+
const lines = cl.tasks.map((t) => `${t.done ? "\u2705" : "\u2b1c"} ${t.text}`);
|
|
39518
|
+
return [header, ...lines].join(`
|
|
39519
|
+
`);
|
|
39520
|
+
}
|
|
39521
|
+
function applyChecklistPatch(cl, patch) {
|
|
39522
|
+
const tasks = cl.tasks.map((t) => ({ ...t }));
|
|
39523
|
+
for (const p of patch.tasks ?? []) {
|
|
39524
|
+
const pid = p.id != null ? Number(p.id) : undefined;
|
|
39525
|
+
const existing = pid != null ? tasks.find((t) => t.id === pid) : undefined;
|
|
39526
|
+
if (existing) {
|
|
39527
|
+
if (p.text != null)
|
|
39528
|
+
existing.text = p.text;
|
|
39529
|
+
if (p.done != null)
|
|
39530
|
+
existing.done = p.done;
|
|
39531
|
+
} else {
|
|
39532
|
+
const nextId = pid != null && Number.isFinite(pid) ? pid : tasks.reduce((m, t) => Math.max(m, t.id), 0) + 1;
|
|
39533
|
+
tasks.push({ id: nextId, text: p.text ?? "", done: p.done === true });
|
|
39534
|
+
}
|
|
39535
|
+
}
|
|
39536
|
+
if (tasks.length > CHECKLIST_MAX_TASKS) {
|
|
39537
|
+
throw new Error(`checklist exceeds ${CHECKLIST_MAX_TASKS}-task limit (got ${tasks.length})`);
|
|
39538
|
+
}
|
|
39539
|
+
return { title: patch.title ?? cl.title, tasks };
|
|
39540
|
+
}
|
|
39541
|
+
function buildNativeChecklistPayload(p) {
|
|
39542
|
+
return {
|
|
39543
|
+
business_connection_id: p.businessConnectionId,
|
|
39544
|
+
chat_id: p.chatId,
|
|
39545
|
+
checklist: {
|
|
39546
|
+
title: p.title,
|
|
39547
|
+
tasks: p.tasks.map((t) => ({ id: t.id, text: t.text }))
|
|
39548
|
+
},
|
|
39549
|
+
...p.replyToMessageId != null ? { reply_parameters: { message_id: p.replyToMessageId } } : {},
|
|
39550
|
+
...p.protectContent === true ? { protect_content: true } : {}
|
|
39551
|
+
};
|
|
39552
|
+
}
|
|
39553
|
+
function buildNativeEditChecklistPayload(p) {
|
|
39554
|
+
return {
|
|
39555
|
+
business_connection_id: p.businessConnectionId,
|
|
39556
|
+
chat_id: p.chatId,
|
|
39557
|
+
message_id: p.messageId,
|
|
39558
|
+
checklist: {
|
|
39559
|
+
title: p.title,
|
|
39560
|
+
tasks: p.tasks.map((t) => ({ id: t.id, text: t.text }))
|
|
39561
|
+
}
|
|
39562
|
+
};
|
|
39563
|
+
}
|
|
39564
|
+
function createChecklistStore(cap = 500) {
|
|
39565
|
+
const map = new Map;
|
|
39566
|
+
return {
|
|
39567
|
+
get: (key) => map.get(key),
|
|
39568
|
+
set: (key, state) => {
|
|
39569
|
+
if (map.has(key))
|
|
39570
|
+
map.delete(key);
|
|
39571
|
+
map.set(key, state);
|
|
39572
|
+
while (map.size > cap) {
|
|
39573
|
+
const oldest = map.keys().next().value;
|
|
39574
|
+
if (oldest == null)
|
|
39575
|
+
break;
|
|
39576
|
+
map.delete(oldest);
|
|
39577
|
+
}
|
|
39578
|
+
}
|
|
39579
|
+
};
|
|
39580
|
+
}
|
|
39581
|
+
function checklistStoreKey(chatId, messageId) {
|
|
39582
|
+
return `${chatId}:${messageId}`;
|
|
39583
|
+
}
|
|
39584
|
+
async function performSendChecklist(deps, args) {
|
|
39585
|
+
const tasks = buildChecklistTasks(args.tasks);
|
|
39586
|
+
if (deps.nativeAvailable && deps.businessConnectionId) {
|
|
39587
|
+
try {
|
|
39588
|
+
const sent2 = await deps.sendNative(buildNativeChecklistPayload({
|
|
39589
|
+
businessConnectionId: deps.businessConnectionId,
|
|
39590
|
+
chatId: args.chatId,
|
|
39591
|
+
title: args.title,
|
|
39592
|
+
tasks,
|
|
39593
|
+
replyToMessageId: args.replyToMessageId,
|
|
39594
|
+
protectContent: args.protectContent
|
|
39595
|
+
}));
|
|
39596
|
+
return {
|
|
39597
|
+
message_id: sent2.message_id,
|
|
39598
|
+
mode: "native",
|
|
39599
|
+
state: { title: args.title, tasks, mode: "native" }
|
|
39600
|
+
};
|
|
39601
|
+
} catch (err) {
|
|
39602
|
+
deps.log(`native sendChecklist failed \u2014 falling back to text render: ${err}
|
|
39603
|
+
`);
|
|
39604
|
+
}
|
|
39605
|
+
}
|
|
39606
|
+
const text = renderChecklistText({ title: args.title, tasks }, { literal: deps.literalText });
|
|
39607
|
+
const sent = await deps.sendText(text);
|
|
39608
|
+
return {
|
|
39609
|
+
message_id: sent.message_id,
|
|
39610
|
+
mode: "text",
|
|
39611
|
+
state: { title: args.title, tasks, mode: "text" }
|
|
39612
|
+
};
|
|
39613
|
+
}
|
|
39614
|
+
function sendChecklistToolText(r) {
|
|
39615
|
+
return JSON.stringify(r.mode === "native" ? { ok: true, message_id: r.message_id, mode: "native" } : {
|
|
39616
|
+
ok: true,
|
|
39617
|
+
message_id: r.message_id,
|
|
39618
|
+
mode: "text",
|
|
39619
|
+
degraded: "text",
|
|
39620
|
+
note: "rendered as a formatted text message (native Telegram checklists require a Business connection) \u2014 tasks are not tappable; use update_checklist with task ids 1..N to tick them"
|
|
39621
|
+
});
|
|
39622
|
+
}
|
|
39623
|
+
async function performUpdateChecklist(deps, patch) {
|
|
39624
|
+
let base = deps.state;
|
|
39625
|
+
if (!base) {
|
|
39626
|
+
const fullReplacement = patch.title != null && (patch.tasks?.length ?? 0) > 0 && (patch.tasks ?? []).every((t) => t.text != null);
|
|
39627
|
+
if (!fullReplacement) {
|
|
39628
|
+
return {
|
|
39629
|
+
ok: false,
|
|
39630
|
+
reason: "unknown_checklist",
|
|
39631
|
+
hint: "no stored state for this checklist (gateway restarted?). Re-send it with send_checklist, or pass a full replacement (title + every task's text) to update_checklist."
|
|
39632
|
+
};
|
|
39633
|
+
}
|
|
39634
|
+
base = { title: patch.title, tasks: [], mode: "text" };
|
|
39635
|
+
}
|
|
39636
|
+
let next;
|
|
39637
|
+
try {
|
|
39638
|
+
next = applyChecklistPatch(base, patch);
|
|
39639
|
+
} catch (err) {
|
|
39640
|
+
return { ok: false, reason: "edit_failed", hint: String(err) };
|
|
39641
|
+
}
|
|
39642
|
+
const state = { title: next.title, tasks: next.tasks, mode: base.mode };
|
|
39643
|
+
if (base.mode === "native") {
|
|
39644
|
+
if (!deps.nativeAvailable || !deps.businessConnectionId) {
|
|
39645
|
+
return {
|
|
39646
|
+
ok: false,
|
|
39647
|
+
reason: "edit_failed",
|
|
39648
|
+
hint: "this checklist was sent natively but the business connection / checklist API is no longer available."
|
|
39649
|
+
};
|
|
39650
|
+
}
|
|
39651
|
+
try {
|
|
39652
|
+
await deps.editNative(buildNativeEditChecklistPayload({
|
|
39653
|
+
businessConnectionId: deps.businessConnectionId,
|
|
39654
|
+
chatId: deps.chatId,
|
|
39655
|
+
messageId: deps.messageId,
|
|
39656
|
+
title: state.title,
|
|
39657
|
+
tasks: state.tasks
|
|
39658
|
+
}));
|
|
39659
|
+
return { ok: true, mode: "native", state };
|
|
39660
|
+
} catch (err) {
|
|
39661
|
+
deps.log(`native editMessageChecklist failed: ${err}
|
|
39662
|
+
`);
|
|
39663
|
+
return { ok: false, reason: "edit_failed", hint: String(err) };
|
|
39664
|
+
}
|
|
39665
|
+
}
|
|
39666
|
+
try {
|
|
39667
|
+
await deps.editText(renderChecklistText(state, { literal: deps.literalText }));
|
|
39668
|
+
return { ok: true, mode: "text", state };
|
|
39669
|
+
} catch (err) {
|
|
39670
|
+
deps.log(`checklist text edit failed: ${err}
|
|
39671
|
+
`);
|
|
39672
|
+
return { ok: false, reason: "edit_failed", hint: String(err) };
|
|
39673
|
+
}
|
|
39674
|
+
}
|
|
39675
|
+
function updateChecklistToolText(r, messageId) {
|
|
39676
|
+
return JSON.stringify(r.ok ? { ok: true, message_id: messageId, mode: r.mode, ...r.mode === "text" ? { degraded: "text" } : {} } : { ok: false, reason: r.reason, hint: r.hint });
|
|
39677
|
+
}
|
|
39678
|
+
|
|
39498
39679
|
// interrupt-marker.ts
|
|
39499
39680
|
function parseInterruptMarker(text) {
|
|
39500
39681
|
const trimmed = text.trimStart();
|
|
@@ -70372,6 +70553,8 @@ function tick(now) {
|
|
|
70372
70553
|
const ceiling = thresholds.fallbackHardCeiling ?? Number.POSITIVE_INFINITY;
|
|
70373
70554
|
const underCeiling = silence < ceiling;
|
|
70374
70555
|
if (underCeiling) {
|
|
70556
|
+
if (activeDeps.isCompactionInFlight?.(key) === true)
|
|
70557
|
+
continue;
|
|
70375
70558
|
const forceDisable = process.env.SWITCHROOM_SILENCE_DEFER_INFLIGHT_TOOLS === "0";
|
|
70376
70559
|
if (!forceDisable && activeDeps.isLegitimatelyWorking != null) {
|
|
70377
70560
|
if (activeDeps.isLegitimatelyWorking(key))
|
|
@@ -71596,6 +71779,14 @@ function projectTranscriptLine(line) {
|
|
|
71596
71779
|
{ kind: "turn_end", durationMs: obj.durationMs ?? 0 }
|
|
71597
71780
|
];
|
|
71598
71781
|
}
|
|
71782
|
+
if (type === "system" && obj.subtype === "compact_boundary") {
|
|
71783
|
+
const meta = obj.compactMetadata;
|
|
71784
|
+
return [{
|
|
71785
|
+
kind: "compact_boundary",
|
|
71786
|
+
trigger: typeof meta?.trigger === "string" ? meta.trigger : null,
|
|
71787
|
+
compactDurationMs: typeof meta?.durationMs === "number" ? meta.durationMs : null
|
|
71788
|
+
}];
|
|
71789
|
+
}
|
|
71599
71790
|
return [];
|
|
71600
71791
|
}
|
|
71601
71792
|
|
|
@@ -77127,6 +77318,10 @@ function compactIfLarge(path2) {
|
|
|
77127
77318
|
} catch {}
|
|
77128
77319
|
}
|
|
77129
77320
|
|
|
77321
|
+
// gateway/outbox-sweep.ts
|
|
77322
|
+
init_rich_send();
|
|
77323
|
+
init_format();
|
|
77324
|
+
|
|
77130
77325
|
// registry/subagents-schema.ts
|
|
77131
77326
|
function countRunningBackgroundSubagents(db2) {
|
|
77132
77327
|
const row = db2.prepare("SELECT count(*) AS n FROM subagents WHERE background = 1 AND status = 'running'").get();
|
|
@@ -78928,13 +79123,28 @@ async function deliverCapturedProse(deps, args) {
|
|
|
78928
79123
|
const plainChunks = splitMarkdownChunks(plain, RICH_MESSAGE_MAX_CHARS);
|
|
78929
79124
|
try {
|
|
78930
79125
|
let liveThreadId = threadId;
|
|
79126
|
+
const plainSentIds = [];
|
|
79127
|
+
const plainSentTexts = [];
|
|
78931
79128
|
for (const c of plainChunks) {
|
|
78932
79129
|
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" });
|
|
79130
|
+
const sentId = sent.message_id;
|
|
79131
|
+
if (sentId != null) {
|
|
79132
|
+
plainSentIds.push(sentId);
|
|
79133
|
+
plainSentTexts.push(c);
|
|
79134
|
+
}
|
|
78933
79135
|
if (liveThreadId != null && sent.message_thread_id == null) {
|
|
78934
79136
|
liveThreadId = undefined;
|
|
78935
79137
|
}
|
|
78936
79138
|
}
|
|
78937
79139
|
outboundDedup.record(chatId, threadId, text4, Date.now(), registryKey);
|
|
79140
|
+
if (HISTORY_ENABLED && plainSentIds.length > 0) {
|
|
79141
|
+
try {
|
|
79142
|
+
recordOutbound2({ chat_id: chatId, thread_id: threadId ?? null, message_ids: plainSentIds, texts: plainSentTexts });
|
|
79143
|
+
} catch (histErr) {
|
|
79144
|
+
process.stderr.write(`telegram gateway: history recordOutbound (captured-prose plain fallback) failed: ${histErr instanceof Error ? histErr.message : String(histErr)}
|
|
79145
|
+
`);
|
|
79146
|
+
}
|
|
79147
|
+
}
|
|
78938
79148
|
process.stderr.write(`telegram gateway: captured-prose recovered via plain-text fallback ` + `(chat=${chatId} origin=${originTurnId})
|
|
78939
79149
|
`);
|
|
78940
79150
|
} catch (plainErr) {
|
|
@@ -81016,6 +81226,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81016
81226
|
let sentIds = [];
|
|
81017
81227
|
let chunkCount = 0;
|
|
81018
81228
|
let delivered = false;
|
|
81229
|
+
let earlyJournaled = false;
|
|
81019
81230
|
try {
|
|
81020
81231
|
const delivery = await deliverAnswer({
|
|
81021
81232
|
chatId: backstopChatId,
|
|
@@ -81023,7 +81234,21 @@ function handleSessionEvent(deps, ev) {
|
|
|
81023
81234
|
text: capturedText,
|
|
81024
81235
|
turnId: turn.turnId,
|
|
81025
81236
|
cardMessageId: backstopCardMessageId,
|
|
81026
|
-
replyToMessageId: turn.sourceMessageId
|
|
81237
|
+
replyToMessageId: turn.sourceMessageId,
|
|
81238
|
+
onAckClaim: (ackIds) => {
|
|
81239
|
+
try {
|
|
81240
|
+
journalExternalDelivery({
|
|
81241
|
+
turnNonce: turn.turnId,
|
|
81242
|
+
text: capturedText,
|
|
81243
|
+
tgMessageId: ackIds.length > 0 ? ackIds[0] : undefined,
|
|
81244
|
+
deliverySource: "flush"
|
|
81245
|
+
}, STATE_DIR);
|
|
81246
|
+
earlyJournaled = true;
|
|
81247
|
+
} catch (err) {
|
|
81248
|
+
process.stderr.write(`telegram gateway: turn-flush send-ack journal write failed (non-fatal): ${err.message}
|
|
81249
|
+
`);
|
|
81250
|
+
}
|
|
81251
|
+
}
|
|
81027
81252
|
});
|
|
81028
81253
|
sentIds = delivery.sentIds;
|
|
81029
81254
|
chunkCount = delivery.chunkCount;
|
|
@@ -81069,7 +81294,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81069
81294
|
chunkCount,
|
|
81070
81295
|
cardMessageId: backstopCardMessageId
|
|
81071
81296
|
});
|
|
81072
|
-
if (delivered) {
|
|
81297
|
+
if (delivered && !earlyJournaled) {
|
|
81073
81298
|
try {
|
|
81074
81299
|
journalExternalDelivery({
|
|
81075
81300
|
turnNonce: turn.turnId,
|
|
@@ -91719,6 +91944,18 @@ function computeTurnStatus(turn) {
|
|
|
91719
91944
|
return turn.finalAnswerDelivered ? "complete" : "no_reply";
|
|
91720
91945
|
}
|
|
91721
91946
|
}
|
|
91947
|
+
function computeTurnRoute(turn) {
|
|
91948
|
+
switch (turn.deliveryOutcome) {
|
|
91949
|
+
case "failed":
|
|
91950
|
+
return "none";
|
|
91951
|
+
case "delivered":
|
|
91952
|
+
return "flush";
|
|
91953
|
+
case "suppressed":
|
|
91954
|
+
return "reply";
|
|
91955
|
+
default:
|
|
91956
|
+
return turn.finalAnswerDelivered ? turn.replyCalled ? "reply" : "stream" : "none";
|
|
91957
|
+
}
|
|
91958
|
+
}
|
|
91722
91959
|
function buildTurnRecord(turn, endedAt) {
|
|
91723
91960
|
return {
|
|
91724
91961
|
ts: Math.floor(endedAt / 1000),
|
|
@@ -91727,6 +91964,11 @@ function buildTurnRecord(turn, endedAt) {
|
|
|
91727
91964
|
tools: turn.toolCallCount ?? 0,
|
|
91728
91965
|
status: computeTurnStatus(turn),
|
|
91729
91966
|
turn_id: turn.turnId,
|
|
91967
|
+
route: computeTurnRoute({
|
|
91968
|
+
finalAnswerDelivered: turn.finalAnswerDelivered,
|
|
91969
|
+
replyCalled: turn.replyCalled ?? false,
|
|
91970
|
+
deliveryOutcome: turn.deliveryOutcome
|
|
91971
|
+
}),
|
|
91730
91972
|
...turn.landedUnconfirmed != null && turn.landedUnconfirmed > 0 ? { landed_unconfirmed: turn.landedUnconfirmed } : {}
|
|
91731
91973
|
};
|
|
91732
91974
|
}
|
|
@@ -91852,6 +92094,7 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
|
|
|
91852
92094
|
const stderr = deps.stderr ?? (() => {});
|
|
91853
92095
|
const chunkCount = chunks.length;
|
|
91854
92096
|
let attempts = 0;
|
|
92097
|
+
let ackClaimed = false;
|
|
91855
92098
|
for (let attempt = 1;attempt <= Math.max(1, maxAttempts); attempt++) {
|
|
91856
92099
|
attempts = attempt;
|
|
91857
92100
|
const resume = ledger.unsentIndices(turnId, chunkCount);
|
|
@@ -91875,6 +92118,18 @@ async function runBackstopDelivery(ledger, turnId, chunks, cardMessageId, deps,
|
|
|
91875
92118
|
`);
|
|
91876
92119
|
}
|
|
91877
92120
|
}
|
|
92121
|
+
if (!ackClaimed && deps.onAckClaim != null) {
|
|
92122
|
+
const allLandedNow = chunkCount > 0 && ledger.unsentIndices(turnId, chunkCount).length === 0;
|
|
92123
|
+
if (allLandedNow && backstopReceiptIds(ledger.sentIds(turnId), cardMessageId).length > 0) {
|
|
92124
|
+
ackClaimed = true;
|
|
92125
|
+
try {
|
|
92126
|
+
deps.onAckClaim(ledger.sentIds(turnId));
|
|
92127
|
+
} catch (err) {
|
|
92128
|
+
stderr(`telegram gateway: backstop send-ack claim callback threw for turn ${turnId} ` + `(non-fatal): ${err instanceof Error ? err.message : String(err)}
|
|
92129
|
+
`);
|
|
92130
|
+
}
|
|
92131
|
+
}
|
|
92132
|
+
}
|
|
91878
92133
|
let demotedAny = false;
|
|
91879
92134
|
for (const i of ledger.landedUnconfirmedIndices(turnId, chunkCount)) {
|
|
91880
92135
|
if (deps.readBack == null) {
|
|
@@ -93239,6 +93494,28 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
|
|
|
93239
93494
|
return { purged };
|
|
93240
93495
|
}
|
|
93241
93496
|
|
|
93497
|
+
// gateway/compaction-marker.ts
|
|
93498
|
+
import { statSync as statSync15, unlinkSync as unlinkSync21 } from "node:fs";
|
|
93499
|
+
import { homedir as homedir15 } from "node:os";
|
|
93500
|
+
import { join as join50 } from "node:path";
|
|
93501
|
+
var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
|
|
93502
|
+
function resolveTelegramStateDir() {
|
|
93503
|
+
return process.env.TELEGRAM_STATE_DIR ?? join50(homedir15(), ".claude", "channels", "telegram");
|
|
93504
|
+
}
|
|
93505
|
+
function readCompactionMarkerAgeMs(stateDir, now) {
|
|
93506
|
+
try {
|
|
93507
|
+
const st = statSync15(join50(stateDir, COMPACTION_MARKER_FILE));
|
|
93508
|
+
return (now ?? Date.now()) - st.mtimeMs;
|
|
93509
|
+
} catch {
|
|
93510
|
+
return null;
|
|
93511
|
+
}
|
|
93512
|
+
}
|
|
93513
|
+
function removeCompactionMarker(stateDir) {
|
|
93514
|
+
try {
|
|
93515
|
+
unlinkSync21(join50(stateDir, COMPACTION_MARKER_FILE));
|
|
93516
|
+
} catch {}
|
|
93517
|
+
}
|
|
93518
|
+
|
|
93242
93519
|
// gateway/hang-restart-decision.ts
|
|
93243
93520
|
var HUMAN_WAIT_TOOLS2 = new Set(["ask_user"]);
|
|
93244
93521
|
var BACKGROUND_TOOLS2 = new Set(["Task", "Agent"]);
|
|
@@ -93346,6 +93623,10 @@ function buildSilencePokeOptions(deps) {
|
|
|
93346
93623
|
thresholdsMs: { fallback: SILENCE_FALLBACK_MS, fallbackHardCeiling: SILENCE_FALLBACK_HARD_MS, floor: SILENCE_FLOOR_MS },
|
|
93347
93624
|
deferFallbackWhileToolInFlight: SILENCE_DEFER_INFLIGHT_TOOLS,
|
|
93348
93625
|
isLegitimatelyWorking: (key) => isLegitimatelyWorking(key),
|
|
93626
|
+
isCompactionInFlight: () => {
|
|
93627
|
+
const ageMs = readCompactionMarkerAgeMs(STATE_DIR);
|
|
93628
|
+
return ageMs != null && ageMs >= 0 && ageMs < SILENCE_FALLBACK_HARD_MS;
|
|
93629
|
+
},
|
|
93349
93630
|
isTurnLive: (key) => !(activeTurnStartedAt.get(key) == null && getCurrentTurnForKey(key) == null),
|
|
93350
93631
|
emitMetric: (event) => {
|
|
93351
93632
|
emitRuntimeMetric2(event);
|
|
@@ -93769,6 +94050,9 @@ function applySilencePokeSessionEvent(silencePoke, pendingProgress, key, ev) {
|
|
|
93769
94050
|
if (ev.toolUseId != null && ev.toolUseId.length > 0) {
|
|
93770
94051
|
silencePoke.noteToolEnd(key, ev.toolUseId, Date.now());
|
|
93771
94052
|
}
|
|
94053
|
+
} else if (ev.kind === "compact_boundary") {
|
|
94054
|
+
removeCompactionMarker(resolveTelegramStateDir());
|
|
94055
|
+
silencePoke.noteProduction(key, Date.now());
|
|
93772
94056
|
}
|
|
93773
94057
|
applyBackgroundShellLiveness(silencePoke, key, ev);
|
|
93774
94058
|
}
|
|
@@ -94054,17 +94338,17 @@ import {
|
|
|
94054
94338
|
readFileSync as readFileSync37,
|
|
94055
94339
|
writeSync as writeSync6
|
|
94056
94340
|
} from "node:fs";
|
|
94057
|
-
import { join as
|
|
94341
|
+
import { join as join51 } from "node:path";
|
|
94058
94342
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
94059
94343
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
94060
94344
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
94061
94345
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
94062
94346
|
var PROPOSAL_SIM_THRESHOLD = 0.5;
|
|
94063
94347
|
function proposalsPath2(stateDir) {
|
|
94064
|
-
return
|
|
94348
|
+
return join51(stateDir, PROPOSALS_FILE2);
|
|
94065
94349
|
}
|
|
94066
94350
|
function rejectedPath2(stateDir) {
|
|
94067
|
-
return
|
|
94351
|
+
return join51(stateDir, REJECTED_FILE2);
|
|
94068
94352
|
}
|
|
94069
94353
|
function ensureDir3(stateDir) {
|
|
94070
94354
|
if (!existsSync41(stateDir)) {
|
|
@@ -94682,7 +94966,7 @@ function escapeBody2(s) {
|
|
|
94682
94966
|
}
|
|
94683
94967
|
|
|
94684
94968
|
// gateway/pid-file.ts
|
|
94685
|
-
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as
|
|
94969
|
+
import { writeFileSync as writeFileSync33, readFileSync as readFileSync38, unlinkSync as unlinkSync22, renameSync as renameSync18 } from "node:fs";
|
|
94686
94970
|
function writePidFile(path3, record) {
|
|
94687
94971
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
94688
94972
|
writeFileSync33(tmp, JSON.stringify(record), "utf-8");
|
|
@@ -94690,7 +94974,7 @@ function writePidFile(path3, record) {
|
|
|
94690
94974
|
}
|
|
94691
94975
|
function clearPidFile(path3) {
|
|
94692
94976
|
try {
|
|
94693
|
-
|
|
94977
|
+
unlinkSync22(path3);
|
|
94694
94978
|
} catch {}
|
|
94695
94979
|
}
|
|
94696
94980
|
|
|
@@ -94907,7 +95191,7 @@ function safeCount(fn) {
|
|
|
94907
95191
|
}
|
|
94908
95192
|
|
|
94909
95193
|
// gateway/session-marker.ts
|
|
94910
|
-
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as
|
|
95194
|
+
import { writeFileSync as writeFileSync34, readFileSync as readFileSync40, renameSync as renameSync19, unlinkSync as unlinkSync23 } from "node:fs";
|
|
94911
95195
|
function writeSessionMarker(path3, marker) {
|
|
94912
95196
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
94913
95197
|
writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
|
|
@@ -94937,7 +95221,7 @@ function shouldFireRestartBanner(input) {
|
|
|
94937
95221
|
}
|
|
94938
95222
|
|
|
94939
95223
|
// gateway/clean-shutdown-marker.ts
|
|
94940
|
-
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as
|
|
95224
|
+
import { writeFileSync as writeFileSync35, readFileSync as readFileSync41, renameSync as renameSync20, unlinkSync as unlinkSync24 } from "node:fs";
|
|
94941
95225
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
94942
95226
|
function writeCleanShutdownMarker(path3, marker) {
|
|
94943
95227
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -94961,7 +95245,7 @@ function readCleanShutdownMarker(path3) {
|
|
|
94961
95245
|
}
|
|
94962
95246
|
function clearCleanShutdownMarker(path3) {
|
|
94963
95247
|
try {
|
|
94964
|
-
|
|
95248
|
+
unlinkSync24(path3);
|
|
94965
95249
|
} catch {}
|
|
94966
95250
|
}
|
|
94967
95251
|
function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
@@ -95321,13 +95605,13 @@ import {
|
|
|
95321
95605
|
existsSync as existsSync42,
|
|
95322
95606
|
openSync as openSync10,
|
|
95323
95607
|
readSync as readSync2,
|
|
95324
|
-
statSync as
|
|
95608
|
+
statSync as statSync16,
|
|
95325
95609
|
closeSync as closeSync10,
|
|
95326
95610
|
watch,
|
|
95327
95611
|
readdirSync as readdirSync10,
|
|
95328
95612
|
readFileSync as readFileSync42
|
|
95329
95613
|
} from "fs";
|
|
95330
|
-
import { join as
|
|
95614
|
+
import { join as join52 } from "path";
|
|
95331
95615
|
|
|
95332
95616
|
// session-tail.ts
|
|
95333
95617
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -96134,7 +96418,7 @@ function startSubagentWatcher(config) {
|
|
|
96134
96418
|
const fs3 = config.fs ?? {
|
|
96135
96419
|
existsSync: existsSync42,
|
|
96136
96420
|
readdirSync: readdirSync10,
|
|
96137
|
-
statSync:
|
|
96421
|
+
statSync: statSync16,
|
|
96138
96422
|
openSync: openSync10,
|
|
96139
96423
|
closeSync: closeSync10,
|
|
96140
96424
|
readSync: readSync2,
|
|
@@ -96650,8 +96934,8 @@ function startSubagentWatcher(config) {
|
|
|
96650
96934
|
if (stopped)
|
|
96651
96935
|
return;
|
|
96652
96936
|
pruneVanishedDirWatchers();
|
|
96653
|
-
const claudeHome =
|
|
96654
|
-
const projectsRoot =
|
|
96937
|
+
const claudeHome = join52(agentDir, ".claude");
|
|
96938
|
+
const projectsRoot = join52(claudeHome, "projects");
|
|
96655
96939
|
if (!fs3.existsSync(projectsRoot))
|
|
96656
96940
|
return;
|
|
96657
96941
|
let projectDirs;
|
|
@@ -96685,7 +96969,7 @@ function startSubagentWatcher(config) {
|
|
|
96685
96969
|
continue;
|
|
96686
96970
|
}
|
|
96687
96971
|
warnedForeignSlugs.delete(pDir);
|
|
96688
|
-
const projectPath =
|
|
96972
|
+
const projectPath = join52(projectsRoot, pDir);
|
|
96689
96973
|
let sessionDirs;
|
|
96690
96974
|
try {
|
|
96691
96975
|
sessionDirs = fs3.readdirSync(projectPath);
|
|
@@ -96695,7 +96979,7 @@ function startSubagentWatcher(config) {
|
|
|
96695
96979
|
for (const sDir of sessionDirs) {
|
|
96696
96980
|
if (sDir.endsWith(".jsonl"))
|
|
96697
96981
|
continue;
|
|
96698
|
-
const subagentsPath =
|
|
96982
|
+
const subagentsPath = join52(projectPath, sDir, "subagents");
|
|
96699
96983
|
if (!fs3.existsSync(subagentsPath))
|
|
96700
96984
|
continue;
|
|
96701
96985
|
const watchAndScan = (dirPath) => {
|
|
@@ -96704,7 +96988,7 @@ function startSubagentWatcher(config) {
|
|
|
96704
96988
|
const w = fs3.watch(dirPath, (_event, filename) => {
|
|
96705
96989
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
96706
96990
|
return;
|
|
96707
|
-
const filePath =
|
|
96991
|
+
const filePath = join52(dirPath, filename.toString());
|
|
96708
96992
|
if (!knownFiles.has(filePath)) {
|
|
96709
96993
|
scanSubagentsDir(dirPath);
|
|
96710
96994
|
}
|
|
@@ -96718,7 +97002,7 @@ function startSubagentWatcher(config) {
|
|
|
96718
97002
|
scanSubagentsDir(dirPath);
|
|
96719
97003
|
};
|
|
96720
97004
|
watchAndScan(subagentsPath);
|
|
96721
|
-
const workflowsPath =
|
|
97005
|
+
const workflowsPath = join52(subagentsPath, "workflows");
|
|
96722
97006
|
if (fs3.existsSync(workflowsPath)) {
|
|
96723
97007
|
let wfDirs;
|
|
96724
97008
|
try {
|
|
@@ -96728,7 +97012,7 @@ function startSubagentWatcher(config) {
|
|
|
96728
97012
|
}
|
|
96729
97013
|
for (const wfDir of wfDirs) {
|
|
96730
97014
|
try {
|
|
96731
|
-
const wfPath =
|
|
97015
|
+
const wfPath = join52(workflowsPath, wfDir);
|
|
96732
97016
|
if (!fs3.statSync(wfPath).isDirectory())
|
|
96733
97017
|
continue;
|
|
96734
97018
|
watchAndScan(wfPath);
|
|
@@ -96748,7 +97032,7 @@ function startSubagentWatcher(config) {
|
|
|
96748
97032
|
for (const e of entries) {
|
|
96749
97033
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
96750
97034
|
continue;
|
|
96751
|
-
const filePath =
|
|
97035
|
+
const filePath = join52(subagentsPath, e);
|
|
96752
97036
|
if (knownFiles.has(filePath))
|
|
96753
97037
|
continue;
|
|
96754
97038
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -96880,17 +97164,17 @@ import {
|
|
|
96880
97164
|
writeFileSync as writeFileSync36,
|
|
96881
97165
|
readFileSync as readFileSync43,
|
|
96882
97166
|
readdirSync as readdirSync11,
|
|
96883
|
-
unlinkSync as
|
|
97167
|
+
unlinkSync as unlinkSync25,
|
|
96884
97168
|
existsSync as existsSync43,
|
|
96885
97169
|
renameSync as renameSync21
|
|
96886
97170
|
} from "node:fs";
|
|
96887
|
-
import { join as
|
|
96888
|
-
import { homedir as
|
|
97171
|
+
import { join as join53, resolve as resolve10 } from "node:path";
|
|
97172
|
+
import { homedir as homedir16 } from "node:os";
|
|
96889
97173
|
function registryDir() {
|
|
96890
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
97174
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join53(homedir16(), ".switchroom", "worktrees"));
|
|
96891
97175
|
}
|
|
96892
97176
|
function recordPath(id) {
|
|
96893
|
-
return
|
|
97177
|
+
return join53(registryDir(), `${id}.json`);
|
|
96894
97178
|
}
|
|
96895
97179
|
function ensureDir4() {
|
|
96896
97180
|
mkdirSync38(registryDir(), { recursive: true });
|
|
@@ -97066,19 +97350,19 @@ function determineRestartReason(opts) {
|
|
|
97066
97350
|
|
|
97067
97351
|
// gateway/update-announce.ts
|
|
97068
97352
|
import { existsSync as existsSync48, mkdirSync as mkdirSync42, openSync as openSync11, closeSync as closeSync11, readFileSync as readFileSync50 } from "node:fs";
|
|
97069
|
-
import { join as
|
|
97070
|
-
import { homedir as
|
|
97353
|
+
import { join as join58 } from "node:path";
|
|
97354
|
+
import { homedir as homedir18 } from "node:os";
|
|
97071
97355
|
|
|
97072
97356
|
// ../src/host-control/audit-reader.ts
|
|
97073
|
-
import { homedir as
|
|
97074
|
-
import { join as
|
|
97357
|
+
import { homedir as homedir17 } from "node:os";
|
|
97358
|
+
import { join as join57 } from "node:path";
|
|
97075
97359
|
|
|
97076
97360
|
// ../src/host-control/audit-rotation-config.ts
|
|
97077
97361
|
var DEFAULT_HOSTD_AUDIT_MAX_BYTES = 32 * 1024 * 1024;
|
|
97078
97362
|
|
|
97079
97363
|
// ../src/host-control/audit-reader.ts
|
|
97080
|
-
function defaultAuditLogPath(home2 =
|
|
97081
|
-
return
|
|
97364
|
+
function defaultAuditLogPath(home2 = homedir17()) {
|
|
97365
|
+
return join57(home2, ".switchroom", "host-control-audit.log");
|
|
97082
97366
|
}
|
|
97083
97367
|
var AUDIT_READ_WINDOW_BYTES = 4 * 1024 * 1024;
|
|
97084
97368
|
function parseAuditLine(line) {
|
|
@@ -97273,15 +97557,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
97273
97557
|
`);
|
|
97274
97558
|
}
|
|
97275
97559
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
97276
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
97277
|
-
const dir =
|
|
97560
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join58(homedir18(), ".switchroom");
|
|
97561
|
+
const dir = join58(stateDir, "update-announced");
|
|
97278
97562
|
try {
|
|
97279
97563
|
mkdirSync42(dir, { recursive: true });
|
|
97280
97564
|
} catch {
|
|
97281
97565
|
return false;
|
|
97282
97566
|
}
|
|
97283
97567
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
97284
|
-
const path3 =
|
|
97568
|
+
const path3 = join58(dir, safeId);
|
|
97285
97569
|
try {
|
|
97286
97570
|
const fd = openSync11(path3, "wx");
|
|
97287
97571
|
closeSync11(fd);
|
|
@@ -97502,8 +97786,8 @@ function createIssuesCardHandle(opts) {
|
|
|
97502
97786
|
}
|
|
97503
97787
|
|
|
97504
97788
|
// issues-watcher.ts
|
|
97505
|
-
import { existsSync as existsSync50, statSync as
|
|
97506
|
-
import { join as
|
|
97789
|
+
import { existsSync as existsSync50, statSync as statSync19 } from "node:fs";
|
|
97790
|
+
import { join as join60 } from "node:path";
|
|
97507
97791
|
|
|
97508
97792
|
// ../src/issues/store.ts
|
|
97509
97793
|
import {
|
|
@@ -97514,12 +97798,12 @@ import {
|
|
|
97514
97798
|
readdirSync as readdirSync13,
|
|
97515
97799
|
readFileSync as readFileSync52,
|
|
97516
97800
|
renameSync as renameSync24,
|
|
97517
|
-
statSync as
|
|
97518
|
-
unlinkSync as
|
|
97801
|
+
statSync as statSync18,
|
|
97802
|
+
unlinkSync as unlinkSync26,
|
|
97519
97803
|
writeFileSync as writeFileSync42,
|
|
97520
97804
|
writeSync as writeSync7
|
|
97521
97805
|
} from "node:fs";
|
|
97522
|
-
import { join as
|
|
97806
|
+
import { join as join59 } from "node:path";
|
|
97523
97807
|
import { randomBytes as randomBytes11 } from "node:crypto";
|
|
97524
97808
|
import { execSync } from "node:child_process";
|
|
97525
97809
|
|
|
@@ -97538,7 +97822,7 @@ init_redact();
|
|
|
97538
97822
|
var ISSUES_FILE = "issues.jsonl";
|
|
97539
97823
|
var ISSUES_LOCK = "issues.lock";
|
|
97540
97824
|
function readAll(stateDir) {
|
|
97541
|
-
const path3 =
|
|
97825
|
+
const path3 = join59(stateDir, ISSUES_FILE);
|
|
97542
97826
|
if (!existsSync49(path3))
|
|
97543
97827
|
return [];
|
|
97544
97828
|
let raw;
|
|
@@ -97575,7 +97859,7 @@ function list2(stateDir, opts = {}) {
|
|
|
97575
97859
|
});
|
|
97576
97860
|
}
|
|
97577
97861
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
97578
|
-
if (!existsSync49(
|
|
97862
|
+
if (!existsSync49(join59(stateDir, ISSUES_FILE)))
|
|
97579
97863
|
return 0;
|
|
97580
97864
|
return withLock(stateDir, () => {
|
|
97581
97865
|
const all2 = readAll(stateDir);
|
|
@@ -97593,7 +97877,7 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
97593
97877
|
});
|
|
97594
97878
|
}
|
|
97595
97879
|
function writeAll(stateDir, events) {
|
|
97596
|
-
const path3 =
|
|
97880
|
+
const path3 = join59(stateDir, ISSUES_FILE);
|
|
97597
97881
|
sweepOrphanTmpFiles(stateDir);
|
|
97598
97882
|
const tmp = `${path3}.tmp-${process.pid}-${randomBytes11(4).toString("hex")}`;
|
|
97599
97883
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -97615,11 +97899,11 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
97615
97899
|
for (const entry of entries) {
|
|
97616
97900
|
if (!entry.startsWith(TMP_PREFIX))
|
|
97617
97901
|
continue;
|
|
97618
|
-
const tmpPath2 =
|
|
97902
|
+
const tmpPath2 = join59(stateDir, entry);
|
|
97619
97903
|
try {
|
|
97620
|
-
const stat =
|
|
97904
|
+
const stat = statSync18(tmpPath2);
|
|
97621
97905
|
if (stat.mtimeMs < cutoff) {
|
|
97622
|
-
|
|
97906
|
+
unlinkSync26(tmpPath2);
|
|
97623
97907
|
}
|
|
97624
97908
|
} catch {}
|
|
97625
97909
|
}
|
|
@@ -97627,7 +97911,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
97627
97911
|
var LOCK_RETRY_MS = 25;
|
|
97628
97912
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
97629
97913
|
function withLock(stateDir, fn) {
|
|
97630
|
-
const lockPath =
|
|
97914
|
+
const lockPath = join59(stateDir, ISSUES_LOCK);
|
|
97631
97915
|
const startedAt = Date.now();
|
|
97632
97916
|
let fd = null;
|
|
97633
97917
|
while (fd === null) {
|
|
@@ -97655,7 +97939,7 @@ function withLock(stateDir, fn) {
|
|
|
97655
97939
|
closeSync12(fd);
|
|
97656
97940
|
} catch {}
|
|
97657
97941
|
try {
|
|
97658
|
-
|
|
97942
|
+
unlinkSync26(lockPath);
|
|
97659
97943
|
} catch {}
|
|
97660
97944
|
}
|
|
97661
97945
|
}
|
|
@@ -97669,13 +97953,13 @@ function tryStealStaleLock(lockPath) {
|
|
|
97669
97953
|
const pid = Number(pidStr);
|
|
97670
97954
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
97671
97955
|
try {
|
|
97672
|
-
|
|
97956
|
+
unlinkSync26(lockPath);
|
|
97673
97957
|
} catch {}
|
|
97674
97958
|
return true;
|
|
97675
97959
|
}
|
|
97676
97960
|
if (pid === process.pid) {
|
|
97677
97961
|
try {
|
|
97678
|
-
|
|
97962
|
+
unlinkSync26(lockPath);
|
|
97679
97963
|
} catch {}
|
|
97680
97964
|
return true;
|
|
97681
97965
|
}
|
|
@@ -97690,7 +97974,7 @@ function tryStealStaleLock(lockPath) {
|
|
|
97690
97974
|
return false;
|
|
97691
97975
|
}
|
|
97692
97976
|
try {
|
|
97693
|
-
|
|
97977
|
+
unlinkSync26(lockPath);
|
|
97694
97978
|
} catch {}
|
|
97695
97979
|
return true;
|
|
97696
97980
|
}
|
|
@@ -97712,7 +97996,7 @@ function isIssueEvent(v) {
|
|
|
97712
97996
|
// issues-watcher.ts
|
|
97713
97997
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
97714
97998
|
function startIssuesWatcher(opts) {
|
|
97715
|
-
const path3 =
|
|
97999
|
+
const path3 = join60(opts.stateDir, ISSUES_FILE);
|
|
97716
98000
|
const log = opts.log ?? (() => {});
|
|
97717
98001
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
97718
98002
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -97763,7 +98047,7 @@ function defaultSignatureProvider(path3) {
|
|
|
97763
98047
|
if (!existsSync50(path3))
|
|
97764
98048
|
return null;
|
|
97765
98049
|
try {
|
|
97766
|
-
const stat =
|
|
98050
|
+
const stat = statSync19(path3);
|
|
97767
98051
|
return `${stat.mtimeMs}:${stat.size}`;
|
|
97768
98052
|
} catch {
|
|
97769
98053
|
return null;
|
|
@@ -98472,7 +98756,7 @@ function readBashCommand(inputPreview) {
|
|
|
98472
98756
|
|
|
98473
98757
|
// gateway/scoped-grant-store.ts
|
|
98474
98758
|
init_atomic();
|
|
98475
|
-
import { join as
|
|
98759
|
+
import { join as join61 } from "node:path";
|
|
98476
98760
|
|
|
98477
98761
|
// scoped-approval.ts
|
|
98478
98762
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -98514,7 +98798,7 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
98514
98798
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
98515
98799
|
}
|
|
98516
98800
|
function createScopedGrantStore(stateDir, env = process.env, log = (l) => process.stderr.write(l)) {
|
|
98517
|
-
const filePath =
|
|
98801
|
+
const filePath = join61(stateDir, "scoped-grants.json");
|
|
98518
98802
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
98519
98803
|
let unreadable = false;
|
|
98520
98804
|
function read() {
|
|
@@ -98893,7 +99177,7 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
98893
99177
|
// credits-watch.ts
|
|
98894
99178
|
init_card_format();
|
|
98895
99179
|
import { readFileSync as readFileSync53, writeFileSync as writeFileSync43, existsSync as existsSync51, mkdirSync as mkdirSync44 } from "fs";
|
|
98896
|
-
import { join as
|
|
99180
|
+
import { join as join62 } from "path";
|
|
98897
99181
|
var STATE_FILE = "credits-watch.json";
|
|
98898
99182
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
98899
99183
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -98915,7 +99199,7 @@ function emptyCreditState() {
|
|
|
98915
99199
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
98916
99200
|
}
|
|
98917
99201
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
98918
|
-
const path3 =
|
|
99202
|
+
const path3 = join62(claudeConfigDir, ".claude.json");
|
|
98919
99203
|
if (!existsSync51(path3))
|
|
98920
99204
|
return null;
|
|
98921
99205
|
let raw;
|
|
@@ -98998,7 +99282,7 @@ function humanizeReason(reason) {
|
|
|
98998
99282
|
}
|
|
98999
99283
|
}
|
|
99000
99284
|
function loadCreditState(stateDir) {
|
|
99001
|
-
const path3 =
|
|
99285
|
+
const path3 = join62(stateDir, STATE_FILE);
|
|
99002
99286
|
if (!existsSync51(path3))
|
|
99003
99287
|
return emptyCreditState();
|
|
99004
99288
|
try {
|
|
@@ -99015,7 +99299,7 @@ function loadCreditState(stateDir) {
|
|
|
99015
99299
|
}
|
|
99016
99300
|
function saveCreditState(stateDir, state7) {
|
|
99017
99301
|
mkdirSync44(stateDir, { recursive: true });
|
|
99018
|
-
const path3 =
|
|
99302
|
+
const path3 = join62(stateDir, STATE_FILE);
|
|
99019
99303
|
writeFileSync43(path3, JSON.stringify(state7, null, 2) + `
|
|
99020
99304
|
`, { mode: 384 });
|
|
99021
99305
|
}
|
|
@@ -99024,7 +99308,7 @@ function saveCreditState(stateDir, state7) {
|
|
|
99024
99308
|
init_auth_snapshot_format();
|
|
99025
99309
|
init_card_format();
|
|
99026
99310
|
import { readFileSync as readFileSync54, writeFileSync as writeFileSync44, existsSync as existsSync52, mkdirSync as mkdirSync45 } from "fs";
|
|
99027
|
-
import { join as
|
|
99311
|
+
import { join as join63 } from "path";
|
|
99028
99312
|
var STATE_FILE2 = "quota-watch.json";
|
|
99029
99313
|
function emptyQuotaWatchState() {
|
|
99030
99314
|
return {};
|
|
@@ -99262,7 +99546,7 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
99262
99546
|
`);
|
|
99263
99547
|
}
|
|
99264
99548
|
function loadQuotaWatchState(stateDir) {
|
|
99265
|
-
const path3 =
|
|
99549
|
+
const path3 = join63(stateDir, STATE_FILE2);
|
|
99266
99550
|
if (!existsSync52(path3))
|
|
99267
99551
|
return emptyQuotaWatchState();
|
|
99268
99552
|
try {
|
|
@@ -99284,7 +99568,7 @@ function loadQuotaWatchState(stateDir) {
|
|
|
99284
99568
|
}
|
|
99285
99569
|
function saveQuotaWatchState(stateDir, state7) {
|
|
99286
99570
|
mkdirSync45(stateDir, { recursive: true });
|
|
99287
|
-
const path3 =
|
|
99571
|
+
const path3 = join63(stateDir, STATE_FILE2);
|
|
99288
99572
|
writeFileSync44(path3, JSON.stringify(state7, null, 2) + `
|
|
99289
99573
|
`, { mode: 384 });
|
|
99290
99574
|
}
|
|
@@ -99337,27 +99621,27 @@ import {
|
|
|
99337
99621
|
mkdirSync as mkdirSync46,
|
|
99338
99622
|
openSync as openSync13,
|
|
99339
99623
|
readFileSync as readFileSync55,
|
|
99340
|
-
statSync as
|
|
99341
|
-
unlinkSync as
|
|
99624
|
+
statSync as statSync20,
|
|
99625
|
+
unlinkSync as unlinkSync27,
|
|
99342
99626
|
utimesSync as utimesSync2,
|
|
99343
99627
|
writeFileSync as writeFileSync45
|
|
99344
99628
|
} from "node:fs";
|
|
99345
|
-
import { join as
|
|
99629
|
+
import { join as join64 } from "node:path";
|
|
99346
99630
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
99347
99631
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
99348
99632
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
99349
99633
|
function removeTurnActiveMarker2(stateDir) {
|
|
99350
99634
|
try {
|
|
99351
|
-
|
|
99635
|
+
unlinkSync27(join64(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
99352
99636
|
} catch {}
|
|
99353
99637
|
}
|
|
99354
99638
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
99355
|
-
const path3 =
|
|
99639
|
+
const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
99356
99640
|
if (!existsSync53(path3))
|
|
99357
99641
|
return false;
|
|
99358
99642
|
const now = opts.now ?? Date.now();
|
|
99359
99643
|
try {
|
|
99360
|
-
const st =
|
|
99644
|
+
const st = statSync20(path3);
|
|
99361
99645
|
const ageMs = now - st.mtimeMs;
|
|
99362
99646
|
const hardExpired = ageMs > opts.hardTtlMs;
|
|
99363
99647
|
const idleExpired = !opts.turnInFlight && ageMs > opts.idleSweepMs;
|
|
@@ -99367,7 +99651,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
99367
99651
|
try {
|
|
99368
99652
|
payload = readFileSync55(path3, "utf8");
|
|
99369
99653
|
} catch {}
|
|
99370
|
-
|
|
99654
|
+
unlinkSync27(path3);
|
|
99371
99655
|
if (opts.onRemove) {
|
|
99372
99656
|
try {
|
|
99373
99657
|
opts.onRemove({
|
|
@@ -99383,9 +99667,9 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
99383
99667
|
}
|
|
99384
99668
|
}
|
|
99385
99669
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
99386
|
-
const path3 =
|
|
99670
|
+
const path3 = join64(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
99387
99671
|
try {
|
|
99388
|
-
const st =
|
|
99672
|
+
const st = statSync20(path3);
|
|
99389
99673
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
99390
99674
|
} catch {
|
|
99391
99675
|
return null;
|
|
@@ -99397,11 +99681,11 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
99397
99681
|
|
|
99398
99682
|
// gateway/gateway-heartbeat.ts
|
|
99399
99683
|
import { mkdirSync as mkdirSync47, utimesSync as utimesSync3, writeFileSync as writeFileSync46 } from "node:fs";
|
|
99400
|
-
import { join as
|
|
99684
|
+
import { join as join65 } from "node:path";
|
|
99401
99685
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
99402
99686
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
99403
99687
|
function touchGatewayHeartbeat(stateDir) {
|
|
99404
|
-
const path3 =
|
|
99688
|
+
const path3 = join65(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
99405
99689
|
const now = new Date;
|
|
99406
99690
|
try {
|
|
99407
99691
|
utimesSync3(path3, now, now);
|
|
@@ -99429,10 +99713,10 @@ import {
|
|
|
99429
99713
|
openSync as openSync14,
|
|
99430
99714
|
readFileSync as readFileSync56,
|
|
99431
99715
|
renameSync as renameSync25,
|
|
99432
|
-
unlinkSync as
|
|
99716
|
+
unlinkSync as unlinkSync28,
|
|
99433
99717
|
writeFileSync as writeFileSync47
|
|
99434
99718
|
} from "node:fs";
|
|
99435
|
-
import { join as
|
|
99719
|
+
import { join as join66 } from "node:path";
|
|
99436
99720
|
var BOOT_BEACON_FILE = "gateway-beacon.json";
|
|
99437
99721
|
var HOST_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
|
|
99438
99722
|
var CGROUP_MEMORY_EVENTS_PATH = "/sys/fs/cgroup/memory.events";
|
|
@@ -99531,7 +99815,7 @@ function sampleBeaconHost(paths = {}) {
|
|
|
99531
99815
|
return sample3;
|
|
99532
99816
|
}
|
|
99533
99817
|
function writeBootBeaconFile(stateDir, beacon) {
|
|
99534
|
-
const path3 =
|
|
99818
|
+
const path3 = join66(stateDir, BOOT_BEACON_FILE);
|
|
99535
99819
|
const tmp = `${path3}.tmp-${process.pid}`;
|
|
99536
99820
|
let fd;
|
|
99537
99821
|
try {
|
|
@@ -99550,7 +99834,7 @@ function writeBootBeaconFile(stateDir, beacon) {
|
|
|
99550
99834
|
} catch {}
|
|
99551
99835
|
}
|
|
99552
99836
|
try {
|
|
99553
|
-
|
|
99837
|
+
unlinkSync28(tmp);
|
|
99554
99838
|
} catch {}
|
|
99555
99839
|
return false;
|
|
99556
99840
|
}
|
|
@@ -99578,6 +99862,8 @@ function attachBootBeacon(stateDir, next) {
|
|
|
99578
99862
|
}
|
|
99579
99863
|
|
|
99580
99864
|
// gateway/outbox-sweep.ts
|
|
99865
|
+
init_rich_send();
|
|
99866
|
+
init_format();
|
|
99581
99867
|
init_flood_circuit_breaker();
|
|
99582
99868
|
async function sweepOutbox(deps) {
|
|
99583
99869
|
const now = deps.now?.() ?? Date.now();
|
|
@@ -99650,15 +99936,20 @@ async function sweepOutbox(deps) {
|
|
|
99650
99936
|
}
|
|
99651
99937
|
const resolvedChat = resolved;
|
|
99652
99938
|
try {
|
|
99653
|
-
const
|
|
99939
|
+
const sendResult = await deps.send(resolvedChat.chatId, resolvedChat.threadId, decision.text ?? record2.text);
|
|
99654
99940
|
appendDelivered({
|
|
99655
99941
|
turnNonce: record2.turnNonce,
|
|
99656
99942
|
textSha256: record2.textSha256,
|
|
99657
|
-
tgMessageId: messageId,
|
|
99943
|
+
tgMessageId: sendResult.messageId,
|
|
99658
99944
|
ts: now,
|
|
99659
99945
|
deliverySource: "sweep",
|
|
99660
99946
|
replyAlreadyDeliveredThisTurn: record2.replyAlreadyDeliveredThisTurn === true
|
|
99661
99947
|
}, deps.stateDir);
|
|
99948
|
+
if (deps.recordOutbound != null && sendResult.chunks.length > 0) {
|
|
99949
|
+
try {
|
|
99950
|
+
deps.recordOutbound(resolvedChat.chatId, resolvedChat.threadId, sendResult.chunks.map((c) => c.messageId), sendResult.chunks.map((c) => c.text));
|
|
99951
|
+
} catch {}
|
|
99952
|
+
}
|
|
99662
99953
|
removeClaimed(record2.turnNonce, deps.stateDir);
|
|
99663
99954
|
summary.delivered++;
|
|
99664
99955
|
log(`outbox-sweep: delivered nonce=${record2.turnNonce} via=${resolvedChat.via} ` + `source=${record2.source} chars=${record2.text.length}${decision.action === "send-delayed" ? " (delayed)" : ""}
|
|
@@ -99713,27 +100004,42 @@ function createSweepBackoff(cfg = {}) {
|
|
|
99713
100004
|
failures: () => failures
|
|
99714
100005
|
};
|
|
99715
100006
|
}
|
|
100007
|
+
async function sendChunkRich(bot, chatId, chunk2, opts) {
|
|
100008
|
+
try {
|
|
100009
|
+
return await bot.api.sendRichMessage(chatId, richMessage(chunk2), opts);
|
|
100010
|
+
} catch (err) {
|
|
100011
|
+
if (isParseEntitiesError(err)) {
|
|
100012
|
+
return await bot.api.sendMessage(chatId, chunk2, opts);
|
|
100013
|
+
}
|
|
100014
|
+
throw err;
|
|
100015
|
+
}
|
|
100016
|
+
}
|
|
99716
100017
|
function createOutboxSend(deps) {
|
|
99717
100018
|
return async (chatId, threadId, text4) => {
|
|
99718
100019
|
const bot = deps.getBot();
|
|
99719
100020
|
if (bot == null)
|
|
99720
100021
|
throw new Error("outbox-sweep: bot unavailable");
|
|
99721
100022
|
if (text4.length === 0)
|
|
99722
|
-
return;
|
|
100023
|
+
return { messageId: undefined, chunks: [] };
|
|
99723
100024
|
const replyMarkup = deps.resolveReplyMarkup?.(chatId, threadId, text4);
|
|
99724
|
-
|
|
99725
|
-
const
|
|
99726
|
-
for (let
|
|
99727
|
-
const chunk2 =
|
|
99728
|
-
const isLast = idx ===
|
|
100025
|
+
const landed = [];
|
|
100026
|
+
const chunks = splitMarkdownChunks(text4);
|
|
100027
|
+
for (let idx = 0;idx < chunks.length; idx++) {
|
|
100028
|
+
const chunk2 = chunks[idx];
|
|
100029
|
+
const isLast = idx === chunks.length - 1;
|
|
99729
100030
|
const res = await retryWithThreadFallback(deps.retry, (tid) => {
|
|
99730
100031
|
const base = tid != null ? { message_thread_id: tid } : {};
|
|
99731
100032
|
const opts = isLast && replyMarkup != null ? { ...base, reply_markup: replyMarkup } : base;
|
|
99732
|
-
return bot
|
|
100033
|
+
return sendChunkRich(bot, chatId, chunk2, opts);
|
|
99733
100034
|
}, { threadId: threadId ?? undefined, chat_id: chatId, verb: "outbox-sweep.sendMessage" });
|
|
99734
|
-
|
|
100035
|
+
const id = res?.message_id;
|
|
100036
|
+
if (id != null)
|
|
100037
|
+
landed.push({ messageId: id, text: chunk2 });
|
|
99735
100038
|
}
|
|
99736
|
-
return
|
|
100039
|
+
return {
|
|
100040
|
+
messageId: landed.length > 0 ? landed[landed.length - 1].messageId : undefined,
|
|
100041
|
+
chunks: landed
|
|
100042
|
+
};
|
|
99737
100043
|
};
|
|
99738
100044
|
}
|
|
99739
100045
|
function startOutboxSweep(deps) {
|
|
@@ -99764,6 +100070,7 @@ function startOutboxSweep(deps) {
|
|
|
99764
100070
|
stateDir: deps.stateDir,
|
|
99765
100071
|
log: deps.log,
|
|
99766
100072
|
send,
|
|
100073
|
+
...deps.recordOutbound != null ? { recordOutbound: deps.recordOutbound } : {},
|
|
99767
100074
|
floodWaitRemainingMs: floodProbe,
|
|
99768
100075
|
textAlreadyDelivered: (chatId, threadId, text4) => deps.dedupCheck(chatId, threadId ?? undefined, text4),
|
|
99769
100076
|
registryChainLookup: (taskId) => {
|
|
@@ -99799,10 +100106,10 @@ function startOutboxSweep(deps) {
|
|
|
99799
100106
|
}
|
|
99800
100107
|
|
|
99801
100108
|
// ../src/build-info.ts
|
|
99802
|
-
var VERSION2 = "0.19.
|
|
99803
|
-
var COMMIT_SHA = "
|
|
99804
|
-
var COMMIT_DATE = "2026-07-
|
|
99805
|
-
var LATEST_PR =
|
|
100109
|
+
var VERSION2 = "0.19.41";
|
|
100110
|
+
var COMMIT_SHA = "e77ee9c0";
|
|
100111
|
+
var COMMIT_DATE = "2026-07-31T09:46:10Z";
|
|
100112
|
+
var LATEST_PR = 4066;
|
|
99806
100113
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
99807
100114
|
|
|
99808
100115
|
// gateway/boot-version.ts
|
|
@@ -99879,12 +100186,12 @@ init_protocol2();
|
|
|
99879
100186
|
init_peercred();
|
|
99880
100187
|
import * as net5 from "node:net";
|
|
99881
100188
|
import * as fs3 from "node:fs";
|
|
99882
|
-
import { homedir as
|
|
99883
|
-
import { join as
|
|
100189
|
+
import { homedir as homedir19 } from "node:os";
|
|
100190
|
+
import { join as join67 } from "node:path";
|
|
99884
100191
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
99885
100192
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
99886
|
-
var LEGACY_SOCKET_PATH2 =
|
|
99887
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
100193
|
+
var LEGACY_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "vault-broker.sock");
|
|
100194
|
+
var OPERATOR_SOCKET_PATH2 = join67(homedir19(), ".switchroom", "broker-operator", "sock");
|
|
99888
100195
|
function defaultBrokerSocketPath2() {
|
|
99889
100196
|
if (fs3.existsSync(OPERATOR_SOCKET_PATH2))
|
|
99890
100197
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -100767,7 +101074,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
100767
101074
|
|
|
100768
101075
|
// registry/turns-schema.ts
|
|
100769
101076
|
import { chmodSync as chmodSync12, mkdirSync as mkdirSync49 } from "fs";
|
|
100770
|
-
import { join as
|
|
101077
|
+
import { join as join68 } from "path";
|
|
100771
101078
|
var DatabaseClass3 = null;
|
|
100772
101079
|
function loadDatabaseClass3() {
|
|
100773
101080
|
if (DatabaseClass3 != null)
|
|
@@ -100839,9 +101146,9 @@ function applySchema(db3) {
|
|
|
100839
101146
|
}
|
|
100840
101147
|
function openTurnsDb(agentDir) {
|
|
100841
101148
|
const Database = loadDatabaseClass3();
|
|
100842
|
-
const dir =
|
|
101149
|
+
const dir = join68(agentDir, "telegram");
|
|
100843
101150
|
mkdirSync49(dir, { recursive: true, mode: 448 });
|
|
100844
|
-
const path3 =
|
|
101151
|
+
const path3 = join68(dir, "registry.db");
|
|
100845
101152
|
const db3 = new Database(path3, { create: true });
|
|
100846
101153
|
applySchema(db3);
|
|
100847
101154
|
try {
|
|
@@ -101186,7 +101493,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
101186
101493
|
}
|
|
101187
101494
|
|
|
101188
101495
|
// gateway/bridge-dead-watchdog.ts
|
|
101189
|
-
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as
|
|
101496
|
+
import { readFileSync as readFileSync58, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as unlinkSync29 } from "node:fs";
|
|
101190
101497
|
|
|
101191
101498
|
// gateway/cron-session.ts
|
|
101192
101499
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -101258,7 +101565,7 @@ function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs
|
|
|
101258
101565
|
}
|
|
101259
101566
|
} catch {}
|
|
101260
101567
|
try {
|
|
101261
|
-
|
|
101568
|
+
unlinkSync29(path3);
|
|
101262
101569
|
} catch {}
|
|
101263
101570
|
return marker;
|
|
101264
101571
|
}
|
|
@@ -101658,7 +101965,7 @@ if (isGatewayMain) {
|
|
|
101658
101965
|
shutdownAnalytics();
|
|
101659
101966
|
});
|
|
101660
101967
|
}
|
|
101661
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
101968
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join69(homedir20(), ".claude", "channels", "telegram");
|
|
101662
101969
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
101663
101970
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
101664
101971
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -101758,11 +102065,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
101758
102065
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
101759
102066
|
timer3.unref?.();
|
|
101760
102067
|
}
|
|
101761
|
-
var ACCESS_FILE =
|
|
101762
|
-
var APPROVED_DIR =
|
|
101763
|
-
var ENV_FILE =
|
|
101764
|
-
var INBOX_DIR =
|
|
101765
|
-
var PEOPLE_FILE =
|
|
102068
|
+
var ACCESS_FILE = join69(STATE_DIR, "access.json");
|
|
102069
|
+
var APPROVED_DIR = join69(STATE_DIR, "approved");
|
|
102070
|
+
var ENV_FILE = join69(STATE_DIR, ".env");
|
|
102071
|
+
var INBOX_DIR = join69(STATE_DIR, "inbox");
|
|
102072
|
+
var PEOPLE_FILE = join69(STATE_DIR, "people.json");
|
|
101766
102073
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
101767
102074
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
101768
102075
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -101857,40 +102164,21 @@ var GRAMMY_VERSION = (() => {
|
|
|
101857
102164
|
var _rawSendChecklist;
|
|
101858
102165
|
var _rawEditMessageChecklist;
|
|
101859
102166
|
var CHECKLIST_API_AVAILABLE = false;
|
|
101860
|
-
async function rawSendChecklist(
|
|
101861
|
-
if (!CHECKLIST_API_AVAILABLE)
|
|
102167
|
+
async function rawSendChecklist(payload) {
|
|
102168
|
+
if (!CHECKLIST_API_AVAILABLE)
|
|
101862
102169
|
throw new Error("sendChecklist is not available in this grammY/Telegram Bot API version");
|
|
101863
|
-
|
|
101864
|
-
const MAX_TASKS = 30;
|
|
101865
|
-
if (args.tasks.length > MAX_TASKS) {
|
|
101866
|
-
throw new Error(`checklist exceeds ${MAX_TASKS}-task limit (got ${args.tasks.length})`);
|
|
101867
|
-
}
|
|
101868
|
-
const result = await _rawSendChecklist({
|
|
101869
|
-
chat_id: Number(args.chat_id),
|
|
101870
|
-
title: args.title,
|
|
101871
|
-
tasks: args.tasks.map((t) => ({ text: t.text, ...t.done != null ? { is_completed: t.done } : {} })),
|
|
101872
|
-
...args.message_thread_id != null ? { message_thread_id: args.message_thread_id } : {},
|
|
101873
|
-
...args.reply_to_message_id != null ? { reply_to_message_id: args.reply_to_message_id } : {},
|
|
101874
|
-
...args.protect_content === true ? { protect_content: true } : {}
|
|
101875
|
-
});
|
|
102170
|
+
const result = await _rawSendChecklist(payload);
|
|
101876
102171
|
return { message_id: result.message_id };
|
|
101877
102172
|
}
|
|
101878
|
-
async function rawEditMessageChecklist(
|
|
101879
|
-
if (!CHECKLIST_API_AVAILABLE)
|
|
102173
|
+
async function rawEditMessageChecklist(payload) {
|
|
102174
|
+
if (!CHECKLIST_API_AVAILABLE)
|
|
101880
102175
|
throw new Error("editMessageChecklist is not available in this grammY/Telegram Bot API version");
|
|
101881
|
-
|
|
101882
|
-
|
|
101883
|
-
|
|
101884
|
-
|
|
101885
|
-
|
|
101886
|
-
|
|
101887
|
-
tasks: args.tasks.map((t) => ({
|
|
101888
|
-
...t.id != null ? { id: Number(t.id) } : {},
|
|
101889
|
-
...t.text != null ? { text: t.text } : {},
|
|
101890
|
-
...t.done != null ? { is_completed: t.done } : {}
|
|
101891
|
-
}))
|
|
101892
|
-
} : {}
|
|
101893
|
-
});
|
|
102176
|
+
await _rawEditMessageChecklist(payload);
|
|
102177
|
+
}
|
|
102178
|
+
var checklistStore = createChecklistStore();
|
|
102179
|
+
function resolveBusinessConnectionId() {
|
|
102180
|
+
const v = process.env.SWITCHROOM_TELEGRAM_BUSINESS_CONNECTION_ID?.trim();
|
|
102181
|
+
return v ? v : undefined;
|
|
101894
102182
|
}
|
|
101895
102183
|
var chatLock = createChatLock();
|
|
101896
102184
|
var lockedBot;
|
|
@@ -101911,7 +102199,7 @@ function assertSendable(f) {
|
|
|
101911
102199
|
} catch {
|
|
101912
102200
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
101913
102201
|
}
|
|
101914
|
-
const inbox =
|
|
102202
|
+
const inbox = join69(stateReal, "inbox");
|
|
101915
102203
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
101916
102204
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
101917
102205
|
}
|
|
@@ -102036,7 +102324,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
102036
102324
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
102037
102325
|
try {
|
|
102038
102326
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
102039
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
102327
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join69(STATE_DIR, "history.db")}
|
|
102040
102328
|
`);
|
|
102041
102329
|
} catch (err) {
|
|
102042
102330
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -102055,9 +102343,9 @@ if (isGatewayMain)
|
|
|
102055
102343
|
let markerTurnKey = null;
|
|
102056
102344
|
let markerAgeMs = null;
|
|
102057
102345
|
try {
|
|
102058
|
-
const markerPath =
|
|
102346
|
+
const markerPath = join69(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
102059
102347
|
if (existsSync57(markerPath)) {
|
|
102060
|
-
const st =
|
|
102348
|
+
const st = statSync23(markerPath);
|
|
102061
102349
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
102062
102350
|
try {
|
|
102063
102351
|
const payload = JSON.parse(readFileSync60(markerPath, "utf8"));
|
|
@@ -102080,10 +102368,10 @@ if (isGatewayMain)
|
|
|
102080
102368
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
102081
102369
|
`);
|
|
102082
102370
|
} else {
|
|
102083
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
102371
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join69(agentDir, "telegram", "registry.db")}
|
|
102084
102372
|
`);
|
|
102085
102373
|
}
|
|
102086
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
102374
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join69(STATE_DIR, "bridge-dead-escalation.json"));
|
|
102087
102375
|
if (bridgeDeadMarker != null) {
|
|
102088
102376
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
102089
102377
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -102096,7 +102384,7 @@ if (isGatewayMain)
|
|
|
102096
102384
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
102097
102385
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
102098
102386
|
if (pending2 != null && selfAgent) {
|
|
102099
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
102387
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
|
|
102100
102388
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
102101
102389
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
102102
102390
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -102209,7 +102497,7 @@ if (isGatewayMain)
|
|
|
102209
102497
|
`);
|
|
102210
102498
|
}
|
|
102211
102499
|
}
|
|
102212
|
-
const pendingEnvPath =
|
|
102500
|
+
const pendingEnvPath = join69(agentDir, ".pending-turn.env");
|
|
102213
102501
|
try {
|
|
102214
102502
|
if (pending2 != null) {
|
|
102215
102503
|
const lines = [
|
|
@@ -102337,7 +102625,7 @@ function checkApprovals() {
|
|
|
102337
102625
|
return;
|
|
102338
102626
|
}
|
|
102339
102627
|
for (const senderId of files) {
|
|
102340
|
-
const file =
|
|
102628
|
+
const file = join69(APPROVED_DIR, senderId);
|
|
102341
102629
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync8(file, { force: true }), (err) => {
|
|
102342
102630
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
102343
102631
|
`);
|
|
@@ -102423,6 +102711,7 @@ async function deliverAnswer(args) {
|
|
|
102423
102711
|
const result = await runBackstopDelivery(backstopDeliveryLedger, turnId, chunks, args.resume ? null : args.cardMessageId, {
|
|
102424
102712
|
sendChunk,
|
|
102425
102713
|
readBack,
|
|
102714
|
+
onAckClaim: args.onAckClaim,
|
|
102426
102715
|
recordOutbound: HISTORY_ENABLED ? (messageIds, texts) => {
|
|
102427
102716
|
try {
|
|
102428
102717
|
recordOutbound({
|
|
@@ -102511,7 +102800,7 @@ function noteAgentOutputAt(key, ts) {
|
|
|
102511
102800
|
lastAgentOutputAt.delete(oldest);
|
|
102512
102801
|
}
|
|
102513
102802
|
}
|
|
102514
|
-
var OBLIGATION_STORE_PATH =
|
|
102803
|
+
var OBLIGATION_STORE_PATH = join69(STATE_DIR, "obligations.json");
|
|
102515
102804
|
var obligationStoreFs = {
|
|
102516
102805
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
102517
102806
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -103280,6 +103569,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
103280
103569
|
toolCallCount: turn.toolCallCount ?? 0,
|
|
103281
103570
|
turnId: turn.turnId,
|
|
103282
103571
|
finalAnswerDelivered: turn.finalAnswerDelivered,
|
|
103572
|
+
replyCalled: turn.replyCalled,
|
|
103283
103573
|
deliveryOutcome: turn.deliveryOutcome,
|
|
103284
103574
|
landedUnconfirmed: turn.landedUnconfirmed
|
|
103285
103575
|
}, endedAt)) + `
|
|
@@ -103288,7 +103578,7 @@ function emitTurnRecord(turn, endedAt) {
|
|
|
103288
103578
|
maybeRotate(turnsPath, {
|
|
103289
103579
|
statSize: (p) => {
|
|
103290
103580
|
try {
|
|
103291
|
-
return
|
|
103581
|
+
return statSync23(p).size;
|
|
103292
103582
|
} catch {
|
|
103293
103583
|
return;
|
|
103294
103584
|
}
|
|
@@ -104856,7 +105146,7 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
104856
105146
|
})();
|
|
104857
105147
|
var statusPinClaims = new Map;
|
|
104858
105148
|
var statusPinRightsCache = new PinRightsCache2;
|
|
104859
|
-
var STATUS_PIN_STORE_PATH =
|
|
105149
|
+
var STATUS_PIN_STORE_PATH = join69(STATE_DIR, "status-pins.json");
|
|
104860
105150
|
var statusPinStoreFs = {
|
|
104861
105151
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104862
105152
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -104864,7 +105154,7 @@ var statusPinStoreFs = {
|
|
|
104864
105154
|
existsSync: (p) => existsSync57(p)
|
|
104865
105155
|
};
|
|
104866
105156
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
104867
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
105157
|
+
var ACTIVITY_CARD_STORE_PATH = join69(STATE_DIR, "activity-cards-pending.json");
|
|
104868
105158
|
var activityCardStoreFs = {
|
|
104869
105159
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104870
105160
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -104872,7 +105162,7 @@ var activityCardStoreFs = {
|
|
|
104872
105162
|
existsSync: (p) => existsSync57(p)
|
|
104873
105163
|
};
|
|
104874
105164
|
var activityCardPersistEnabled = !STATIC;
|
|
104875
|
-
var QUEUED_CARD_STORE_PATH =
|
|
105165
|
+
var QUEUED_CARD_STORE_PATH = join69(STATE_DIR, "queued-cards-pending.json");
|
|
104876
105166
|
var queuedCardStoreFs = {
|
|
104877
105167
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
104878
105168
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
@@ -105164,7 +105454,7 @@ async function unpinAllStatusPins() {
|
|
|
105164
105454
|
}
|
|
105165
105455
|
}
|
|
105166
105456
|
var stalePinSweepEligible = false;
|
|
105167
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
105457
|
+
var STALE_PIN_SWEEP_STORE_PATH = join69(STATE_DIR, "stale-pin-sweep.json");
|
|
105168
105458
|
var stalePinSweeper = createGatewayStalePinSweeper({
|
|
105169
105459
|
telegram: { handle: () => lockedBot, call: robustApiCall },
|
|
105170
105460
|
claims: () => statusPinClaims.values(),
|
|
@@ -105205,12 +105495,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
105205
105495
|
var completeProgressCardTurn = null;
|
|
105206
105496
|
var subagentWatcher = null;
|
|
105207
105497
|
var workerActivityFeed = null;
|
|
105208
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
105498
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join69(STATE_DIR, "gateway.sock");
|
|
105209
105499
|
if (isGatewayMain)
|
|
105210
105500
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
105211
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
105212
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
105213
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
105501
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join69(STATE_DIR, "gateway.pid.json");
|
|
105502
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join69(STATE_DIR, "gateway-session.json");
|
|
105503
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join69(STATE_DIR, "clean-shutdown.json");
|
|
105214
105504
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
105215
105505
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
105216
105506
|
var activeBootCard = null;
|
|
@@ -105239,7 +105529,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
105239
105529
|
bot: botApi,
|
|
105240
105530
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
105241
105531
|
`),
|
|
105242
|
-
persistPath:
|
|
105532
|
+
persistPath: join69(stateDir, "issues-card.json")
|
|
105243
105533
|
});
|
|
105244
105534
|
activeIssuesWatcher = startIssuesWatcher({
|
|
105245
105535
|
stateDir,
|
|
@@ -105417,7 +105707,11 @@ function runDeliveryConfirmSweep() {
|
|
|
105417
105707
|
}
|
|
105418
105708
|
var _deliveryConfirmSweep = isGatewayMain ? setInterval(runDeliveryConfirmSweep, DELIVERY_CONFIRM_SWEEP_MS) : undefined;
|
|
105419
105709
|
_deliveryConfirmSweep?.unref?.();
|
|
105420
|
-
startOutboxSweep({ isGatewayMain, stateDir: STATE_DIR, getBot: () => bot, getTurnsDb: () => turnsDb, dedupCheck: (c, t, x) => outboundDedup.check(c, t, x, Date.now()) != null,
|
|
105710
|
+
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) => {
|
|
105711
|
+
try {
|
|
105712
|
+
recordOutbound({ chat_id: chatId, thread_id: threadId, message_ids, texts });
|
|
105713
|
+
} catch {}
|
|
105714
|
+
} : 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) });
|
|
105421
105715
|
if (isGatewayMain)
|
|
105422
105716
|
startTimer2({
|
|
105423
105717
|
editMessage: async (ctx) => {
|
|
@@ -105439,14 +105733,14 @@ if (isGatewayMain)
|
|
|
105439
105733
|
var inboundSpool;
|
|
105440
105734
|
if (isGatewayMain)
|
|
105441
105735
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
105442
|
-
path:
|
|
105736
|
+
path: join69(STATE_DIR, "inbound-spool.jsonl"),
|
|
105443
105737
|
fs: {
|
|
105444
105738
|
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
105445
105739
|
readFileSync: (p) => readFileSync60(p, "utf8"),
|
|
105446
105740
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
105447
105741
|
renameSync: (a, b) => renameSync27(a, b),
|
|
105448
105742
|
existsSync: (p) => existsSync57(p),
|
|
105449
|
-
statSizeSync: (p) =>
|
|
105743
|
+
statSizeSync: (p) => statSync23(p).size,
|
|
105450
105744
|
fsyncFileSync: fsyncPathSync,
|
|
105451
105745
|
fsyncDirSync: fsyncPathSync
|
|
105452
105746
|
},
|
|
@@ -105509,7 +105803,7 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
105509
105803
|
let transcriptText;
|
|
105510
105804
|
try {
|
|
105511
105805
|
const projectsDir = getProjectsDirForCwd();
|
|
105512
|
-
const path3 =
|
|
105806
|
+
const path3 = join69(projectsDir, `${sessionId}.jsonl`);
|
|
105513
105807
|
if (!existsSync57(path3)) {
|
|
105514
105808
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
105515
105809
|
`);
|
|
@@ -105674,8 +105968,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
105674
105968
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
105675
105969
|
isShuttingDown: () => shuttingDown,
|
|
105676
105970
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
105677
|
-
crashLogPath:
|
|
105678
|
-
markerPath:
|
|
105971
|
+
crashLogPath: join69(STATE_DIR, "bridge-crash.log"),
|
|
105972
|
+
markerPath: join69(STATE_DIR, "bridge-dead-escalation.json"),
|
|
105679
105973
|
log: (line) => process.stderr.write(`${line}
|
|
105680
105974
|
`),
|
|
105681
105975
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -105781,8 +106075,8 @@ if (isGatewayMain)
|
|
|
105781
106075
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
105782
106076
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
105783
106077
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
105784
|
-
configSnapshotPath:
|
|
105785
|
-
bootCardStatePath:
|
|
106078
|
+
configSnapshotPath: join69(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
106079
|
+
bootCardStatePath: join69(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
105786
106080
|
floodStatePath: FLOOD_STATE_PATH,
|
|
105787
106081
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
105788
106082
|
}, ackMsgId).then((handle) => {
|
|
@@ -106450,7 +106744,7 @@ if (isGatewayMain)
|
|
|
106450
106744
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
106451
106745
|
if (Number.isInteger(receiverUid))
|
|
106452
106746
|
allowedUids.push(receiverUid);
|
|
106453
|
-
const socketPath =
|
|
106747
|
+
const socketPath = join69(STATE_DIR, "webhook.sock");
|
|
106454
106748
|
const webhookInject = (agentName3, inbound) => {
|
|
106455
106749
|
const msg = inbound;
|
|
106456
106750
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -106600,17 +106894,24 @@ async function executeSendChecklist(args) {
|
|
|
106600
106894
|
const protectContent = args.protect_content === true;
|
|
106601
106895
|
assertAllowedChat(chat_id);
|
|
106602
106896
|
const { title: redactedTitle, tasks: redactedTasks } = redactChecklistFields(title, tasks, (t) => redactOutboundText(t, "send_checklist"));
|
|
106603
|
-
const
|
|
106604
|
-
|
|
106605
|
-
title: redactedTitle,
|
|
106606
|
-
tasks: redactedTasks,
|
|
106897
|
+
const literal = (loadAccess().parseMode ?? "html") === "text";
|
|
106898
|
+
const sendOpts = {
|
|
106607
106899
|
...threadId != null ? { message_thread_id: threadId } : {},
|
|
106608
|
-
...replyTo != null ? {
|
|
106900
|
+
...replyTo != null ? { reply_parameters: { message_id: replyTo } } : {},
|
|
106609
106901
|
...protectContent ? { protect_content: true } : {}
|
|
106610
|
-
}
|
|
106611
|
-
|
|
106902
|
+
};
|
|
106903
|
+
const result = await performSendChecklist({
|
|
106904
|
+
businessConnectionId: resolveBusinessConnectionId(),
|
|
106905
|
+
nativeAvailable: CHECKLIST_API_AVAILABLE,
|
|
106906
|
+
sendNative: rawSendChecklist,
|
|
106907
|
+
sendText: (text5) => robustApiCall(() => literal ? lockedBot.api.sendMessage(chat_id, text5, sendOpts) : lockedBot.api.sendRichMessage(chat_id, richMessage2(text5), sendOpts), { verb: "sendMessage", chat_id, threadId }),
|
|
106908
|
+
literalText: literal,
|
|
106909
|
+
log: (l) => process.stderr.write(`telegram gateway: ${l}`)
|
|
106910
|
+
}, { title: redactedTitle, tasks: redactedTasks, chatId: Number(chat_id), replyToMessageId: replyTo, protectContent });
|
|
106911
|
+
checklistStore.set(checklistStoreKey(chat_id, result.message_id), result.state);
|
|
106912
|
+
process.stderr.write(`telegram gateway: send_checklist: sent chatId=${chat_id} messageId=${result.message_id} tasks=${tasks.length} mode=${result.mode}
|
|
106612
106913
|
`);
|
|
106613
|
-
return { content: [{ type: "text", text:
|
|
106914
|
+
return { content: [{ type: "text", text: sendChecklistToolText(result) }] };
|
|
106614
106915
|
}
|
|
106615
106916
|
var linearAuthAlertLast = new Map;
|
|
106616
106917
|
var LINEAR_AUTH_ALERT_COOLDOWN_MS = 21600000;
|
|
@@ -106662,10 +106963,26 @@ async function executeUpdateChecklist(args) {
|
|
|
106662
106963
|
const tasks = args.tasks;
|
|
106663
106964
|
assertAllowedChat(chat_id);
|
|
106664
106965
|
const { title: redactedTitle, tasks: redactedTasks } = redactChecklistFields(title, tasks, (t) => redactOutboundText(t, "update_checklist"));
|
|
106665
|
-
|
|
106666
|
-
|
|
106966
|
+
const literal = (loadAccess().parseMode ?? "html") === "text";
|
|
106967
|
+
const key = checklistStoreKey(chat_id, message_id);
|
|
106968
|
+
const result = await performUpdateChecklist({
|
|
106969
|
+
state: checklistStore.get(key),
|
|
106970
|
+
businessConnectionId: resolveBusinessConnectionId(),
|
|
106971
|
+
nativeAvailable: CHECKLIST_API_AVAILABLE,
|
|
106972
|
+
editNative: rawEditMessageChecklist,
|
|
106973
|
+
editText: async (text5) => {
|
|
106974
|
+
await robustApiCall(() => lockedBot.api.editMessageText(chat_id, Number(message_id), literal ? text5 : richMessage2(text5)));
|
|
106975
|
+
},
|
|
106976
|
+
literalText: literal,
|
|
106977
|
+
log: (l) => process.stderr.write(`telegram gateway: ${l}`),
|
|
106978
|
+
chatId: Number(chat_id),
|
|
106979
|
+
messageId: Number(message_id)
|
|
106980
|
+
}, { title: redactedTitle, tasks: redactedTasks });
|
|
106981
|
+
if (result.ok)
|
|
106982
|
+
checklistStore.set(key, result.state);
|
|
106983
|
+
process.stderr.write(`telegram gateway: update_checklist: ${result.ok ? `updated mode=${result.mode}` : `failed reason=${result.reason}`} chatId=${chat_id} messageId=${message_id}
|
|
106667
106984
|
`);
|
|
106668
|
-
return { content: [{ type: "text", text:
|
|
106985
|
+
return { content: [{ type: "text", text: updateChecklistToolText(result, Number(message_id)) }] };
|
|
106669
106986
|
}
|
|
106670
106987
|
function redactOutboundText(text5, site) {
|
|
106671
106988
|
const masked = redact2(text5);
|
|
@@ -106678,9 +106995,9 @@ function redactOutboundText(text5, site) {
|
|
|
106678
106995
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
106679
106996
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
106680
106997
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
106681
|
-
persistPath:
|
|
106998
|
+
persistPath: join69(STATE_DIR, "voice-ondemand.json")
|
|
106682
106999
|
});
|
|
106683
|
-
var VOICE_CACHE_DIR =
|
|
107000
|
+
var VOICE_CACHE_DIR = join69(STATE_DIR, "voice-cache");
|
|
106684
107001
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
106685
107002
|
runJob: async (job) => {
|
|
106686
107003
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -107082,7 +107399,7 @@ async function executeSendGif(rawArgs) {
|
|
|
107082
107399
|
};
|
|
107083
107400
|
}
|
|
107084
107401
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
107085
|
-
const accountPath =
|
|
107402
|
+
const accountPath = join69(STATE_DIR, "telegraph-account.json");
|
|
107086
107403
|
let account = null;
|
|
107087
107404
|
try {
|
|
107088
107405
|
if (existsSync57(accountPath)) {
|
|
@@ -108637,7 +108954,7 @@ function restartMarkerPath() {
|
|
|
108637
108954
|
const agentDir = resolveAgentDirFromEnv();
|
|
108638
108955
|
if (!agentDir)
|
|
108639
108956
|
return null;
|
|
108640
|
-
return
|
|
108957
|
+
return join69(agentDir, "restart-pending.json");
|
|
108641
108958
|
}
|
|
108642
108959
|
function writeRestartMarker(marker) {
|
|
108643
108960
|
const p = restartMarkerPath();
|
|
@@ -108829,7 +109146,7 @@ function _resetDockerReachableCache() {
|
|
|
108829
109146
|
}
|
|
108830
109147
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
108831
109148
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
108832
|
-
const logPath =
|
|
109149
|
+
const logPath = join69(STATE_DIR, "detached-spawn.log");
|
|
108833
109150
|
let outFd = null;
|
|
108834
109151
|
try {
|
|
108835
109152
|
mkdirSync51(STATE_DIR, { recursive: true });
|
|
@@ -109122,7 +109439,7 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
109122
109439
|
}
|
|
109123
109440
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
109124
109441
|
try {
|
|
109125
|
-
const auditPath =
|
|
109442
|
+
const auditPath = join69(homedir20(), ".switchroom", "vault-audit.log");
|
|
109126
109443
|
if (!existsSync57(auditPath))
|
|
109127
109444
|
return [];
|
|
109128
109445
|
const raw = readFileSync60(auditPath, "utf8");
|
|
@@ -109176,7 +109493,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
109176
109493
|
try {
|
|
109177
109494
|
const agentDir = resolveAgentDirFromEnv();
|
|
109178
109495
|
if (agentDir) {
|
|
109179
|
-
const raw = readFileSync60(
|
|
109496
|
+
const raw = readFileSync60(join69(agentDir, ".claude", ".claude.json"), "utf8");
|
|
109180
109497
|
claudeJson = JSON.parse(raw);
|
|
109181
109498
|
}
|
|
109182
109499
|
} catch {}
|
|
@@ -109305,7 +109622,7 @@ function buildModelDeps(restartCtx) {
|
|
|
109305
109622
|
try {
|
|
109306
109623
|
const agentDir = resolveAgentDirFromEnv();
|
|
109307
109624
|
if (agentDir) {
|
|
109308
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
109625
|
+
const local = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
|
|
109309
109626
|
if (local.ok)
|
|
109310
109627
|
return formatQuotaLine2(local.data);
|
|
109311
109628
|
}
|
|
@@ -109552,10 +109869,10 @@ function effortMenuReplyMarkup(reply) {
|
|
|
109552
109869
|
function flushAgentHandoff(agentDir) {
|
|
109553
109870
|
let removed = 0;
|
|
109554
109871
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
109555
|
-
const p =
|
|
109872
|
+
const p = join69(agentDir, fname);
|
|
109556
109873
|
try {
|
|
109557
109874
|
if (existsSync57(p)) {
|
|
109558
|
-
|
|
109875
|
+
unlinkSync31(p);
|
|
109559
109876
|
removed++;
|
|
109560
109877
|
}
|
|
109561
109878
|
} catch (err) {
|
|
@@ -109610,7 +109927,7 @@ async function handleNewCommand(ctx) {
|
|
|
109610
109927
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
109611
109928
|
if (agentDir != null) {
|
|
109612
109929
|
try {
|
|
109613
|
-
writeFileSync50(
|
|
109930
|
+
writeFileSync50(join69(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
109614
109931
|
`, "utf8");
|
|
109615
109932
|
} catch (err) {
|
|
109616
109933
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -109727,7 +110044,7 @@ var lockoutOps = {
|
|
|
109727
110044
|
writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
|
|
109728
110045
|
existsSync: (p) => existsSync57(p),
|
|
109729
110046
|
mkdirSync: (p, opts) => mkdirSync51(p, opts),
|
|
109730
|
-
joinPath: (...parts) =>
|
|
110047
|
+
joinPath: (...parts) => join69(...parts)
|
|
109731
110048
|
};
|
|
109732
110049
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
109733
110050
|
function isAuthBrokerSocketReachable() {
|
|
@@ -109987,7 +110304,7 @@ async function runCreditWatch() {
|
|
|
109987
110304
|
if (!agentDir)
|
|
109988
110305
|
return;
|
|
109989
110306
|
const agentName3 = getMyAgentName();
|
|
109990
|
-
const claudeConfigDir =
|
|
110307
|
+
const claudeConfigDir = join69(agentDir, ".claude");
|
|
109991
110308
|
const stateDir = STATE_DIR;
|
|
109992
110309
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
109993
110310
|
const prev = loadCreditState(stateDir);
|
|
@@ -111743,7 +112060,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
111743
112060
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
111744
112061
|
return;
|
|
111745
112062
|
}
|
|
111746
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
112063
|
+
const result = await fetchQuota2({ claudeConfigDir: join69(agentDir, ".claude") });
|
|
111747
112064
|
if (!result.ok) {
|
|
111748
112065
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
111749
112066
|
return;
|
|
@@ -112999,7 +113316,7 @@ async function startGateway() {
|
|
|
112999
113316
|
return;
|
|
113000
113317
|
}
|
|
113001
113318
|
})();
|
|
113002
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
113319
|
+
const resolvedAgentDirForBootCard = agentDir ?? join69(homedir20(), ".switchroom", "agents", agentSlug);
|
|
113003
113320
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
113004
113321
|
agentName: agentDisplayName,
|
|
113005
113322
|
agentSlug,
|
|
@@ -113013,8 +113330,8 @@ async function startGateway() {
|
|
|
113013
113330
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
113014
113331
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
113015
113332
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
113016
|
-
configSnapshotPath:
|
|
113017
|
-
bootCardStatePath:
|
|
113333
|
+
configSnapshotPath: join69(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
113334
|
+
bootCardStatePath: join69(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
113018
113335
|
floodStatePath: FLOOD_STATE_PATH,
|
|
113019
113336
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
113020
113337
|
}, ackMsgId);
|
|
@@ -113047,7 +113364,7 @@ async function startGateway() {
|
|
|
113047
113364
|
if (smAgentDir) {
|
|
113048
113365
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
113049
113366
|
const resolved = await waitForSessionModelResolution({
|
|
113050
|
-
barrierExists: () => existsSync57(
|
|
113367
|
+
barrierExists: () => existsSync57(join69(smAgentDir, ".session-model-resolved")),
|
|
113051
113368
|
timeoutMs: resolutionTimeoutMs
|
|
113052
113369
|
});
|
|
113053
113370
|
if (!resolved) {
|
|
@@ -113055,7 +113372,7 @@ async function startGateway() {
|
|
|
113055
113372
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
113056
113373
|
`);
|
|
113057
113374
|
} else {
|
|
113058
|
-
const activePath =
|
|
113375
|
+
const activePath = join69(smAgentDir, ".active-session-model");
|
|
113059
113376
|
if (existsSync57(activePath)) {
|
|
113060
113377
|
try {
|
|
113061
113378
|
const launched = readFileSync60(activePath, "utf8").trim();
|
|
@@ -113091,12 +113408,12 @@ async function startGateway() {
|
|
|
113091
113408
|
deliverModelSwitchBootNotice({
|
|
113092
113409
|
...modelBootCardDeps,
|
|
113093
113410
|
confirmation,
|
|
113094
|
-
hasSessionModelAlert: existsSync57(
|
|
113411
|
+
hasSessionModelAlert: existsSync57(join69(smAgentDir, ".session-model-alert"))
|
|
113095
113412
|
});
|
|
113096
113413
|
}
|
|
113097
113414
|
} catch {}
|
|
113098
113415
|
}
|
|
113099
|
-
const activeEffortPath =
|
|
113416
|
+
const activeEffortPath = join69(smAgentDir, ".active-session-effort");
|
|
113100
113417
|
if (existsSync57(activeEffortPath)) {
|
|
113101
113418
|
try {
|
|
113102
113419
|
const launchedEffort = readFileSync60(activeEffortPath, "utf8").trim();
|
|
@@ -113104,7 +113421,7 @@ async function startGateway() {
|
|
|
113104
113421
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
113105
113422
|
} catch {}
|
|
113106
113423
|
}
|
|
113107
|
-
const alertPath =
|
|
113424
|
+
const alertPath = join69(smAgentDir, ".session-model-alert");
|
|
113108
113425
|
if (existsSync57(alertPath)) {
|
|
113109
113426
|
let alertText = null;
|
|
113110
113427
|
try {
|
|
@@ -113113,7 +113430,7 @@ async function startGateway() {
|
|
|
113113
113430
|
alertText = null;
|
|
113114
113431
|
}
|
|
113115
113432
|
try {
|
|
113116
|
-
|
|
113433
|
+
unlinkSync31(alertPath);
|
|
113117
113434
|
} catch {}
|
|
113118
113435
|
if (alertText && alertText.length > 0) {
|
|
113119
113436
|
const operators = loadAccess().allowFrom;
|