switchroom 0.13.54 → 0.13.56
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 +51 -0
- package/dist/auth-broker/index.js +51 -0
- package/dist/cli/ack-first-pretool.mjs +75 -0
- package/dist/cli/notion-write-pretool.mjs +13394 -0
- package/dist/cli/switchroom.js +1105 -375
- package/dist/host-control/main.js +51 -0
- package/dist/vault/approvals/kernel-server.js +52 -1
- package/dist/vault/broker/server.js +52 -1
- package/package.json +1 -1
- package/skills/notion/SKILL.md +148 -0
- package/telegram-plugin/ack-flag.ts +66 -0
- package/telegram-plugin/dist/gateway/gateway.js +413 -254
- package/telegram-plugin/gateway/gateway.ts +80 -1
- package/telegram-plugin/runtime-metrics.ts +17 -0
- package/telegram-plugin/silence-poke.ts +82 -0
- package/telegram-plugin/tests/ack-flag.test.ts +65 -0
- package/telegram-plugin/tests/post-fallback-outbound-count.test.ts +78 -0
- package/telegram-plugin/tests/silence-poke.test.ts +117 -7
|
@@ -16334,10 +16334,10 @@ __export(exports_client, {
|
|
|
16334
16334
|
AuthBrokerClient: () => AuthBrokerClient
|
|
16335
16335
|
});
|
|
16336
16336
|
import * as net from "node:net";
|
|
16337
|
-
import { existsSync as
|
|
16337
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
16338
16338
|
import { homedir as homedir3 } from "node:os";
|
|
16339
16339
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
16340
|
-
import { join as
|
|
16340
|
+
import { join as join9 } from "node:path";
|
|
16341
16341
|
function reviveDate(v) {
|
|
16342
16342
|
if (v == null)
|
|
16343
16343
|
return null;
|
|
@@ -16347,7 +16347,7 @@ function reviveDate(v) {
|
|
|
16347
16347
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
16348
16348
|
}
|
|
16349
16349
|
function operatorSocketPath(home = homedir3()) {
|
|
16350
|
-
return
|
|
16350
|
+
return join9(home, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
16351
16351
|
}
|
|
16352
16352
|
function resolveAuthBrokerSocketPath(opts) {
|
|
16353
16353
|
if (opts?.socket)
|
|
@@ -16617,7 +16617,7 @@ async function withAuthBrokerClient(fn, opts) {
|
|
|
16617
16617
|
}
|
|
16618
16618
|
}
|
|
16619
16619
|
function authBrokerSocketExists(opts) {
|
|
16620
|
-
return
|
|
16620
|
+
return existsSync7(resolveAuthBrokerSocketPath(opts));
|
|
16621
16621
|
}
|
|
16622
16622
|
var DEFAULT_TIMEOUT_MS = 5000, AuthBrokerError, AuthBrokerUnreachableError;
|
|
16623
16623
|
var init_client = __esm(() => {
|
|
@@ -23607,7 +23607,7 @@ var init_dist = __esm(() => {
|
|
|
23607
23607
|
});
|
|
23608
23608
|
|
|
23609
23609
|
// ../src/config/schema.ts
|
|
23610
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
23610
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReleaseBlock, NetworkIsolationSchema, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, HostdConfigSchema, SwitchroomConfigSchema;
|
|
23611
23611
|
var init_schema = __esm(() => {
|
|
23612
23612
|
init_zod();
|
|
23613
23613
|
CodeRepoEntrySchema = exports_external.object({
|
|
@@ -23792,6 +23792,16 @@ var init_schema = __esm(() => {
|
|
|
23792
23792
|
authority: exports_external.string().url().optional().describe("Microsoft authority endpoint. Defaults to " + "'https://login.microsoftonline.com/common' which accepts both " + "personal MSA and work/school tenants. Override only for " + "single-tenant deployments."),
|
|
23793
23793
|
org_mode: exports_external.boolean().optional().describe("Opt-in to Teams + SharePoint surfaces (RFC \u00a76.4). When true, " + "the v1 scope set adds Sites.ReadWrite.All AND the launcher " + "spawns softeria with --org-mode. Defaults to false \u2014 personal " + "MSA + standard work surfaces only. Flipping for an existing " + "consented account requires re-running 'auth microsoft account " + "add --replace' to consent the additional scope.")
|
|
23794
23794
|
}).optional();
|
|
23795
|
+
NotionWorkspaceConfigSchema = exports_external.object({
|
|
23796
|
+
vault_key: exports_external.string().min(1).default("notion/integration-token").describe("Vault key holding the Notion internal-integration token. Default " + "`notion/integration-token`. Override only for non-standard vault " + "layouts. The broker's --allow ACL on this key is the authoritative " + "list of which agents may receive the token."),
|
|
23797
|
+
databases: exports_external.record(exports_external.string().regex(/^[a-z0-9][a-z0-9_-]{0,62}$/, {
|
|
23798
|
+
message: "notion_workspace.databases friendly names must match " + "/^[a-z0-9][a-z0-9_-]{0,62}$/ \u2014 lowercase letters, digits, " + "hyphens, underscores. Got: '%s'."
|
|
23799
|
+
}), exports_external.string().regex(/^[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}$/, {
|
|
23800
|
+
message: "notion_workspace.databases values must be Notion database " + "UUIDs (32 hex characters, optional dashes)."
|
|
23801
|
+
})).default({}).describe("Friendly-name \u2192 Notion database UUID map. Operator-managed; agents " + "reference databases by friendly name only \u2014 they never see or type " + "UUIDs. Populate via `switchroom notion list-dbs` (PR 4) after " + "vault-putting the integration token and sharing DBs with the " + "integration in Notion's UI."),
|
|
23802
|
+
mcp_version: exports_external.string().min(1).optional().describe("Optional pin for the upstream `@notionhq/notion-mcp-server` npm " + "package version. Default is the build-time `NOTION_MCP_PINNED_VERSION` " + "constant. Override only when reproducing operator-specific bugs."),
|
|
23803
|
+
rate_limit_rps: exports_external.number().int().positive().max(10).optional().describe("Optional global rate-limit budget in requests per second across all " + "switchroom agents sharing this integration token. Defaults to 3 " + "(Notion's documented public-API limit). Lower it if you also use " + "the integration token from outside switchroom and need to share " + "budget. Higher than 10 is rejected \u2014 if you think you need it, " + "your usage probably needs a workspace-tier upgrade with Notion.")
|
|
23804
|
+
}).optional();
|
|
23795
23805
|
AgentGoogleWorkspaceConfigSchema = exports_external.object({
|
|
23796
23806
|
account: exports_external.string().regex(/^[^@\s:]+@[^@\s:]+\.[^@\s:]+$/, {
|
|
23797
23807
|
message: "google_workspace.account must be a Google account email like " + "'alice@example.com' (colons not allowed)"
|
|
@@ -23805,6 +23815,13 @@ var init_schema = __esm(() => {
|
|
|
23805
23815
|
}).transform((v) => v.trim().toLowerCase()).optional().describe("RFC #1873: the Microsoft account this agent uses for the M365 MCP. " + "Must be a key in top-level `microsoft_accounts:` with this agent " + "listed in its `enabled_for[]`. Read by the auth-broker " + "(get-credentials, provider=microsoft) and by the scaffold to " + "decide whether to emit the `ms-365` MCP entry. Normalized to " + "lowercase so it matches the microsoft_accounts key (which is " + "also normalized)."),
|
|
23806
23816
|
org_mode: exports_external.boolean().optional().describe("Per-agent org_mode override (RFC #1873 \u00a76.4). When set, replaces " + "the top-level microsoft_workspace.org_mode for this agent. " + "Defaults to top-level value (which defaults to false).")
|
|
23807
23817
|
}).optional();
|
|
23818
|
+
AgentNotionWorkspaceConfigSchema = exports_external.object({
|
|
23819
|
+
databases: exports_external.array(exports_external.string().regex(/^[a-z0-9][a-z0-9_-]{0,62}$/, {
|
|
23820
|
+
message: "notion_workspace.databases entries must be friendly names " + "matching /^[a-z0-9][a-z0-9_-]{0,62}$/ \u2014 these must appear as " + "keys in top-level notion_workspace.databases."
|
|
23821
|
+
})).min(1, {
|
|
23822
|
+
message: "notion_workspace.databases must list at least one friendly " + "name. An empty list rejects every Notion tool call \u2014 if you " + "want to remove this agent's Notion access, delete the entire " + "notion_workspace block instead."
|
|
23823
|
+
}).optional().describe("Optional per-agent allowlist of database friendly names this " + "agent may read/write. Each name must exist as a key in top-level " + "notion_workspace.databases. Omit the field (or leave it undefined) " + "to grant access to every DB the upstream integration can see \u2014 " + "appropriate for an admin/orchestrator agent. Set the list to " + "narrow access for specialist agents.")
|
|
23824
|
+
}).optional();
|
|
23808
23825
|
ReactionsSchema = exports_external.object({
|
|
23809
23826
|
enabled: exports_external.boolean().optional().describe("Master switch for the reaction-trigger path. When false, " + "reactions are still persisted via recordReaction but never " + "dispatched to the agent as synthetic inbound turns. Default true."),
|
|
23810
23827
|
trigger_emojis: exports_external.array(exports_external.string()).optional().describe("Emoji allowlist that triggers a synthetic inbound when reacted " + "to a bot message. Default ['\uD83D\uDC4E', '\u274c', '\uD83D\uDC4D', '\u2705']. Cascade " + "mode: REPLACE (not union) \u2014 setting this at a layer replaces " + "lower layers entirely, so an operator can narrow to [] to " + "disable triggering without flipping `enabled`."),
|
|
@@ -23941,6 +23958,7 @@ var init_schema = __esm(() => {
|
|
|
23941
23958
|
drive: AgentGoogleWorkspaceConfigSchema.describe("RFC D legacy key \u2014 use `google_workspace:` instead. Per-agent " + "google_workspace overrides (currently approvers + tier). When set, " + "replaces the top-level approvers list for this agent. " + "google_client_id/secret are not per-agent \u2014 they live at the top level."),
|
|
23942
23959
|
google_workspace: AgentGoogleWorkspaceConfigSchema.describe("RFC G canonical key. Per-agent Google Workspace overrides \u2014 currently " + "approvers (replaces, does not extend the top-level list) and tier " + "(`core` | `extended` | `complete`, replaces top-level default). " + "google_client_id/secret are not per-agent \u2014 they live at the top level. " + "Mutually exclusive with `drive:` on the same agent (loader fails fast " + "if both are set)."),
|
|
23943
23960
|
microsoft_workspace: AgentMicrosoftWorkspaceConfigSchema.describe("RFC #1873 (Microsoft 365 integration). Per-agent Microsoft Workspace " + "override \u2014 pins the Microsoft account this agent reads via the " + "auth-broker (must be a key in top-level `microsoft_accounts:` with " + "this agent in its `enabled_for[]`) and optionally overrides org_mode. " + "microsoft_client_id/secret are not per-agent."),
|
|
23961
|
+
notion_workspace: AgentNotionWorkspaceConfigSchema.describe("RFC docs/rfcs/notion-integration.md. Per-agent Notion access. " + "Presence opts the agent IN (launcher scaffolded, MCP entry emitted, " + "broker grants the integration token). Optional `databases:` filter " + "narrows which DBs this agent may read/write \u2014 names must resolve in " + "top-level notion_workspace.databases. Absence opts the agent OUT."),
|
|
23944
23962
|
repos: exports_external.record(exports_external.string().regex(/^[a-z0-9][a-z0-9-]*$/, "Repo slug must be kebab-case ASCII: start with a lowercase letter or digit, contain only lowercase letters, digits, and hyphens"), exports_external.object({
|
|
23945
23963
|
url: exports_external.string().min(1).describe("Git remote URL for the repo (e.g. 'git@github.com:org/repo.git' or " + "'https://github.com/org/repo.git'). Used verbatim for git clone."),
|
|
23946
23964
|
branch_default: exports_external.string().optional().describe("Default branch to track (defaults to the remote's HEAD, typically 'main'). " + "The per-agent branch 'agent/<agentName>/main' fast-forwards to this branch " + "when the worktree is clean on session start.")
|
|
@@ -24064,6 +24082,7 @@ var init_schema = __esm(() => {
|
|
|
24064
24082
|
drive: GoogleWorkspaceConfigSchema.describe("RFC D legacy key \u2014 use `google_workspace:` instead. Optional Google " + "Workspace onboarding configuration. When set, supplies Google OAuth " + "client credentials, the approver allowlist for `switchroom drive " + "connect`, and the optional tier knob. Env vars " + "(SWITCHROOM_GOOGLE_CLIENT_ID, SWITCHROOM_GOOGLE_CLIENT_SECRET, " + "SWITCHROOM_APPROVER_USER_ID) take precedence over this block when " + "set, preserving back-compat with the env-only flow shipped in #766."),
|
|
24065
24083
|
google_workspace: GoogleWorkspaceConfigSchema.describe("RFC G canonical key. Top-level Google Workspace configuration \u2014 " + "OAuth client credentials, approver allowlist, and tier knob (`core` " + "| `extended` | `complete`, default `core`). Mutually exclusive with " + "`drive:` at the top level (loader fails fast if both are set)."),
|
|
24066
24084
|
microsoft_workspace: MicrosoftWorkspaceConfigSchema.describe("RFC #1873 (Microsoft 365 integration). Top-level Microsoft Workspace " + "configuration \u2014 OAuth client credentials (Entra app), authority " + "endpoint (defaults to /common for personal MSA + work), and the " + "org_mode opt-in for Teams/SharePoint surfaces. Block is optional; " + "when omitted the broker does not register the Microsoft provider."),
|
|
24085
|
+
notion_workspace: NotionWorkspaceConfigSchema.describe("RFC docs/rfcs/notion-integration.md. Top-level Notion integration " + "config \u2014 vault key for the integration token, friendly-name \u2192 " + "database UUID map, optional MCP-package version pin, and optional " + "global rate-limit override (default 3 rps, Notion's documented " + "public-API limit). Block is optional; when omitted no agent gets a " + "Notion MCP entry regardless of per-agent config."),
|
|
24067
24086
|
quota: QuotaConfigSchema.optional().describe("Optional weekly/monthly USD spend budgets rendered in the session " + "greeting. Usage is read from ccusage at runtime; no network calls."),
|
|
24068
24087
|
host_control: HostControlConfigSchema.default({}).describe("Host-control daemon configuration. Defaults to enabled=true since " + "RFC C Phase 2 (docs/rfcs/host-control-daemon.md). Omit the block " + "to accept defaults; set `enabled: false` only on legacy systemd-" + "mode installs (removal tracked as RFC C Phase 3)."),
|
|
24069
24088
|
hostd: HostdConfigSchema.default({}).describe("hostd verb-level knobs (RFC admin-agent-config-edit). Distinct " + "from `host_control:` which governs whether the daemon runs at " + "all. Currently scopes the opt-in flag and rate cap for the new " + "`config_propose_edit` verb (PR 1a \u2014 disabled by default)."),
|
|
@@ -24090,7 +24109,7 @@ var init_schema = __esm(() => {
|
|
|
24090
24109
|
});
|
|
24091
24110
|
|
|
24092
24111
|
// ../src/config/paths.ts
|
|
24093
|
-
import { existsSync as
|
|
24112
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
24094
24113
|
import { resolve as resolve2 } from "node:path";
|
|
24095
24114
|
function home() {
|
|
24096
24115
|
return process.env.HOME ?? "/root";
|
|
@@ -24109,9 +24128,9 @@ function resolveDualPath(pathStr) {
|
|
|
24109
24128
|
const absolute = resolve2(h, rest);
|
|
24110
24129
|
if (rest.startsWith(`${DEFAULT_STATE_DIR}/`)) {
|
|
24111
24130
|
const frag = rest.slice(DEFAULT_STATE_DIR.length + 1);
|
|
24112
|
-
if (!
|
|
24131
|
+
if (!existsSync8(absolute)) {
|
|
24113
24132
|
const legacy = resolve2(h, LEGACY_STATE_DIR, frag);
|
|
24114
|
-
if (
|
|
24133
|
+
if (existsSync8(legacy)) {
|
|
24115
24134
|
warnLegacyStateOnce(legacy);
|
|
24116
24135
|
return legacy;
|
|
24117
24136
|
}
|
|
@@ -24136,14 +24155,14 @@ var init_overlay_schema = __esm(() => {
|
|
|
24136
24155
|
});
|
|
24137
24156
|
|
|
24138
24157
|
// ../src/config/overlay-loader.ts
|
|
24139
|
-
import { existsSync as
|
|
24158
|
+
import { existsSync as existsSync9, readFileSync as readFileSync4, readdirSync, statSync as statSync2 } from "node:fs";
|
|
24140
24159
|
import { resolve as resolve3 } from "node:path";
|
|
24141
24160
|
function overlayDirFor(agentName3, subdir) {
|
|
24142
24161
|
const base = resolveDualPath(`~/.switchroom/agents/${agentName3}/${subdir}`);
|
|
24143
24162
|
return resolve3(base);
|
|
24144
24163
|
}
|
|
24145
24164
|
function listYamlFiles(dir) {
|
|
24146
|
-
if (!
|
|
24165
|
+
if (!existsSync9(dir))
|
|
24147
24166
|
return [];
|
|
24148
24167
|
let entries;
|
|
24149
24168
|
try {
|
|
@@ -24571,8 +24590,36 @@ var init_merge = __esm(() => {
|
|
|
24571
24590
|
})(mergeAgentConfig ||= {});
|
|
24572
24591
|
});
|
|
24573
24592
|
|
|
24593
|
+
// ../src/config/notion-workspace-acl.ts
|
|
24594
|
+
function validateNotionWorkspaceConfig(config) {
|
|
24595
|
+
const issues = [];
|
|
24596
|
+
const dbMap = config.notion_workspace?.databases ?? {};
|
|
24597
|
+
const known = new Set(Object.keys(dbMap));
|
|
24598
|
+
for (const [agentName3, agentRaw] of Object.entries(config.agents ?? {})) {
|
|
24599
|
+
if (!agentRaw)
|
|
24600
|
+
continue;
|
|
24601
|
+
const dbFilter = agentRaw.notion_workspace?.databases;
|
|
24602
|
+
if (dbFilter === undefined)
|
|
24603
|
+
continue;
|
|
24604
|
+
if (dbFilter.length === 0) {
|
|
24605
|
+
issues.push(` agents.${agentName3}.notion_workspace.databases is an empty ` + `list. Delete the entire notion_workspace block to remove Notion ` + `access, or list at least one database friendly name.`);
|
|
24606
|
+
continue;
|
|
24607
|
+
}
|
|
24608
|
+
if (config.notion_workspace === undefined) {
|
|
24609
|
+
issues.push(` agents.${agentName3}.notion_workspace is set but the top-level ` + `notion_workspace block is missing. Configure the integration ` + `globally first (vault_key + databases map), then grant per-agent ` + `access.`);
|
|
24610
|
+
continue;
|
|
24611
|
+
}
|
|
24612
|
+
for (const name of dbFilter) {
|
|
24613
|
+
if (!known.has(name)) {
|
|
24614
|
+
issues.push(` agents.${agentName3}.notion_workspace.databases references ` + `unknown database "${name}". Add it to top-level ` + `notion_workspace.databases (run \`switchroom notion list-dbs\` ` + `to see the UUIDs the integration can read), or remove the ` + `reference.`);
|
|
24615
|
+
}
|
|
24616
|
+
}
|
|
24617
|
+
}
|
|
24618
|
+
return issues;
|
|
24619
|
+
}
|
|
24620
|
+
|
|
24574
24621
|
// ../src/config/loader.ts
|
|
24575
|
-
import { readFileSync as readFileSync5, existsSync as
|
|
24622
|
+
import { readFileSync as readFileSync5, existsSync as existsSync10 } from "node:fs";
|
|
24576
24623
|
import { homedir as homedir5 } from "node:os";
|
|
24577
24624
|
import { resolve as resolve4 } from "node:path";
|
|
24578
24625
|
function formatZodErrors(error) {
|
|
@@ -24639,7 +24686,7 @@ function findConfigFile(startDir) {
|
|
|
24639
24686
|
resolve4(userDir, "clerk.yml")
|
|
24640
24687
|
].filter(Boolean);
|
|
24641
24688
|
for (const path of searchPaths) {
|
|
24642
|
-
if (
|
|
24689
|
+
if (existsSync10(path)) {
|
|
24643
24690
|
return path;
|
|
24644
24691
|
}
|
|
24645
24692
|
}
|
|
@@ -24647,7 +24694,7 @@ function findConfigFile(startDir) {
|
|
|
24647
24694
|
}
|
|
24648
24695
|
function loadConfig(configPath) {
|
|
24649
24696
|
const filePath = configPath ?? findConfigFile();
|
|
24650
|
-
if (!
|
|
24697
|
+
if (!existsSync10(filePath)) {
|
|
24651
24698
|
throw new ConfigError(`Config file not found: ${filePath}`);
|
|
24652
24699
|
}
|
|
24653
24700
|
let raw;
|
|
@@ -24685,6 +24732,10 @@ function loadConfig(configPath) {
|
|
|
24685
24732
|
}
|
|
24686
24733
|
applyAgentOverlays(config);
|
|
24687
24734
|
validateAllCronTopicAliases(config, filePath);
|
|
24735
|
+
const notionIssues = validateNotionWorkspaceConfig(config);
|
|
24736
|
+
if (notionIssues.length > 0) {
|
|
24737
|
+
throw new ConfigError(`Invalid notion_workspace configuration in ${filePath}`, notionIssues);
|
|
24738
|
+
}
|
|
24688
24739
|
return config;
|
|
24689
24740
|
}
|
|
24690
24741
|
function validateAllCronTopicAliases(config, filePath) {
|
|
@@ -24751,7 +24802,7 @@ __export(exports_history, {
|
|
|
24751
24802
|
_resetForTests: () => _resetForTests
|
|
24752
24803
|
});
|
|
24753
24804
|
import { chmodSync as chmodSync2, mkdirSync as mkdirSync9 } from "fs";
|
|
24754
|
-
import { join as
|
|
24805
|
+
import { join as join12 } from "path";
|
|
24755
24806
|
function loadDatabaseClass() {
|
|
24756
24807
|
if (DatabaseClass != null)
|
|
24757
24808
|
return DatabaseClass;
|
|
@@ -24774,7 +24825,7 @@ function initHistory(stateDir, retentionDays = 30) {
|
|
|
24774
24825
|
return;
|
|
24775
24826
|
const Database = loadDatabaseClass();
|
|
24776
24827
|
mkdirSync9(stateDir, { recursive: true, mode: 448 });
|
|
24777
|
-
const path =
|
|
24828
|
+
const path = join12(stateDir, "history.db");
|
|
24778
24829
|
db = new Database(path, { create: true });
|
|
24779
24830
|
db.exec("PRAGMA journal_mode = WAL");
|
|
24780
24831
|
db.exec("PRAGMA synchronous = NORMAL");
|
|
@@ -24964,11 +25015,11 @@ var DatabaseClass = null, DEFAULT_LIMIT = 10, MAX_LIMIT = 50, db = null;
|
|
|
24964
25015
|
var init_history = () => {};
|
|
24965
25016
|
|
|
24966
25017
|
// quota-check.ts
|
|
24967
|
-
import { readFileSync as readFileSync8, existsSync as
|
|
24968
|
-
import { join as
|
|
25018
|
+
import { readFileSync as readFileSync8, existsSync as existsSync13 } from "fs";
|
|
25019
|
+
import { join as join13 } from "path";
|
|
24969
25020
|
function readOauthToken(claudeConfigDir) {
|
|
24970
|
-
const tokenFile =
|
|
24971
|
-
if (!
|
|
25021
|
+
const tokenFile = join13(claudeConfigDir, ".oauth-token");
|
|
25022
|
+
if (!existsSync13(tokenFile))
|
|
24972
25023
|
return null;
|
|
24973
25024
|
try {
|
|
24974
25025
|
const raw = readFileSync8(tokenFile, "utf-8").trim();
|
|
@@ -25450,7 +25501,7 @@ function isDockerRuntime() {
|
|
|
25450
25501
|
import * as net3 from "node:net";
|
|
25451
25502
|
import * as fs from "node:fs";
|
|
25452
25503
|
import { homedir as homedir7 } from "node:os";
|
|
25453
|
-
import { join as
|
|
25504
|
+
import { join as join17 } from "node:path";
|
|
25454
25505
|
function defaultBrokerSocketPath() {
|
|
25455
25506
|
if (fs.existsSync(OPERATOR_SOCKET_PATH))
|
|
25456
25507
|
return OPERATOR_SOCKET_PATH;
|
|
@@ -25459,7 +25510,7 @@ function defaultBrokerSocketPath() {
|
|
|
25459
25510
|
return LEGACY_SOCKET_PATH;
|
|
25460
25511
|
}
|
|
25461
25512
|
function vaultTokenFilePath(agentSlug) {
|
|
25462
|
-
return
|
|
25513
|
+
return join17(homedir7(), ".switchroom", "agents", agentSlug, ".vault-token");
|
|
25463
25514
|
}
|
|
25464
25515
|
function readVaultTokenFile(agentSlug) {
|
|
25465
25516
|
const filePath = vaultTokenFilePath(agentSlug);
|
|
@@ -25614,8 +25665,8 @@ var DEFAULT_TIMEOUT_MS3 = 2000, LEGACY_SOCKET_PATH, OPERATOR_SOCKET_PATH;
|
|
|
25614
25665
|
var init_client2 = __esm(() => {
|
|
25615
25666
|
init_protocol2();
|
|
25616
25667
|
init_peercred();
|
|
25617
|
-
LEGACY_SOCKET_PATH =
|
|
25618
|
-
OPERATOR_SOCKET_PATH =
|
|
25668
|
+
LEGACY_SOCKET_PATH = join17(homedir7(), ".switchroom", "vault-broker.sock");
|
|
25669
|
+
OPERATOR_SOCKET_PATH = join17(homedir7(), ".switchroom", "broker-operator", "sock");
|
|
25619
25670
|
});
|
|
25620
25671
|
|
|
25621
25672
|
// ../src/drive/deep-links.ts
|
|
@@ -27804,15 +27855,15 @@ function renderAuthLine(state4, agentName3, now = Date.now()) {
|
|
|
27804
27855
|
}
|
|
27805
27856
|
|
|
27806
27857
|
// gateway/quota-cache.ts
|
|
27807
|
-
import { existsSync as
|
|
27808
|
-
import { join as
|
|
27858
|
+
import { existsSync as existsSync24, readFileSync as readFileSync22, writeFileSync as writeFileSync13, mkdirSync as mkdirSync11 } from "fs";
|
|
27859
|
+
import { join as join21, dirname as dirname8 } from "path";
|
|
27809
27860
|
function defaultCachePath() {
|
|
27810
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
27861
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join21(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
27811
27862
|
}
|
|
27812
27863
|
function readQuotaCache(opts = {}) {
|
|
27813
27864
|
const path = opts.path ?? defaultCachePath();
|
|
27814
27865
|
const now = opts.now ?? Date.now();
|
|
27815
|
-
if (!
|
|
27866
|
+
if (!existsSync24(path))
|
|
27816
27867
|
return null;
|
|
27817
27868
|
let entry;
|
|
27818
27869
|
try {
|
|
@@ -27853,8 +27904,8 @@ var init_quota_cache = __esm(() => {
|
|
|
27853
27904
|
});
|
|
27854
27905
|
|
|
27855
27906
|
// gateway/boot-probes.ts
|
|
27856
|
-
import { readFileSync as readFileSync23, readdirSync as readdirSync4, existsSync as
|
|
27857
|
-
import { join as
|
|
27907
|
+
import { readFileSync as readFileSync23, readdirSync as readdirSync4, existsSync as existsSync25 } from "fs";
|
|
27908
|
+
import { join as join22 } from "path";
|
|
27858
27909
|
import { execFile as execFileCb } from "child_process";
|
|
27859
27910
|
import { promisify as promisify3 } from "util";
|
|
27860
27911
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -27896,8 +27947,8 @@ function mapPlan(billingType, hasExtra) {
|
|
|
27896
27947
|
}
|
|
27897
27948
|
async function probeAccount(agentDir) {
|
|
27898
27949
|
return withTimeout("Account", (async () => {
|
|
27899
|
-
const claudeDir =
|
|
27900
|
-
const claudeJsonPath =
|
|
27950
|
+
const claudeDir = join22(agentDir, ".claude");
|
|
27951
|
+
const claudeJsonPath = join22(claudeDir, ".claude.json");
|
|
27901
27952
|
let cfg = {};
|
|
27902
27953
|
try {
|
|
27903
27954
|
const raw = readFileSync23(claudeJsonPath, "utf8");
|
|
@@ -27918,10 +27969,10 @@ async function probeAccount(agentDir) {
|
|
|
27918
27969
|
let tokenStr = "";
|
|
27919
27970
|
let status = "ok";
|
|
27920
27971
|
for (const candidate of [
|
|
27921
|
-
|
|
27922
|
-
|
|
27972
|
+
join22(claudeDir, ".oauth-token.meta.json"),
|
|
27973
|
+
join22(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
27923
27974
|
]) {
|
|
27924
|
-
if (
|
|
27975
|
+
if (existsSync25(candidate)) {
|
|
27925
27976
|
try {
|
|
27926
27977
|
const meta = JSON.parse(readFileSync23(candidate, "utf8"));
|
|
27927
27978
|
if (meta.expiresAt) {
|
|
@@ -28098,7 +28149,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
28098
28149
|
if (!cgroup)
|
|
28099
28150
|
return null;
|
|
28100
28151
|
const procsPath = `/sys/fs/cgroup${cgroup}/cgroup.procs`;
|
|
28101
|
-
if (!
|
|
28152
|
+
if (!existsSync25(procsPath))
|
|
28102
28153
|
return null;
|
|
28103
28154
|
const pidsRaw = readFileSync23(procsPath, "utf-8");
|
|
28104
28155
|
const pids = pidsRaw.split(`
|
|
@@ -28305,9 +28356,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
28305
28356
|
let claudeDirForProbe = null;
|
|
28306
28357
|
for (const candidate of [
|
|
28307
28358
|
claudeConfigDir,
|
|
28308
|
-
|
|
28359
|
+
join22(claudeConfigDir, "accounts", "default")
|
|
28309
28360
|
]) {
|
|
28310
|
-
if (
|
|
28361
|
+
if (existsSync25(join22(candidate, ".oauth-token"))) {
|
|
28311
28362
|
claudeDirForProbe = candidate;
|
|
28312
28363
|
break;
|
|
28313
28364
|
}
|
|
@@ -28478,7 +28529,7 @@ async function probeUds(label, socketPath, opts = {}) {
|
|
|
28478
28529
|
}
|
|
28479
28530
|
return withTimeout(label, (async () => {
|
|
28480
28531
|
if (!opts.connectImpl) {
|
|
28481
|
-
if (!
|
|
28532
|
+
if (!existsSync25(socketPath)) {
|
|
28482
28533
|
return {
|
|
28483
28534
|
status: "fail",
|
|
28484
28535
|
label,
|
|
@@ -28542,7 +28593,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
28542
28593
|
return withTimeout("Skills", (async () => {
|
|
28543
28594
|
const fs2 = opts.fs ?? realSkillsFs;
|
|
28544
28595
|
const max = opts.maxNamesShown ?? 3;
|
|
28545
|
-
const skillsDir =
|
|
28596
|
+
const skillsDir = join22(agentDir, ".claude", "skills");
|
|
28546
28597
|
if (!fs2.exists(skillsDir)) {
|
|
28547
28598
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
28548
28599
|
}
|
|
@@ -28557,17 +28608,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
28557
28608
|
}
|
|
28558
28609
|
const dangling = [];
|
|
28559
28610
|
for (const name of entries) {
|
|
28560
|
-
const skillPath =
|
|
28611
|
+
const skillPath = join22(skillsDir, name);
|
|
28561
28612
|
if (!fs2.exists(skillPath)) {
|
|
28562
28613
|
dangling.push(name);
|
|
28563
28614
|
continue;
|
|
28564
28615
|
}
|
|
28565
|
-
const skillMd =
|
|
28616
|
+
const skillMd = join22(skillPath, "SKILL.md");
|
|
28566
28617
|
if (!fs2.exists(skillMd) && !fs2.exists(skillPath + ".md")) {
|
|
28567
28618
|
continue;
|
|
28568
28619
|
}
|
|
28569
28620
|
}
|
|
28570
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
28621
|
+
const overlayDir = opts.overlaySkillsDir ?? join22(agentDir, "skills.d");
|
|
28571
28622
|
const overlaySlugs = new Set;
|
|
28572
28623
|
if (fs2.exists(overlayDir)) {
|
|
28573
28624
|
let overlayEntries = [];
|
|
@@ -28622,16 +28673,16 @@ var init_boot_probes = __esm(() => {
|
|
|
28622
28673
|
const { statSync: statSync7 } = __require("fs");
|
|
28623
28674
|
return statSync7(p).mtimeMs;
|
|
28624
28675
|
},
|
|
28625
|
-
exists: (p) =>
|
|
28676
|
+
exists: (p) => existsSync25(p)
|
|
28626
28677
|
};
|
|
28627
28678
|
realSkillsFs = {
|
|
28628
28679
|
readdir: (p) => readdirSync4(p),
|
|
28629
|
-
exists: (p) =>
|
|
28680
|
+
exists: (p) => existsSync25(p)
|
|
28630
28681
|
};
|
|
28631
28682
|
});
|
|
28632
28683
|
|
|
28633
28684
|
// gateway/boot-issue-cache.ts
|
|
28634
|
-
import { existsSync as
|
|
28685
|
+
import { existsSync as existsSync26, readFileSync as readFileSync24, writeFileSync as writeFileSync14, mkdirSync as mkdirSync12, renameSync as renameSync9 } from "fs";
|
|
28635
28686
|
import { dirname as dirname9 } from "path";
|
|
28636
28687
|
function fingerprintProbe(key, r) {
|
|
28637
28688
|
if (r.status === "ok")
|
|
@@ -28711,7 +28762,7 @@ function diffProbes(probes, cache, opts = {}) {
|
|
|
28711
28762
|
return out;
|
|
28712
28763
|
}
|
|
28713
28764
|
function loadCache(path, now = Date.now) {
|
|
28714
|
-
if (!
|
|
28765
|
+
if (!existsSync26(path))
|
|
28715
28766
|
return { ...EMPTY_CACHE, probes: {} };
|
|
28716
28767
|
let raw;
|
|
28717
28768
|
try {
|
|
@@ -28782,7 +28833,7 @@ __export(exports_boot_card, {
|
|
|
28782
28833
|
renderBootCard: () => renderBootCard,
|
|
28783
28834
|
renderAccountRows: () => renderAuthLine
|
|
28784
28835
|
});
|
|
28785
|
-
import { join as
|
|
28836
|
+
import { join as join23 } from "path";
|
|
28786
28837
|
function resolvePersonaName(slug, loadConfig3) {
|
|
28787
28838
|
try {
|
|
28788
28839
|
const config = loadConfig3 ? loadConfig3() : loadConfig();
|
|
@@ -28863,7 +28914,7 @@ function renderBootCard(opts) {
|
|
|
28863
28914
|
`);
|
|
28864
28915
|
}
|
|
28865
28916
|
async function runAllProbes(opts) {
|
|
28866
|
-
const claudeDir =
|
|
28917
|
+
const claudeDir = join23(opts.agentDir, ".claude");
|
|
28867
28918
|
const probes = {};
|
|
28868
28919
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
28869
28920
|
await Promise.allSettled([
|
|
@@ -29107,10 +29158,10 @@ import { randomBytes as randomBytes5, scryptSync, createCipheriv, createDecipher
|
|
|
29107
29158
|
import {
|
|
29108
29159
|
readFileSync as readFileSync31,
|
|
29109
29160
|
writeFileSync as writeFileSync19,
|
|
29110
|
-
existsSync as
|
|
29161
|
+
existsSync as existsSync33,
|
|
29111
29162
|
renameSync as renameSync11,
|
|
29112
29163
|
mkdirSync as mkdirSync18,
|
|
29113
|
-
unlinkSync as
|
|
29164
|
+
unlinkSync as unlinkSync13,
|
|
29114
29165
|
lstatSync,
|
|
29115
29166
|
realpathSync
|
|
29116
29167
|
} from "node:fs";
|
|
@@ -29145,7 +29196,7 @@ function normalizeSecrets(raw) {
|
|
|
29145
29196
|
return out;
|
|
29146
29197
|
}
|
|
29147
29198
|
function openVault(passphrase, vaultPath) {
|
|
29148
|
-
if (!
|
|
29199
|
+
if (!existsSync33(vaultPath)) {
|
|
29149
29200
|
throw new VaultError(`Vault file not found: ${vaultPath}`);
|
|
29150
29201
|
}
|
|
29151
29202
|
let vaultFile;
|
|
@@ -29196,15 +29247,15 @@ var init_vault = __esm(() => {
|
|
|
29196
29247
|
// ../src/vault/resolver.ts
|
|
29197
29248
|
import {
|
|
29198
29249
|
chmodSync as chmodSync4,
|
|
29199
|
-
closeSync as
|
|
29250
|
+
closeSync as closeSync8,
|
|
29200
29251
|
mkdirSync as mkdirSync19,
|
|
29201
29252
|
mkdtempSync as mkdtempSync2,
|
|
29202
|
-
openSync as
|
|
29253
|
+
openSync as openSync8,
|
|
29203
29254
|
rmSync as rmSync3,
|
|
29204
29255
|
statSync as statSync11,
|
|
29205
29256
|
writeSync as writeSync2
|
|
29206
29257
|
} from "node:fs";
|
|
29207
|
-
import { join as
|
|
29258
|
+
import { join as join32 } from "node:path";
|
|
29208
29259
|
import { tmpdir } from "node:os";
|
|
29209
29260
|
import { constants as fsConstants } from "node:fs";
|
|
29210
29261
|
function isVaultReference(value) {
|
|
@@ -29256,26 +29307,26 @@ function materializationRoot() {
|
|
|
29256
29307
|
return cachedRoot;
|
|
29257
29308
|
const xdg = process.env.XDG_RUNTIME_DIR;
|
|
29258
29309
|
if (xdg) {
|
|
29259
|
-
const base =
|
|
29310
|
+
const base = join32(xdg, "switchroom", "vault");
|
|
29260
29311
|
mkdirSync19(base, { recursive: true, mode: 448 });
|
|
29261
|
-
cachedRoot = mkdtempSync2(
|
|
29312
|
+
cachedRoot = mkdtempSync2(join32(base, "run-"));
|
|
29262
29313
|
} else {
|
|
29263
|
-
cachedRoot = mkdtempSync2(
|
|
29314
|
+
cachedRoot = mkdtempSync2(join32(tmpdir(), "switchroom-vault-"));
|
|
29264
29315
|
}
|
|
29265
29316
|
chmodSync4(cachedRoot, 448);
|
|
29266
29317
|
return cachedRoot;
|
|
29267
29318
|
}
|
|
29268
29319
|
function writeFileExclusive(filePath, content) {
|
|
29269
29320
|
const buf = typeof content === "string" ? Buffer.from(content, "utf8") : content;
|
|
29270
|
-
const fd =
|
|
29321
|
+
const fd = openSync8(filePath, fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL, 384);
|
|
29271
29322
|
try {
|
|
29272
29323
|
writeSync2(fd, buf);
|
|
29273
29324
|
} finally {
|
|
29274
|
-
|
|
29325
|
+
closeSync8(fd);
|
|
29275
29326
|
}
|
|
29276
29327
|
}
|
|
29277
29328
|
function materializeFilesEntry(key, files) {
|
|
29278
|
-
const dir =
|
|
29329
|
+
const dir = join32(materializationRoot(), key);
|
|
29279
29330
|
if (materializedDirs.has(dir)) {
|
|
29280
29331
|
try {
|
|
29281
29332
|
rmSync3(dir, { recursive: true, force: true });
|
|
@@ -29291,7 +29342,7 @@ function materializeFilesEntry(key, files) {
|
|
|
29291
29342
|
if (filename.includes("/") || filename.includes("\\") || filename === ".." || filename === "." || filename.includes("\x00")) {
|
|
29292
29343
|
throw new Error(`Refusing to materialize vault file with unsafe name: ${filename}`);
|
|
29293
29344
|
}
|
|
29294
|
-
const filePath =
|
|
29345
|
+
const filePath = join32(dir, filename);
|
|
29295
29346
|
const content = encoding === "base64" ? Buffer.from(value, "base64") : value;
|
|
29296
29347
|
writeFileExclusive(filePath, content);
|
|
29297
29348
|
}
|
|
@@ -29424,7 +29475,7 @@ __export(exports_materialize_bot_token, {
|
|
|
29424
29475
|
materializeBotToken: () => materializeBotToken,
|
|
29425
29476
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
29426
29477
|
});
|
|
29427
|
-
import { existsSync as
|
|
29478
|
+
import { existsSync as existsSync34 } from "node:fs";
|
|
29428
29479
|
function pickConfiguredToken(config, agentName3) {
|
|
29429
29480
|
if (agentName3) {
|
|
29430
29481
|
const agent = config.agents?.[agentName3];
|
|
@@ -29438,7 +29489,7 @@ function tryDirectVaultRead(ref, config, passphrase) {
|
|
|
29438
29489
|
if (!passphrase)
|
|
29439
29490
|
return null;
|
|
29440
29491
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
29441
|
-
if (!
|
|
29492
|
+
if (!existsSync34(vaultPath))
|
|
29442
29493
|
return null;
|
|
29443
29494
|
try {
|
|
29444
29495
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -29743,7 +29794,7 @@ __export(exports_tmux, {
|
|
|
29743
29794
|
captureAgentPane: () => captureAgentPane
|
|
29744
29795
|
});
|
|
29745
29796
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
29746
|
-
import { mkdirSync as mkdirSync20, readdirSync as readdirSync6, statSync as statSync12, unlinkSync as
|
|
29797
|
+
import { mkdirSync as mkdirSync20, readdirSync as readdirSync6, statSync as statSync12, unlinkSync as unlinkSync14, writeFileSync as writeFileSync20 } from "node:fs";
|
|
29747
29798
|
import { resolve as resolve7 } from "node:path";
|
|
29748
29799
|
function captureAgentPane(opts) {
|
|
29749
29800
|
const { agentName: agentName3, agentDir, reason } = opts;
|
|
@@ -29857,7 +29908,7 @@ function pruneOldReports(dir, retain) {
|
|
|
29857
29908
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
29858
29909
|
for (const stale of files.slice(retain)) {
|
|
29859
29910
|
try {
|
|
29860
|
-
|
|
29911
|
+
unlinkSync14(stale.full);
|
|
29861
29912
|
} catch {}
|
|
29862
29913
|
}
|
|
29863
29914
|
}
|
|
@@ -30453,14 +30504,14 @@ import {
|
|
|
30453
30504
|
renameSync as renameSync12,
|
|
30454
30505
|
realpathSync as realpathSync2,
|
|
30455
30506
|
chmodSync as chmodSync5,
|
|
30456
|
-
openSync as
|
|
30457
|
-
closeSync as
|
|
30458
|
-
existsSync as
|
|
30459
|
-
unlinkSync as
|
|
30507
|
+
openSync as openSync9,
|
|
30508
|
+
closeSync as closeSync9,
|
|
30509
|
+
existsSync as existsSync35,
|
|
30510
|
+
unlinkSync as unlinkSync15,
|
|
30460
30511
|
appendFileSync as appendFileSync3
|
|
30461
30512
|
} from "fs";
|
|
30462
30513
|
import { homedir as homedir12 } from "os";
|
|
30463
|
-
import { join as
|
|
30514
|
+
import { join as join33, extname, sep as sep3, basename as basename7 } from "path";
|
|
30464
30515
|
|
|
30465
30516
|
// plugin-logger.ts
|
|
30466
30517
|
import { appendFileSync, mkdirSync, renameSync, statSync, existsSync } from "fs";
|
|
@@ -37702,6 +37753,7 @@ function classifyInbound(text) {
|
|
|
37702
37753
|
// silence-poke.ts
|
|
37703
37754
|
var DEFAULT_THRESHOLDS = {
|
|
37704
37755
|
ack: 1e4,
|
|
37756
|
+
awarenessPing: 60000,
|
|
37705
37757
|
soft: 75000,
|
|
37706
37758
|
firm: 180000,
|
|
37707
37759
|
fallback: 300000,
|
|
@@ -37728,6 +37780,7 @@ function startTurn(key, now) {
|
|
|
37728
37780
|
lastThinkingAt: null,
|
|
37729
37781
|
fallbackFired: false,
|
|
37730
37782
|
ackPokeFired: false,
|
|
37783
|
+
awarenessPingFired: false,
|
|
37731
37784
|
lastPokeFiredAt: null,
|
|
37732
37785
|
inFlightTools: new Map
|
|
37733
37786
|
});
|
|
@@ -37845,6 +37898,42 @@ function tick(now) {
|
|
|
37845
37898
|
});
|
|
37846
37899
|
continue;
|
|
37847
37900
|
}
|
|
37901
|
+
if (!s.awarenessPingFired && s.lastOutboundAt == null && !s.subagentDispatchActive && silence >= thresholds.awarenessPing) {
|
|
37902
|
+
s.awarenessPingFired = true;
|
|
37903
|
+
const { chatId, threadId } = parseKey(key);
|
|
37904
|
+
const recentThinking = s.lastThinkingAt != null && now - s.lastThinkingAt < 30000;
|
|
37905
|
+
const fallbackKind = recentThinking ? "thinking" : "working";
|
|
37906
|
+
const inFlightTools = Array.from(s.inFlightTools.values()).sort((a, b) => a.startedAt - b.startedAt).map((t) => ({
|
|
37907
|
+
name: t.name,
|
|
37908
|
+
label: t.label,
|
|
37909
|
+
durationMs: now - t.startedAt
|
|
37910
|
+
}));
|
|
37911
|
+
activeDeps.emitMetric({
|
|
37912
|
+
kind: "awareness_ping_sent",
|
|
37913
|
+
key,
|
|
37914
|
+
fallback_kind: fallbackKind,
|
|
37915
|
+
silence_ms: silence
|
|
37916
|
+
});
|
|
37917
|
+
try {
|
|
37918
|
+
const ret = activeDeps.onAwarenessPing({
|
|
37919
|
+
key,
|
|
37920
|
+
chatId,
|
|
37921
|
+
threadId,
|
|
37922
|
+
fallbackKind,
|
|
37923
|
+
silenceMs: silence,
|
|
37924
|
+
inFlightTools
|
|
37925
|
+
});
|
|
37926
|
+
if (ret != null && typeof ret.then === "function") {
|
|
37927
|
+
ret.catch((err) => {
|
|
37928
|
+
process.stderr.write(`silence-poke: awareness-ping handler rejected: ${err}
|
|
37929
|
+
`);
|
|
37930
|
+
});
|
|
37931
|
+
}
|
|
37932
|
+
} catch (err) {
|
|
37933
|
+
process.stderr.write(`silence-poke: awareness-ping handler threw: ${err}
|
|
37934
|
+
`);
|
|
37935
|
+
}
|
|
37936
|
+
}
|
|
37848
37937
|
if (s.pokesFired === 0 && silence >= softThreshold) {
|
|
37849
37938
|
s.pokeArmed = { level: "soft" };
|
|
37850
37939
|
s.pokesFired = 1;
|
|
@@ -38167,6 +38256,45 @@ function recordSilentTurnEnd(args, deps) {
|
|
|
38167
38256
|
}
|
|
38168
38257
|
var recordUndeliveredTurnEnd = recordSilentTurnEnd;
|
|
38169
38258
|
|
|
38259
|
+
// ack-flag.ts
|
|
38260
|
+
import { closeSync, existsSync as existsSync6, openSync, unlinkSync as unlinkSync2 } from "node:fs";
|
|
38261
|
+
import { join as join7 } from "node:path";
|
|
38262
|
+
var ACK_SENT_MARKER = "ack-sent.flag";
|
|
38263
|
+
function markerPath() {
|
|
38264
|
+
const dir = process.env.TELEGRAM_STATE_DIR;
|
|
38265
|
+
if (!dir)
|
|
38266
|
+
return null;
|
|
38267
|
+
return join7(dir, ACK_SENT_MARKER);
|
|
38268
|
+
}
|
|
38269
|
+
function markAckSent() {
|
|
38270
|
+
const path = markerPath();
|
|
38271
|
+
if (path == null)
|
|
38272
|
+
return;
|
|
38273
|
+
if (existsSync6(path))
|
|
38274
|
+
return;
|
|
38275
|
+
try {
|
|
38276
|
+
const fd = openSync(path, "w");
|
|
38277
|
+
closeSync(fd);
|
|
38278
|
+
} catch (err) {
|
|
38279
|
+
process.stderr.write(`ack-flag: markAckSent failed path=${path}: ${err}
|
|
38280
|
+
`);
|
|
38281
|
+
}
|
|
38282
|
+
}
|
|
38283
|
+
function clearAckSent() {
|
|
38284
|
+
const path = markerPath();
|
|
38285
|
+
if (path == null)
|
|
38286
|
+
return;
|
|
38287
|
+
try {
|
|
38288
|
+
unlinkSync2(path);
|
|
38289
|
+
} catch (err) {
|
|
38290
|
+
const code = err?.code;
|
|
38291
|
+
if (code === "ENOENT")
|
|
38292
|
+
return;
|
|
38293
|
+
process.stderr.write(`ack-flag: clearAckSent failed path=${path}: ${err}
|
|
38294
|
+
`);
|
|
38295
|
+
}
|
|
38296
|
+
}
|
|
38297
|
+
|
|
38170
38298
|
// final-answer-detect.ts
|
|
38171
38299
|
var FINAL_ANSWER_MIN_CHARS = 200;
|
|
38172
38300
|
function isFinalAnswerReply(input) {
|
|
@@ -38590,7 +38718,7 @@ async function gatewayStartupRetry(fn, opts = {}) {
|
|
|
38590
38718
|
|
|
38591
38719
|
// gateway/quarantine.ts
|
|
38592
38720
|
import { mkdirSync as mkdirSync6, writeFileSync as writeFileSync4 } from "node:fs";
|
|
38593
|
-
import { join as
|
|
38721
|
+
import { join as join8 } from "node:path";
|
|
38594
38722
|
var QUARANTINE_FILENAME = "quarantine.json";
|
|
38595
38723
|
function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.now) {
|
|
38596
38724
|
mkdirSync6(telegramStateDir, { recursive: true, mode: 448 });
|
|
@@ -38600,7 +38728,7 @@ function writeQuarantineMarker(telegramStateDir, reason, detail, nowFn = Date.no
|
|
|
38600
38728
|
ts: nowFn(),
|
|
38601
38729
|
detail
|
|
38602
38730
|
};
|
|
38603
|
-
writeFileSync4(
|
|
38731
|
+
writeFileSync4(join8(telegramStateDir, QUARANTINE_FILENAME), JSON.stringify(marker) + `
|
|
38604
38732
|
`, "utf-8");
|
|
38605
38733
|
}
|
|
38606
38734
|
|
|
@@ -39485,7 +39613,7 @@ import * as net2 from "node:net";
|
|
|
39485
39613
|
init_protocol();
|
|
39486
39614
|
import { homedir as homedir4 } from "node:os";
|
|
39487
39615
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
39488
|
-
import { join as
|
|
39616
|
+
import { join as join10 } from "node:path";
|
|
39489
39617
|
var DEFAULT_TIMEOUT_MS2 = 5000;
|
|
39490
39618
|
function reviveDate2(v) {
|
|
39491
39619
|
if (v == null)
|
|
@@ -39496,7 +39624,7 @@ function reviveDate2(v) {
|
|
|
39496
39624
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
39497
39625
|
}
|
|
39498
39626
|
function operatorSocketPath2(home = homedir4()) {
|
|
39499
|
-
return
|
|
39627
|
+
return join10(home, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
39500
39628
|
}
|
|
39501
39629
|
function resolveAuthBrokerSocketPath2(opts) {
|
|
39502
39630
|
if (opts?.socket)
|
|
@@ -39828,16 +39956,16 @@ function createFleetFallbackGate(opts) {
|
|
|
39828
39956
|
|
|
39829
39957
|
// gateway/auth-add-flow.ts
|
|
39830
39958
|
import { spawn } from "node:child_process";
|
|
39831
|
-
import { existsSync as
|
|
39959
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync7, rmSync as rmSync2 } from "node:fs";
|
|
39832
39960
|
import { homedir as homedir6 } from "node:os";
|
|
39833
|
-
import { join as
|
|
39961
|
+
import { join as join11 } from "node:path";
|
|
39834
39962
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
39835
39963
|
|
|
39836
39964
|
// ../src/auth/manager.ts
|
|
39837
39965
|
import {
|
|
39838
39966
|
readFileSync as readFileSync6,
|
|
39839
39967
|
readdirSync as readdirSync2,
|
|
39840
|
-
existsSync as
|
|
39968
|
+
existsSync as existsSync11,
|
|
39841
39969
|
writeFileSync as writeFileSync5,
|
|
39842
39970
|
mkdirSync as mkdirSync7,
|
|
39843
39971
|
mkdtempSync,
|
|
@@ -39864,7 +39992,7 @@ function parseSetupTokenUrl(output) {
|
|
|
39864
39992
|
}
|
|
39865
39993
|
function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
39866
39994
|
try {
|
|
39867
|
-
if (!
|
|
39995
|
+
if (!existsSync11(credentialsFilePath))
|
|
39868
39996
|
return null;
|
|
39869
39997
|
const raw = readFileSync6(credentialsFilePath, "utf-8");
|
|
39870
39998
|
const parsed = JSON.parse(raw);
|
|
@@ -39883,7 +40011,7 @@ function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
|
39883
40011
|
var pendingAuthAddFlows = new Map;
|
|
39884
40012
|
function pickScratchDir(label, home2 = homedir6()) {
|
|
39885
40013
|
const suffix = randomBytes2(8).toString("hex");
|
|
39886
|
-
return
|
|
40014
|
+
return join11(home2, ".switchroom", "accounts", ".in-progress", `${label}-${suffix}`);
|
|
39887
40015
|
}
|
|
39888
40016
|
function cleanScratchDir(scratchDir) {
|
|
39889
40017
|
try {
|
|
@@ -39944,7 +40072,7 @@ async function startAccountAuthSession(label, opts = {}) {
|
|
|
39944
40072
|
async function submitAccountAuthCode(flow, code, opts = {}) {
|
|
39945
40073
|
const pollIntervalMs = opts.pollIntervalMs ?? 250;
|
|
39946
40074
|
const pollTimeoutMs = opts.pollTimeoutMs ?? 120000;
|
|
39947
|
-
const credentialsPath =
|
|
40075
|
+
const credentialsPath = join11(flow.scratchDir, ".credentials.json");
|
|
39948
40076
|
if (!flow.child.stdin || flow.child.stdin.destroyed) {
|
|
39949
40077
|
cleanScratchDir(flow.scratchDir);
|
|
39950
40078
|
throw new Error("claude setup-token process stdin is not writable (child may have exited)");
|
|
@@ -39954,7 +40082,7 @@ async function submitAccountAuthCode(flow, code, opts = {}) {
|
|
|
39954
40082
|
const deadline = Date.now() + pollTimeoutMs;
|
|
39955
40083
|
while (Date.now() < deadline) {
|
|
39956
40084
|
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
39957
|
-
if (
|
|
40085
|
+
if (existsSync12(credentialsPath)) {
|
|
39958
40086
|
const token = readTokenFromCredentialsFile(credentialsPath);
|
|
39959
40087
|
if (token) {
|
|
39960
40088
|
try {
|
|
@@ -41514,8 +41642,8 @@ function isTurnFlushSafetyEnabled(env = process.env) {
|
|
|
41514
41642
|
}
|
|
41515
41643
|
|
|
41516
41644
|
// handoff-continuity.ts
|
|
41517
|
-
import { readFileSync as readFileSync9, unlinkSync as
|
|
41518
|
-
import { dirname as dirname7, join as
|
|
41645
|
+
import { readFileSync as readFileSync9, unlinkSync as unlinkSync3, existsSync as existsSync14, writeFileSync as writeFileSync6, renameSync as renameSync2 } from "node:fs";
|
|
41646
|
+
import { dirname as dirname7, join as join14 } from "node:path";
|
|
41519
41647
|
var TOPIC_DISPLAY_MAX = 117;
|
|
41520
41648
|
var HANDOFF_TOPIC_FILENAME = ".handoff-topic";
|
|
41521
41649
|
var LAST_TURN_SUMMARY_FILENAME = ".last-turn-summary";
|
|
@@ -41526,8 +41654,8 @@ function resolveAgentDirFromEnv() {
|
|
|
41526
41654
|
return dirname7(state3);
|
|
41527
41655
|
}
|
|
41528
41656
|
function readHandoffTopic(agentDir) {
|
|
41529
|
-
const p =
|
|
41530
|
-
if (!
|
|
41657
|
+
const p = join14(agentDir, HANDOFF_TOPIC_FILENAME);
|
|
41658
|
+
if (!existsSync14(p))
|
|
41531
41659
|
return null;
|
|
41532
41660
|
let raw;
|
|
41533
41661
|
try {
|
|
@@ -41545,8 +41673,8 @@ function readHandoffTopic(agentDir) {
|
|
|
41545
41673
|
return topic;
|
|
41546
41674
|
}
|
|
41547
41675
|
function readLastTurnSummary(agentDir) {
|
|
41548
|
-
const p =
|
|
41549
|
-
if (!
|
|
41676
|
+
const p = join14(agentDir, LAST_TURN_SUMMARY_FILENAME);
|
|
41677
|
+
if (!existsSync14(p))
|
|
41550
41678
|
return null;
|
|
41551
41679
|
let raw;
|
|
41552
41680
|
try {
|
|
@@ -41565,16 +41693,16 @@ function readLastTurnSummary(agentDir) {
|
|
|
41565
41693
|
}
|
|
41566
41694
|
function consumeHandoffTopic(agentDir) {
|
|
41567
41695
|
const primary = readHandoffTopic(agentDir);
|
|
41568
|
-
const primaryPath =
|
|
41569
|
-
const fallbackPath =
|
|
41696
|
+
const primaryPath = join14(agentDir, HANDOFF_TOPIC_FILENAME);
|
|
41697
|
+
const fallbackPath = join14(agentDir, LAST_TURN_SUMMARY_FILENAME);
|
|
41570
41698
|
const removeFallback = () => {
|
|
41571
41699
|
try {
|
|
41572
|
-
|
|
41700
|
+
unlinkSync3(fallbackPath);
|
|
41573
41701
|
} catch {}
|
|
41574
41702
|
};
|
|
41575
41703
|
if (primary !== null) {
|
|
41576
41704
|
try {
|
|
41577
|
-
|
|
41705
|
+
unlinkSync3(primaryPath);
|
|
41578
41706
|
} catch {}
|
|
41579
41707
|
removeFallback();
|
|
41580
41708
|
return primary;
|
|
@@ -41619,15 +41747,15 @@ function escapeMarkdownV2(s) {
|
|
|
41619
41747
|
}
|
|
41620
41748
|
|
|
41621
41749
|
// active-reactions.ts
|
|
41622
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, renameSync as renameSync3, existsSync as
|
|
41623
|
-
import { join as
|
|
41750
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, renameSync as renameSync3, existsSync as existsSync15, unlinkSync as unlinkSync4 } from "node:fs";
|
|
41751
|
+
import { join as join15 } from "node:path";
|
|
41624
41752
|
var ACTIVE_REACTIONS_FILENAME = ".active-reactions.json";
|
|
41625
41753
|
function reactionsPath(agentDir) {
|
|
41626
|
-
return
|
|
41754
|
+
return join15(agentDir, ACTIVE_REACTIONS_FILENAME);
|
|
41627
41755
|
}
|
|
41628
41756
|
function readActiveReactions(agentDir) {
|
|
41629
41757
|
const p = reactionsPath(agentDir);
|
|
41630
|
-
if (!
|
|
41758
|
+
if (!existsSync15(p))
|
|
41631
41759
|
return [];
|
|
41632
41760
|
let raw;
|
|
41633
41761
|
try {
|
|
@@ -41657,7 +41785,7 @@ function writeActiveReactions(agentDir, reactions) {
|
|
|
41657
41785
|
const p = reactionsPath(agentDir);
|
|
41658
41786
|
if (reactions.length === 0) {
|
|
41659
41787
|
try {
|
|
41660
|
-
|
|
41788
|
+
unlinkSync4(p);
|
|
41661
41789
|
} catch {}
|
|
41662
41790
|
return;
|
|
41663
41791
|
}
|
|
@@ -41682,20 +41810,20 @@ function removeActiveReaction(agentDir, chatId, messageId) {
|
|
|
41682
41810
|
}
|
|
41683
41811
|
function clearActiveReactions(agentDir) {
|
|
41684
41812
|
try {
|
|
41685
|
-
|
|
41813
|
+
unlinkSync4(reactionsPath(agentDir));
|
|
41686
41814
|
} catch {}
|
|
41687
41815
|
}
|
|
41688
41816
|
|
|
41689
41817
|
// active-reactions.ts
|
|
41690
|
-
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync4, existsSync as
|
|
41691
|
-
import { join as
|
|
41818
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync4, existsSync as existsSync16, unlinkSync as unlinkSync5 } from "node:fs";
|
|
41819
|
+
import { join as join16 } from "node:path";
|
|
41692
41820
|
var ACTIVE_REACTIONS_FILENAME2 = ".active-reactions.json";
|
|
41693
41821
|
function reactionsPath2(agentDir) {
|
|
41694
|
-
return
|
|
41822
|
+
return join16(agentDir, ACTIVE_REACTIONS_FILENAME2);
|
|
41695
41823
|
}
|
|
41696
41824
|
function readActiveReactions2(agentDir) {
|
|
41697
41825
|
const p = reactionsPath2(agentDir);
|
|
41698
|
-
if (!
|
|
41826
|
+
if (!existsSync16(p))
|
|
41699
41827
|
return [];
|
|
41700
41828
|
let raw;
|
|
41701
41829
|
try {
|
|
@@ -41723,7 +41851,7 @@ function readActiveReactions2(agentDir) {
|
|
|
41723
41851
|
}
|
|
41724
41852
|
function clearActiveReactions2(agentDir) {
|
|
41725
41853
|
try {
|
|
41726
|
-
|
|
41854
|
+
unlinkSync5(reactionsPath2(agentDir));
|
|
41727
41855
|
} catch {}
|
|
41728
41856
|
}
|
|
41729
41857
|
|
|
@@ -42576,14 +42704,14 @@ async function approvalRecord(args, opts) {
|
|
|
42576
42704
|
}
|
|
42577
42705
|
|
|
42578
42706
|
// quota-check.ts
|
|
42579
|
-
import { readFileSync as readFileSync13, existsSync as
|
|
42580
|
-
import { join as
|
|
42707
|
+
import { readFileSync as readFileSync13, existsSync as existsSync18 } from "fs";
|
|
42708
|
+
import { join as join18 } from "path";
|
|
42581
42709
|
var OAUTH_BETA2 = "oauth-2025-04-20";
|
|
42582
42710
|
var DEFAULT_USER_AGENT2 = "claude-cli/1.0.0 (external, cli)";
|
|
42583
42711
|
var DEFAULT_PROBE_MODEL2 = "claude-haiku-4-5-20251001";
|
|
42584
42712
|
function readOauthToken2(claudeConfigDir) {
|
|
42585
|
-
const tokenFile =
|
|
42586
|
-
if (!
|
|
42713
|
+
const tokenFile = join18(claudeConfigDir, ".oauth-token");
|
|
42714
|
+
if (!existsSync18(tokenFile))
|
|
42587
42715
|
return null;
|
|
42588
42716
|
try {
|
|
42589
42717
|
const raw = readFileSync13(tokenFile, "utf-8").trim();
|
|
@@ -43182,7 +43310,7 @@ init_schema();
|
|
|
43182
43310
|
init_paths();
|
|
43183
43311
|
init_overlay_loader();
|
|
43184
43312
|
init_merge();
|
|
43185
|
-
import { readFileSync as readFileSync14, existsSync as
|
|
43313
|
+
import { readFileSync as readFileSync14, existsSync as existsSync19 } from "node:fs";
|
|
43186
43314
|
import { homedir as homedir8 } from "node:os";
|
|
43187
43315
|
import { resolve as resolve5 } from "node:path";
|
|
43188
43316
|
|
|
@@ -43258,7 +43386,7 @@ function findConfigFile2(startDir) {
|
|
|
43258
43386
|
resolve5(userDir, "clerk.yml")
|
|
43259
43387
|
].filter(Boolean);
|
|
43260
43388
|
for (const path of searchPaths) {
|
|
43261
|
-
if (
|
|
43389
|
+
if (existsSync19(path)) {
|
|
43262
43390
|
return path;
|
|
43263
43391
|
}
|
|
43264
43392
|
}
|
|
@@ -43266,7 +43394,7 @@ function findConfigFile2(startDir) {
|
|
|
43266
43394
|
}
|
|
43267
43395
|
function loadConfig2(configPath) {
|
|
43268
43396
|
const filePath = configPath ?? findConfigFile2();
|
|
43269
|
-
if (!
|
|
43397
|
+
if (!existsSync19(filePath)) {
|
|
43270
43398
|
throw new ConfigError2(`Config file not found: ${filePath}`);
|
|
43271
43399
|
}
|
|
43272
43400
|
let raw;
|
|
@@ -43304,6 +43432,10 @@ function loadConfig2(configPath) {
|
|
|
43304
43432
|
}
|
|
43305
43433
|
applyAgentOverlays(config);
|
|
43306
43434
|
validateAllCronTopicAliases2(config, filePath);
|
|
43435
|
+
const notionIssues = validateNotionWorkspaceConfig(config);
|
|
43436
|
+
if (notionIssues.length > 0) {
|
|
43437
|
+
throw new ConfigError2(`Invalid notion_workspace configuration in ${filePath}`, notionIssues);
|
|
43438
|
+
}
|
|
43307
43439
|
return config;
|
|
43308
43440
|
}
|
|
43309
43441
|
function validateAllCronTopicAliases2(config, filePath) {
|
|
@@ -43695,9 +43827,9 @@ function resolveOutboundTopic(config, event) {
|
|
|
43695
43827
|
}
|
|
43696
43828
|
|
|
43697
43829
|
// ../src/agents/perf.ts
|
|
43698
|
-
import { existsSync as
|
|
43830
|
+
import { existsSync as existsSync20, readFileSync as readFileSync15 } from "node:fs";
|
|
43699
43831
|
function readTurnUsages(jsonlPath, lastN) {
|
|
43700
|
-
if (!
|
|
43832
|
+
if (!existsSync20(jsonlPath))
|
|
43701
43833
|
return [];
|
|
43702
43834
|
if (lastN <= 0)
|
|
43703
43835
|
return [];
|
|
@@ -43841,7 +43973,7 @@ function nextCompactNotify(state3, ev) {
|
|
|
43841
43973
|
}
|
|
43842
43974
|
|
|
43843
43975
|
// gateway/hostd-dispatch.ts
|
|
43844
|
-
import { existsSync as
|
|
43976
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
43845
43977
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
43846
43978
|
|
|
43847
43979
|
// ../src/host-control/client.ts
|
|
@@ -44132,13 +44264,13 @@ function hostdSocketPath(agentName3) {
|
|
|
44132
44264
|
function hostdWillBeUsed(agentName3) {
|
|
44133
44265
|
if (!isHostdEnabled())
|
|
44134
44266
|
return false;
|
|
44135
|
-
return
|
|
44267
|
+
return existsSync21(hostdSocketPath(agentName3));
|
|
44136
44268
|
}
|
|
44137
44269
|
async function tryHostdDispatch(agentName3, req) {
|
|
44138
44270
|
if (!isHostdEnabled())
|
|
44139
44271
|
return "not-configured";
|
|
44140
44272
|
const sockPath = hostdSocketPath(agentName3);
|
|
44141
|
-
if (!
|
|
44273
|
+
if (!existsSync21(sockPath))
|
|
44142
44274
|
return "not-configured";
|
|
44143
44275
|
try {
|
|
44144
44276
|
return await hostdRequest({ socketPath: sockPath, timeoutMs: 5000 }, req);
|
|
@@ -44162,7 +44294,7 @@ async function hostdGetStatusOnce(agentName3, targetRequestId) {
|
|
|
44162
44294
|
if (!isHostdEnabled())
|
|
44163
44295
|
return "not-configured";
|
|
44164
44296
|
const sockPath = hostdSocketPath(agentName3);
|
|
44165
|
-
if (!
|
|
44297
|
+
if (!existsSync21(sockPath))
|
|
44166
44298
|
return "not-configured";
|
|
44167
44299
|
try {
|
|
44168
44300
|
const resp = await hostdRequest({ socketPath: sockPath, timeoutMs: 3000 }, {
|
|
@@ -44183,7 +44315,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
|
|
|
44183
44315
|
if (!isHostdEnabled())
|
|
44184
44316
|
return "not-configured";
|
|
44185
44317
|
const sockPath = hostdSocketPath(agentName3);
|
|
44186
|
-
if (!
|
|
44318
|
+
if (!existsSync21(sockPath))
|
|
44187
44319
|
return "not-configured";
|
|
44188
44320
|
const now = opts.now ?? Date.now;
|
|
44189
44321
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -44261,7 +44393,7 @@ function shouldSweepChatAtBoot(chatId) {
|
|
|
44261
44393
|
}
|
|
44262
44394
|
|
|
44263
44395
|
// gateway/ipc-server.ts
|
|
44264
|
-
import { renameSync as renameSync5, unlinkSync as
|
|
44396
|
+
import { renameSync as renameSync5, unlinkSync as unlinkSync6 } from "fs";
|
|
44265
44397
|
var MAX_BUFFER_SIZE = 1024 * 1024;
|
|
44266
44398
|
var VALID_OPERATOR_KINDS = new Set([
|
|
44267
44399
|
"credentials-expired",
|
|
@@ -44379,7 +44511,7 @@ function createIpcServer(options) {
|
|
|
44379
44511
|
renameSync5(socketPath, socketPath + ".bak");
|
|
44380
44512
|
} catch {}
|
|
44381
44513
|
try {
|
|
44382
|
-
|
|
44514
|
+
unlinkSync6(socketPath + ".bak");
|
|
44383
44515
|
} catch {}
|
|
44384
44516
|
const clients = new Set;
|
|
44385
44517
|
const agentIndex = new Map;
|
|
@@ -46442,7 +46574,7 @@ function escapeBody(s) {
|
|
|
46442
46574
|
}
|
|
46443
46575
|
|
|
46444
46576
|
// gateway/pid-file.ts
|
|
46445
|
-
import { writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as
|
|
46577
|
+
import { writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync7, renameSync as renameSync6 } from "node:fs";
|
|
46446
46578
|
function writePidFile(path, record) {
|
|
46447
46579
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
46448
46580
|
writeFileSync9(tmp, JSON.stringify(record), "utf-8");
|
|
@@ -46450,7 +46582,7 @@ function writePidFile(path, record) {
|
|
|
46450
46582
|
}
|
|
46451
46583
|
function clearPidFile(path) {
|
|
46452
46584
|
try {
|
|
46453
|
-
|
|
46585
|
+
unlinkSync7(path);
|
|
46454
46586
|
} catch {}
|
|
46455
46587
|
}
|
|
46456
46588
|
|
|
@@ -46667,7 +46799,7 @@ function safeCount(fn) {
|
|
|
46667
46799
|
}
|
|
46668
46800
|
|
|
46669
46801
|
// gateway/session-marker.ts
|
|
46670
|
-
import { writeFileSync as writeFileSync10, readFileSync as readFileSync18, renameSync as renameSync7, unlinkSync as
|
|
46802
|
+
import { writeFileSync as writeFileSync10, readFileSync as readFileSync18, renameSync as renameSync7, unlinkSync as unlinkSync8 } from "node:fs";
|
|
46671
46803
|
function writeSessionMarker(path, marker) {
|
|
46672
46804
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
46673
46805
|
writeFileSync10(tmp, JSON.stringify(marker), "utf-8");
|
|
@@ -46697,7 +46829,7 @@ function shouldFireRestartBanner(input) {
|
|
|
46697
46829
|
}
|
|
46698
46830
|
|
|
46699
46831
|
// gateway/clean-shutdown-marker.ts
|
|
46700
|
-
import { writeFileSync as writeFileSync11, readFileSync as readFileSync19, renameSync as renameSync8, unlinkSync as
|
|
46832
|
+
import { writeFileSync as writeFileSync11, readFileSync as readFileSync19, renameSync as renameSync8, unlinkSync as unlinkSync9 } from "node:fs";
|
|
46701
46833
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
46702
46834
|
function writeCleanShutdownMarker(path, marker) {
|
|
46703
46835
|
const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -46721,7 +46853,7 @@ function readCleanShutdownMarker(path) {
|
|
|
46721
46853
|
}
|
|
46722
46854
|
function clearCleanShutdownMarker(path) {
|
|
46723
46855
|
try {
|
|
46724
|
-
|
|
46856
|
+
unlinkSync9(path);
|
|
46725
46857
|
} catch {}
|
|
46726
46858
|
}
|
|
46727
46859
|
function shouldSuppressRecoveryBanner(marker, now, maxAgeMs = DEFAULT_MAX_AGE_MS) {
|
|
@@ -47501,16 +47633,16 @@ function classifyAdminGate(text, myAgentName) {
|
|
|
47501
47633
|
|
|
47502
47634
|
// subagent-watcher.ts
|
|
47503
47635
|
import {
|
|
47504
|
-
existsSync as
|
|
47505
|
-
openSync as
|
|
47636
|
+
existsSync as existsSync23,
|
|
47637
|
+
openSync as openSync3,
|
|
47506
47638
|
readSync,
|
|
47507
47639
|
statSync as statSync6,
|
|
47508
|
-
closeSync as
|
|
47640
|
+
closeSync as closeSync3,
|
|
47509
47641
|
watch,
|
|
47510
47642
|
readdirSync as readdirSync3,
|
|
47511
47643
|
readFileSync as readFileSync21
|
|
47512
47644
|
} from "fs";
|
|
47513
|
-
import { join as
|
|
47645
|
+
import { join as join20 } from "path";
|
|
47514
47646
|
|
|
47515
47647
|
// operator-events.ts
|
|
47516
47648
|
var DEFAULT_OPERATOR_EVENT_COOLDOWN_MS2 = 5 * 60000;
|
|
@@ -47752,29 +47884,29 @@ function bumpSubagentActivity(db2, args) {
|
|
|
47752
47884
|
|
|
47753
47885
|
// gateway/turn-active-marker.ts
|
|
47754
47886
|
import {
|
|
47755
|
-
closeSync,
|
|
47756
|
-
existsSync as
|
|
47887
|
+
closeSync as closeSync2,
|
|
47888
|
+
existsSync as existsSync22,
|
|
47757
47889
|
mkdirSync as mkdirSync10,
|
|
47758
|
-
openSync,
|
|
47890
|
+
openSync as openSync2,
|
|
47759
47891
|
readFileSync as readFileSync20,
|
|
47760
47892
|
statSync as statSync5,
|
|
47761
|
-
unlinkSync as
|
|
47893
|
+
unlinkSync as unlinkSync10,
|
|
47762
47894
|
utimesSync,
|
|
47763
47895
|
writeFileSync as writeFileSync12
|
|
47764
47896
|
} from "node:fs";
|
|
47765
|
-
import { join as
|
|
47897
|
+
import { join as join19 } from "node:path";
|
|
47766
47898
|
var TURN_ACTIVE_MARKER_FILE = "turn-active.json";
|
|
47767
47899
|
function touchTurnActiveMarker(stateDir) {
|
|
47768
|
-
const path =
|
|
47769
|
-
if (!
|
|
47900
|
+
const path = join19(stateDir, TURN_ACTIVE_MARKER_FILE);
|
|
47901
|
+
if (!existsSync22(path))
|
|
47770
47902
|
return;
|
|
47771
47903
|
const now = new Date;
|
|
47772
47904
|
try {
|
|
47773
47905
|
utimesSync(path, now, now);
|
|
47774
47906
|
} catch {
|
|
47775
47907
|
try {
|
|
47776
|
-
const fd =
|
|
47777
|
-
|
|
47908
|
+
const fd = openSync2(path, "r+");
|
|
47909
|
+
closeSync2(fd);
|
|
47778
47910
|
} catch {}
|
|
47779
47911
|
}
|
|
47780
47912
|
}
|
|
@@ -47988,11 +48120,11 @@ function startSubagentWatcher(config) {
|
|
|
47988
48120
|
clearTimeout(ref.ref);
|
|
47989
48121
|
});
|
|
47990
48122
|
const fs2 = config.fs ?? {
|
|
47991
|
-
existsSync:
|
|
48123
|
+
existsSync: existsSync23,
|
|
47992
48124
|
readdirSync: readdirSync3,
|
|
47993
48125
|
statSync: statSync6,
|
|
47994
|
-
openSync:
|
|
47995
|
-
closeSync:
|
|
48126
|
+
openSync: openSync3,
|
|
48127
|
+
closeSync: closeSync3,
|
|
47996
48128
|
readSync,
|
|
47997
48129
|
watch
|
|
47998
48130
|
};
|
|
@@ -48222,8 +48354,8 @@ function startSubagentWatcher(config) {
|
|
|
48222
48354
|
function rescanSubagentDirs() {
|
|
48223
48355
|
if (stopped)
|
|
48224
48356
|
return;
|
|
48225
|
-
const claudeHome =
|
|
48226
|
-
const projectsRoot =
|
|
48357
|
+
const claudeHome = join20(agentDir, ".claude");
|
|
48358
|
+
const projectsRoot = join20(claudeHome, "projects");
|
|
48227
48359
|
if (!fs2.existsSync(projectsRoot))
|
|
48228
48360
|
return;
|
|
48229
48361
|
let projectDirs;
|
|
@@ -48240,7 +48372,7 @@ function startSubagentWatcher(config) {
|
|
|
48240
48372
|
}
|
|
48241
48373
|
continue;
|
|
48242
48374
|
}
|
|
48243
|
-
const projectPath =
|
|
48375
|
+
const projectPath = join20(projectsRoot, pDir);
|
|
48244
48376
|
let sessionDirs;
|
|
48245
48377
|
try {
|
|
48246
48378
|
sessionDirs = fs2.readdirSync(projectPath);
|
|
@@ -48250,7 +48382,7 @@ function startSubagentWatcher(config) {
|
|
|
48250
48382
|
for (const sDir of sessionDirs) {
|
|
48251
48383
|
if (sDir.endsWith(".jsonl"))
|
|
48252
48384
|
continue;
|
|
48253
|
-
const subagentsPath =
|
|
48385
|
+
const subagentsPath = join20(projectPath, sDir, "subagents");
|
|
48254
48386
|
if (!fs2.existsSync(subagentsPath))
|
|
48255
48387
|
continue;
|
|
48256
48388
|
if (!dirWatchers.has(subagentsPath)) {
|
|
@@ -48258,7 +48390,7 @@ function startSubagentWatcher(config) {
|
|
|
48258
48390
|
const w = fs2.watch(subagentsPath, (_event, filename) => {
|
|
48259
48391
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
48260
48392
|
return;
|
|
48261
|
-
const filePath =
|
|
48393
|
+
const filePath = join20(subagentsPath, filename.toString());
|
|
48262
48394
|
if (!knownFiles.has(filePath)) {
|
|
48263
48395
|
scanSubagentsDir(subagentsPath);
|
|
48264
48396
|
}
|
|
@@ -48283,7 +48415,7 @@ function startSubagentWatcher(config) {
|
|
|
48283
48415
|
for (const e of entries) {
|
|
48284
48416
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
48285
48417
|
continue;
|
|
48286
|
-
const filePath =
|
|
48418
|
+
const filePath = join20(subagentsPath, e);
|
|
48287
48419
|
if (knownFiles.has(filePath))
|
|
48288
48420
|
continue;
|
|
48289
48421
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -48400,15 +48532,15 @@ function determineRestartReason(opts) {
|
|
|
48400
48532
|
init_boot_card();
|
|
48401
48533
|
|
|
48402
48534
|
// gateway/update-announce.ts
|
|
48403
|
-
import { existsSync as
|
|
48404
|
-
import { join as
|
|
48535
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync13, openSync as openSync4, closeSync as closeSync4, readFileSync as readFileSync25 } from "node:fs";
|
|
48536
|
+
import { join as join25 } from "node:path";
|
|
48405
48537
|
import { homedir as homedir10 } from "node:os";
|
|
48406
48538
|
|
|
48407
48539
|
// ../src/host-control/audit-reader.ts
|
|
48408
48540
|
import { homedir as homedir9 } from "node:os";
|
|
48409
|
-
import { join as
|
|
48541
|
+
import { join as join24 } from "node:path";
|
|
48410
48542
|
function defaultAuditLogPath(home2 = homedir9()) {
|
|
48411
|
-
return
|
|
48543
|
+
return join24(home2, ".switchroom", "host-control-audit.log");
|
|
48412
48544
|
}
|
|
48413
48545
|
function parseAuditLine(line) {
|
|
48414
48546
|
const trimmed = line.trim();
|
|
@@ -48514,7 +48646,7 @@ function readAndFilter(raw, filters, limit) {
|
|
|
48514
48646
|
var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
|
|
48515
48647
|
function readLastTerminalUpdateAudit(opts = {}) {
|
|
48516
48648
|
const path = opts.auditLogPath ?? defaultAuditLogPath();
|
|
48517
|
-
const exists = opts.exists ??
|
|
48649
|
+
const exists = opts.exists ?? existsSync27;
|
|
48518
48650
|
const readFile = opts.readFile ?? ((p) => readFileSync25(p, "utf-8"));
|
|
48519
48651
|
if (!exists(path))
|
|
48520
48652
|
return null;
|
|
@@ -48576,18 +48708,18 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
48576
48708
|
`);
|
|
48577
48709
|
}
|
|
48578
48710
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
48579
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
48580
|
-
const dir =
|
|
48711
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join25(homedir10(), ".switchroom");
|
|
48712
|
+
const dir = join25(stateDir, "update-announced");
|
|
48581
48713
|
try {
|
|
48582
48714
|
mkdirSync13(dir, { recursive: true });
|
|
48583
48715
|
} catch {
|
|
48584
48716
|
return false;
|
|
48585
48717
|
}
|
|
48586
48718
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
48587
|
-
const path =
|
|
48719
|
+
const path = join25(dir, safeId);
|
|
48588
48720
|
try {
|
|
48589
|
-
const fd =
|
|
48590
|
-
|
|
48721
|
+
const fd = openSync4(path, "wx");
|
|
48722
|
+
closeSync4(fd);
|
|
48591
48723
|
return true;
|
|
48592
48724
|
} catch {
|
|
48593
48725
|
return false;
|
|
@@ -48804,24 +48936,24 @@ function createIssuesCardHandle(opts) {
|
|
|
48804
48936
|
}
|
|
48805
48937
|
|
|
48806
48938
|
// issues-watcher.ts
|
|
48807
|
-
import { existsSync as
|
|
48808
|
-
import { join as
|
|
48939
|
+
import { existsSync as existsSync29, statSync as statSync8 } from "node:fs";
|
|
48940
|
+
import { join as join27 } from "node:path";
|
|
48809
48941
|
|
|
48810
48942
|
// ../src/issues/store.ts
|
|
48811
48943
|
import {
|
|
48812
|
-
closeSync as
|
|
48813
|
-
existsSync as
|
|
48944
|
+
closeSync as closeSync5,
|
|
48945
|
+
existsSync as existsSync28,
|
|
48814
48946
|
mkdirSync as mkdirSync14,
|
|
48815
|
-
openSync as
|
|
48947
|
+
openSync as openSync5,
|
|
48816
48948
|
readdirSync as readdirSync5,
|
|
48817
48949
|
readFileSync as readFileSync27,
|
|
48818
48950
|
renameSync as renameSync10,
|
|
48819
48951
|
statSync as statSync7,
|
|
48820
|
-
unlinkSync as
|
|
48952
|
+
unlinkSync as unlinkSync11,
|
|
48821
48953
|
writeFileSync as writeFileSync16,
|
|
48822
48954
|
writeSync
|
|
48823
48955
|
} from "node:fs";
|
|
48824
|
-
import { join as
|
|
48956
|
+
import { join as join26 } from "node:path";
|
|
48825
48957
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
48826
48958
|
import { execSync } from "node:child_process";
|
|
48827
48959
|
|
|
@@ -48837,8 +48969,8 @@ var SEVERITY_RANK2 = {
|
|
|
48837
48969
|
var ISSUES_FILE = "issues.jsonl";
|
|
48838
48970
|
var ISSUES_LOCK = "issues.lock";
|
|
48839
48971
|
function readAll(stateDir) {
|
|
48840
|
-
const path =
|
|
48841
|
-
if (!
|
|
48972
|
+
const path = join26(stateDir, ISSUES_FILE);
|
|
48973
|
+
if (!existsSync28(path))
|
|
48842
48974
|
return [];
|
|
48843
48975
|
let raw;
|
|
48844
48976
|
try {
|
|
@@ -48874,7 +49006,7 @@ function list(stateDir, opts = {}) {
|
|
|
48874
49006
|
});
|
|
48875
49007
|
}
|
|
48876
49008
|
function resolve6(stateDir, fingerprint, nowFn = Date.now) {
|
|
48877
|
-
if (!
|
|
49009
|
+
if (!existsSync28(join26(stateDir, ISSUES_FILE)))
|
|
48878
49010
|
return 0;
|
|
48879
49011
|
return withLock(stateDir, () => {
|
|
48880
49012
|
const all = readAll(stateDir);
|
|
@@ -48892,7 +49024,7 @@ function resolve6(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
48892
49024
|
});
|
|
48893
49025
|
}
|
|
48894
49026
|
function writeAll(stateDir, events) {
|
|
48895
|
-
const path =
|
|
49027
|
+
const path = join26(stateDir, ISSUES_FILE);
|
|
48896
49028
|
sweepOrphanTmpFiles(stateDir);
|
|
48897
49029
|
const tmp = `${path}.tmp-${process.pid}-${randomBytes4(4).toString("hex")}`;
|
|
48898
49030
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -48914,11 +49046,11 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
48914
49046
|
for (const entry of entries) {
|
|
48915
49047
|
if (!entry.startsWith(TMP_PREFIX))
|
|
48916
49048
|
continue;
|
|
48917
|
-
const tmpPath2 =
|
|
49049
|
+
const tmpPath2 = join26(stateDir, entry);
|
|
48918
49050
|
try {
|
|
48919
49051
|
const stat = statSync7(tmpPath2);
|
|
48920
49052
|
if (stat.mtimeMs < cutoff) {
|
|
48921
|
-
|
|
49053
|
+
unlinkSync11(tmpPath2);
|
|
48922
49054
|
}
|
|
48923
49055
|
} catch {}
|
|
48924
49056
|
}
|
|
@@ -48926,12 +49058,12 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
48926
49058
|
var LOCK_RETRY_MS = 25;
|
|
48927
49059
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
48928
49060
|
function withLock(stateDir, fn) {
|
|
48929
|
-
const lockPath =
|
|
49061
|
+
const lockPath = join26(stateDir, ISSUES_LOCK);
|
|
48930
49062
|
const startedAt = Date.now();
|
|
48931
49063
|
let fd = null;
|
|
48932
49064
|
while (fd === null) {
|
|
48933
49065
|
try {
|
|
48934
|
-
fd =
|
|
49066
|
+
fd = openSync5(lockPath, "wx");
|
|
48935
49067
|
try {
|
|
48936
49068
|
writeSync(fd, String(process.pid));
|
|
48937
49069
|
} catch {}
|
|
@@ -48951,10 +49083,10 @@ function withLock(stateDir, fn) {
|
|
|
48951
49083
|
return fn();
|
|
48952
49084
|
} finally {
|
|
48953
49085
|
try {
|
|
48954
|
-
|
|
49086
|
+
closeSync5(fd);
|
|
48955
49087
|
} catch {}
|
|
48956
49088
|
try {
|
|
48957
|
-
|
|
49089
|
+
unlinkSync11(lockPath);
|
|
48958
49090
|
} catch {}
|
|
48959
49091
|
}
|
|
48960
49092
|
}
|
|
@@ -48968,13 +49100,13 @@ function tryStealStaleLock(lockPath) {
|
|
|
48968
49100
|
const pid = Number(pidStr);
|
|
48969
49101
|
if (!Number.isFinite(pid) || pid <= 0) {
|
|
48970
49102
|
try {
|
|
48971
|
-
|
|
49103
|
+
unlinkSync11(lockPath);
|
|
48972
49104
|
} catch {}
|
|
48973
49105
|
return true;
|
|
48974
49106
|
}
|
|
48975
49107
|
if (pid === process.pid) {
|
|
48976
49108
|
try {
|
|
48977
|
-
|
|
49109
|
+
unlinkSync11(lockPath);
|
|
48978
49110
|
} catch {}
|
|
48979
49111
|
return true;
|
|
48980
49112
|
}
|
|
@@ -48989,7 +49121,7 @@ function tryStealStaleLock(lockPath) {
|
|
|
48989
49121
|
return false;
|
|
48990
49122
|
}
|
|
48991
49123
|
try {
|
|
48992
|
-
|
|
49124
|
+
unlinkSync11(lockPath);
|
|
48993
49125
|
} catch {}
|
|
48994
49126
|
return true;
|
|
48995
49127
|
}
|
|
@@ -49011,7 +49143,7 @@ function isIssueEvent(v) {
|
|
|
49011
49143
|
// issues-watcher.ts
|
|
49012
49144
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
49013
49145
|
function startIssuesWatcher(opts) {
|
|
49014
|
-
const path =
|
|
49146
|
+
const path = join27(opts.stateDir, ISSUES_FILE);
|
|
49015
49147
|
const log = opts.log ?? (() => {});
|
|
49016
49148
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
49017
49149
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -49059,7 +49191,7 @@ function startIssuesWatcher(opts) {
|
|
|
49059
49191
|
};
|
|
49060
49192
|
}
|
|
49061
49193
|
function defaultSignatureProvider(path) {
|
|
49062
|
-
if (!
|
|
49194
|
+
if (!existsSync29(path))
|
|
49063
49195
|
return null;
|
|
49064
49196
|
try {
|
|
49065
49197
|
const stat = statSync8(path);
|
|
@@ -49299,8 +49431,8 @@ function skillBasenameFromPath2(input) {
|
|
|
49299
49431
|
}
|
|
49300
49432
|
|
|
49301
49433
|
// credits-watch.ts
|
|
49302
|
-
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, existsSync as
|
|
49303
|
-
import { join as
|
|
49434
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, existsSync as existsSync30, mkdirSync as mkdirSync15 } from "fs";
|
|
49435
|
+
import { join as join28 } from "path";
|
|
49304
49436
|
var STATE_FILE = "credits-watch.json";
|
|
49305
49437
|
var FATAL_REASONS = new Set([
|
|
49306
49438
|
"out_of_credits",
|
|
@@ -49312,8 +49444,8 @@ function emptyCreditState() {
|
|
|
49312
49444
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
49313
49445
|
}
|
|
49314
49446
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
49315
|
-
const path =
|
|
49316
|
-
if (!
|
|
49447
|
+
const path = join28(claudeConfigDir, ".claude.json");
|
|
49448
|
+
if (!existsSync30(path))
|
|
49317
49449
|
return null;
|
|
49318
49450
|
let raw;
|
|
49319
49451
|
try {
|
|
@@ -49397,8 +49529,8 @@ function escapeHtml10(s) {
|
|
|
49397
49529
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
49398
49530
|
}
|
|
49399
49531
|
function loadCreditState(stateDir) {
|
|
49400
|
-
const path =
|
|
49401
|
-
if (!
|
|
49532
|
+
const path = join28(stateDir, STATE_FILE);
|
|
49533
|
+
if (!existsSync30(path))
|
|
49402
49534
|
return emptyCreditState();
|
|
49403
49535
|
try {
|
|
49404
49536
|
const raw = readFileSync28(path, "utf-8");
|
|
@@ -49414,54 +49546,54 @@ function loadCreditState(stateDir) {
|
|
|
49414
49546
|
}
|
|
49415
49547
|
function saveCreditState(stateDir, state4) {
|
|
49416
49548
|
mkdirSync15(stateDir, { recursive: true });
|
|
49417
|
-
const path =
|
|
49549
|
+
const path = join28(stateDir, STATE_FILE);
|
|
49418
49550
|
writeFileSync17(path, JSON.stringify(state4, null, 2) + `
|
|
49419
49551
|
`, { mode: 384 });
|
|
49420
49552
|
}
|
|
49421
49553
|
|
|
49422
49554
|
// gateway/turn-active-marker.ts
|
|
49423
49555
|
import {
|
|
49424
|
-
closeSync as
|
|
49425
|
-
existsSync as
|
|
49556
|
+
closeSync as closeSync6,
|
|
49557
|
+
existsSync as existsSync31,
|
|
49426
49558
|
mkdirSync as mkdirSync16,
|
|
49427
|
-
openSync as
|
|
49559
|
+
openSync as openSync6,
|
|
49428
49560
|
readFileSync as readFileSync29,
|
|
49429
49561
|
statSync as statSync9,
|
|
49430
|
-
unlinkSync as
|
|
49562
|
+
unlinkSync as unlinkSync12,
|
|
49431
49563
|
utimesSync as utimesSync2,
|
|
49432
49564
|
writeFileSync as writeFileSync18
|
|
49433
49565
|
} from "node:fs";
|
|
49434
|
-
import { join as
|
|
49566
|
+
import { join as join29 } from "node:path";
|
|
49435
49567
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
49436
49568
|
function writeTurnActiveMarker(stateDir, marker) {
|
|
49437
49569
|
try {
|
|
49438
49570
|
mkdirSync16(stateDir, { recursive: true });
|
|
49439
|
-
writeFileSync18(
|
|
49571
|
+
writeFileSync18(join29(stateDir, TURN_ACTIVE_MARKER_FILE2), JSON.stringify(marker, null, 2) + `
|
|
49440
49572
|
`, { mode: 384 });
|
|
49441
49573
|
} catch {}
|
|
49442
49574
|
}
|
|
49443
49575
|
function touchTurnActiveMarker2(stateDir) {
|
|
49444
|
-
const path =
|
|
49445
|
-
if (!
|
|
49576
|
+
const path = join29(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
49577
|
+
if (!existsSync31(path))
|
|
49446
49578
|
return;
|
|
49447
49579
|
const now = new Date;
|
|
49448
49580
|
try {
|
|
49449
49581
|
utimesSync2(path, now, now);
|
|
49450
49582
|
} catch {
|
|
49451
49583
|
try {
|
|
49452
|
-
const fd =
|
|
49453
|
-
|
|
49584
|
+
const fd = openSync6(path, "r+");
|
|
49585
|
+
closeSync6(fd);
|
|
49454
49586
|
} catch {}
|
|
49455
49587
|
}
|
|
49456
49588
|
}
|
|
49457
49589
|
function removeTurnActiveMarker(stateDir) {
|
|
49458
49590
|
try {
|
|
49459
|
-
|
|
49591
|
+
unlinkSync12(join29(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
49460
49592
|
} catch {}
|
|
49461
49593
|
}
|
|
49462
49594
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
49463
|
-
const path =
|
|
49464
|
-
if (!
|
|
49595
|
+
const path = join29(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
49596
|
+
if (!existsSync31(path))
|
|
49465
49597
|
return false;
|
|
49466
49598
|
const now = opts.now ?? Date.now();
|
|
49467
49599
|
try {
|
|
@@ -49475,7 +49607,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
49475
49607
|
try {
|
|
49476
49608
|
payload = readFileSync29(path, "utf8");
|
|
49477
49609
|
} catch {}
|
|
49478
|
-
|
|
49610
|
+
unlinkSync12(path);
|
|
49479
49611
|
if (opts.onRemove) {
|
|
49480
49612
|
try {
|
|
49481
49613
|
opts.onRemove({
|
|
@@ -49492,10 +49624,10 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
49492
49624
|
}
|
|
49493
49625
|
|
|
49494
49626
|
// ../src/build-info.ts
|
|
49495
|
-
var VERSION = "0.13.
|
|
49496
|
-
var COMMIT_SHA = "
|
|
49497
|
-
var COMMIT_DATE = "2026-05-
|
|
49498
|
-
var LATEST_PR =
|
|
49627
|
+
var VERSION = "0.13.56";
|
|
49628
|
+
var COMMIT_SHA = "821a114e";
|
|
49629
|
+
var COMMIT_DATE = "2026-05-27T20:20:37Z";
|
|
49630
|
+
var LATEST_PR = 1923;
|
|
49499
49631
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
49500
49632
|
|
|
49501
49633
|
// gateway/boot-version.ts
|
|
@@ -49569,11 +49701,11 @@ init_peercred();
|
|
|
49569
49701
|
import * as net4 from "node:net";
|
|
49570
49702
|
import * as fs2 from "node:fs";
|
|
49571
49703
|
import { homedir as homedir11 } from "node:os";
|
|
49572
|
-
import { join as
|
|
49704
|
+
import { join as join30 } from "node:path";
|
|
49573
49705
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
49574
49706
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
49575
|
-
var LEGACY_SOCKET_PATH2 =
|
|
49576
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
49707
|
+
var LEGACY_SOCKET_PATH2 = join30(homedir11(), ".switchroom", "vault-broker.sock");
|
|
49708
|
+
var OPERATOR_SOCKET_PATH2 = join30(homedir11(), ".switchroom", "broker-operator", "sock");
|
|
49577
49709
|
function defaultBrokerSocketPath2() {
|
|
49578
49710
|
if (fs2.existsSync(OPERATOR_SOCKET_PATH2))
|
|
49579
49711
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -49796,7 +49928,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
49796
49928
|
|
|
49797
49929
|
// registry/turns-schema.ts
|
|
49798
49930
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync17 } from "fs";
|
|
49799
|
-
import { join as
|
|
49931
|
+
import { join as join31 } from "path";
|
|
49800
49932
|
var DatabaseClass2 = null;
|
|
49801
49933
|
function loadDatabaseClass2() {
|
|
49802
49934
|
if (DatabaseClass2 != null)
|
|
@@ -49855,9 +49987,9 @@ function applySchema(db2) {
|
|
|
49855
49987
|
}
|
|
49856
49988
|
function openTurnsDb(agentDir) {
|
|
49857
49989
|
const Database = loadDatabaseClass2();
|
|
49858
|
-
const dir =
|
|
49990
|
+
const dir = join31(agentDir, "telegram");
|
|
49859
49991
|
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
49860
|
-
const path =
|
|
49992
|
+
const path = join31(dir, "registry.db");
|
|
49861
49993
|
const db2 = new Database(path, { create: true });
|
|
49862
49994
|
applySchema(db2);
|
|
49863
49995
|
try {
|
|
@@ -49998,11 +50130,11 @@ installGlobalErrorHandlers();
|
|
|
49998
50130
|
process.on("beforeExit", () => {
|
|
49999
50131
|
shutdownAnalytics();
|
|
50000
50132
|
});
|
|
50001
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
50002
|
-
var ACCESS_FILE =
|
|
50003
|
-
var APPROVED_DIR =
|
|
50004
|
-
var ENV_FILE =
|
|
50005
|
-
var INBOX_DIR =
|
|
50133
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join33(homedir12(), ".claude", "channels", "telegram");
|
|
50134
|
+
var ACCESS_FILE = join33(STATE_DIR, "access.json");
|
|
50135
|
+
var APPROVED_DIR = join33(STATE_DIR, "approved");
|
|
50136
|
+
var ENV_FILE = join33(STATE_DIR, ".env");
|
|
50137
|
+
var INBOX_DIR = join33(STATE_DIR, "inbox");
|
|
50006
50138
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
50007
50139
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
50008
50140
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -50193,7 +50325,7 @@ function assertSendable(f) {
|
|
|
50193
50325
|
} catch {
|
|
50194
50326
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
50195
50327
|
}
|
|
50196
|
-
const inbox =
|
|
50328
|
+
const inbox = join33(stateReal, "inbox");
|
|
50197
50329
|
if (real.startsWith(stateReal + sep3) && !real.startsWith(inbox + sep3)) {
|
|
50198
50330
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
50199
50331
|
}
|
|
@@ -50299,7 +50431,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
50299
50431
|
if (HISTORY_ENABLED) {
|
|
50300
50432
|
try {
|
|
50301
50433
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
50302
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
50434
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join33(STATE_DIR, "history.db")}
|
|
50303
50435
|
`);
|
|
50304
50436
|
} catch (err) {
|
|
50305
50437
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -50316,10 +50448,10 @@ try {
|
|
|
50316
50448
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s) as ended_via='restart'
|
|
50317
50449
|
`);
|
|
50318
50450
|
} else {
|
|
50319
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
50451
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join33(agentDir, "telegram", "registry.db")}
|
|
50320
50452
|
`);
|
|
50321
50453
|
}
|
|
50322
|
-
const pendingEnvPath =
|
|
50454
|
+
const pendingEnvPath = join33(agentDir, ".pending-turn.env");
|
|
50323
50455
|
try {
|
|
50324
50456
|
const pending2 = findMostRecentInterruptedTurn(turnsDb);
|
|
50325
50457
|
if (pending2 != null) {
|
|
@@ -50339,7 +50471,7 @@ try {
|
|
|
50339
50471
|
renameSync12(pendingEnvTmp, pendingEnvPath);
|
|
50340
50472
|
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
50341
50473
|
`);
|
|
50342
|
-
} else if (
|
|
50474
|
+
} else if (existsSync35(pendingEnvPath)) {
|
|
50343
50475
|
rmSync4(pendingEnvPath, { force: true });
|
|
50344
50476
|
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
50345
50477
|
`);
|
|
@@ -50393,7 +50525,7 @@ function checkApprovals() {
|
|
|
50393
50525
|
return;
|
|
50394
50526
|
}
|
|
50395
50527
|
for (const senderId of files) {
|
|
50396
|
-
const file =
|
|
50528
|
+
const file = join33(APPROVED_DIR, senderId);
|
|
50397
50529
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync4(file, { force: true }), (err) => {
|
|
50398
50530
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
50399
50531
|
`);
|
|
@@ -51270,11 +51402,11 @@ var unpinProgressCardForChat = null;
|
|
|
51270
51402
|
var getPinnedProgressCardMessageId = null;
|
|
51271
51403
|
var completeProgressCardTurn = null;
|
|
51272
51404
|
var subagentWatcher = null;
|
|
51273
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
51405
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join33(STATE_DIR, "gateway.sock");
|
|
51274
51406
|
mkdirSync21(STATE_DIR, { recursive: true, mode: 448 });
|
|
51275
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
51276
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
51277
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
51407
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join33(STATE_DIR, "gateway.pid.json");
|
|
51408
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join33(STATE_DIR, "gateway-session.json");
|
|
51409
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join33(STATE_DIR, "clean-shutdown.json");
|
|
51278
51410
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
51279
51411
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
51280
51412
|
var activeBootCard = null;
|
|
@@ -51303,7 +51435,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
51303
51435
|
bot: botApi,
|
|
51304
51436
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
51305
51437
|
`),
|
|
51306
|
-
persistPath:
|
|
51438
|
+
persistPath: join33(stateDir, "issues-card.json")
|
|
51307
51439
|
});
|
|
51308
51440
|
activeIssuesWatcher = startIssuesWatcher({
|
|
51309
51441
|
stateDir,
|
|
@@ -51347,6 +51479,21 @@ startTimer({
|
|
|
51347
51479
|
emitMetric: (event) => {
|
|
51348
51480
|
emitRuntimeMetric(event);
|
|
51349
51481
|
},
|
|
51482
|
+
onAwarenessPing: async (ctx) => {
|
|
51483
|
+
if (activeTurnStartedAt.get(ctx.key) == null && currentTurn == null) {
|
|
51484
|
+
return;
|
|
51485
|
+
}
|
|
51486
|
+
const text = formatFrameworkFallbackText(ctx.fallbackKind, ctx.silenceMs, ctx.inFlightTools);
|
|
51487
|
+
try {
|
|
51488
|
+
await robustApiCall(() => bot.api.sendMessage(ctx.chatId, text, {
|
|
51489
|
+
...ctx.threadId != null ? { message_thread_id: ctx.threadId } : {},
|
|
51490
|
+
disable_notification: true
|
|
51491
|
+
}), { chat_id: ctx.chatId, ...ctx.threadId != null ? { threadId: ctx.threadId } : {} });
|
|
51492
|
+
} catch (err) {
|
|
51493
|
+
process.stderr.write(`silence-poke awareness-ping sendMessage failed chat=${ctx.chatId} thread=${ctx.threadId}: ${err}
|
|
51494
|
+
`);
|
|
51495
|
+
}
|
|
51496
|
+
},
|
|
51350
51497
|
onFrameworkFallback: async (ctx) => {
|
|
51351
51498
|
if (activeTurnStartedAt.get(ctx.key) == null && currentTurn == null) {
|
|
51352
51499
|
process.stderr.write(`telegram gateway: silence-poke framework-fallback late-fire skipped \u2014 ` + `turn ended cleanly during silence window chat=${ctx.chatId} thread=${ctx.threadId ?? "-"} silence_ms=${ctx.silenceMs}
|
|
@@ -51395,7 +51542,6 @@ startTimer({
|
|
|
51395
51542
|
longest_silent_gap_ms: outboundMetrics.longestOutboundGapMs,
|
|
51396
51543
|
ended_via: "framework_fallback"
|
|
51397
51544
|
});
|
|
51398
|
-
clear(fbKey);
|
|
51399
51545
|
}
|
|
51400
51546
|
if (turnsDb != null && turnMatchesFallback && wedgedTurn?.registryKey != null) {
|
|
51401
51547
|
const _turnKey = wedgedTurn.registryKey;
|
|
@@ -51458,13 +51604,13 @@ startTimer2({
|
|
|
51458
51604
|
}
|
|
51459
51605
|
});
|
|
51460
51606
|
var inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
51461
|
-
path:
|
|
51607
|
+
path: join33(STATE_DIR, "inbound-spool.jsonl"),
|
|
51462
51608
|
fs: {
|
|
51463
51609
|
appendFileSync: (p, d) => appendFileSync3(p, d),
|
|
51464
51610
|
readFileSync: (p) => readFileSync32(p, "utf8"),
|
|
51465
51611
|
writeFileSync: (p, d) => writeFileSync21(p, d),
|
|
51466
51612
|
renameSync: (a, b) => renameSync12(a, b),
|
|
51467
|
-
existsSync: (p) =>
|
|
51613
|
+
existsSync: (p) => existsSync35(p),
|
|
51468
51614
|
statSizeSync: (p) => statSync13(p).size
|
|
51469
51615
|
}
|
|
51470
51616
|
});
|
|
@@ -52277,6 +52423,12 @@ ${url}`;
|
|
|
52277
52423
|
});
|
|
52278
52424
|
noteOutbound(statusKey(chat_id, threadId), Date.now());
|
|
52279
52425
|
noteOutbound2(statusKey(chat_id, threadId), Date.now());
|
|
52426
|
+
try {
|
|
52427
|
+
markAckSent();
|
|
52428
|
+
} catch (err) {
|
|
52429
|
+
process.stderr.write(`telegram gateway: markAckSent failed: ${err}
|
|
52430
|
+
`);
|
|
52431
|
+
}
|
|
52280
52432
|
if (isFinalAnswerReply({ text: rawText, disableNotification })) {
|
|
52281
52433
|
clearSilentEndState(statusKey(chat_id, threadId));
|
|
52282
52434
|
}
|
|
@@ -52604,6 +52756,12 @@ async function executeStreamReply(args) {
|
|
|
52604
52756
|
const sKey = statusKey(streamChatId, streamThreadId);
|
|
52605
52757
|
noteOutbound(sKey, Date.now());
|
|
52606
52758
|
noteOutbound2(sKey, Date.now());
|
|
52759
|
+
try {
|
|
52760
|
+
markAckSent();
|
|
52761
|
+
} catch (err) {
|
|
52762
|
+
process.stderr.write(`telegram gateway: markAckSent (stream_reply) failed: ${err}
|
|
52763
|
+
`);
|
|
52764
|
+
}
|
|
52607
52765
|
if (isFinalAnswerReply({
|
|
52608
52766
|
text: args.text ?? "",
|
|
52609
52767
|
disableNotification: args.disable_notification === true,
|
|
@@ -52954,10 +53112,10 @@ async function executeSendGif(rawArgs) {
|
|
|
52954
53112
|
};
|
|
52955
53113
|
}
|
|
52956
53114
|
async function publishToTelegraph(text, shortName, authorName) {
|
|
52957
|
-
const accountPath =
|
|
53115
|
+
const accountPath = join33(STATE_DIR, "telegraph-account.json");
|
|
52958
53116
|
let account = null;
|
|
52959
53117
|
try {
|
|
52960
|
-
if (
|
|
53118
|
+
if (existsSync35(accountPath)) {
|
|
52961
53119
|
const raw = readFileSync32(accountPath, "utf-8");
|
|
52962
53120
|
const parsed = JSON.parse(raw);
|
|
52963
53121
|
if (parsed.shortName && parsed.accessToken) {
|
|
@@ -53450,6 +53608,7 @@ function handleSessionEvent(ev) {
|
|
|
53450
53608
|
if (ev.chatId) {
|
|
53451
53609
|
const enqThreadId = ev.threadId != null ? Number(ev.threadId) : undefined;
|
|
53452
53610
|
clearPending(statusKey(ev.chatId, enqThreadId), "handback");
|
|
53611
|
+
clearAckSent();
|
|
53453
53612
|
}
|
|
53454
53613
|
if (ev.chatId) {
|
|
53455
53614
|
const prior = currentTurn;
|
|
@@ -54907,7 +55066,7 @@ function restartMarkerPath() {
|
|
|
54907
55066
|
const agentDir = resolveAgentDirFromEnv();
|
|
54908
55067
|
if (!agentDir)
|
|
54909
55068
|
return null;
|
|
54910
|
-
return
|
|
55069
|
+
return join33(agentDir, "restart-pending.json");
|
|
54911
55070
|
}
|
|
54912
55071
|
function writeRestartMarker(marker) {
|
|
54913
55072
|
const p = restartMarkerPath();
|
|
@@ -55031,7 +55190,7 @@ var _dockerReachable;
|
|
|
55031
55190
|
function isDockerReachable() {
|
|
55032
55191
|
if (_dockerReachable !== undefined)
|
|
55033
55192
|
return _dockerReachable;
|
|
55034
|
-
if (!
|
|
55193
|
+
if (!existsSync35("/var/run/docker.sock")) {
|
|
55035
55194
|
_dockerReachable = false;
|
|
55036
55195
|
return _dockerReachable;
|
|
55037
55196
|
}
|
|
@@ -55048,11 +55207,11 @@ function _resetDockerReachableCache() {
|
|
|
55048
55207
|
}
|
|
55049
55208
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
55050
55209
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
55051
|
-
const logPath =
|
|
55210
|
+
const logPath = join33(STATE_DIR, "detached-spawn.log");
|
|
55052
55211
|
let outFd = null;
|
|
55053
55212
|
try {
|
|
55054
55213
|
mkdirSync21(STATE_DIR, { recursive: true });
|
|
55055
|
-
outFd =
|
|
55214
|
+
outFd = openSync9(logPath, "a");
|
|
55056
55215
|
writeFileSync21(logPath, `
|
|
55057
55216
|
[${new Date().toISOString()}] spawn ${SWITCHROOM_CLI} ${fullArgs.join(" ")}
|
|
55058
55217
|
`, { flag: "a" });
|
|
@@ -55067,7 +55226,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
55067
55226
|
});
|
|
55068
55227
|
if (outFd != null) {
|
|
55069
55228
|
try {
|
|
55070
|
-
|
|
55229
|
+
closeSync9(outFd);
|
|
55071
55230
|
} catch {}
|
|
55072
55231
|
}
|
|
55073
55232
|
if (onFailure) {
|
|
@@ -55421,8 +55580,8 @@ bot.use(async (ctx, next) => {
|
|
|
55421
55580
|
});
|
|
55422
55581
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
55423
55582
|
try {
|
|
55424
|
-
const auditPath =
|
|
55425
|
-
if (!
|
|
55583
|
+
const auditPath = join33(homedir12(), ".switchroom", "vault-audit.log");
|
|
55584
|
+
if (!existsSync35(auditPath))
|
|
55426
55585
|
return [];
|
|
55427
55586
|
const raw = readFileSync32(auditPath, "utf8");
|
|
55428
55587
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
@@ -55475,7 +55634,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
55475
55634
|
try {
|
|
55476
55635
|
const agentDir = resolveAgentDirFromEnv();
|
|
55477
55636
|
if (agentDir) {
|
|
55478
|
-
const raw = readFileSync32(
|
|
55637
|
+
const raw = readFileSync32(join33(agentDir, ".claude", ".claude.json"), "utf8");
|
|
55479
55638
|
claudeJson = JSON.parse(raw);
|
|
55480
55639
|
}
|
|
55481
55640
|
} catch {}
|
|
@@ -55689,10 +55848,10 @@ bot.command("restart", async (ctx) => {
|
|
|
55689
55848
|
function flushAgentHandoff(agentDir) {
|
|
55690
55849
|
let removed = 0;
|
|
55691
55850
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
55692
|
-
const p =
|
|
55851
|
+
const p = join33(agentDir, fname);
|
|
55693
55852
|
try {
|
|
55694
|
-
if (
|
|
55695
|
-
|
|
55853
|
+
if (existsSync35(p)) {
|
|
55854
|
+
unlinkSync15(p);
|
|
55696
55855
|
removed++;
|
|
55697
55856
|
}
|
|
55698
55857
|
} catch (err) {
|
|
@@ -55747,7 +55906,7 @@ async function handleNewOrResetCommand(ctx, kind) {
|
|
|
55747
55906
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
55748
55907
|
if (agentDir != null) {
|
|
55749
55908
|
try {
|
|
55750
|
-
writeFileSync21(
|
|
55909
|
+
writeFileSync21(join33(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
55751
55910
|
`, "utf8");
|
|
55752
55911
|
} catch (err) {
|
|
55753
55912
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -56108,14 +56267,14 @@ bot.command("interrupt", async (ctx) => {
|
|
|
56108
56267
|
var lockoutOps = {
|
|
56109
56268
|
readFileSync: (p, enc) => readFileSync32(p, enc),
|
|
56110
56269
|
writeFileSync: (p, data, opts) => writeFileSync21(p, data, opts),
|
|
56111
|
-
existsSync: (p) =>
|
|
56270
|
+
existsSync: (p) => existsSync35(p),
|
|
56112
56271
|
mkdirSync: (p, opts) => mkdirSync21(p, opts),
|
|
56113
|
-
joinPath: (...parts) =>
|
|
56272
|
+
joinPath: (...parts) => join33(...parts)
|
|
56114
56273
|
};
|
|
56115
56274
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
56116
56275
|
function isAuthBrokerSocketReachable() {
|
|
56117
56276
|
try {
|
|
56118
|
-
return
|
|
56277
|
+
return existsSync35(resolveAuthBrokerSocketPath2());
|
|
56119
56278
|
} catch {
|
|
56120
56279
|
return false;
|
|
56121
56280
|
}
|
|
@@ -56176,7 +56335,7 @@ async function runCreditWatch() {
|
|
|
56176
56335
|
if (!agentDir)
|
|
56177
56336
|
return;
|
|
56178
56337
|
const agentName3 = getMyAgentName();
|
|
56179
|
-
const claudeConfigDir =
|
|
56338
|
+
const claudeConfigDir = join33(agentDir, ".claude");
|
|
56180
56339
|
const stateDir = STATE_DIR;
|
|
56181
56340
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
56182
56341
|
const prev = loadCreditState(stateDir);
|
|
@@ -56386,9 +56545,9 @@ async function handleVaultRecentDenialCallback(ctx, data) {
|
|
|
56386
56545
|
return;
|
|
56387
56546
|
}
|
|
56388
56547
|
const { token, id } = result;
|
|
56389
|
-
const tokenPath =
|
|
56548
|
+
const tokenPath = join33(homedir12(), ".switchroom", "agents", agentName3, ".vault-token");
|
|
56390
56549
|
try {
|
|
56391
|
-
mkdirSync21(
|
|
56550
|
+
mkdirSync21(join33(homedir12(), ".switchroom", "agents", agentName3), { recursive: true });
|
|
56392
56551
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
56393
56552
|
} catch (err) {
|
|
56394
56553
|
await switchroomReply(ctx, `<b>Grant created (${escapeHtmlForTg(id)}) but token write failed:</b> ${escapeHtmlForTg(String(err))}
|
|
@@ -56465,9 +56624,9 @@ async function performVaultAccessApproval(ctx, pending2, stageId, senderId, atte
|
|
|
56465
56624
|
return;
|
|
56466
56625
|
}
|
|
56467
56626
|
const { token, id } = result;
|
|
56468
|
-
const tokenPath =
|
|
56627
|
+
const tokenPath = join33(homedir12(), ".switchroom", "agents", pending2.agent, ".vault-token");
|
|
56469
56628
|
try {
|
|
56470
|
-
mkdirSync21(
|
|
56629
|
+
mkdirSync21(join33(homedir12(), ".switchroom", "agents", pending2.agent), { recursive: true });
|
|
56471
56630
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
56472
56631
|
} catch (err) {
|
|
56473
56632
|
await switchroomReply(ctx, `<b>Grant created (${escapeHtmlForTg(id)}) but token write failed:</b> ${escapeHtmlForTg(String(err))}
|
|
@@ -56943,9 +57102,9 @@ async function executeGrantWizard(ctx, chatId, state4) {
|
|
|
56943
57102
|
return;
|
|
56944
57103
|
}
|
|
56945
57104
|
const { token, id } = result;
|
|
56946
|
-
const tokenPath =
|
|
57105
|
+
const tokenPath = join33(homedir12(), ".switchroom", "agents", state4.agent, ".vault-token");
|
|
56947
57106
|
try {
|
|
56948
|
-
mkdirSync21(
|
|
57107
|
+
mkdirSync21(join33(homedir12(), ".switchroom", "agents", state4.agent), { recursive: true });
|
|
56949
57108
|
writeFileSync21(tokenPath, token, { mode: 384 });
|
|
56950
57109
|
} catch (err) {
|
|
56951
57110
|
await switchroomReply(ctx, `<b>Grant created but token write failed:</b> ${escapeHtmlForTg(String(err))}`, { html: true });
|
|
@@ -57803,7 +57962,7 @@ bot.command("usage", async (ctx) => {
|
|
|
57803
57962
|
await switchroomReply(ctx, "<b>/usage:</b> cannot resolve agent dir.", { html: true });
|
|
57804
57963
|
return;
|
|
57805
57964
|
}
|
|
57806
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
57965
|
+
const result = await fetchQuota2({ claudeConfigDir: join33(agentDir, ".claude") });
|
|
57807
57966
|
if (!result.ok) {
|
|
57808
57967
|
await switchroomReply(ctx, `<b>/usage:</b> ${escapeHtmlForTg(result.reason)}`, { html: true });
|
|
57809
57968
|
return;
|
|
@@ -58348,7 +58507,7 @@ async function maybeTranscribeVoice(fileId, mimeType, language) {
|
|
|
58348
58507
|
let apiKey = null;
|
|
58349
58508
|
try {
|
|
58350
58509
|
const path = __require("path").join(__require("os").homedir(), ".switchroom", "openai-api-key");
|
|
58351
|
-
if (
|
|
58510
|
+
if (existsSync35(path)) {
|
|
58352
58511
|
apiKey = readFileSync32(path, "utf-8").trim();
|
|
58353
58512
|
}
|
|
58354
58513
|
} catch (err) {
|
|
@@ -59209,7 +59368,7 @@ var didOneTimeSetup = false;
|
|
|
59209
59368
|
agentName: agentDisplayName,
|
|
59210
59369
|
agentSlug,
|
|
59211
59370
|
version: formatBootVersion(),
|
|
59212
|
-
agentDir: agentDir ??
|
|
59371
|
+
agentDir: agentDir ?? join33(homedir12(), ".switchroom", "agents", agentSlug),
|
|
59213
59372
|
gatewayInfo: { pid: process.pid, startedAtMs: GATEWAY_STARTED_AT_MS },
|
|
59214
59373
|
restartReason: reason,
|
|
59215
59374
|
restartAgeMs: markerAgeMs,
|